;----------------------------------------------------------------
;
;	例外ハンドラ
;
;----------------------------------------------------------------

	.include	t02const.equ

	.cpu	68060

;----------------------------------------------------------------
;
;	アクセスエラー例外
;
;----------------------------------------------------------------
accessError::
	btst.b	#FSLW_BPE_BIT,($000C+3,sp)	;FSLWのBPEビットをテストする
	bne	branchPredictionError	;BPEビットがセットされていたら分岐予測エラー
	jmp	([vectorOldAccessError])

;----------------------------------------------------------------
;
;	分岐予測エラー
;
;----------------------------------------------------------------
branchPredictionError::
;分岐キャッシュをクリアする
	move.l	d0,-(sp)
	movec.l	cacr,d0
	bset.l	#CACR_CABC_BIT,d0	;分岐キャッシュをクリア
	movec.l	d0,cacr			;CABCビットはreadは常に0なので元に戻す必要はない
	move.l	(sp)+,d0
;マニュアルではBPE以外のBusErrorが発生していないことを確認してからrteするように
;書かれているが、何故か必ずWEビットもセットされてしまっているので、とりあえず
;無視して復帰する
	rte


;----------------------------------------------------------------
;----------------------------------------------------------------
UNIMPLEMENTED_INTEGER	equ	5
;MOVEPエミュレーションルーチンの履歴
;1	〜v0.47
;		スタックにレジスタテーブルを生成
;		ROM 1.5(97/03/26,97/05/29)もこれと同じ
;2	v0.49〜v0.51
;		スーパースケーラを意識して最適化
;		エンバグがあり,パターンによっては正しくエミュレートできない
;		エミュレート中の割り込みによってデータが破壊される
;3	v0.52
;		パターンによって正しくエミュレートできていなかった部分だけ修正
;		割り込みによるデータ破壊は未修正
;4	v0.53
;		割り込みによるデータ破壊を修正,完成
;5(97/08/17,97/09/15)
;		スタックのレジスタテーブルをやめ,レジスタ番号で分岐
;		MOVEPエミュレーションルーチンがかなり大きくなった
;		実効アドレスのアクセスウェイトを多少考慮
;6(予定)
;		実効アドレスのアクセスウェイトを積極的に活用する
;		<ea>→Dnの順で確定し,読み出し時は読み出しながらDnを確定する
;		書き込み時は書き込みながら直後の命令もMOVEPでないか調べ,
;		MOVEPが続いていたら例外処理から復帰せずにエミュレートを続ける
;		実効アドレスのアクセスの最中は,なるべく他のアドレスをアクセスしない
;		(キャッシュがミスするとそこで待たされるため)
;		ストアバッファの効果で,1回目の書き込みはすぐに復帰する可能性がある
;		分岐方法も改良



  .if UNIMPLEMENTED_INTEGER=1



;----------------------------------------------------------------
;
;	未実装整数命令例外
;
;----------------------------------------------------------------
;----------------------------------------------------------------
;MOVEP以外の未実装整数命令
ispCall:
	movem.l	(sp)+,d0-d1
	lea.l	(4*(8-2),sp),sp
	movea.l	(sp)+,a0
	lea.l	(4*(8-1),sp),sp
	bra	_isp_unimp		;_060ISP_TABLE+$00000238
					;_060ISP_TABLE+$00

;MOVEPでユーザモードのとき
_movepUser:
	move.l	usp,a1			;例外発生時のusp
	move.l	a1,(4*15,sp)		;例外発生時のsp
	bra	_movepSuper

;----------------------------------------------------------------
;Unimplemented Integer Instruction
;未実装整数命令例外処理ルーチン
;	MOVEPだけ特別扱いにして高速に処理しています
;	その他の未実装整数命令の処理はISPに任せます
_060_isp_unint::
	pea.l	(8,sp)			;例外発生時のssp
	movem.l	d0-d7/a0-a6,-(sp)
	movea.l	(4*16+2,sp),a0		;例外発生時のpc
;<a0.l:例外発生時のpc
	move.w	(a0)+,d1		;命令コード
;<d1.w:例外発生時の(pc).w
;MOVEPか
	move.w	d1,d0
	and.w	#$F138,d0
	cmp.w	#$0108,d0
	bne	ispCall
;----------------------------------------------------------------
;MOVEP命令
;	MOVEP.{WL} Dx,(d16,Ay)
;	MOVEP.{WL} (d16,Ay),Dx
;	ファンクションコードのチェック/変更を一切行っていません
;	転送中のアクセスエラーを考慮していません
;	次のような異常なメモリ操作は正しくエミュレートできません
;		MOVEP.W Dx,(d16,SSP) (-$004A<=d16<=-$0001)
;		MOVEP.L Dx,(d16,SSP) (-$004E<=d16<=-$0001)
;<d1.w:例外発生時の(pc).w
;	0000ddd1ws001aaa
;		ddd	data register
;		w	read/write(0=read,1=write)
;		s	size(0=word,1=long)
;		aaa	address register
;<a0.l:例外発生時のpc+2
;<sp.l:スタックに例外発生時のレジスタの内容を保持
;	0000	.l	d0
;	0004	.l	d1
;	0008	.l	d2
;	000C	.l	d3
;	0010	.l	d4
;	0014	.l	d5
;	0018	.l	d6
;	001C	.l	d7
;	0020	.l	a0
;	0024	.l	a1
;	0028	.l	a2
;	002C	.l	a3
;	0030	.l	a4
;	0034	.l	a5
;	0038	.l	a6
;	003C	.l	ssp
;	0040	.w	sr
;	0042	.l	pc		pcは次の命令のアドレスに更新すること
;	0046	.w	ベクタオフセット
;	0048		sspの位置
_movep:
	btst.b	#5,(4*16,sp)		;例外発生時のsrのS
	beq	_movepUser		;スーパーバイザモードを優先
_movepSuper:
;<sp.l:スタックに例外発生時のレジスタの内容を保持
;	0000	.l	d0
;	0004	.l	d1
;	0008	.l	d2
;	000C	.l	d3
;	0010	.l	d4
;	0014	.l	d5
;	0018	.l	d6
;	001C	.l	d7
;	0020	.l	a0
;	0024	.l	a1
;	0028	.l	a2
;	002C	.l	a3
;	0030	.l	a4
;	0034	.l	a5
;	0038	.l	a6
;	003C	.l	uspまたはssp
;	0040	.w	sr
;	0042	.l	pc		pcは次の命令のアドレスに更新すること
;	0046	.w	ベクタオフセット
;	0048		sspの位置
;実効アドレスを求める
	moveq.l	#7,d0			;0000000000000111
	and.w	d1,d0			;0000000000000aaa
	movea.l	(4*8,sp,d0.w*4),a1	;アドレスレジスタの内容
	adda.w	(a0)+,a1		;ディスプレースメントを加える
;<a0.l:例外発生時のpc+4
;<a1.l:実効アドレス
;復帰アドレスを更新する
	move.l	a0,(4*16+2,sp)		;復帰アドレスを更新
;データレジスタのアドレスを求める
	move.w	d1,d0			;0000ddd1ws001aaa
	lsr.w	#8,d0			;000000000000ddd1
	lea.l	(-2,sp,d0.w*2),a0	;00000000000ddd10
					;00000000000ddd00
					;データレジスタのアドレス
;<a0.l:データレジスタのアドレス
;オペレーションモードに従って転送する
	add.b	d1,d1
	bcc	_movepRead		;writeを優先
;レジスタ→メモリ
;	MOVEP.{WL} Dx,(d16,Ay)
_movepWrite:
	bpl	_movepWriteWord		;ロングワードを優先
;レジスタ→メモリ,ロングワード
;	MOVEP.L Dx,(d16,Ay)
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepWriteLong:
	move.b	(a0)+,(a1)
	move.b	(a0)+,(2,a1)
	move.b	(a0)+,(4,a1)
	move.b	(a0),(6,a1)
	movem.l	(sp)+,d0-d1
	lea.l	(4*(8-2),sp),sp
	movem.l	(sp)+,a0-a1
	lea.l	(4*(8-2),sp),sp
	rte

;レジスタ→メモリ,ワード
;	MOVEP.W Dx,(d16,Ay)
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepWriteWord:
	addq.w	#2,a0
	move.b	(a0)+,(a1)
	move.b	(a0),(2,a1)
	movem.l	(sp)+,d0-d1
	lea.l	(4*(8-2),sp),sp
	movem.l	(sp)+,a0-a1
	lea.l	(4*(8-2),sp),sp
	rte

;メモリ→レジスタ
;	MOVEP.{WL} (d16,Ay),Dx
_movepRead:
	bpl	_movepReadWord		;ロングワードを優先
;メモリ→レジスタ,ロングワード
;	MOVEP.L	(d16,Ay),Dx
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepReadLong:
	move.b	(a1),(a0)+
	move.b	(2,a1),(a0)+
	move.b	(4,a1),(a0)+
	move.b	(6,a1),(a0)
	movem.l	(sp)+,d0-d7/a0-a1
	lea.l	(4*(8-2),sp),sp
	rte

;メモリ→レジスタ,ワード
;	MOVEP.W (d16,Ay),Dx
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepReadWord:
	addq.w	#2,a0
	move.b	(a1),(a0)+
	move.b	(2,a1),(a0)
	movem.l	(sp)+,d0-d7/a0-a1
	lea.l	(4*(8-2),sp),sp
	rte



  .elseif UNIMPLEMENTED_INTEGER=4



;----------------------------------------------------------------
;
;	未実装整数命令例外
;
;----------------------------------------------------------------
;----------------------------------------------------------------
;MOVEP以外の未実装整数命令
ispCall:
	movem.l	(sp)+,d0-d1
	lea.l	(4*(8-2),sp),sp
	movea.l	(sp)+,a0
	lea.l	(4*(8-1),sp),sp
	bra	_isp_unimp		;_060ISP_TABLE+$00000238
					;_060ISP_TABLE+$00

;MOVEPでユーザモードのとき
_movepUser:
	move.l	usp,a1			;例外発生時のusp
	move.l	a1,(4*15,sp)		;例外発生時のsp
	bra	_movepSuper

;----------------------------------------------------------------
;Unimplemented Integer Instruction
;未実装整数命令例外処理ルーチン
;	MOVEPだけ特別扱いにして高速に処理しています
;	その他の未実装整数命令の処理はISPに任せます
_060_isp_unint::
	pea.l	(8,sp)			;例外発生時のssp
	movem.l	d0-d7/a0-a6,-(sp)	;movem.l <register-list>,-(sp)は,
					;move.l rn,-(sp)で展開しても速くならない
	movea.l	(4*16+2,sp),a0		;例外発生時のpc
;<a0.l:例外発生時のpc
	move.w	(a0)+,d1		;命令コード
;<d1.w:例外発生時の(pc).w
;MOVEPか
	move.w	d1,d0
	and.w	#$F138,d0
	cmp.w	#$0108,d0
	bne	ispCall
;----------------------------------------------------------------
;MOVEP命令
;	MOVEP.{WL} Dx,(d16,Ay)
;	MOVEP.{WL} (d16,Ay),Dx
;	ファンクションコードのチェック/変更を一切行っていません
;	転送中のアクセスエラーを考慮していません
;	次のような異常なメモリ操作は正しくエミュレートできません
;		MOVEP.W Dx,(d16,SSP) (-$004A<=d16<=-$0001)
;		MOVEP.L Dx,(d16,SSP) (-$004E<=d16<=-$0001)
;<d1.w:例外発生時の(pc).w
;	0000ddd1ws001aaa
;		ddd	data register
;		w	read/write(0=read,1=write)
;		s	size(0=word,1=long)
;		aaa	address register
;<a0.l:例外発生時のpc+2
;<sp.l:スタックに例外発生時のレジスタの内容を保持
;	0000	.l	d0
;	0004	.l	d1
;	0008	.l	d2
;	000C	.l	d3
;	0010	.l	d4
;	0014	.l	d5
;	0018	.l	d6
;	001C	.l	d7
;	0020	.l	a0
;	0024	.l	a1
;	0028	.l	a2
;	002C	.l	a3
;	0030	.l	a4
;	0034	.l	a5
;	0038	.l	a6
;	003C	.l	ssp
;	0040	.w	sr
;	0042	.l	pc		pcは次の命令のアドレスに更新すること
;	0046	.w	ベクタオフセット
;	0048		sspの位置
_movep:
	btst.b	#5,(4*16,sp)		;例外発生時のsrのS
	beq	_movepUser		;スーパーバイザモードを優先
_movepSuper:
;<sp.l:スタックに例外発生時のレジスタの内容を保持
;	0000	.l	d0
;	0004	.l	d1
;	0008	.l	d2
;	000C	.l	d3
;	0010	.l	d4
;	0014	.l	d5
;	0018	.l	d6
;	001C	.l	d7
;	0020	.l	a0
;	0024	.l	a1
;	0028	.l	a2
;	002C	.l	a3
;	0030	.l	a4
;	0034	.l	a5
;	0038	.l	a6
;	003C	.l	uspまたはssp
;	0040	.w	sr
;	0042	.l	pc		pcは次の命令のアドレスに更新すること
;	0046	.w	ベクタオフセット
;	0048		sspの位置
;実効アドレスを求める
	moveq.l	#7,d0			;0000000000000111
	and.w	d1,d0			;0000000000000aaa
	movea.l	(4*8,sp,d0.w*4),a1	;アドレスレジスタの内容
	adda.w	(a0)+,a1		;ディスプレースメントを加える
;<a0.l:例外発生時のpc+4
;<a1.l:実効アドレス
		move.w	d1,d0		;0000ddd1ws001aaa
;復帰アドレスを更新する
	move.l	a0,(4*16+2,sp)		;復帰アドレスを更新
;データレジスタのアドレスを求める
		lsr.w	#8,d0		;000000000000ddd1
	add.b	d1,d1
		lea.l	(-2,sp,d0.w*2),a0	;00000000000ddd10
					;00000000000ddd00
					;データレジスタのアドレス
;<a0.l:データレジスタのアドレス
;オペレーションモードに従って転送する
	bcc	_movepRead		;writeを優先
;レジスタ→メモリ
;	MOVEP.{WL} Dx,(d16,Ay)
_movepWrite:
	bpl	_movepWriteWord		;ロングワードを優先
;レジスタ→メモリ,ロングワード
;	MOVEP.L Dx,(d16,Ay)
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepWriteLong:
					;movem.l (sp)+,<register-list>は,
					;move.l (sp)+,rnで展開すると速くなる
	move.b	(a0)+,(a1)
	move.b	(a0)+,(2,a1)
	move.b	(a0)+,(4,a1)
	move.b	(a0),(6,a1)
		move.l	(sp)+,d0
	move.l	(sp)+,d1
		movea.l	(4*(8-2),sp),a0
	movea.l	(4*(9-2),sp),a1
		lea.l	(4*(16-2),sp),sp
	rte

;レジスタ→メモリ,ワード
;	MOVEP.W Dx,(d16,Ay)
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepWriteWord:
	move.b	(2,a0),(a1)
	move.b	(3,a0),(2,a1)
		move.l	(sp)+,d0
	move.l	(sp)+,d1
		movea.l	(4*(8-2),sp),a0
	movea.l	(4*(9-2),sp),a1
		lea.l	(4*(16-2),sp),sp
	rte

;メモリ→レジスタ
;	MOVEP.{WL} (d16,Ay),Dx
_movepRead:
	bpl	_movepReadWord		;ロングワードを優先
;メモリ→レジスタ,ロングワード
;	MOVEP.L	(d16,Ay),Dx
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepReadLong:
	move.b	(a1),(a0)+
	move.b	(2,a1),(a0)+
	move.b	(4,a1),(a0)+
	move.b	(6,a1),(a0)
		move.l	(sp)+,d0
	move.l	(sp)+,d1
		move.l	(sp)+,d2
	move.l	(sp)+,d3
		move.l	(sp)+,d4
	move.l	(sp)+,d5
		move.l	(sp)+,d6
	move.l	(sp)+,d7
		movea.l	(sp)+,a0
	movea.l	(sp)+,a1
		lea.l	(4*(16-10),sp),sp
	rte

;メモリ→レジスタ,ワード
;	MOVEP.W (d16,Ay),Dx
;<a0.l:データレジスタのアドレス
;<a1.l:実効アドレス
_movepReadWord:
	move.b	(a1),(2,a0)
	move.b	(2,a1),(3,a0)
		move.l	(sp)+,d0
	move.l	(sp)+,d1
		move.l	(sp)+,d2
	move.l	(sp)+,d3
		move.l	(sp)+,d4
	move.l	(sp)+,d5
		move.l	(sp)+,d6
	move.l	(sp)+,d7
		movea.l	(sp)+,a0
	movea.l	(sp)+,a1
		lea.l	(4*(16-10),sp),sp
	rte



  .elseif UNIMPLEMENTED_INTEGER=5



;----------------------------------------------------------------
;
;	未実装整数命令例外
;
;----------------------------------------------------------------
;----------------------------------------------------------------
;MOVEP以外の未実装整数命令
ispCall:
	movea.l	(sp)+,a1		;順序に注意
	move.w	(sp)+,d0
	movea.l	(sp)+,a0
	bra	_isp_unimp		;_060ISP_TABLE+$00000238
					;_060ISP_TABLE+$00

;----------------------------------------------------------------
;Unimplemented Integer Instruction
;未実装整数命令例外処理ルーチン
;	MOVEPだけ特別扱いにして高速に処理しています
;	その他の未実装整数命令の処理はISPに任せます
	.align	4
_060_isp_unint::
	move.l	a0,-(sp)		;順序に注意
	move.w	d0,-(sp)		;上位ワードは保護しないので注意
	move.l	a1,-(sp)
	movea.l	((4+2+4)+2,sp),a1	;例外発生時のpc
;<a1.l:例外発生時のpc
	movea.w	(a1)+,a0		;命令コード
;<a0.w:例外発生時の(pc).w
;MOVEPか
	move.w	a0,d0
	and.w	#$F138,d0
	cmp.w	#$0108,d0
	bne	ispCall
;----------------------------------------------------------------
;MOVEP命令
;	MOVEP.{WL} Dx,(d16,Ay)
;	MOVEP.{WL} (d16,Ay),Dx
;	ファンクションコードのチェック/変更を一切行っていません
;	転送中のアクセスエラーを考慮していません
;	次のような異常なメモリ操作は正しくエミュレートできません
;		MOVEP.W Dx,(d16,SSP) (-$004A<=d16<=-$0001)
;		MOVEP.L Dx,(d16,SSP) (-$004E<=d16<=-$0001)
;<a0.w:例外発生時の(pc).w
;	0000ddd1ws001aaa
;		ddd	data register
;		w	read/write(0=read,1=write)
;		s	size(0=word,1=long)
;		aaa	address register
;<a1.l:例外発生時のpc+2
;<sp.l:スタックに例外発生時のレジスタの内容を保持
;	0000	.l	a1
;	0004	.w	d0
;	0006	.l	a0
;	000A	.w	sr
;	000C	.l	pc		pcは次の命令のアドレスに更新すること
;	0010	.w	例外フォーマット番号,ベクタオフセット
;	0012		例外発生時のsspの位置
_movep:
;実効アドレスを求める
	move.w	a0,d0			;0000ddd1ws001aaa
	and.b	#7,d0			;0000000000000aaa
					; 0  1  2  3  4  5  6  7
	beq	_movep_a0		; 0
	subq.b	#4,d0			;   -3 -2 -1  0  1  2  3
	bmi	_movep_a123		;   -3 -2 -1
	beq	_movep_a4		;             0
_movep_a567:				;                1  2  3
	subq.b	#2,d0			;               -1  0  1
	bmi	_movep_a5		;               -1
	beq	_movep_a6		;                   0
_movep_a7:				;                      1
	move.w	a0,d0			;0000ddd1ws001aaa
	lea.l	((4+2+4)+8,sp),a0		;例外発生時のssp
	btst.b	#5,((4+2+4)+0,sp)
	bne	_movep_d
	movea.l	usp,a0			;例外発生時のusp
	bra	_movep_d

_movep_a6:				;                   0
	move.w	a0,d0			;0000ddd1ws001aaa
	movea.l	a6,a0			;例外発生時のa6
	bra	_movep_d

_movep_a5:				;               -1
	move.w	a0,d0			;0000ddd1ws001aaa
	movea.l	a5,a0			;例外発生時のa5
	bra	_movep_d

_movep_a4:				;             0
	move.w	a0,d0			;0000ddd1ws001aaa
	movea.l	a4,a0			;例外発生時のa4
	bra	_movep_d

_movep_a123:				;   -3 -2 -1
	addq.b	#2,d0			;   -1  0  1
	bmi	_movep_a1		;   -1
	beq	_movep_a2		;       0
_movep_a3:				;          1
	move.w	a0,d0			;0000ddd1ws001aaa
	movea.l	a3,a0			;例外発生時のa3
	bra	_movep_d

_movep_a2:				;       0
	move.w	a0,d0			;0000ddd1ws001aaa
	movea.l	a2,a0			;例外発生時のa2
	bra	_movep_d

_movep_a1:				;   -1
	move.w	a0,d0			;0000ddd1ws001aaa
	movea.l	(sp),a0			;例外発生時のa1
	bra	_movep_d

_movep_a0:				; 0
	move.w	a0,d0			;0000ddd1ws001aaa
	movea.l	((4+2),sp),a0		;例外発生時のa0
;<a0.l:アドレスレジスタの内容
;<a1.l:例外発生時のpc+2
_movep_d:
	adda.w	(a1)+,a0		;ディスプレースメントを加える
;<d0.w:0000ddd1ws001aaa
;<a0.l:実効アドレス
;<a1.l:例外発生時のpc+4
;復帰アドレスを更新する
	move.l	a1,((4+2+4)+2,sp)	;復帰アドレスを更新
	movea.l	(sp)+,a1
;オペレーションモードに従って転送する
;<d0.w:0000ddd1ws001aaa
;<a0.l:実効アドレス
	add.b	d0,d0			;c-flag=w,n-flag=s
	bcc	_movep_read		;writeを優先
;レジスタ→メモリ
;	MOVEP.{WL} Dx,(d16,Ay)
;<d0.w:0000ddd1s001aaa0
;<a0.l:実効アドレス
_movep_write:
	bpl	_movep_write_word	;longを優先
;レジスタ→メモリ,ロングワード
;	MOVEP.L Dx,(d16,Ay)
;<d0.w:0000ddd1s001aaa0
;<a0.l:実効アドレス
_movep_write_long:
	lsr.w	#8,d0			;000000000000ddd1
	lsr.b	#1,d0			;0000000000000ddd
					; 0  1  2  3  4  5  6  7
	beq	_movep_write_long_d0	; 0
	subq.b	#4,d0			;   -3 -2 -1  0  1  2  3
	bmi	_movep_write_long_d123	;   -3 -2 -1
	beq	_movep_write_long_d4	;             0
_movep_write_long_d567:			;                1  2  3
	subq.b	#2,d0			;               -1  0  1
	bmi	_movep_write_long_d5	;               -1
	beq	_movep_write_long_d6	;                   0
;	MOVEP.L D7,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d7:			;                      1
	rol.l	#8,d7
	move.b	d7,(a0)
	rol.l	#8,d7
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d7,(2,a0)
	rol.l	#8,d7
	move.b	d7,(4,a0)
	rol.l	#8,d7
	move.b	d7,(6,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.L D6,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d6:			;                   0
	rol.l	#8,d6
	move.b	d6,(a0)
	rol.l	#8,d6
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d6,(2,a0)
	rol.l	#8,d6
	move.b	d6,(4,a0)
	rol.l	#8,d6
	move.b	d6,(6,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.L D5,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d5:			;               -1
	rol.l	#8,d5
	move.b	d5,(a0)
	rol.l	#8,d5
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d5,(2,a0)
	rol.l	#8,d5
	move.b	d5,(4,a0)
	rol.l	#8,d5
	move.b	d5,(6,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.L D4,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d4:			;             0
	rol.l	#8,d4
	move.b	d4,(a0)
	rol.l	#8,d4
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d4,(2,a0)
	rol.l	#8,d4
	move.b	d4,(4,a0)
	rol.l	#8,d4
	move.b	d4,(6,a0)
	movea.l	(sp)+,a0
	rte

_movep_write_long_d123:			;   -3 -2 -1
	addq.b	#2,d0			;   -1  0  1
	bmi	_movep_write_long_d1	;   -1
	beq	_movep_write_long_d2	;       0
;	MOVEP.L D3,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d3:			;          1
	rol.l	#8,d3
	move.b	d3,(a0)
	rol.l	#8,d3
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d3,(2,a0)
	rol.l	#8,d3
	move.b	d3,(4,a0)
	rol.l	#8,d3
	move.b	d3,(6,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.L D2,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d2:			;       0
	rol.l	#8,d2
	move.b	d2,(a0)
	rol.l	#8,d2
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d2,(2,a0)
	rol.l	#8,d2
	move.b	d2,(4,a0)
	rol.l	#8,d2
	move.b	d2,(6,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.L D1,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d1:			;   -1
	rol.l	#8,d1
	move.b	d1,(a0)
	rol.l	#8,d1
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d1,(2,a0)
	rol.l	#8,d1
	move.b	d1,(4,a0)
	rol.l	#8,d1
	move.b	d1,(6,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.L D0,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_long_d0:			; 0
	move.w	(sp)+,d0		;先に復元すること
	rol.l	#8,d0
	move.b	d0,(a0)
	rol.l	#8,d0
	move.b	d0,(2,a0)
	rol.l	#8,d0
	move.b	d0,(4,a0)
	rol.l	#8,d0
	move.b	d0,(6,a0)
	movea.l	(sp)+,a0
	rte

;レジスタ→メモリ,ワード
;	MOVEP.W Dx,(d16,Ay)
;<d0.w:0000ddd1s001aaa0
;<a0.l:実効アドレス
_movep_write_word:
	lsr.w	#8,d0			;000000000000ddd1
	lsr.b	#1,d0			;0000000000000ddd
					; 0  1  2  3  4  5  6  7
	beq	_movep_write_word_d0	; 0
	subq.b	#4,d0			;   -3 -2 -1  0  1  2  3
	bmi	_movep_write_word_d123	;   -3 -2 -1
	beq	_movep_write_word_d4	;             0
_movep_write_word_d567:			;                1  2  3
	subq.b	#2,d0			;               -1  0  1
	bmi	_movep_write_word_d5	;               -1
	beq	_movep_write_word_d6	;                   0
;	MOVEP.W D7,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d7:			;                      1
	rol.w	#8,d7
	move.b	d7,(a0)
	rol.w	#8,d7
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d7,(2,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.W D6,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d6:			;                   0
	rol.w	#8,d6
	move.b	d6,(a0)
	rol.w	#8,d6
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d6,(2,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.W D5,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d5:			;               -1
	rol.w	#8,d5
	move.b	d5,(a0)
	rol.w	#8,d5
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d5,(2,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.W D4,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d4:			;             0
	rol.w	#8,d4
	move.b	d4,(a0)
	rol.w	#8,d4
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d4,(2,a0)
	movea.l	(sp)+,a0
	rte

_movep_write_word_d123:			;   -3 -2 -1
	addq.b	#2,d0			;   -1  0  1
	bmi	_movep_write_word_d1	;   -1
	beq	_movep_write_word_d2	;       0
;	MOVEP.W D3,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d3:			;          1
	rol.w	#8,d3
	move.b	d3,(a0)
	rol.w	#8,d3
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d3,(2,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.W D2,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d2:			;       0
	rol.w	#8,d2
	move.b	d2,(a0)
	rol.w	#8,d2
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d2,(2,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.W D1,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d1:			;   -1
	rol.w	#8,d1
	move.b	d1,(a0)
	rol.w	#8,d1
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	d1,(2,a0)
	movea.l	(sp)+,a0
	rte

;	MOVEP.W D0,(d16,Ay)
;<a0.l:実効アドレス
_movep_write_word_d0:			; 0
	move.w	(sp)+,d0		;先に復元すること
	rol.w	#8,d0
	move.b	d0,(a0)
	rol.w	#8,d0
	move.b	d0,(2,a0)
	movea.l	(sp)+,a0
	rte

;メモリ→レジスタ
;	MOVEP.{WL} (d16,Ay),Dx
;<d0.w:0000ddd1s001aaa0
;<a0.l:実効アドレス
_movep_read:
	bpl	_movep_read_word	;longを優先
;メモリ→レジスタ,ロングワード
;	MOVEP.L	(d16,Ay),Dx
;<d0.w:0000ddd1s001aaa0
;<a0.l:実効アドレス
_movep_read_long:
	lsr.w	#8,d0			;000000000000ddd1
	lsr.b	#1,d0			;0000000000000ddd
					; 0  1  2  3  4  5  6  7
	beq	_movep_read_long_d0	; 0
	subq.b	#4,d0			;   -3 -2 -1  0  1  2  3
	bmi	_movep_read_long_d123	;   -3 -2 -1
	beq	_movep_read_long_d4	;             0
_movep_read_long_d567:			;                1  2  3
	subq.b	#2,d0			;               -1  0  1
	bmi	_movep_read_long_d5	;               -1
	beq	_movep_read_long_d6	;                   0
;	MOVEP.L	(d16,Ay),D7
;<a0.l:実効アドレス
_movep_read_long_d7:			;                      1
	move.b	(a0),d7
	lsl.l	#8,d7
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d7
	lsl.l	#8,d7
	move.b	(4,a0),d7
	lsl.l	#8,d7
	move.b	(6,a0),d7
	movea.l	(sp)+,a0
	rte

;	MOVEP.L	(d16,Ay),D6
;<a0.l:実効アドレス
_movep_read_long_d6:			;                      1
	move.b	(a0),d6
	lsl.l	#8,d6
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d6
	lsl.l	#8,d6
	move.b	(4,a0),d6
	lsl.l	#8,d6
	move.b	(6,a0),d6
	movea.l	(sp)+,a0
	rte

;	MOVEP.L	(d16,Ay),D5
;<a0.l:実効アドレス
_movep_read_long_d5:			;                      1
	move.b	(a0),d5
	lsl.l	#8,d5
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d5
	lsl.l	#8,d5
	move.b	(4,a0),d5
	lsl.l	#8,d5
	move.b	(6,a0),d5
	movea.l	(sp)+,a0
	rte

;	MOVEP.L	(d16,Ay),D4
;<a0.l:実効アドレス
_movep_read_long_d4:			;             0
	move.b	(a0),d4
	lsl.l	#8,d4
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d4
	lsl.l	#8,d4
	move.b	(4,a0),d4
	lsl.l	#8,d4
	move.b	(6,a0),d4
	movea.l	(sp)+,a0
	rte

_movep_read_long_d123:			;   -3 -2 -1
	addq.b	#2,d0			;   -1  0  1
	bmi	_movep_read_long_d1	;   -1
	beq	_movep_read_long_d2	;       0
;	MOVEP.L	(d16,Ay),D3
;<a0.l:実効アドレス
_movep_read_long_d3:			;          1
	move.b	(a0),d3
	lsl.l	#8,d3
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d3
	lsl.l	#8,d3
	move.b	(4,a0),d3
	lsl.l	#8,d3
	move.b	(6,a0),d3
	movea.l	(sp)+,a0
	rte

;	MOVEP.L	(d16,Ay),D2
;<a0.l:実効アドレス
_movep_read_long_d2:			;       0
	move.b	(a0),d2
	lsl.l	#8,d2
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d2
	lsl.l	#8,d2
	move.b	(4,a0),d2
	lsl.l	#8,d2
	move.b	(6,a0),d2
	movea.l	(sp)+,a0
	rte

;	MOVEP.L	(d16,Ay),D1
;<a0.l:実効アドレス
_movep_read_long_d1:			;   -1
	move.b	(a0),d1
	lsl.l	#8,d1
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d1
	lsl.l	#8,d1
	move.b	(4,a0),d1
	lsl.l	#8,d1
	move.b	(6,a0),d1
	movea.l	(sp)+,a0
	rte

;	MOVEP.L	(d16,Ay),D0
;<a0.l:実効アドレス
_movep_read_long_d0:			; 0
	move.b	(a0),d0
	lsl.l	#8,d0
	addq.l	#2,sp			;スタックのd0を捨てる
					;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d0
	lsl.l	#8,d0
	move.b	(4,a0),d0
	lsl.l	#8,d0
	move.b	(6,a0),d0
	movea.l	(sp)+,a0
	rte

;メモリ→レジスタ,ワード
;	MOVEP.W (d16,Ay),Dx
;<d0.w:0000ddd1s001aaa0
;<a0.l:実効アドレス
_movep_read_word:
	lsr.w	#8,d0			;000000000000ddd1
	lsr.b	#1,d0			;0000000000000ddd
					; 0  1  2  3  4  5  6  7
	beq	_movep_read_word_d0	; 0
	subq.b	#4,d0			;   -3 -2 -1  0  1  2  3
	bmi	_movep_read_word_d123	;   -3 -2 -1
	beq	_movep_read_word_d4	;             0
_movep_read_word_d567:			;                1  2  3
	subq.b	#2,d0			;               -1  0  1
	bmi	_movep_read_word_d5	;               -1
	beq	_movep_read_word_d6	;                   0
;	MOVEP.W	(d16,Ay),D7
;<a0.l:実効アドレス
_movep_read_word_d7:			;                      1
	move.b	(a0),d7
	lsl.w	#8,d7
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d7
	movea.l	(sp)+,a0
	rte

;	MOVEP.W	(d16,Ay),D6
;<a0.l:実効アドレス
_movep_read_word_d6:			;                      1
	move.b	(a0),d6
	lsl.w	#8,d6
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d6
	movea.l	(sp)+,a0
	rte

;	MOVEP.W	(d16,Ay),D5
;<a0.l:実効アドレス
_movep_read_word_d5:			;                      1
	move.b	(a0),d5
	lsl.w	#8,d5
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d5
	movea.l	(sp)+,a0
	rte

;	MOVEP.W	(d16,Ay),D4
;<a0.l:実効アドレス
_movep_read_word_d4:			;             0
	move.b	(a0),d4
	lsl.w	#8,d4
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d4
	movea.l	(sp)+,a0
	rte

_movep_read_word_d123:			;   -3 -2 -1
	addq.b	#2,d0			;   -1  0  1
	bmi	_movep_read_word_d1	;   -1
	beq	_movep_read_word_d2	;       0
;	MOVEP.W	(d16,Ay),D3
;<a0.l:実効アドレス
_movep_read_word_d3:			;          1
	move.b	(a0),d3
	lsl.w	#8,d3
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d3
	movea.l	(sp)+,a0
	rte

;	MOVEP.W	(d16,Ay),D2
;<a0.l:実効アドレス
_movep_read_word_d2:			;       0
	move.b	(a0),d2
	lsl.w	#8,d2
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d2
	movea.l	(sp)+,a0
	rte

;	MOVEP.W	(d16,Ay),D1
;<a0.l:実効アドレス
_movep_read_word_d1:			;   -1
	move.b	(a0),d1
	lsl.w	#8,d1
	move.w	(sp)+,d0		;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d1
	movea.l	(sp)+,a0
	rte

;	MOVEP.W	(d16,Ay),D0
;<a0.l:実効アドレス
_movep_read_word_d0:			; 0
	move.b	(a0),d0
	lsl.w	#8,d0
	addq.l	#2,sp			;スタックのd0を捨てる
					;(a0)が遅い可能性があるのでここに挟む
	move.b	(2,a0),d0
	movea.l	(sp)+,a0
	rte



  .elseif UNIMPLEMENTED_INTEGER=6



;----------------------------------------------------------------
;
;	未実装整数命令例外
;
;----------------------------------------------------------------
;----------------------------------------------------------------
;MOVEP以外の未実装整数命令
ispCall:
	move.l	(sp)+,d0
	move.l	(sp)+,d1
	movea.l	(sp)+,a0
	movea.l	(sp)+,a1
	bra	_isp_unimp		;_060ISP_TABLE+$00000238
					;_060ISP_TABLE+$00

;----------------------------------------------------------------
;Unimplemented Integer Instruction
;未実装整数命令例外処理ルーチン
;	MOVEPだけ特別扱いにして高速に処理しています
;	その他の未実装整数命令の処理はISPに任せます
	.align	4
_060_isp_unint::
	move.l	a1,-(sp)
	move.l	a0,-(sp)
	move.l	d1,-(sp)
	move.l	d0,-(sp)
	movea.l	(4*4+2,sp),a1		;例外発生時のpc
;<a1.l:例外発生時のpc
	move.w	(a1)+,d1		;命令コード
;<d1.w:例外発生時の(pc).w
;MOVEPか
	move.w	d1,d0
	and.w	#$F138,d0
	cmp.w	#$0108,d0
	bne	ispCall
;----------------------------------------------------------------
;MOVEP命令
;	MOVEP.{WL} Dx,(d16,Ay)
;	MOVEP.{WL} (d16,Ay),Dx
;	ファンクションコードのチェック/変更を一切行っていません
;	転送中のアクセスエラーを考慮していません
;	次のような異常なメモリ操作は正しくエミュレートできません
;		MOVEP.W Dx,(d16,SSP) (-$004A<=d16<=-$0001)
;		MOVEP.L Dx,(d16,SSP) (-$004E<=d16<=-$0001)
;<d1.w:例外発生時の(pc).w
;	0000ddd1ws001aaa
;		ddd	data register
;		w	read/write(0=read,1=write)
;		s	size(0=word,1=long)
;		aaa	address register
;<a1.l:例外発生時のpc+2
;<sp.l:スタックに例外発生時のレジスタの内容を保持
;	0000	.l	d0
;	0004	.l	d0
;	0008	.l	a0
;	000C	.l	a1
;	0010	.w	sr
;	0012	.l	pc		pcは次の命令のアドレスに更新すること
;	0016	.w	例外フォーマット番号,ベクタオフセット
;	0018		例外発生時のsspの位置
_movep:
	ror.b	#3,d1			;0000ddd1aaaws001,n=aaa[2]
	bpl	_movep_a0123
_movep_a4567:
	lsl.b	#2,d1			;0000ddd1aws00100,c=aaa[1],n=aaa[0]
	bcc	_movep_a45
_movep_a67:
	bpl	_movep_a6
_movep_a7:
	lea.l	(4*4+8,sp),a0		;例外発生時のssp
	btst.b	#5,(4*4+0,sp)
	bne	_movep_an
	movea.l	usp,a0			;例外発生時のusp
	bra	_movep_an

_movep_a6:
	movea.l	a6,a0			;例外発生時のa6
	bra	_movep_an

_movep_a45:
	bpl	_movep_a4
_movep_a5:
	movea.l	a5,a0			;例外発生時のa5
	bra	_movep_an

_movep_a4:
	movea.l	a4,a0			;例外発生時のa4
	bra	_movep_an

_movep_a0123:
	lsl.b	#2,d1			;0000ddd1aws00100,c=aaa[1],n=aaa[0]
	bcc	_movep_a01
_movep_a23:
	bpl	_movep_a2
_movep_a3:
	movea.l	a3,a0			;例外発生時のa3
	bra	_movep_an

_movep_a2:
	movea.l	a2,a0			;例外発生時のa2
	bra	_movep_an

_movep_a01:
	bpl	_movep_a0
_movep_a1:
	movea.l	(4,sp),a0		;例外発生時のa1
	bra	_movep_an

_movep_a0:
	movea.l	(sp),a0			;例外発生時のa0
;<d1.w:0000ddd1aws00100
;<a0.l:An
;<a1.l:例外発生時のpc+2
_movep_an:
	adda.w	(a1)+,a0		;ディスプレースメントを加える
;<a0.l:実効アドレス
;<a1.l:例外発生時のpc+4
	lsl.b	#2,d1			;0000ddd1s0010000,c=w,n=s
	bcc	_movep_read		;writeを優先
;レジスタ→メモリ
;	MOVEP.{WL} Dx,(d16,Ay)
;<d1.w:0000ddd1s0010000
;<a0.l:実効アドレス
;<a1.l:例外発生時のpc+4
_movep_write:
	lsl.w	#5,d1			;dd1s001000000000,c=ddd[2],n=ddd[1]
	bcc	_movep_write_d0123
_movep_write_d4567:
	bpl	_movep_write_d45
_movep_write_d67:
	lsl.w	#2,d1			;1s00100000000000,c=ddd[0]
	bcc	_movep_write_d6
_movep_write_d7:
	move.l	d7,d0
	bra	_movep_write_dn

_movep_write_d6:
	move.l	d6,d0
	bra	_movep_write_dn

_movep_write_d45:
	lsl.w	#2,d1			;1s00100000000000,c=ddd[0]
	bcc	_movep_write_d4
_movep_write_d5:
	move.l	d5,d0
	bra	_movep_write_dn

_movep_write_d4:
	move.l	d4,d0
	bra	_movep_write_dn

_movep_write_d0123:
	bpl	_movep_write_d01
_movep_write_d23:
	lsl.w	#2,d1			;1s00100000000000,c=ddd[0]
	bcc	_movep_write_d2
_movep_write_d3:
	move.l	d3,d0
	bra	_movep_write_dn

_movep_write_d2:
	move.l	d2,d0
	bra	_movep_write_dn

_movep_write_d01:
	lsl.w	#2,d1			;1s00100000000000,c=ddd[0]
	bcc	_movep_write_d0
_movep_write_d1:
	move.l	(4,sp),d0
	bra	_movep_write_dn

_movep_write_d0:
	move.l	(sp),d0
;<d0.l:Dn
;<d1.w:1s00100000000000
;<a0.l:実効アドレス
;<a1.l:例外発生時のpc+4
_movep_write_dn:
	lsl.w	#2,d1			;0010000000000000,c=s
	bpl	_movep_write_word	;longを優先
;レジスタ→メモリ,ロングワード
;	MOVEP.L Dx,(d16,Ay)
;<d0.l:Dn
;<d1.w:0010000000000000
;<a0.l:実効アドレス
;<a1.l:例外発生時のpc+4
_movep_write_long:
	rol.l	#8,d0
	tst.l	(a1)			;MOVEPの直後の2ワードをキャッシュに乗せておく
	move.b	d0,(a0)			;1バイト目を書き込む
	move.w	(a1),d1			;MOVEPの直後のワード
					;キャッシュはヒットするはず
	rol.l	#8,d0			;書き込んだ直後に次の1バイトを用意する
	and.w	#$F138,d1		;直後の命令もMOVEPか?
	cmp.w	#$0108,d1
	bne	_movep_write_long_stop	;MOVEPではない
;MOVEPの直後の命令もMOVEPだった
;書き込みながら直後のMOVEPのAnとDnを確定する
_movep_write_long_cont:
	move.w	(a1)+,d1		;直後のMOVEP
					;キャッシュはヒットするはず
;<d1.w:直後のMOVEP,0000ddd1ws001aaa
;<a1.l:直後の命令のpc+2
	ror.b	#3,d1			;0000ddd1aaaws001,n=aaa[2]
	bpl	_movep_long_cont_a0123
_movep_long_cont_a4567:
	lsl.b	#2,d1			;0000ddd1aws00100,c=aaa[1],n=aaa[0]
	bcc	_movep_long_cont_a45
_movep_long_cont_a67:
	bpl	_movep_long_cont_a6
_movep_long_cont_a7:
	move.b	d0,(2,a0)		;2バイト目を書き込む
	rol.l	#8,d0			;書き込んだ直後に次の1バイトを用意する





;MOVEPの直後の命令はMOVEPではなかった
;残りのデータを書き込んで復帰アドレスを更新して終わり

_movep_write_long_stop:
;復帰アドレスを更新する
	move.l	a1,(4*4+2,sp)		;復帰アドレスを更新




;レジスタ→メモリ,ワード
;	MOVEP.W Dx,(d16,Ay)
;<d0.l:Dn
;<d1.w:0010000000000000
;<a0.l:実効アドレス
;<a1.l:例外発生時のpc+4
_movep_write_word:




;メモリ→レジスタ
;	MOVEP.{WL} (d16,Ay),Dx
;<d1.w:0000ddd1s0010000
;<a0.l:実効アドレス
;<a1.l:例外発生時のpc+4
_movep_read:
;復帰アドレスを更新する
	move.l	a1,(4*4+2,sp)		;復帰アドレスを更新
	move.b	(a0),d0			;サイズ未確定のまま1バイト目をread
					;(d16,Ay)でキャッシュはヒットしないと想定して,
					;ウェイトの間になるべく多くの処理を行う
					;ここではウェイトの間にDnを確定してみる
					;これでもウェイトがかなり余るはず
					;メモリアクセスは極力避けること(キャッシュが
					;ミスするとそこにウェイトが入ってしまう)
	tst.b	d1			;0000ddd1s0010000,n=s
					;_movep_readの直後で分岐すればtstは不要だが,
					;あえてここに入れる
	bpl	_movep_read_word	;longを優先
;メモリ→レジスタ,ロングワード
;	MOVEP.L (d16,Ay),Dx
_movep_read_long:
	lsl.w	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(2,a0),d0		;2バイト目をread
	lsl.w	#4,d1			;ddd1s00100000000,s=1,n=ddd[2]
					;1ビットずつテストするのでcは使わない
	bpl	_movep_read_long_d0123	;アクセスの度に分岐を1〜2個ずつ入れる
					;命令キャッシュさえヒットすれば,
					;分岐キャッシュがミスしても問題ない
_movep_read_long_d4567:
	lsl.l	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(4,a0),d0		;3バイト目をread
	lsl.w	#1,d1			;dd1s001000000000,s=1,n=ddd[1]
	bpl	_movep_read_long_d45
_movep_read_long_d67:
	lsl.l	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(6,a0),d0		;4バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=1,n=ddd[0]
	bpl	_movep_read_long_d6
_movep_read_long_d7:
	move.l	d0,d7
	bra	_movep_read_long_dn

_movep_read_long_d6:
	move.l	d0,d6
	bra	_movep_read_long_dn

_movep_read_long_d45:
	lsl.l	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(6,a0),d0		;4バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=1,n=ddd[0]
	bpl	_movep_read_long_d4
_movep_read_long_d5:
	move.l	d0,d5
	bra	_movep_read_long_dn

_movep_read_long_d4:
	move.l	d0,d4
	bra	_movep_read_long_dn

_movep_read_long_d0123:
	lsl.l	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(4,a0),d0		;3バイト目をread
	lsl.w	#1,d1			;dd1s001000000000,s=1,n=ddd[1]
	bpl	_movep_read_long_d01
_movep_read_long_d23:
	lsl.l	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(6,a0),d0		;4バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=1,n=ddd[0]
	bpl	_movep_read_long_d2
_movep_read_long_d3:
	move.l	d0,d3
	bra	_movep_read_long_dn

_movep_read_long_d2:
	move.l	d0,d2
_movep_read_long_dn:
	move.l	(sp)+,d0
_movep_read_long_dn_d1:
	move.l	(sp)+,d1
_movep_read_long_dn_a0:
	movea.l	(sp)+,a0
	movea.l	(sp)+,a1
	rte

_movep_read_long_d01:
	lsl.l	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(6,a0),d0		;4バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=1,n=ddd[0]
	bpl	_movep_read_long_d0
_movep_read_long_d1:
	move.l	d0,d1
	move.l	(sp)+,d0
	addq.l	#4,sp			;スタックのd1を破棄する
	bra	_movep_read_long_dn_a0

_movep_read_long_d0:
	addq.l	#4,sp			;スタックのd0を破棄して,
					;読み出したd0をそのまま返す
	bra	_movep_read_long_dn_d1

;メモリ→レジスタ,ワード
;	MOVEP.W (d16,Ay),Dx
_movep_read_word:
	lsl.w	#5,d1			;dd1s001000000000,s=0,c=ddd[2],n=ddd[1]
	bcc	_movep_read_word_d0123	;アクセスの度に分岐を2〜3個ずつ入れる
					;分岐キャッシュが全部ミスしても,
					;命令キャッシュさえヒットしていれば,
					;これでもウェイトに入り切ると思われる
					;(入り切らなくても問題はない)
_movep_read_word_d4567:
	bpl	_movep_read_word_d45
_movep_read_word_d67:
	lsl.w	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(2,a0),d0		;2バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=0,n=ddd[0]
	bpl	_movep_read_word_d6
_movep_read_word_d7:
	move.w	d0,d7
	bra	_movep_read_word_dn

_movep_read_word_d6:
	move.w	d0,d6
	bra	_movep_read_word_dn

_movep_read_word_d45:
	lsl.w	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(2,a0),d0		;2バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=0,n=ddd[0]
	bpl	_movep_read_word_d4
_movep_read_word_d5:
	move.w	d0,d5
	bra	_movep_read_word_dn

_movep_read_word_d4:
	move.w	d0,d4
	bra	_movep_read_word_dn

_movep_read_word_d0123:
	bpl	_movep_read_word_d01
_movep_read_word_d23:
	lsl.w	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(2,a0),d0		;2バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=0,n=ddd[0]
	bpl	_movep_read_word_d2
_movep_read_word_d3:
	move.w	d0,d3
	bra	_movep_read_word_dn

_movep_read_word_d2:
	move.w	d0,d2
_movep_read_word_dn:
	move.l	(sp)+,d0
_movep_read_word_dn_d1:
	move.l	(sp)+,d1
_movep_read_word_dn_a0:
	movea.l	(sp)+,a0
	movea.l	(sp)+,a1
	rte

_movep_read_word_d01:
	lsl.w	#8,d0			;ウェイト終了までd0が確定しないので,
					;次のアクセスの直前でシフトする
	move.b	(2,a0),d0		;2バイト目をread
	lsl.w	#1,d1			;d1s0010000000000,s=0,n=ddd[0]
	bpl	_movep_read_word_d0
_movep_read_word_d1:
	move.w	d0,d1			;d1の上位ワードは破壊されていないので,
					;そのまま返す
	move.l	(sp)+,d0
	addq.l	#4,sp			;スタックのd1を破棄する
	bra	_movep_read_word_dn_a0

_movep_read_word_d0:
					;d0の上位ワードは破壊されていないので,
					;そのまま返す
	addq.l	#4,sp			;スタックのd0を破棄する
	bra	_movep_read_word_dn_d1



  .endif



;----------------------------------------------------------------
;
;	F-line未実装命令例外/特権違反例外
;
;----------------------------------------------------------------
;----------------------------------------------------------------
;Line 1111 Emulator (Unimplemented F-Line Opcode)
;	FLOATn.Xが特権違反例外をF-lineに落としてしまうので、
;	ここにも特権違反例外が入ってくることがある
	.dc.b	'060turbo'
	.dc.l	0
_060_fpsp_fline::
	cmpi.w	#$2000,(6,sp)		;フォーマットが2以上ならばFPSPに渡す
	bcc	_fpsp_fline
	move.l	a6,-(sp)
	movea.l	(4+2,sp),a6		;例外発生時のPC
;<a6.l:例外発生時のpc
	cmpi.b	#$FE,(a6)
	beq	feCall			;$FExx FEファンクションコール
	bhi	dosCall			;$FFxx DOSコール
	cmpi.b	#$F0,(a6)
	blo	flineToPrivilege	;F-Lineでなければ特権違反例外
;----------------------------------------------------------------
;$FExxでも$FFxxでもないF-Line OpcodeはFPSPに任せる
fpspCall::
	movea.l	(sp)+,a6
	bra	_fpsp_fline		;_060FPSP_TABLE+$00001B8C
					;_060FPSP_TABLE+$30

;----------------------------------------------------------------
;DOSコール
;<a6.l:例外発生時のpc
dosCall::
;;;	movea.l	(sp)+,a6
;;;	jmp	([vectorOldFLINE])
	cmpi.w	#$FFF5,(a6)
	bcc	dosCallThread
	movem.l	d1-d7/a0-a5,-(sp)
	move.w	(a6)+,d0		;(pc).w
	and.l	#$000000FF,d0
;<d0.l:DOSコール番号
	move.l	a6,(dosPC,sp)		;復帰アドレスを更新
	lea.l	(dosSSP,sp),a6		;例外発生時のssp
	btst.b	#5,(dosSR,sp)
	bne	@f
	move.l	usp,a6			;例外発生時のusp
@@:
;<a6.l:パラメータのアドレス
	tst.w	$1C08.w			;DOSコールのレベル(ここから_INDOSFLG)
	bne	@f
	move.l	sp,$1C5C.w		;DOSコールにレベル0で入ったときのssp
	move.b	d0,$1C0A.w		;レベル0で入ったDOSコール番号
@@:
	addq.w	#1,$1C08.w		;DOSコールのレベル(ここから_INDOSFLG)
	clr.l	$1C98.w			;DOSコールに入ってからオープンしたFCBテーブル
	jsr	([$1800,d0.l*4])
;	jsr	([$1800+$0400,d0.w*4])	;DOSコール実行
					;d0.l	$xxxxFFxx
					;拡張	$FFFFFFxx
					;4倍	$FFFFFCxx
					;本来の値より$0400足りないのでbdに加えておく
	clr.l	$1C98.w			;DOSコールに入ってからオープンしたFCBテーブル
	subq.w	#1,$1C08.w		;DOSコールのレベル(ここから_INDOSFLG)
	bne	@f
	clr.b	$1C0A.w			;レベル0で入ったDOSコール番号
@@:	move.l	d0,-(sp)
	jsr	$00008740		;breakチェック
	movem.l	(sp)+,d0-d7/a0-a6
	tst.b	$1C14.w			;DOSコール終了時にスレッドを切り替えるか(0=no,1=yes)
	bne	dosCallThreadChange
	tst.w	(sp)
	bmi	@f
	rte

@@:	ori.w	#$8000,sr
	rte

;スレッド管理関係のDOSコール
dosCallThread::
	move.l	a5,-(sp)
	move.l	d0,-(sp)
	move.w	(a6)+,d0		;(pc).w
	move.l	a6,(4*3+2,sp)		;復帰アドレスを更新
	lea.l	(4*3+8,sp),a6		;パラメータのアドレス
	jmp	$0000E31C

;DOSコール終了時にスレッドを切り替える
dosCallThreadChange::
	jmp	$0000E050

;----------------------------------------------------------------
;FEファンクションコール
;<a6.l:例外発生時のpc
feCall::
	move.l	d7,-(sp)
	move.w	(a6)+,d7		;例外発生時の(pc).w
;<d7.w:例外発生時の(pc).w
;<a6.l:例外発生時のpc+2
	move.l	a6,(4+4+2,sp)		;復帰アドレスを更新する
	jmp	([feJumpTable+$0200*4,pc,d7.w*4])	;各FEファンクションへ分岐
					;+$0200*4はオフセットの調節のため
					;d7.wを符号拡張すると	$FFFFFE00〜$FFFFFEFF
					;4倍すると		$FFFFF800〜$FFFFFBFC
					;オフセットが$0200*4足りないのでその分加えている

;----------------------------------------------------------------
;
;	特権違反例外
;
;----------------------------------------------------------------
;----------------------------------------------------------------
;特権違反例外
privilegeViolation::
	move.l	a6,-(sp)
	movea.l	(4+2,sp),a6		;例外発生時のPC
flineToPrivilege:
	cmpi.w	#$40C0,(a6)
	blo	unknownPrivilege
	cmpi.w	#$40FF,(a6)
	bhi	unknownPrivilege
;----------------------------------------------------------------
;MOVE from SR
;	このままでは書き換えが反映される前に特権違反が発生してしまい、
;	そのとき既にMOVE from CCRになっているので白窓が出る
;	~008652:
;		move.l	a6,d0			;MOVE from CCRに変更する
;		or.w	#$0200,d0
;		move.w	d0,-(a5)
;		movec.l	cacr,d0			;命令キャッシュフラッシュ
;		or.w	#$0008,d0
;		movec.l	d0,cacr
;		movem.l	(sp)+,d0/a5-a6
;		rte
moveFromSr::
	bset.b	#1,(a6)			;MOVE from SRをMOVE from CCRにする
					;d0は壊れているので使わないこと
	bsr	cache_flush
	movea.l	(sp)+,a6
	rte

;----------------------------------------------------------------
;解釈できない特権違反例外
;スーパーバイザモードでもSTOPでSRのSビットをクリアしようとしたときなどに発生する
unknownPrivilege::
	move.l	(sp)+,a6
;----------------------------------------------------------------
;FPSPにも解釈できないF-Line Opcodeや特権違反例外は白窓へ
;[$002C.w]に飛ばすと無限ループに陥ってしまうので[$0010.w]を使う
_060_real_fline::
	jmp	([$0010.w])

;----------------------------------------------------------------
;
;	ISPとFPSPが使うサブルーチン
;
;----------------------------------------------------------------
;----------------------------------------------------------------
_060_real_lock_page::
_060_real_unlock_page::
	clr.l	d0
	rts

;----------------------------------------------------------------
_060_dmem_write::
_060_imem_read::
_060_dmem_read::
@@:	move.b	(a0)+,(a1)+
	subq.l	#1,d0
	bne	@b
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_dmem_read_byte::
	clr.l	d0
	move.b	(a0),d0
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_dmem_write_byte::
	move.b	d0,(a0)
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_dmem_read_word::
	clr.l	d0
	move.w	(a0),d0
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_imem_read_word::
	move.w	(a0),d0
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_dmem_write_word::
	move.w	d0,(a0)
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_dmem_read_long::
_060_imem_read_long::
	move.l	(a0),d0
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_dmem_write_long::
	move.l	d0,(a0)
	clr.l	d1
	rts

;----------------------------------------------------------------
_060_real_chk::
_060_real_divbyzero::
	tst.w	(sp)
	bmi	@f
	rte

@@:	move.b	#$24,(7,sp)
;----------------------------------------------------------------
_060_real_trace::
	jmp	([$0024.w])		;トレース

;----------------------------------------------------------------
_060_real_access::
	jmp	([$0008.w])		;アクセスエラー

;----------------------------------------------------------------
_060_real_trap::
	jmp	([$001C.w])		;FTRAPcc

;----------------------------------------------------------------
_060_real_inex::
_060_real_dz::
_060_real_unfl::
_060_real_operr::
_060_real_ovfl::
_060_real_snan::
	fsave	-(sp)
	move.w	#$6000,(2,sp)
	frestore	(sp)+
	rte

;----------------------------------------------------------------
_060_real_bsun::
	fsave	-(sp)
	fmove.l	fpsr,-(sp)
	and.b	#$FE,(sp)
	fmove.l	(sp)+,fpsr
	lea.l	(12,sp),sp
	rte

;----------------------------------------------------------------
_060_real_fpu_disabled::
	move.l	d0,-(sp)
	movec.l	pcr,d0			;FPUをイネーブルにする
	bclr.l	#1,d0
	movec.l	d0,pcr
	move.l	(sp)+,d0
	move.l	(12,sp),(2,sp)		;リトライ
	rte

;----------------------------------------------------------------
;
;	ISPとFPSPの出口
;
;----------------------------------------------------------------
;----------------------------------------------------------------
_060_isp_done::
	rte

;----------------------------------------------------------------
_060_fpsp_done::
	rte
