misc/stupsnd.s- Source code ソースコード - XEiJ - STUDIO KAMADA
misc/stupsnd.s

    ;========================================================================================
    ;  stupsnd.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/
    ;========================================================================================

    ;----------------------------------------------------------------------------------------
    ;	stupsnd.x
    ;		X68030以上とIPLROM 1.6の起動音をon/offする
    ;	オプション
    ;		off
    ;			起動音を鳴らさない
    ;		on
    ;			起動音をキーコード76(o5c)で鳴らす
    ;		2..127
    ;		$02..$7F
    ;		o5cなど
    ;			起動音を指定されたキーコードで鳴らす
    ;		play
    ;			今すぐ起動音を再生する
    ;			FM音源ドライバを外しておくこと
    ;	音色パラメータ
    ;		kc,kf,tm,va[0],...,va[54]
    ;			音色パラメータを指定する
    ;			kc	キーコード
    ;			kf	キーフラクション
    ;			tm	キーオンからキーオフまでの時間(単位は1万分の1秒)
    ;			va	OPMDRV.Xと共通の音色パラメータ
    ;		save
    ;			レジスタデータをstupsnd.datに保存する
    ;			起動音に反映させるには、データをIPLROM 1.6へ埋め込む必要がある
    ;----------------------------------------------------------------------------------------

    TITLE	reg	'stupsnd.x (2025-04-13)'

    	.include	control2.mac
    	.include	doscall.mac
    	.include	fefunc.mac
    	.include	iocscall.mac
    	.include	mfp.equ
    	.include	misc.mac
    	.include	push2.mac
    	.include	sram.equ
    	.include	sysport.equ

    ;グローバルレジスタを決める
    dPREV	reg	d6			;変更前の設定。0=off,1..255=on,2..127=kc
    dMODE	reg	d7			;変更後の設定。-1=なし,0=off,1..255=on,2..127=kc
    aBASE	reg	a6			;相対アクセスベースアドレス
    base:
    	lea.l	base(pc),aBASE
    r	reg	-base(aBASE)

    ;引数を読み取る
    	addq.l	#1,a2			;コマンドライン
    	moveq.l	#-1,dMODE		;変更後の設定なし
    	clr.b	(param_array)r		;音色パラメータなし
    	sf.b	(play_flag)r		;今すぐ起動音を再生しない
    	sf.b	(save_flag)r		;レジスタデータを保存しない
    	dostart
    		lea.l	buffer(pc),a0
    		movestr	<'play'>,a1
    		bsr	stricmp
    		if	eq
    			st.b	(play_flag)r		;今すぐ起動音を再生する
    			restart
    		endif
    		movestr	<'save'>,a1
    		bsr	stricmp
    		if	eq
    			st.b	(save_flag)r		;レジスタデータを保存する
    			restart
    		endif
    		moveq.l	#$20,d0
    		or.b	(a0),d0
    		if	<cmp.b #'o',d0>,eq	;off,on,o5cなど
    			addq.l	#1,a0
    			moveq.l	#$20,d0
    			or.b	(a0),d0
    			if	<cmp.b #'f',d0>,eq
    				addq.l	#1,a0
    				moveq.l	#$20,d0
    				or.b	(a0),d0
    				if	<cmp.b #'f',d0>,eq
    					addq.l	#1,a0
    					moveq.l	#0,d0			;off
    				else
    					goto	help
    				endif
    			elif	<cmp.b #'n',d0>,eq
    				addq.l	#1,a0
    				moveq.l	#1,d0			;on
    			else
    				moveq.l	#-'0',d0
    				add.b	(a0)+,d0
    				goto	<cmp.b #'8'-'0',d0>,hi,help
    				moveq.l	#0,d1
    				move.b	d0,d1
    				mulu.w	#12,d1			;番号
    				moveq.l	#$20,d0
    				or.b	(a0)+,d0
    				sub.b	#'a',d0
    				goto	<cmp.b #'g'-'a',d0>,hi,help
    				lea.l	note_to_number(pc),a1
    				add.b	(a1,d0.w),d1
    				ifor	<cmpi.b #'#',(a0)>,eq,<cmpi.b #'+',(a0)>,eq	;シャープ
    					addq.l	#1,a0
    					addq.b	#1,d1
    				elif	<cmpi.b #'-',(a0)>,eq	;フラット
    					addq.l	#1,a0
    					subq.b	#1,d1
    				endif
    				goto	<tst.b d1>,mi,help
    				move.l	d1,d0			;x1
    				divu.w	#3,d1			;x1/3
    				add.b	d1,d0			;x4/3。キーコード
    				gotoor	<cmp.b #2,d0>,lo,<tst.b d0>,mi,help
    			endif
    		elif	<cmp.b #'$',(a0)>,eq	;$02..$7F
    			addq.l	#1,a0
    			bsr	stoh
    			goto	cs,help
    			moveq.l	#2,d1
    			goto	<cmp.l d1,d0>,lo,help
    			moveq.l	#127,d1
    			goto	<cmp.l d1,d0>,hi,help
    		elifand	<cmp.b #'0',(a0)>,hs,<cmp.b #'9',(a0)>,ls	;2..127
    			bsr	stou
    			goto	cs,help
    			moveq.l	#2,d1
    			goto	<cmp.l d1,d0>,lo,help
    			moveq.l	#127,d1
    			goto	<cmp.l d1,d0>,hi,help
    		else
    			goto	help
    		endif
    		if	<cmpi.b #',',(a0)>,ne	;','がない。変更後の設定
    			move.l	d0,dMODE
    		else				;','がある。音色パラメータ
    			gotoor	<cmp.b #2,d0>,lo,<tst.b d0>,mi,help	;kc以外は不可
    			lea.l	param_array(pc),a1
    			move.b	d0,(a1)+		;0:kc
    			moveq.l	#57-1,d2
    			for	d2
    				goto	<cmpi.b #',',(a0)>,ne,help
    				addq.l	#1,a0
    				if	<cmp.b #'$',(a0)>,eq
    					addq.l	#1,a0
    					bsr	stoh
    				elifand	<cmp.b #'0',(a0)>,hs,<cmp.b #'9',(a0)>,ls
    					bsr	stou
    				else
    					goto	help
    				endif
    				goto	cs,help
    				if	<cmp.w #56-1,d2>,hi	;1:kf
    					moveq.l	#63,d1
    					goto	<cmp.l d1,d0>,hi,help
    					move.b	d0,(a1)+
    				elif	eq			;2..3:tm
    					goto	<cmp.l #65535,d0>,hi,help
    					move.w	d0,(a1)+		;tmは2バイト。偶数アドレスに配置すること
    				else				;4..58:va[0],...,va[54]
    					goto	<cmp.l #255,d0>,hi,help
    					move.b	d0,(a1)+
    				endif
    			next
    		endif
    		goto	<tst.b (a0)>,ne,help
    	start
    		lea.l	buffer(pc),a0
    		movea.l	a2,a1
    		bsr	argcpy
    		movea.l	a1,a2
    	while	ne			;引数がある

    ;音色パラメータをレジスタデータに変換する
    	lea.l	param_array(pc),a0
    	move.b	(a0)+,d0		;kc
    	if	ne
    		if	<tst.l dMODE>,mi	;音色パラメータがあり変更後の設定がないとき
    			moveq.l	#0,dMODE
    			move.b	d0,dMODE		;音色パラメータのkcを変更後の設定にする
    		endif
    		move.b	(a0)+,d1		;kf
    		move.w	(a0)+,d2		;tmは2バイト。偶数アドレスに配置すること
    		bsr	stupsnd_conv
    	endif

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

    ;変更前の設定を保存する
    	moveq.l	#0,dPREV
    	move.b	SRAM_STARTUP_SOUND,dPREV	;変更前の設定
    ;<dPREV.l:変更前の設定。0=off,1..255=on,2..127=kc

    ;設定を変更する
    	ifand	<tst.l dMODE>,pl,<cmp.b dPREV,dMODE>,ne	;変更後の設定があり、変更前と変更後の設定が異なる
    		unlocksram			;SRAM書き込み許可
    		move.b	dMODE,SRAM_STARTUP_SOUND	;変更後の設定
    		locksram			;SRAM書き込み禁止
    	endif

    ;今すぐ起動音を再生する
    	if	<tst.b (play_flag)r>,ne
    		bsr	play_stupsnd
    	endif

    ;設定を表示する
    	lea.l	buffer(pc),a0
    	movestr	<'startup sound switch is '>,a1
    	bsr	strcpy
    	move.l	dMODE,d0
    	if	mi
    		move.l	dPREV,d0
    	endif
    	if	eq			;0=off
    		move.b	#'o',(a0)+
    		move.b	#'f',(a0)+
    		move.b	#'f',(a0)+
    	else				;1..255=on
    		move.b	#'o',(a0)+
    		move.b	#'n',(a0)+
    		if	<cmp.b #2,d0>,ge	;2..127=kc。キーコードが指定されている
    			movestr	<' with key code '>,a1
    			bsr	strcpy
    			bsr	utos
    			move.b	#' ',(a0)+
    			move.b	#'(',(a0)+
    			move.b	d0,d1			;x1
    			lsr.b	#2,d1			;x1/4
    			sub.b	d1,d0			;x3/4。番号
    			divu.w	#12,d0			;ノート|オクターブ
    			move.l	d0,d1
    			swap.w	d1			;ノート
    			if	<cmp.w #9,d1>,hs	;c c# dは
    				addq.w	#1,d0			;1つ上のオクターブ
    			endif
    			move.b	#'o',(a0)+
    			add.b	#'0',d0
    			move.b	d0,(a0)+
    			add.w	d1,d1
    			lea.l	number_to_note(pc),a1
    			adda.w	d1,a1
    			move.b	(a1)+,(a0)+
    			move.b	(a1),d0
    			if	ne
    				move.b	d0,(a0)+
    			endif
    			move.b	#')',(a0)+
    		endif
    	endif
    	bsr	crlf
    	lea.l	buffer(pc),a0
    	bsr	print

    ;IPLROMのバージョンを確認する
    	IOCS	_ROMVER
    	move.l	#$13000000,d1		;IPLROM 1.3以上
    	if	<cmp.b #2,dMODE>,ge	;2..127=kc。キーコードが指定されている
    		move.l	#$16240226,d1		;IPLROM 1.6 (24-02-26)以上
    	endif
    	if	<cmp.l d1,d0>,lo		;IPLROMのバージョンが合っていない
    		ifand	<tst.b dMODE>,pl,<cmp.b dPREV,dMODE>,ne	;変更後の設定があり、変更前と変更後の設定が異なる
    			unlocksram			;SRAM書き込み許可
    			move.b	dPREV,SRAM_STARTUP_SOUND	;変更前の設定を復元する
    			locksram			;SRAM書き込み禁止
    		endif
    		movestr	<'unsupported IPLROM version',13,10>,a0
    		bsr	print
    	endif

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

    ;レジスタデータを保存する
    	if	<tst.b (save_flag)r>,ne
    		move.w	#$0020,-(sp)
    		pea.l	data_name(pc)
    		DOS	_CREATE
    		addq.l	#6,sp
    		move.l	d0,d1
    		if	mi
    			movestr	<'create error',13,10>,a0
    			bsr	print
    		else
    			moveq.l	#42,d2			;42バイト
    			move.l	d2,-(sp)
    			pea.l	stupsnd_data(pc)	;レジスタデータ
    			move.w	d1,-(sp)
    			DOS	_WRITE
    			move.l	d0,d3
    			DOS	_CLOSE
    			lea.l	10(sp),sp
    			if	<cmp.l d2,d3>,ne	;ディスクフル？
    				pea.l	data_name(pc)
    				DOS	_DELETE
    				addq.l	#4,sp
    				movestr	<'write error',13,10>,a0
    				bsr	print
    			endif
    		endif
    	endif

    ;終了する
    	DOS	_EXIT

    ;オプションを表示してエラー終了する
    help:
    	lea.l	options(pc),a0
    	bsr	print
    	move.w	#1,-(sp)
    	DOS	_EXIT2

    ;オプション
    options:
    	.dc.b	TITLE,13,10
    	.dc.b	'  turn on/off startup sound switch of X68030 or higher and IPLROM 1.6',13,10
    	.dc.b	'options',13,10
    	.dc.b	'  off',13,10
    	.dc.b	'    turn off startup sound switch',13,10
    	.dc.b	'  on',13,10
    	.dc.b	'    turn on startup sound switch with key code 76 (o5c)',13,10
    	.dc.b	'  2..127',13,10
    	.dc.b	'  $02..$7F',13,10
    	.dc.b	'  o5c etc.',13,10
    	.dc.b	'    turn on startup sound switch with specified key code',13,10
    	.dc.b	'  play',13,10
    	.dc.b	'    play startup sound right now',13,10
    	.dc.b	'    FM sound driver must be removed',13,10
    	.dc.b	'tone parameters',13,10
    	.dc.b	'  kc,kf,tm,va[0],...,va[54]',13,10
    	.dc.b	'    specify tone parameters',13,10
    	.dc.b	'    kc -- key code',13,10
    	.dc.b	'    kf -- key fraction',13,10
    	.dc.b	'    tm -- time from key-on to key-off (unit is 1/10,000 of a second)',13,10
    	.dc.b	'    va -- tone parameters common to OPMDRV.X',13,10
    	.dc.b	'  save',13,10
    	.dc.b	'    save register data to stupsnd.dat',13,10
    	.dc.b	'    to reflect in the startup sound, inserting data into IPLROM 1.6 is required',13,10
    	.dc.b	0

    ;ノートの変換表
    note_to_number:
    	.dc.b	6			;a
    	.dc.b	8			;b
    	.dc.b	-3			;c
    	.dc.b	-1			;d
    	.dc.b	1			;e
    	.dc.b	2			;f
    	.dc.b	4			;g
    number_to_note:
    	.dc.b	'd#'			;0
    	.dc.b	'e',0			;1
    	.dc.b	'f',0			;2
    	.dc.b	'f#'			;3
    	.dc.b	'g',0			;4
    	.dc.b	'g#'			;5
    	.dc.b	'a',0			;6
    	.dc.b	'a#'			;7
    	.dc.b	'b',0			;8
    	.dc.b	'c',0			;9
    	.dc.b	'c#'			;10
    	.dc.b	'd',0			;11

    data_name:
    	.dc.b	'stupsnd.dat',0

    	.bss
    	.even
    param_array:
    	.ds.b	59			;音色パラメータ。kc,kf,tmH,tmL,va[0],...,va[54]。偶数アドレスに配置すること
    play_flag:
    	.ds.b	1			;-1=今すぐ起動音を再生する
    save_flag:
    	.ds.b	1			;-1=音色パラメータを保存する
    buffer:
    	.ds.b	1024			;文字列バッファ

    	.text
    	.even

    ;----------------------------------------------------------------
    ;起動音

    CH	equ	0

    KC	equ	76
    KF	equ	5
    TM	equ	2500/100

    FLCON	equ	(1<<3)|3		;|FL###|CON###|
    SLOT	equ	%1101			;|C2|M2|C1|M1|
    WAVE	equ	0
    SYNC	equ	1
    SPEED	equ	0
    PMD	equ	0
    AMD	equ	0
    PMS	equ	0
    AMS	equ	0
    PAN	equ	%11			;|R|L|

    M1AR	equ	6
    M1D1R	equ	11
    M1D2R	equ	4
    M1RR	equ	4
    M1D1L	equ	0
    M1TL	equ	29
    M1KS	equ	0
    M1MUL	equ	0
    M1DT1	equ	0
    M1DT2	equ	3
    M1AMSEN	equ	1

    C1AR	equ	31
    C1D1R	equ	6
    C1D2R	equ	0
    C1RR	equ	2
    C1D1L	equ	2
    C1TL	equ	40
    C1KS	equ	2
    C1MUL	equ	1
    C1DT1	equ	0
    C1DT2	equ	3
    C1AMSEN	equ	1

    M2AR	equ	3
    M2D1R	equ	2
    M2D2R	equ	7
    M2RR	equ	2
    M2D1L	equ	3
    M2TL	equ	28
    M2KS	equ	1
    M2MUL	equ	3
    M2DT1	equ	0
    M2DT2	equ	1
    M2AMSEN	equ	1

    C2AR	equ	31
    C2D1R	equ	21
    C2D2R	equ	6
    C2RR	equ	4
    C2D1L	equ	2
    C2TL	equ	2
    C2KS	equ	1
    C2MUL	equ	1
    C2DT1	equ	0
    C2DT2	equ	0
    C2AMSEN	equ	1

    play_stupsnd:
    	push	d0-d4/a0
    	move.b	SRAM_STARTUP_SOUND,d3	;0=off,1..255=on,2..127=kc
    	if	ne			;on
    		moveq.l	#$08,d1			;KeyOff
    		moveq.l	#(0<<3)|CH,d2		;|-|C2|M2|C1|M1|CH###|
    		bsr	stupsnd_opmset
    		lea.l	stupsnd_data(pc),a0	;レジスタデータの配列
    		moveq.l	#$20+CH,d1		;レジスタアドレス
    		moveq.l	#28-1,d4		;0..27
    		for	d4
    			move.b	(a0)+,d2		;レジスタデータ
    			ifand	<cmp.b #$28+CH,d1>,eq,<cmp.b #2,d3>,ge	;2..127=kc。キーコードが指定されている
    				move.b	d3,d2
    			endif
    			bsr	stupsnd_opmset
    			addq.b	#8,d1			;次のレジスタアドレス
    		next
    		moveq.l	#6-1,d4			;28..39
    		for	d4
    			move.b	(a0)+,d1		;レジスタアドレス
    			move.b	(a0)+,d2		;レジスタデータ
    			bsr	stupsnd_opmset
    		next
    		moveq.l	#$08,d1			;KeyOn
    		moveq.l	#(SLOT<<3)|CH,d2	;|-|C2|M2|C1|M1|CH###|
    		bsr	stupsnd_opmset
    		moveq.l	#0,d0
    		move.w	(a0)+,d0		;40..41。tm@100us
    		add.l	d0,d0			;tm@50us
    		jsr	wait_50us		;50us単位のウェイト
    	;	moveq.l	#$08,d1			;KeyOff
    		moveq.l	#(0<<3)|CH,d2		;|-|C2|M2|C1|M1|CH###|
    		bsr	stupsnd_opmset
    	endif
    	pop
    	rts

    stupsnd_opmset:
    	IOCS	_OPMSET
    	rts

    ;レジスタデータ(42バイト)。偶数アドレスに配置すること
    	.even
    stupsnd_data:
      .ifdef STUPSNDDAT
    	.insert	stupsnd.dat
      .else
    	.dc.b	(PAN<<6)|FLCON		;0 $20+CH |PAN##|FL###|CON###|
    	.dc.b	KC			;1 $28+CH |-|KC#######|
    	.dc.b	KF<<2			;2 $30+CH |KF######|--|
    	.dc.b	(PMS<<4)|AMS		;3 $38+CH |-|PMS###|--|AMS##|
    	.dc.b	(M1DT1<<4)|M1MUL	;4 $40+CH M1 |-|DT1###|MUL####|
    	.dc.b	(M2DT1<<4)|M2MUL	;5 $48+CH M2
    	.dc.b	(C1DT1<<4)|C1MUL	;6 $50+CH C1
    	.dc.b	(C2DT1<<4)|C2MUL	;7 $58+CH C2
    	.dc.b	M1TL			;8 $60+CH M1 |-|TL#######|
    	.dc.b	M2TL			;9 $68+CH M2
    	.dc.b	C1TL			;10 $70+CH C1
    	.dc.b	C2TL			;11 $78+CH C2
    	.dc.b	(M1KS<<6)|M1AR		;12 $80+CH M1 |KS##|-|AR#####|
    	.dc.b	(M2KS<<6)|M2AR		;13 $88+CH M2
    	.dc.b	(C1KS<<6)|C1AR		;14 $90+CH C1
    	.dc.b	(C2KS<<6)|C2AR		;15 $98+CH C2
    	.dc.b	(M1AMSEN<<7)|M1D1R	;16 $A0+CH M1 |AMSEN|--|D1R#####|
    	.dc.b	(M2AMSEN<<7)|M2D1R	;17 $A8+CH M2
    	.dc.b	(C1AMSEN<<7)|C1D1R	;18 $B0+CH C1
    	.dc.b	(C2AMSEN<<7)|C2D1R	;19 $B8+CH C2
    	.dc.b	(M1DT2<<6)|M1D2R	;20 $C0+CH M1 |DT2##|-|D2R#####|
    	.dc.b	(M2DT2<<6)|M2D2R	;21 $C8+CH M2
    	.dc.b	(C1DT2<<6)|C1D2R	;22 $D0+CH C1
    	.dc.b	(C2DT2<<6)|C2D2R	;23 $D8+CH C2
    	.dc.b	(M1D1L<<4)|M1RR		;24 $E0+CH M1 |D1L####|RR####|
    	.dc.b	(M2D1L<<4)|M2RR		;25 $E8+CH M2
    	.dc.b	(C1D1L<<4)|C1RR		;26 $F0+CH C1
    	.dc.b	(C2D1L<<4)|C2RR		;27 $F8+CH C2
    	.dc.b	$18,SPEED		;28,29 $18 |LFRQ########|
    	.dc.b	$19,(0<<7)|AMD		;30,31 $19 |0|AMD#######|
    	.dc.b	$19,(1<<7)|PMD		;32,33 $19 |1|PMD#######|
    	.dc.b	$1B,WAVE		;34,35 $1B |CT1|CT2|----|WAVE##|
    	.dc.b	$01,SYNC<<1		;36,37 $01 |------|LFORESET|-|
    	.dc.b	$01,0<<1		;38,39 $01 |------|LFORESET|-|
    	.dc.w	TM			;40,41 tm@100us
    					;42
    	.even
      .endif

    ;----------------------------------------------------------------
    ;音色パラメータをレジスタデータに変換する
    ;<d0.b:kc
    ;<d1.b:kf
    ;<d2.w:tm
    ;<a0.l:音色パラメータ(55バイト)。va[0],...,va[54]
    ;		+0	+1	+2	+3	+4	+5	+6	+7	+8	+9	+10
    ;	0	FLCON	SLOT	WAVE	SYNC	SPEED	PMD	AMD	PMS	AMS	PAN	0
    ;	11	M1AR	M1D1R	M1D2R	M1RR	M1D1L	M1TL	M1KS	M1MUL	M1DT1	M1DT2	M1AMSEN
    ;	22	C1AR	C1D1R	C1D2R	C1RR	C1D1L	C1TL	C1KS	C1MUL	C1DT1	C1DT2	C1AMSEN
    ;	33	M2AR	M2D1R	M2D2R	M2RR	M2D1L	M2TL	M2KS	M2MUL	M2DT1	M2DT2	M2AMSEN
    ;	44	C2AR	C2D1R	C2D2R	C2RR	C2D1L	C2TL	C2KS	C2MUL	C2DT1	C2DT2	C2AMSEN
    ;	55	kc	kf
    stupsnd_conv:
    	push	d0-d4/a0-a2,58
    	movea.l	sp,a1
    	moveq.l	#55-1,d3
    	for	d3
    		move.b	(a0)+,(a1)+
    	next
    	move.b	d0,(a1)+		;kc
    	move.b	d1,(a1)+		;kf
    	movea.l	sp,a0			;音色パラメータ+kc+kf(57バイト)。va[0],...,va[54],kc,kf
    	tas.b	5(a0)			;|1|PMD#######|
    	lea.l	stupsnd_data(pc),a1	;レジスタデータ(42バイト)
    	lea.l	100f(pc),a2		;音色パラメータ→レジスタデータ変換表
    	moveq.l	#0,d1
    	moveq.l	#28+6-1,d3
    	for	d3
    		if	<cmp.b #6-1,d3>,ls	;最後の6個
    			move.b	(a2)+,(a1)+		;レジスタアドレス
    		endif
    		moveq.l	#0,d0			;レジスタデータ
    		dostart
    			move.b	(a0,d1.w),d1		;音色パラメータ+kc+kfに含まれるレジスタデータの部品
    			and.b	(a2)+,d1		;マスク
    			move.b	(a2)+,d4		;シフトカウント
    			lsl.b	d4,d1
    			or.b	d1,d0			;部品を並べる
    		start
    			move.b	(a2)+,d1		;音色パラメータ+kc+kfのインデックス
    		while	pl
    		move.b	d0,(a1)+		;レジスタデータ
    	next
    	move.w	d2,(a1)+		;40,41 tm
    	pop
    	rts

    ;音色パラメータ→レジスタデータ変換表
    100:
    ;音色パラメータ+kc+kfのインデックス,マスク,シフトカウント,…,-1
    	.dc.b	9,3,6,0,63,0,-1		;0 $20+CH |PAN##|FL###|CON###|
    	.dc.b	55+0,127,0,-1		;1 $28+CH |-|KC#######|
    	.dc.b	55+1,63,2,-1		;2 $30+CH |KF######|--|
    	.dc.b	7,7,4,6,3,0,-1		;3 $38+CH |-|PMS###|--|AMS##|
    	.dc.b	11+8,7,4,11+7,15,0,-1	;4 $40+CH M1 |-|DT1###|MUL####|
    	.dc.b	33+8,7,4,33+7,15,0,-1	;5 $48+CH M2
    	.dc.b	22+8,7,4,22+7,15,0,-1	;6 $50+CH C1
    	.dc.b	44+8,7,4,44+7,15,0,-1	;7 $58+CH C2
    	.dc.b	11+5,127,0,-1		;8 $60+CH M1 |-|TL#######|
    	.dc.b	33+5,127,0,-1		;9 $68+CH M2
    	.dc.b	22+5,127,0,-1		;10 $70+CH C1
    	.dc.b	44+5,127,0,-1		;11 $78+CH C2
    	.dc.b	11+6,3,6,11+0,31,0,-1	;12 $80+CH M1 |KS##|-|AR#####|
    	.dc.b	33+6,3,6,33+0,31,0,-1	;13 $88+CH M2
    	.dc.b	22+6,3,6,22+0,31,0,-1	;14 $90+CH C1
    	.dc.b	44+6,3,6,44+0,31,0,-1	;15 $98+CH C2
    	.dc.b	11+10,1,7,11+1,31,0,-1	;16 $A0+CH M1 |AMSEN|--|D1R#####|
    	.dc.b	33+10,1,7,33+1,31,0,-1	;17 $A8+CH M2
    	.dc.b	22+10,1,7,22+1,31,0,-1	;18 $B0+CH C1
    	.dc.b	44+10,1,7,44+1,31,0,-1	;19 $B8+CH C2
    	.dc.b	11+9,3,6,11+2,31,0,-1	;20 $C0+CH M1 |DT2##|-|D2R#####|
    	.dc.b	33+9,3,6,33+2,31,0,-1	;21 $C8+CH M2
    	.dc.b	22+9,3,6,22+2,31,0,-1	;22 $D0+CH C1
    	.dc.b	44+9,3,6,44+2,31,0,-1	;23 $D8+CH C2
    	.dc.b	11+4,15,4,11+3,15,0,-1	;24 $E0+CH M1 |D1L####|RR####|
    	.dc.b	33+4,15,4,33+3,15,0,-1	;25 $E8+CH M2
    	.dc.b	22+4,15,4,22+3,15,0,-1	;26 $F0+CH C1
    	.dc.b	44+4,15,4,44+3,15,0,-1	;27 $F8+CH C2
    ;レジスタアドレス,音色パラメータ+kc+kfのインデックス,マスク,シフトカウント,…,-1
    	.dc.b	$18,4,255,0,-1		;28,29 $18 |LFRQ########|
    	.dc.b	$19,6,127,0,-1		;30,31 $19 |0|AMD#######|
    	.dc.b	$19,5,127,0,-1		;32,33 $19 |1|PMD#######|
    	.dc.b	$1B,2,3,0,-1		;34,35 $1B |CT1|CT2|----|WAVE##|
    	.dc.b	$01,3,1,1,-1		;36,37 $01 |------|LFORESET|-|
    	.dc.b	$01,3,0,1,-1		;38,39 $01 |------|LFORESET|-|
    	.even

    ;----------------------------------------------------------------
    ;引数をコピーする
    ;	空白を読み飛ばしてから次の空白の手前までコピーする
    ;	"～"または'～'で囲むと引数に空白を含めることができる
    ;	""または''と書くと長さが0の引数を与えることができる
    ;<a0.l:コピー先のバッファの先頭
    ;<a1.l:コピー元の文字列の先頭
    ;>d0.l:0=引数がない,1=引数がある
    ;>a0.l:コピー先の文字列の末尾の0の位置
    ;>a1.l:コピー元の引数の直後。なければコピー元の文字列の末尾の0の位置
    ;>eq=引数がない,ne=引数がある
    argcpy::
    	exg.l	a0,a1
    	bsr	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

    ;----------------------------------------------------------------
    ;16進数の文字を整数に変換する
    ;<d0.b:文字
    ;>d0.l:0～16。-1=16進数の文字ではない
    ;>n:mi=16進数の文字ではない
    fromxdigit::
    	sub.b	#'0',d0
    	blo	1f			;x<0
    	sub.b	#('9'+1)-'0',d0
    	blo	3f			;0<=x<=9
    	subq.b	#'A'-('9'+1),d0
    	blo	1f			;9<x<A
    	subq.b	#('F'+1)-'A',d0
    	blo	2f			;A<=x<=F
    	sub.b	#'a'-('F'+1),d0
    	blo	1f			;F<x<A
    	subq.b	#('f'+1)-'a',d0
    	blo	2f			;a<=x<=f
    1:	moveq.l	#-1,d0			;x<0||9<x<A||F<x<a||f<x
    	rts
    2:	addq.b	#6,d0			;A<=x<=F||a<=x<=f
    3:	add.b	#10,d0			;0<=x<=9
    	ext.w	d0
    	ext.l	d0
    	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ならば終了
    		redo	<cmp.b #' ',d0>,eq	;' 'ならば繰り返す
    	whileand	<cmp.b #9,d0>,hs,<cmp.b #13,d0>,ls	;\t\n\v\f\rならば繰り返す
    	subq.l	#1,a0			;進み過ぎた分戻る
    	tst.l	d0
    	rts

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

    ;----------------------------------------------------------------
    ;16進数の文字列を符号なし整数に変換する
    ;<a0.l:16進数の文字列。先頭の空白は認めない
    ;>d0.l:符号なし整数。(csのとき)下位32ビット
    ;>a0.l:16進数ではない文字または0の位置
    ;>c:cc=成功,cs=16進数の文字がないまたはオーバーフロー
    ;>v:(csのとき)vc=16進数の文字がない,vs=オーバーフロー
    stoh::
    	push	d1-d2/a1
    	moveq.l	#0,d1			;符号なし整数
    	moveq.l	#0,d2			;オーバーフロー判定用
    	movea.l	a0,a1			;開始位置
    	dostart
    		or.l	d1,d2			;16倍する直前の値のOR
    		lsl.l	#4,d1			;16倍して
    		or.b	d0,d1			;1桁加える
    	start
    		move.b	(a0)+,d0		;次の文字
    		bsr	fromxdigit
    	while	pl			;16進数の文字ならば繰り返す
    	subq.l	#1,a0			;進み過ぎた分戻る
    	add.l	#$F0000000,d2
    	subx.w	d2,d2			;16倍する直前の値のORの上位4ビットが0でないすなわちオーバーフローのとき-1、さもなくば0
    	and.w	#%00011,d2		;オーバーフローのときvs,cs、さもなくばvc,cc
    	if	<cmpa.l a1,a0>,eq	;進んでいない
    		or.w	#%00001,d2		;16進数の文字がないときcs
    	endif
    	move.l	d1,d0			;符号なし整数
    	move.w	d2,ccr
    	popm
    	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

    ;----------------------------------------------------------------
    ;50us単位のウェイト
    ;<d0.l:待ち時間(50us単位)
    wait_50us::
    aTCDR	reg	a0
    	push	d0-d2/aTCDR
    	lea.l	MFP_TCDR,aTCDR		;Timer-Cデータレジスタ。200,199,…,2,1,0→200,199,…(50us単位)
    	moveq.l	#0,d1
    	move.b	(aTCDR),d1
    	move.b	(aTCDR),d1		;d1=前回の値
    	do
    		moveq.l	#0,d2
    		move.b	(aTCDR),d2		;d2=今回の値
    		redo	<cmp.b (aTCDR),d2>,lo	;0→200のとき読み直す
    		sub.w	d2,d1			;d1=前回の値-今回の値=経過時間
    		if	lo			;0→200を跨いだとき
    			add.w	#200,d1			;今回の値が200増えた分経過時間が200減るので加え戻す
    		endif
    		exg.l	d1,d2			;d1=今回の値=次回の前回の値,d2=経過時間
    		sub.l	d2,d0			;d0=待ち時間-経過時間=次回の待ち時間
    	while	hi			;待ち時間がなくなるまで繰り返す
    	pop
    	rts

    	.end

STUDIO KAMADA
Copyright © 1999-2026 Makoto Kamada