misc/fullpatfnc.s
;========================================================================================
;  fullpatfnc.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	control2.mac
	.include	doscall.mac
	.include	fnc.equ
	.include	iocscall.mac
	.include	sprc.equ

;インフォメーションテーブル
information_table:
	.dc.l	init_routine		;初期化ルーチン
	.dc.l	run_routine		;RUNルーチン
	.dc.l	end_routine		;ENDルーチン
	.dc.l	system_routine		;SYSTEM/EXITルーチン
	.dc.l	break_routine		;BREAK/CTRL+Cルーチン
	.dc.l	ctrld_routine		;CTRL+D(外部関数初期化)ルーチン
	.dcb.l	2,reserved		;予約
	.dc.l	token_table		;トークンテーブル
	.dc.l	param_table		;パラメータテーブル
	.dc.l	func_table		;実行アドレステーブル
	.dcb.l	5,0			;空き

;初期化ルーチン
init_routine:
;RUNルーチン
run_routine:
;ENDルーチン
end_routine:
;SYSTEM/EXITルーチン
system_routine:
;BREAK/CTRL+Cルーチン
break_routine:
;予約
reserved:
	rts

;CTRL+D(外部関数初期化)ルーチン
ctrld_routine:
	IOCS	_SP_OFF
	rts

;トークンテーブル
token_table:
	.dc.b	'bg_fill',0
	.dc.b	'bg_get',0
	.dc.b	'bg_put',0
	.dc.b	'bg_scroll',0
	.dc.b	'bg_set',0
	.dc.b	'bg_stat',0
	.dc.b	'sp_clr',0
	.dc.b	'sp_color',0
	.dc.b	'sp_def',0
	.dc.b	'sp_disp',0
	.dc.b	'sp_init',0
	.dc.b	'sp_move',0
	.dc.b	'sp_off',0
	.dc.b	'sp_on',0
	.dc.b	'sp_pat',0
	.dc.b	'sp_set',0
	.dc.b	'sp_stat',0
	.dc.b	'sp_wait',0
	.dc.b	0
	.even

;パラメータテーブル
param_table:
	.dc.l	param_bg_fill
	.dc.l	param_bg_get
	.dc.l	param_bg_put
	.dc.l	param_bg_scroll
	.dc.l	param_bg_set
	.dc.l	param_bg_stat
	.dc.l	param_sp_clr
	.dc.l	param_sp_color
	.dc.l	param_sp_def
	.dc.l	param_sp_disp
	.dc.l	param_sp_init
	.dc.l	param_sp_move
	.dc.l	param_sp_off
	.dc.l	param_sp_on
	.dc.l	param_sp_pat
	.dc.l	param_sp_set
	.dc.l	param_sp_stat
	.dc.l	param_sp_wait

;実行アドレステーブル
func_table:
	.dc.l	func_bg_fill
	.dc.l	func_bg_get
	.dc.l	func_bg_put
	.dc.l	func_bg_scroll
	.dc.l	func_bg_set
	.dc.l	func_bg_stat
	.dc.l	func_sp_clr
	.dc.l	func_sp_color
	.dc.l	func_sp_def
	.dc.l	func_sp_disp
	.dc.l	func_sp_init
	.dc.l	func_sp_move
	.dc.l	func_sp_off
	.dc.l	func_sp_on
	.dc.l	func_sp_pat
	.dc.l	func_sp_set
	.dc.l	func_sp_stat
	.dc.l	func_sp_wait

;----------------------------------------------------------------
;int bg_fill(char t,int c)
;	バックグラウンドテキストをキャラクタで埋め尽くします。
;	t	テキスト番号。0~3
;	c	キャラクタ。0~65535
param_bg_fill:
	.dc.w	P_CHAR
	.dc.w	P_INT
	.dc.w	R_INT
func_bg_fill:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=テキスト番号。0~3
	goto	<cmp.b #3,d1>,hi,text_number_error
	move.l	P2_INT(sp),d2		;d2=キャラクタ。0~65535
	goto	<cmp.l #65535,d2>,hi,character_error
	IOCS	_BGTEXTCL
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int bg_get(char t,char x,char y)
;	バックグラウンドテキストからキャラクタを読み出します。
;	t	テキスト番号。0~3
;	x	X座標。0~63
;	y	Y座標。0~63
;	戻り値	キャラクタ。0~65535
param_bg_get:
	.dc.w	P_CHAR
	.dc.w	P_CHAR
	.dc.w	P_CHAR
	.dc.w	R_INT
func_bg_get:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=テキスト番号。0~3
	goto	<cmp.b #3,d1>,hi,text_number_error
	moveq.l	#0,d2
	move.b	P2_CHAR(sp),d2		;d2=X座標。0~63
	goto	<cmp.b #63,d2>,hi,x_error_64
	moveq.l	#0,d3
	move.b	P3_CHAR(sp),d3		;d3=Y座標。0~63
	goto	<cmp.b #63,d3>,hi,y_error_64
	IOCS	_BGTEXTGT
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_d0

;----------------------------------------------------------------
;int bg_put(char t,char x,char y,int c)
;	バックグラウンドテキストにキャラクタを書き込みます。
;	t	テキスト番号。0~3
;	x	X座標。0~63
;	y	Y座標。0~63
;	c	キャラクタ。0~65535
param_bg_put:
	.dc.w	P_CHAR
	.dc.w	P_CHAR
	.dc.w	P_CHAR
	.dc.w	P_INT
	.dc.w	R_INT
func_bg_put:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=テキスト番号。0~3
	goto	<cmp.b #3,d1>,hi,text_number_error
	moveq.l	#0,d2
	move.b	P2_CHAR(sp),d2		;d2=X座標。0~63
	goto	<cmp.b #63,d2>,hi,x_error_64
	moveq.l	#0,d3
	move.b	P3_CHAR(sp),d3		;d3=Y座標。0~63
	goto	<cmp.b #63,d3>,hi,y_error_64
	move.l	P4_INT(sp),d4		;d4=キャラクタ。0~65535
	goto	<cmp.l #65535,d4>,hi,character_error
	IOCS	_BGTEXTST
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int bg_scroll(char b,[int x],[int y],[char v])
;	バックグラウンドスクロールレジスタを設定します。
;	b	バックグラウンド番号。0~1
;	x	X座標。0~1023。省略すると変更しない
;	y	Y座標。0~1023。省略すると変更しない
;	v	VDISPの立ち下がり。0=待つ,1=待たない。省略すると1
param_bg_scroll:
	.dc.w	P_CHAR
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_CHAR
	.dc.w	R_INT
func_bg_scroll:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=バックグラウンド番号。0~1
	goto	<cmp.b #1,d1>,hi,background_number_error
	lea.l	SPRC_RESOLUTION,a1
	IOCS	_B_WPEEK
	and.w	#3,d0
	if	eq			;256x256
		moveq.l	#-1,d2			;省略すると変更しない
		if	<tst.w P2_TYPE(sp)>,pl
			move.l	P2_INT(sp),d2		;d2=X座標。0~1023
			goto	<cmp.l #511,d2>,hi,x_error_512
		endif
		moveq.l	#-1,d3			;省略すると変更しない
		if	<tst.w P3_TYPE(sp)>,pl
			move.l	P3_INT(sp),d3		;d3=Y座標。0~1023
			goto	<cmp.l #511,d3>,hi,y_error_512
		endif
	else				;512x512
		moveq.l	#-1,d2			;省略すると変更しない
		if	<tst.w P2_TYPE(sp)>,pl
			move.l	P2_INT(sp),d2		;d2=X座標。0~1023
			goto	<cmp.l #1023,d2>,hi,x_error_1024
		endif
		moveq.l	#-1,d3			;省略すると変更しない
		if	<tst.w P3_TYPE(sp)>,pl
			move.l	P3_INT(sp),d3		;d3=Y座標。0~1023
			goto	<cmp.l #1023,d3>,hi,y_error_1024
		endif
	endif
	moveq.l	#1,d4			;省略すると1
	if	<tst.w P4_TYPE(sp)>,pl
		move.b	P4_CHAR(sp),d4		;d4=VDISPの立ち下がり。0=待つ,1=待たない
		goto	<cmp.b #1,d4>,hi,vdisp_error
	endif
	ror.l	#1,d4
	or.l	d4,d1
	IOCS	_BGSCRLST
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int bg_set(char b[,char t,char d])
;	バックグラウンド制御レジスタを設定します。
;	b	バックグラウンド番号。0~1
;	t	テキスト番号。0~3。省略すると変更しない
;	d	表示の有無。0~1。省略すると変更しない
param_bg_set:
	.dc.w	P_CHAR
	.dc.w	P_OPT|P_CHAR
	.dc.w	P_OPT|P_CHAR
	.dc.w	R_INT
func_bg_set:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=バックグラウンド番号。0~1
	goto	<cmp.b #1,d1>,hi,background_number_error
	moveq.l	#-1,d2			;省略すると変更しない
	if	<tst.w P2_TYPE(sp)>,pl
		moveq.l	#0,d2
		move.b	P2_CHAR(sp),d2		;d2=テキスト番号。0~3
		goto	<cmp.b #3,d2>,hi,text_number_error
	endif
	moveq.l	#-1,d3			;省略すると変更しない
	if	<tst.w P3_TYPE(sp)>,pl
		moveq.l	#0,d3
		move.b	P3_CHAR(sp),d3		;d3=表示の有無。0~1
		goto	<cmp.b #1,d3>,hi,display_error
	endif
  .if 1
	ifand	<tst.b d1>,ne,<tst.l d3>,gt	;バックグラウンド1を表示
		lea.l	SPRC_RESOLUTION,a1
		IOCS	_B_WPEEK
		and.w	#3,d0
		goto	ne,background_1_error
	endif
  .endif
	IOCS	_BGCTRLST
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int bg_stat(char b,char m)
;	バックグラウンドスクロールレジスタまたはバックグラウンド制御レジスタを取得します。
;	b	バックグラウンド番号。0~1
;	m	モード。0~3
;		0	X座標。0~1023
;		1	Y座標。0~1023
;		2	テキスト番号。0~3
;		3	表示の有無。0~1
;	戻り値	取得した値
param_bg_stat:
	.dc.w	P_CHAR
	.dc.w	P_CHAR
	.dc.w	R_INT
func_bg_stat:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=バックグラウンド番号。0~1
	goto	<cmp.b #1,d1>,hi,background_number_error
	move.b	P2_CHAR(sp),d0		;d0=モード。0~3
	if	eq			;0 X座標。0~1023
		IOCS	_BGSCRLGT
		goto	<tst.l d0>,mi,screen_mode_error
		move.l	d2,d0
		goto	return_d0
	endif
	subq.b	#2,d0
	if	lo			;1 Y座標。0~1023
		IOCS	_BGSCRLGT
		goto	<tst.l d0>,mi,screen_mode_error
		move.l	d3,d0
		goto	return_d0
	endif
	if	eq			;2 テキスト番号。0~3
		IOCS	_BGCTRLGT
		goto	<tst.l d0>,mi,screen_mode_error
		lsr.l	#1,d0
		goto	return_d0
	endif
	subq.b	#2,d0
	if	lo			;3 表示の有無。0~1
		IOCS	_BGCTRLGT
		goto	<tst.l d0>,mi,screen_mode_error
		moveq.l	#1,d1
		and.l	d1,d0
		goto	return_d0
	endif
	goto	mode_error_4

;----------------------------------------------------------------
;int sp_clr([int p1],[int p2])
;	パターンをゼロクリアします。
;	p1	開始パターン番号。0~511。省略すると0から
;	p2	終了パターン番号。0~511。省略するとp1のみ、両方省略すると511まで
param_sp_clr:
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_INT
	.dc.w	R_INT
func_sp_clr:
	moveq.l	#-1,d2
	if	<tst.w P1_TYPE(sp)>,pl
		move.l	P1_INT(sp),d2		;d2=開始パターン番号。0~511
		goto	<cmp.l #511,d2>,hi,pattern_number_error
	endif
	moveq.l	#-1,d3
	if	<tst.w P2_TYPE(sp)>,pl
		move.l	P2_INT(sp),d3		;d3=終了パターン番号。0~511
		goto	<cmp.l #511,d3>,hi,pattern_number_error
	endif
	if	<tst.l d2>,mi		;開始パターン番号を省略すると
		moveq.l	#0,d2			;0から
		if	<tst.l d3>,mi		;両方省略すると
			move.l	#511,d3			;511まで
		endif
	elif	<tst.l d3>,mi		;終了パターン番号を省略すると
		move.l	d2,d3			;開始パターン番号のみ
	endif
	if	<cmp.l d3,d2>,hi	;終了パターン番号<開始パターン番号のときは
		exg.l	d2,d3			;入れ替える
	endif
	move.l	d2,d1
	sub.w	d2,d3
	for	d3
		IOCS	_SP_CGCLR
		goto	<tst.l d0>,mi,screen_mode_error
		addq.w	#1,d1
	next
	goto	return_zero

;----------------------------------------------------------------
;int sp_color(char p,[int c],[char b],[char v])
;	スプライトパレットを設定または取得します。
;	p	パレットコード。0~15
;	c	カラーコード。0~65535。省略すると取得のみ
;	b	パレットブロック。1~15。省略すると1
;	v	VDISPの立ち下がり。0=待つ,1=待たない。省略すると1
;	戻り値	設定前のカラーコード
param_sp_color:
	.dc.w	P_CHAR
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_CHAR
	.dc.w	P_OPT|P_CHAR
	.dc.w	R_INT
func_sp_color:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=パレットコード。0~15
	goto	<cmp.b #15,d1>,hi,palet_code_error
	moveq.l	#-1,d3			;省略すると取得のみ
	if	<tst.w P2_TYPE(sp)>,pl
		move.l	P2_INT(sp),d3		;d3=カラーコード。0~65535
		goto	<cmp.l #65535,d3>,hi,color_code_error
	endif
	moveq.l	#1,d2			;省略すると1
	if	<tst.w P3_TYPE(sp)>,pl
		moveq.l	#0,d2
		move.b	P3_CHAR(sp),d2		;d2=パレットブロック。1~15
		gotoor	<>,eq,<cmp.b #15,d2>,hi,palet_block_error
	endif
	moveq.l	#1,d4			;省略すると1
	if	<tst.w P4_TYPE(sp)>,pl
	;	moveq.l	#0,d4
		move.b	P4_CHAR(sp),d4		;d4=VDISPの立ち下がり。0=待つ,1=待たない
		goto	<cmp.b #1,d4>,hi,vdisp_error
	endif
	ror.l	#1,d4
	or.l	d4,d1
	IOCS	_SPALET
	goto	return_d0

;----------------------------------------------------------------
;int sp_def(int p,char/int(a),[char s],[int o])
;	パターンを設定します。
;	p	パターン番号。0~511
;	a	データの配列
;	s	サイズ。0=8x8,1=16x16。省略すると1
;	o	オフセット。省略すると0
param_sp_def:
	.dc.w	P_INT
	.dc.w	P_DIM1|P_PTR|P_CHAR|P_INT
	.dc.w	P_OPT|P_CHAR
	.dc.w	P_OPT|P_INT
	.dc.w	R_INT
func_sp_def:
	move.l	P1_INT(sp),d1		;d1=パターン番号。0~511
	goto	<cmp.l #511,d1>,hi,pattern_number_error
	movea.l	P2_INT(sp),a2		;a2=データの配列
	moveq.l	#1,d2			;省略すると1
	if	<tst.w P3_TYPE(sp)>,pl
	;	moveq.l	#0,d2
		move.b	P3_CHAR(sp),d2		;d2=サイズ。0=8x8,1=16x16
		goto	<cmp.b #1,d2>,hi,pattern_size_error
	endif
	moveq.l	#0,d3			;省略すると0
	if	<tst.w P4_TYPE(sp)>,pl
		move.l	P4_INT(sp),d3		;d3=オフセット
		goto	<cmp.l #65535,d3>,hi,offset_error
	endif
	lea.l	D1_DATA(a2),a0		;a0=データの先頭
	moveq.l	#0,d0
	move.w	D1_IMAX(a2),d0		;d0=配列の最大要素番号
	if	<tst.b d2>,eq		;8x8
		if	<cmpi.w #1,D1_UNIT(a2)>,eq	;char()
			moveq.l	#8*8-1,d4
			add.l	d3,d4			;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lea.l	-32(sp),sp
			adda.l	d3,a0			;配列の開始位置
			movea.l	sp,a1			;バッファの開始位置
			moveq.l	#4*8-1,d3
			for	d3
				move.w	(a0)+,d0		;.H.L
				lsl.b	#4,d0			;.HL_
				lsr.w	#4,d0			;_.HL
				move.b	d0,(a1)+		;HL
			next
			movea.l	sp,a1
			IOCS	_SP_DEFCG
			lea.l	32(sp),sp
		else				;int()
			move.l	d3,d4
			addq.l	#8-1,d4			;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lsl.l	#2,d3
			lea.l	(a0,d3.l),a1		;配列の開始位置
			IOCS	_SP_DEFCG
		endif
	else				;16x16
		if	<cmpi.w #1,D1_UNIT(a2)>,eq	;char()
			move.l	d3,d4
			add.l	#16*16-1,d4		;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lea.l	-128(sp),sp
			lsl.l	#2,d3
			adda.l	d3,a0			;配列の開始位置
			movea.l	sp,a1			;バッファの開始位置
			moveq.l	#16-1,d3
			for	d3
				moveq.l	#4-1,d4
				for	d4
					move.w	(a0)+,d0		;.H.L
					lsl.b	#4,d0			;.HL_
					lsr.w	#4,d0			;_.HL
					move.b	d0,(a1)+		;HL
					move.w	8-2(a0),d0		;.H.L
					lsl.b	#4,d0			;.HL_
					lsr.w	#4,d0			;_.HL
					move.b	d0,64-1(a1)		;HL
				next
				addq.l	#8,a0
			next
			movea.l	sp,a1
			IOCS	_SP_DEFCG
			lea.l	128(sp),sp
		else				;int()
			moveq.l	#32-1,d4
			add.l	d3,d4			;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lsl.l	#2,d3
			lea.l	(a0,d3.l),a1		;配列の開始位置
			IOCS	_SP_DEFCG
		endif
	endif
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int sp_disp(char m)
;	スプライト画面を表示するか選択します。
;	m	モード。0~1
;		0	表示しない
;		1	表示する
param_sp_disp:
	.dc.w	P_CHAR
	.dc.w	R_INT
func_sp_disp:
	move.b	P1_CHAR(sp),d0		;d0=モード。0~1
	if	eq			;0 表示しない
		IOCS	_SP_OFF
		goto	return_zero
	endif
	subq.b	#2,d0
	if	lo			;1 表示する
		IOCS	_SP_ON
		goto	<tst.l d0>,mi,screen_mode_error
		goto	return_zero
	endif
	goto	mode_error_2

;----------------------------------------------------------------
;int sp_init()
;	スプライト・バックグラウンドを初期化します。
param_sp_init:
	.dc.w	R_INT
func_sp_init:
  .if 1
	lea.l	4*($100+_SP_INIT).w,a1
	IOCS	_B_LPEEK
	movea.l	d0,a1
	subq.l	#8,a1
	IOCS	_B_LPEEK
	goto	<cmpi.l #'FLPT',d0>,ne,fullpat_error
  .endif
	IOCS	_SP_INIT
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int sp_move(char s,[int x],[int y],[int p])
;	スプライトスクロールレジスタを設定します。
;	s	スプライト番号。0~127
;	x	X座標。-16~1007。省略すると変更しない
;	y	Y座標。-16~1007。省略すると変更しない
;	p	パターン番号。0~511。省略すると変更しない
param_sp_move:
	.dc.w	P_CHAR
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_INT
	.dc.w	R_INT
func_sp_move:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=スプライト番号。0~127
	goto	<tst.b d1>,mi,sprite_number_error
	moveq.l	#-1,d2			;省略すると変更しない
	if	<tst.w P2_TYPE(sp)>,pl
		moveq.l	#16,d2
		add.l	P2_INT(sp),d2		;d2=X座標。-16~1007
		goto	<cmp.l #1023,d2>,hi,x_error_1008
	endif
	moveq.l	#-1,d3			;省略すると変更しない
	if	<tst.w P3_TYPE(sp)>,pl
		moveq.l	#16,d3
		add.l	P3_INT(sp),d3		;d3=Y座標。-16~1007
		goto	<cmp.l #1023,d3>,hi,y_error_1008
	endif
	moveq.l	#-1,d4			;省略すると変更しない
	moveq.l	#-1,d5
	if	<tst.w P4_TYPE(sp)>,pl
		move.l	P4_INT(sp),d4		;d4=パターン番号。0~511
		goto	<cmp.l #511,d4>,hi,pattern_number_error
		moveq.l	#3,d5			;d5=プライオリティは3
		bset.l	#8,d4			;パレットブロックは1、反転なし
		if	ne
			addq.b	#4,d5			;キャラクタbit8→プライオリティbit2
		endif
	endif
	bset.l	#31,d1			;VDISPの立ち下がりを待たない
	IOCS	_SP_REGST
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int sp_off([char s1],[char s2])
;	スプライトを表示しません。
;	s1	開始スプライト番号。0~127。省略すると0から
;	s2	終了スプライト番号。0~127。省略するとs1のみ、両方省略すると127まで
param_sp_off:
	.dc.w	P_OPT|P_CHAR
	.dc.w	P_OPT|P_CHAR
	.dc.w	R_INT
func_sp_off:
	moveq.l	#-1,d6
	if	<tst.w P1_TYPE(sp)>,pl
		moveq.l	#0,d6
		move.b	P1_CHAR(sp),d6		;d6=開始スプライト番号。0~127
		goto	<tst.b d6>,mi,sprite_number_error
	endif
	moveq.l	#-1,d7
	if	<tst.w P2_TYPE(sp)>,pl
		moveq.l	#0,d7
		move.b	P2_CHAR(sp),d7		;d7=終了スプライト番号。0~127
		goto	<tst.b d7>,mi,sprite_number_error
	endif
	if	<tst.l d6>,mi		;開始スプライト番号を省略すると
		moveq.l	#0,d6			;0から
		if	<tst.l d7>,mi		;両方省略すると
			moveq.l	#127,d7			;127まで
		endif
	elif	<tst.l d7>,mi		;終了スプライト番号を省略すると
		move.l	d6,d7			;開始スプライト番号のみ
	endif
	if	<cmp.l d7,d6>,hi	;終了スプライト番号<開始スプライト番号のときは
		exg.l	d6,d7			;入れ替える
	endif
	move.l	d6,d1
	bset.l	#31,d1			;VDISPの立ち下がりを待たない
	sub.w	d6,d7
	for	d7
		IOCS	_SP_REGGT
		goto	<tst.l d0>,mi,screen_mode_error
		and.b	#.notb.3,d5		;優先順位を0にする
		IOCS	_SP_REGST
		addq.w	#1,d1
	next
	goto	return_zero

;----------------------------------------------------------------
;int sp_on([char s1],[char s2])
;	スプライトを表示します。
;	s1	開始スプライト番号。0~127。省略すると0から
;	s2	終了スプライト番号。0~127。省略するとs1のみ、両方省略すると127まで
param_sp_on:
	.dc.w	P_OPT|P_CHAR
	.dc.w	P_OPT|P_CHAR
	.dc.w	R_INT
func_sp_on:
	moveq.l	#-1,d6
	if	<tst.w P1_TYPE(sp)>,pl
		moveq.l	#0,d6
		move.b	P1_CHAR(sp),d6		;d6=開始スプライト番号。0~127
		goto	<tst.b d6>,mi,sprite_number_error
	endif
	moveq.l	#-1,d7
	if	<tst.w P2_TYPE(sp)>,pl
		moveq.l	#0,d7
		move.b	P2_CHAR(sp),d7		;d7=終了スプライト番号。0~127
		goto	<tst.b d7>,mi,sprite_number_error
	endif
	if	<tst.l d6>,mi		;開始スプライト番号を省略すると
		moveq.l	#0,d6			;0から
		if	<tst.l d7>,mi		;両方省略すると
			moveq.l	#127,d7			;127まで
		endif
	elif	<tst.l d7>,mi		;終了スプライト番号を省略すると
		move.l	d6,d7			;開始スプライト番号のみ
	endif
	if	<cmp.l d7,d6>,hi	;終了スプライト番号<開始スプライト番号のときは
		exg.l	d6,d7			;入れ替える
	endif
	move.l	d6,d1
	bset.l	#31,d1			;VDISPの立ち下がりを待たない
	sub.w	d6,d7
	for	d7
		IOCS	_SP_REGGT
		goto	<tst.l d0>,mi,screen_mode_error
		or.b	#3,d5			;優先順位を3にする
		IOCS	_SP_REGST
		addq.w	#1,d1
	next
	goto	return_zero

;----------------------------------------------------------------
;int sp_pat(int p,char/int(a),[char s],[int o])
;	パターンを取得します。
;	p	パターン番号。0~511
;	a	データの配列
;	s	サイズ。0=8x8,1=16x16。省略すると1
;	o	オフセット。省略すると0
param_sp_pat:
	.dc.w	P_INT
	.dc.w	P_DIM1|P_PTR|P_CHAR|P_INT
	.dc.w	P_OPT|P_CHAR
	.dc.w	P_OPT|P_INT
	.dc.w	R_INT
func_sp_pat:
	move.l	P1_INT(sp),d1		;d1=パターン番号。0~511
	goto	<cmp.l #511,d1>,hi,pattern_number_error
	movea.l	P2_INT(sp),a2		;a2=データの配列
	moveq.l	#1,d2			;省略すると1
	if	<tst.w P3_TYPE(sp)>,pl
	;	moveq.l	#0,d2
		move.b	P3_CHAR(sp),d2		;d2=サイズ。0=8x8,1=16x16
		goto	<cmp.b #1,d2>,hi,pattern_size_error
	endif
	moveq.l	#0,d3			;省略すると0
	if	<tst.w P4_TYPE(sp)>,pl
		move.l	P4_INT(sp),d3		;d3=オフセット
		goto	<cmp.l #65535,d3>,hi,offset_error
	endif
	lea.l	D1_DATA(a2),a0		;a0=データの先頭
	moveq.l	#0,d0
	move.w	D1_IMAX(a2),d0		;d0=配列の最大要素番号
	if	<tst.b d2>,eq		;8x8
		if	<cmpi.w #1,D1_UNIT(a2)>,eq	;char()
			moveq.l	#8*8-1,d4
			add.l	d3,d4			;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lea.l	-32(sp),sp
			movea.l	sp,a1
			IOCS	_SP_GTPCG
			adda.l	d3,a0			;配列の開始位置
			movea.l	sp,a1			;バッファの開始位置
			moveq.l	#4*8-1,d3
			for	d3
				clr.w	d0			;____
				move.b	(a1)+,d0		;__HL
				lsl.w	#4,d0			;_HL_
				lsr.b	#4,d0			;_H_L
				move.w	d0,(a0)+		;_H_L
			next
			lea.l	32(sp),sp
		else				;int()
			move.l	d3,d4
			addq.l	#8-1,d4			;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lsl.l	#2,d3
			lea.l	(a0,d3.l),a1		;配列の開始位置
			IOCS	_SP_GTPCG
		endif
	else				;16x16
		if	<cmpi.w #1,D1_UNIT(a2)>,eq	;char()
			move.l	d3,d4
			add.l	#16*16-1,d4		;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lea.l	-128(sp),sp
			movea.l	sp,a1
			IOCS	_SP_GTPCG
			lsl.l	#2,d3
			adda.l	d3,a0			;配列の開始位置
			movea.l	sp,a1			;バッファの開始位置
			moveq.l	#16-1,d3
			for	d3
				moveq.l	#4-1,d4
				for	d4
					clr.w	d0			;____
					move.b	(a1)+,d0		;__HL
					lsl.w	#4,d0			;_HL_
					lsr.b	#4,d0			;_H_L
					move.w	d0,(a0)+		;_H_L
					clr.w	d0			;____
					move.b	64-1(a1),d0		;__HL
					lsl.w	#4,d0			;_HL_
					lsr.b	#4,d0			;_H_L
					move.w	d0,8-2(a0)		;_H_L
				next
				addq.l	#8,a0
			next
			lea.l	128(sp),sp
		else				;int()
			moveq.l	#32-1,d4
			add.l	d3,d4			;d4=参照する最大要素番号
			goto	<cmp.l d0,d4>,hi,array_size_error
			lsl.l	#2,d3
			lea.l	(a0,d3.l),a1		;配列の開始位置
			IOCS	_SP_GTPCG
		endif
	endif
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int sp_set(char s,[int x],[int y],[int c],[char p],[char v])
;	スプライトスクロールレジスタを設定します。
;	s	スプライト番号。0~127
;	x	X座標。-16~1007。省略すると変更しない
;	y	Y座標。-16~1007。省略すると変更しない
;	c	キャラクタ。0~65535。省略すると変更しない
;	p	プライオリティ。0~7。省略すると変更しない
;	v	VDISPの立ち下がり。0=待つ,1=待たない。省略すると1
param_sp_set:
	.dc.w	P_CHAR
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_INT
	.dc.w	P_OPT|P_CHAR
	.dc.w	P_OPT|P_CHAR
	.dc.w	R_INT
func_sp_set:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=スプライト番号。0~127
	goto	<tst.b d1>,mi,sprite_number_error
	moveq.l	#-1,d2			;省略すると変更しない
	if	<tst.w P2_TYPE(sp)>,pl
		move.l	P2_INT(sp),d2		;d2=X座標。0~1023
		goto	<cmp.l #1023,d2>,hi,x_error_1024
	endif
	moveq.l	#-1,d3			;省略すると変更しない
	if	<tst.w P3_TYPE(sp)>,pl
		move.l	P3_INT(sp),d3		;d3=Y座標。0~1023
		goto	<cmp.l #1023,d3>,hi,y_error_1024
	endif
	moveq.l	#-1,d4			;省略すると変更しない
	if	<tst.w P4_TYPE(sp)>,pl
		move.l	P4_INT(sp),d4		;d4=キャラクタ。0~65535
		goto	<cmp.l #65535,d4>,hi,character_error
	endif
	moveq.l	#-1,d5			;省略すると変更しない
	if	<tst.w P5_TYPE(sp)>,pl
		moveq.l	#0,d5
		move.b	P5_CHAR(sp),d5		;d5=プライオリティ。0~7
		goto	<cmp.b #7,d5>,hi,priority_error
	endif
	moveq.l	#1,d6			;省略すると1
	if	<tst.w P6_TYPE(sp)>,pl
	;	moveq.l	#0,d6
		move.b	P6_CHAR(sp),d6		;d6=VDISPの立ち下がり。0=待つ,1=待たない
		goto	<cmp.b #1,d6>,hi,vdisp_error
	endif
	ror.l	#1,d6
	or.l	d6,d1
	IOCS	_SP_REGST
	goto	<tst.l d0>,mi,screen_mode_error
	goto	return_zero

;----------------------------------------------------------------
;int sp_stat(char s,char m)
;	スプライトスクロールレジスタを取得します。
;	s	スプライト番号。0~127
;	m	モード。0~3
;		0	X座標。0~1023
;		1	Y座標。0~1023
;		2	キャラクタ。0~65535
;		3	プライオリティ。0~7
;	戻り値	取得した値
param_sp_stat:
	.dc.w	P_CHAR
	.dc.w	P_CHAR
	.dc.w	R_INT
func_sp_stat:
	moveq.l	#0,d1
	move.b	P1_CHAR(sp),d1		;d1=スプライト番号。0~127
	goto	<tst.b d1>,mi,sprite_number_error
	IOCS	_SP_REGGT
	goto	<tst.l d0>,mi,screen_mode_error
	move.b	P2_CHAR(sp),d0		;d0=モード。0~3
	if	eq			;0 X座標。0~1023
		move.l	d2,d0
		goto	return_d0
	endif
	subq.b	#2,d0
	if	lo			;1 Y座標。0~1023
		move.l	d3,d0
		goto	return_d0
	endif
	if	eq			;2 キャラクタ。0~65535
		move.l	d4,d0
		goto	return_d0
	endif
	subq.b	#2,d0
	if	lo			;3 プライオリティ。0~7
		move.l	d5,d0
		goto	return_d0
	endif
	goto	mode_error_4

;----------------------------------------------------------------
;int sp_wait([char n])
;	VDISPの立ち下がりを待ちます。
;	n	回数。省略すると1
param_sp_wait:
	.dc.w	P_OPT|P_CHAR
	.dc.w	R_INT
func_sp_wait:
	moveq.l	#1,d4			;省略すると1
	if	<tst.w P1_TYPE(sp)>,pl
		move.b	P1_CHAR(sp),d4		;d4=回数
	endif
	forcontinue	d4
		moveq.l	#0,d1
		moveq.l	#-1,d2
		moveq.l	#-1,d3
		IOCS	_BGSCRLST
		goto	<tst.l d0>,mi,screen_mode_error
	next
	goto	return_zero

;----------------------------------------------------------------
;戻り値0で正常終了
return_zero:
	moveq.l	#0,d0
;正常終了
;<d0.l:戻り値
return_d0:
	lea.l	return_value(pc),a0	;戻り値。voidのときは不要
	move.l	d0,R1_INT(a0)		;戻り値
	moveq.l	#0,d0			;終了コードは0。エラーメッセージは不要
	rts

;----------------------------------------------------------------
;エラー終了
;<d0.l:エラーコード。0以外。負はDOSコールエラー
;<a1.l:エラーメッセージ。DOSコールエラーのときは不要
;	5はCTRL+E 現在のカーソル以降1行を消す
error_exit:
	lea.l	return_value(pc),a0	;戻り値。voidのときは不要
	move.l	d0,R1_INT(a0)		;error offのときの戻り値。エラーコード
	rts

array_size_error:
	moveq.l	#1,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'配列のサイズが範囲外です',5,0
	.even

background_1_error:
	moveq.l	#2,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'現在の画面モードではバックグラウンド1を表示できません',5,0
	.even

background_number_error:
	moveq.l	#3,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'バックグラウンド番号が0~1の範囲外です',5,0
	.even

character_error:
	moveq.l	#4,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'キャラクタが0~65535の範囲外です',5,0
	.even

color_code_error:
	moveq.l	#5,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'カラーコードが0~65535の範囲外です',5,0
	.even

display_error:
	moveq.l	#6,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'表示の有無が0~1の範囲外です',5,0
	.even

fullpat_error:
	moveq.l	#7,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'fullpat.xが組み込まれていません',5,0
	.even

mode_error_2:
	moveq.l	#8,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'モードが0~1の範囲外です',5,0
	.even

mode_error_4:
	moveq.l	#9,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'モードが0~3の範囲外です',5,0
	.even

offset_error:
	moveq.l	#10,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'配列のオフセットが範囲外です',5,0
	.even

palet_block_error:
	moveq.l	#11,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'パレットブロックが1~15の範囲外です',5,0
	.even

palet_code_error:
	moveq.l	#12,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'パレットコードが0~15の範囲外です',5,0
	.even

pattern_number_error:
	moveq.l	#13,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'パターン番号が0~511の範囲外です',5,0
	.even

pattern_size_error:
	moveq.l	#14,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'パターンサイズが0~1の範囲外です',5,0
	.even

priority_error:
	moveq.l	#15,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'プライオリティが0~7の範囲外です',5,0
	.even

screen_mode_error:
	moveq.l	#16,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'現在の画面モードではスプライト画面を使用できません',5,0
	.even

sprite_number_error:
	moveq.l	#17,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'スプライト番号が0~127の範囲外です',5,0
	.even

text_number_error:
	moveq.l	#18,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'テキスト番号が0~3の範囲外です',5,0
	.even

vdisp_error:
	moveq.l	#19,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'VDISPの立ち下がりが0~1の範囲外です',5,0
	.even

x_error_64:
	moveq.l	#20,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'X座標が0~63の範囲外です',5,0
	.even

x_error_512:
	moveq.l	#21,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'X座標が0~511の範囲外です',5,0
	.even

x_error_1008:
	moveq.l	#22,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'X座標が-16~1007の範囲外です',5,0
	.even

x_error_1024:
	moveq.l	#23,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'X座標が0~1023の範囲外です',5,0
	.even

y_error_64:
	moveq.l	#24,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'Y座標が0~63の範囲外です',5,0
	.even

y_error_512:
	moveq.l	#25,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'Y座標が0~511の範囲外です',5,0
	.even

y_error_1008:
	moveq.l	#26,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'Y座標が-16~1007の範囲外です',5,0
	.even

y_error_1024:
	moveq.l	#27,d0
	lea.l	@f(pc),a1
	goto	error_exit
@@:	.dc.b	'Y座標が0~511の範囲外です',5,0
	.even

;----------------------------------------------------------------
	.bss
	.even

;戻り値。voidのときは不要
return_value:
	.ds.b	R1_SIZE