File:  [Isaki's NoNo m68k/m88k emulator] / nono / m680x0 / m68030ops.cpp
Revision 1.1.1.8 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:26 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v020, HEAD
nono 1.0.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

#include "mpu680x0.h"
#include "m68030acc.h"
#include "m68030bitfield.h"

#define OP_DEF(name)	void __CONCAT(MPU680x0Device::op_,name)()
#define OP_FUNC(name)	__CONCAT(op_,name)()

#define CCR reg.ccr
#define ACC (*(m68030acc*)&reg.ccr)

#define RegIRX			((ir >> 9) & 7)
#define RegIRY			(ir & 7)
#define RegDX			reg.D[RegIRX]
#define RegAX			reg.A[RegIRX]
#define RegDY			reg.D[RegIRY]
#define RegAY			reg.A[RegIRY]

// 副作用のあるマクロ
// 特権違反例外のスタックに積む PC は違反を起こした命令先頭。
#define SUPERVISOR_OP	do { \
	if (!IsSuper()) {	\
		CYCLE2(18, 20);	\
		Exception(M68K::EXCEP_PRIV);	\
		return;	\
	}	\
} while (0)

// FPU 命令の FSAVE/FRESTORE 以外のグループ全員で実行開始時に必要な処理
inline void
MPU680x0Device::fpu_op_start()
{
	fpu_dirty = true;

	// 現在の FPCR/FPSR を fe 構造体にコピー。
	//
	// fe.fe_{fpcr,fpsr} のほうはこの fpe 用の内部ワークなので破壊してよい。
	// 命令実行の結果、FPSR レジスタの値を更新する際は fpu_upd_fpsr() を
	// 呼ぶこと。これを使わず独自に更新する場合は fe.fe_fpframe->fpf_fpsr
	// (こっちがレジスタ値) と fe.fe_fpsr (FPE 用) を同時に更新すること。
	// FPCR のほうは FMOVE-to-FPCR 命令以外で変更されることはないはず。
	fe.fe_fpcr = RegFPCR;
	fe.fe_fpsr = RegFPSR;
}

// %0000_000000_mmmrrr	ORI.B #<imm>,<ea>
// %0000_000000_111100	ORI.B #<imm>,CCR
OP_DEF(ori_b)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// ORI.B #<imm>,Dn
		CYCLE(2);
		uint32 dst = (reg.D[n] & 0xff) | src;
		ACC.move_8(dst);
		reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
	} else if (n == 0b111100) {
		// ORI.B #<imm>,CCR
		CYCLE2(12, 14);
		CCR.Set(CCR.Get() | src);
	} else {
		// ORI.B #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst |= src;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

// %0000_000001_mmmrrr	ORI.W #<imm>,<ea>
// %0000_000001_111100	ORI.W #<imm>,SR
OP_DEF(ori_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// ORI.W #<imm>,Dn
		CYCLE(2);
		uint32 src = fetch_2();
		uint32 dst = (reg.D[n] & 0xffff) | src;
		ACC.move_16(dst);
		reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
	} else if (n == 0b111100) {
		// ORI.W #<imm>,SR
		SUPERVISOR_OP;
		CYCLE2(12, 14);
		uint32 src = fetch_2();
		SetSR(GetSR() | src);
	} else {
		// ORI.W #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 src = fetch_2();
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst |= src;
		ACC.move_16(dst);
		write_2(ea, dst);
	}
}

// %0000_000010_mmmrrr	ORI.L #<imm>,<ea>
OP_DEF(ori_l)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_4();
	if (n < 8) {
		// ORI.L #<imm>,Dn
		CYCLE(2);
		reg.D[n] |= src;
		ACC.move_32(reg.D[n]);
	} else {
		// ORI.L #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 dst = read_4(ea);
		dst |= src;
		ACC.move_32(dst);
		write_4(ea, dst);
	}
}

// %0000_000011_mmmrrr	CMP2/CHK2.B <ea>,Rn
OP_DEF(cmp2chk2_b)
{
	ir2 = fetch_2();
	uint32 compare;
	uint32 ea = cea_ctrl();
	uint32 lower;
	uint32 upper;

	if ((ir2 & 0x8000) == 0) {
		// compare が Dn
		compare = (int32)(int8)(reg.R[ir2 >> 12] & 0xff);
	} else {
		// compare が An
		compare = reg.R[ir2 >> 12];
	}

	// 本当は PC 相対ならプログラム空間アクセス、
	// それ以外はデータ空間アクセスだが、ここでは区別しない。
	lower = (int32)(int8)read_1(ea);
	upper = (int32)(int8)read_1(ea + 1);

	ACC.chk2cmp2_32(compare, lower, upper);

	// サイクル数はこれは実際には全部最大値
	if ((ir2 & 0x0800)) {
		// CHK2 で条件を満たしていれば例外
		if (reg.ccr.CondCS()) {
			CYCLE2(40, 42);
			Exception(M68K::EXCEP_CHK);
		} else {
			CYCLE(18);
		}
	} else {
		// CMP2
		CYCLE(20);
	}
}

// MOVEP.[WL] (d,Ay),Dx と
// MOVEP.[WL] Dx,(d,Ay) の共通部分。
void
MPU680x0Device::ops_movep()
{
	uint32 disp = (int32)(int16)fetch_2();
	uint32 ea = RegAY + disp;
	bool size_long = ((ir & 0x40) != 0);
	bool reg2mem = ((ir & 0x80) != 0);

	CYCLE(14);

	if (reg2mem) {
		// Dx -> memory
		uint32 dx = RegDX;
		if (size_long) {
			write_1(ea, (dx >> 24));
			ea += 2;
			write_1(ea, (dx >> 16) & 0xff);
			ea += 2;
		}
		write_1(ea, (dx >> 8) & 0xff);
		ea += 2;
		write_1(ea, (dx & 0xff));
	} else {
		// memory -> Dx
		uint32 dx = 0;
		if (size_long) {
			dx = read_1(ea);
			dx <<= 8;
			ea += 2;
			dx |= read_1(ea);
			dx <<= 8;
			ea += 2;
		}
		// word
		dx |= read_1(ea);
		dx <<= 8;
		ea += 2;
		dx |= read_1(ea);

		if (size_long) {
			RegDX = dx;
		} else {
			RegDX = (RegDX & 0xffff0000) | (dx & 0xffff);
		}
	}
}

// %0000_xxx100_000yyy	BTST.L Dx,Dy
// %0000_xxx100_001yyy	MOVEP.W (d,Ay),Dx
// %0000_xxx100_mmmrrr	BTST.B Dx,<ea>
OP_DEF(btst_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BTST.L Dx,Dy
		CYCLE(4);
		uint bit = (RegDX & 31);
		ACC.btst(RegDY, bit);
	} else if (n < 16) {
		// MOVEP.W (d,Ay),Dx
		ops_movep();
	} else {
		// BTST.B Dx,<ea>
		CYCLE(4);
		uint bit = (RegDX & 7);
		uint32 data = fea_data_1();
		ACC.btst(data, bit);
	}
}

// %0000_xxx101_000yyy	BCHG.L Dx,Dy
// %0000_xxx101_001yyy	MOVEP.L (d,Ay),Dx
// %0000_xxx101_mmmrrr	BCHG.B Dx,<ea>
OP_DEF(bchg_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BCHG.L Dx,Dy
		CYCLE(6);
		uint bit = (RegDX & 31);
		RegDY = ACC.bchg(RegDY, bit);
	} else if (n < 16) {
		// MOVEP.L (d,Ay),Dx
		ops_movep();
	} else {
		// BCHG.B Dx,<ea>
		CYCLE(6);
		uint bit = (RegDX & 7);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.bchg(data, bit);
		write_1(ea, data);
	}
}

// %0000_xxx110_000yyy	BCLR.L Dx,Dy
// %0000_xxx110_001yyy	MOVEP.W Dx,(d,Ay)
// %0000_xxx110_mmmrrr	BCLR.B Dx,<ea>
OP_DEF(bclr_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BCLR.L Dx,Dy
		CYCLE(6);
		uint bit = (RegDX & 31);
		RegDY = ACC.bclr(RegDY, bit);
	} else if (n < 16) {
		// MOVEP.W Dx,(d,Ay)
		ops_movep();
	} else {
		// BCLR.B Dx,<ea>
		CYCLE(6);
		uint bit = (RegDX & 7);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.bclr(data, bit);
		write_1(ea, data);
	}
}

// %0000_xxx111_000yyy	BSET.L Dx,Dy
// %0000_xxx111_001yyy	MOVEP.L Dx,(d,Ay)
// %0000_xxx111_mmmrrr	BSET.B Dx,<ea>
OP_DEF(bset_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BSET.L Dx,Dy
		CYCLE(6);
		uint bit = (RegDX & 31);
		RegDY = ACC.bset(RegDY, bit);
	} else if (n < 16) {
		// MOVEP.L Dx,(d,Ay)
		ops_movep();
	} else {
		// BSET.B Dx,<ea>
		CYCLE(6);
		uint bit = (RegDX & 7);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.bset(data, bit);
		write_1(ea, data);
	}
}

// %0000_001000_mmmrrr	ANDI.B #<imm>,<ea>
// %0000_001000_111100	ANDI.B #<imm>,CCR
OP_DEF(andi_b)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// ANDI.B #<imm>,Dn
		CYCLE(2);
		uint32 dst = reg.D[n] & 0xff;
		dst &= src;
		ACC.move_8(dst);
		reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
	} else if (n == 0b111100) {
		// ANDI.B #<imm>,CCR
		CYCLE2(12, 14);
		CCR.Set(CCR.Get() & src);
	} else {
		// ANDI.B #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst &= src;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

// %0000_001001_mmmrrr	ANDI.W #<imm>,<ea>
// %0000_001001_111100	ANDI.W #<imm>,SR
OP_DEF(andi_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// ANDI.W #<imm>,Dn
		CYCLE(2);
		uint32 src = fetch_2();
		uint32 dst = reg.D[n] & 0xffff;
		dst &= src;
		ACC.move_16(dst);
		reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
	} else if (n == 0b111100) {
		// ANDI.W #<imm>,SR
		SUPERVISOR_OP;
		CYCLE2(12, 14);
		uint32 src = fetch_2();
		SetSR(GetSR() & src);
	} else {
		// ANDI.W #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 src = fetch_2();
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst &= src;
		ACC.move_16(dst);
		write_2(ea, dst);
	}
}

// %0000_001010_mmmrrr	ANDI.L #<imm>,<ea>
OP_DEF(andi_l)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_4();
	if (n < 8) {
		// ANDI.L #<imm>,Dn
		CYCLE(2);
		reg.D[n] &= src;
		ACC.move_32(reg.D[n]);
	} else {
		// ANDI.L #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 dst = read_4(ea);
		dst &= src;
		ACC.move_32(dst);
		write_4(ea, dst);
	}
}

// %0000_001011_mmmrrr	CMP2/CHK2.W <ea>,Rn
OP_DEF(cmp2chk2_w)
{
	ir2 = fetch_2();
	uint32 compare;
	uint32 ea = cea_ctrl();
	uint32 lower;
	uint32 upper;

	if ((ir2 & 0x8000) == 0) {
		// compare が Dn
		compare = (int32)(int16)(reg.R[ir2 >> 12] & 0xffff);
	} else {
		// compare が An
		compare = reg.R[ir2 >> 12];
	}

	// 本当は PC 相対ならプログラム空間アクセス、
	// それ以外はデータ空間アクセスだが、ここでは区別しない。
	lower = (int32)(int16)read_2(ea);
	upper = (int32)(int16)read_2(ea + 2);

	ACC.chk2cmp2_32(compare, lower, upper);

	// サイクル数はこれは実際には全部最大値
	if ((ir2 & 0x0800)) {
		// CHK2 で条件を満たしていれば例外
		if (reg.ccr.CondCS()) {
			CYCLE2(40, 42);
			Exception(M68K::EXCEP_CHK);
		} else {
			CYCLE(18);
		}
	} else {
		// CMP2
		CYCLE(20);
	}
}

// %0000_010000_mmmrrr	SUBI.B #<imm>,<ea>
OP_DEF(subi_b)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// SUBI.B #<imm>,Dn
		CYCLE(2);
		uint32 dst = reg.D[n] & 0xff;
		dst = ACC.sub_8(src, dst);
		reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
	} else {
		// SUBI.B #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst = ACC.sub_8(src, dst);
		write_1(ea, dst);
	}
}

// %0000_010001_mmmrrr	SUBI.W #<imm>,<ea>
OP_DEF(subi_w)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2();
	if (n < 8) {
		// SUBI.W #<imm>,Dn
		CYCLE(2);
		uint32 dst = reg.D[n] & 0xffff;
		dst = ACC.sub_16(src, dst);
		reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
	} else {
		// SUBI.W #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst = ACC.sub_16(src, dst);
		write_2(ea, dst);
	}
}

// %0000_010010_mmmrrr	SUBI.L #<imm>,<ea>
OP_DEF(subi_l)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_4();
	if (n < 8) {
		// SUBI.L #<imm>,Dn
		CYCLE(2);
		reg.D[n] = ACC.sub_32(src, reg.D[n]);
	} else {
		// SUBI.L #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 dst = read_4(ea);
		dst = ACC.sub_32(src, dst);
		write_4(ea, dst);
	}
}

// %0000_010011_mmmrrr	CMP2/CHK2.L <ea>,Rn
OP_DEF(cmp2chk2_l)
{
	ir2 = fetch_2();
	uint32 compare = reg.R[ir2 >> 12];
	uint32 ea = cea_ctrl();
	uint32 lower;
	uint32 upper;

	// 本当は PC 相対ならプログラム空間アクセス、
	// それ以外はデータ空間アクセスだが、ここでは区別しない。
	lower = read_4(ea);
	upper = read_4(ea + 4);

	ACC.chk2cmp2_32(compare, lower, upper);

	// サイクル数はこれは実際には全部最大値
	if ((ir2 & 0x0800)) {
		// CHK2 で条件を満たしていれば例外
		if (reg.ccr.CondCS()) {
			CYCLE2(40, 42);
			Exception(M68K::EXCEP_CHK);
		} else {
			CYCLE(18);
		}
	} else {
		// CMP2
		CYCLE(20);
	}
}

// %0000_011000_mmmrrr	ADDI.B #<imm>,<ea>
OP_DEF(addi_b)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// ADDI.B #<imm>,Dn
		CYCLE(2);
		uint32 dst = reg.D[n] & 0xff;
		dst = ACC.add_8(src, dst);
		reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
	} else {
		// ADDI.B #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst = ACC.add_8(src, dst);
		write_1(ea, dst);
	}
}

// %0000_011001_mmmrrr	ADDI.W #<imm>,<ea>
OP_DEF(addi_w)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2();
	if (n < 8) {
		// ADDI.W #<imm>,Dn
		CYCLE(2);
		uint32 dst = reg.D[n] & 0xffff;
		dst = ACC.add_16(src, dst);
		reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
	} else {
		// ADDI.W #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst = ACC.add_16(src, dst);
		write_2(ea, dst);
	}
}

// %0000_011010_mmmrrr	ADDI.L #<imm>,<ea>
OP_DEF(addi_l)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_4();
	if (n < 8) {
		// ADDI.L #<imm>,Dn
		CYCLE(2);
		reg.D[n] = ACC.add_32(src, reg.D[n]);
	} else {
		// ADDI.L #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 dst = read_4(ea);
		dst = ACC.add_32(src, dst);
		write_4(ea, dst);
	}
}

// %0000_011011_00nnnn	RTM Rn
// %0000_011011_mmmrrr	CALLM #<imm>,<ea>
OP_DEF(callm)
{
	op_illegal();
}

// %0000_100000_000yyy	BTST.L #<imm>,Dy
// %0000_100000_mmmrrr	BTST.B #<imm>,<ea>
OP_DEF(btst_imm_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BTST.L #<imm>,Dy
		CYCLE(4);
		uint bit = fetch_2() & 31;
		ACC.btst(RegDY, bit);
	} else if (n == 0x3c) {
		// BTST.B #<imm>,<ea> の <ea> には #imm はない
		op_illegal();
	} else {
		// BTST.B #<imm>,<ea>
		CYCLE(4);
		uint bit = fetch_2() & 7;
		uint32 data = fea_data_1();
		ACC.btst(data, bit);
	}
}

// %0000_100001_000yyy	BCHG.L #<imm>,Dy
// %0000_100001_mmmrrr	BCHG.B #<imm>,<ea>
OP_DEF(bchg_imm_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BCHG.L #<imm>,Dy
		CYCLE(6);
		uint bit = fetch_2() & 31;
		RegDY = ACC.bchg(RegDY, bit);
	} else if (n == 0x3c) {
		// BCHG.B #<imm>,<ea> の <ea> には #imm はない
		op_illegal();
	} else {
		// BCHG.B #<imm>,<ea>
		CYCLE(6);
		uint bit = fetch_2() & 7;
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.bchg(data, bit);
		write_1(ea, data);
	}
}

// %0000_100010_000yyy	BCLR.L #<imm>,Dy
// %0000_100010_mmmrrr	BCLR.B #<imm>,<ea>
OP_DEF(bclr_imm_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BCLR.L #<imm>,Dy
		CYCLE(6);
		uint bit = fetch_2() & 31;
		RegDY = ACC.bclr(RegDY, bit);
	} else if (n == 0x3c) {
		// BCLR.B #<imm>,<ea> の <ea> には #imm はない
		op_illegal();
	} else {
		// BCLR.B #<imm>,<ea>
		CYCLE(6);
		uint bit = fetch_2() & 7;
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.bclr(data, bit);
		write_1(ea, data);
	}
}

// %0000_100011_000yyy	BSET.L #<imm>,Dy
// %0000_100011_mmmrrr	BSET.B #<imm>,<ea>
OP_DEF(bset_imm_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BSET.L #<imm>,Dy
		CYCLE(6);
		uint bit = fetch_2() & 31;
		RegDY = ACC.bset(RegDY, bit);
	} else if (n == 0x3c) {
		// BSET.B #<imm>,<ea> の <ea> には #imm はない
		op_illegal();
	} else {
		// BSET.B #<imm>,<ea>
		CYCLE(6);
		uint bit = fetch_2() & 7;
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.bset(data, bit);
		write_1(ea, data);
	}
}

// %0000_101000_mmmrrr	EORI.B #<imm>,<ea>
// %0000_101000_111100	EORI.B #<imm>,CCR
OP_DEF(eori_b)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// EORI.B #<imm>,Dn
		CYCLE(2);
		uint32 dst = (reg.D[n] & 0xff) ^ src;
		ACC.move_8(dst);
		reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
	} else if (n == 0b111100) {
		// EORI.B #<imm>,CCR
		CYCLE2(12, 14);
		CCR.Set(CCR.Get() ^ src);
	} else {
		// EORI.B #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst ^= src;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

// %0000_101001_mmmrrr	EORI.W #<imm>,<ea>
// %0000_101001_111100	EORI.W #<imm>,SR
OP_DEF(eori_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EORI.W #<imm>,Dn
		CYCLE(2);
		uint32 src = fetch_2();
		uint32 dst = (reg.D[n] & 0xffff) ^ src;
		ACC.move_16(dst);
		reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
	} else if (n == 0b111100) {
		// EORI.W #<imm>,SR
		SUPERVISOR_OP;
		CYCLE2(12, 14);
		uint32 src = fetch_2();
		SetSR(GetSR() ^ src);
	} else {
		// EORI.W #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 src = fetch_2();
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst ^= src;
		ACC.move_16(dst);
		write_2(ea, dst);
	}
}

// %0000_101010_mmmrrr	EORI.L #<imm>,<ea>
OP_DEF(eori_l)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_4();
	if (n < 8) {
		// EORI.L #<imm>,Dn
		CYCLE(2);
		reg.D[n] ^= src;
		ACC.move_32(reg.D[n]);
	} else {
		// EORI.L #<imm>,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 dst = read_4(ea);
		dst ^= src;
		ACC.move_32(dst);
		write_4(ea, dst);
	}
}

// %0000_101011_mmmrrr	CAS.B Dc,Du,<ea>
OP_DEF(cas_b)
{
	ir2 = fetch_2();
	uint c = ir2 & 7;
	uint u = (ir2 >> 6) & 7;
	uint32 dc = reg.D[c] & 0xff;
	uint32 du = reg.D[u] & 0xff;
	uint ea = cea_data_1();
	uint32 dst = read_1(ea);

	ACC.cmp_8(dc, dst);
	if (CCR.IsZ()) {
		// 等しければ、Du -> dst
		CYCLE(13);
		write_1(ea, du);
	} else {
		// そうでなければ、dst -> Dc
		CYCLE(11);
		reg.D[c] = (reg.D[c] & 0xffffff00) | dst;
	}
}

// %0000_110000_mmmrrr	CMPI.B #<imm>,<ea>
OP_DEF(cmpi_b)
{
	uint n = ir & 0x3f;

	// CMPI はデータアドレッシングだが #imm がないことに注意
	if (n == 0x3c) {
		op_illegal();
		return;
	}
	CYCLE(2);
	uint32 src = fetch_2() & 0xff;
	uint32 dst = fea_data_1();
	ACC.cmp_8(src, dst);
}

// %0000_110001_mmmrrr	CMPI.W #<imm>,<ea>
OP_DEF(cmpi_w)
{
	uint n = ir & 0x3f;

	// CMPI はデータアドレッシングだが #imm がないことに注意
	if (n == 0x3c) {
		op_illegal();
		return;
	}
	CYCLE(2);
	uint32 src = fetch_2();
	uint32 dst = fea_data_2();
	ACC.cmp_16(src, dst);
}

// %0000_110010_mmmrrr	CMPI.L #<imm>,<ea>
OP_DEF(cmpi_l)
{
	uint n = ir & 0x3f;

	// CMPI はデータアドレッシングだが #imm がないことに注意
	if (n == 0x3c) {
		op_illegal();
		return;
	}
	CYCLE(2);
	uint32 src = fetch_4();
	uint32 dst = fea_data_4();
	ACC.cmp_32(src, dst);
}

// %0000_110011_mmmrrr	CAS.W Dc,Du,<ea>
// %0000_110011_111100	CAS2.W Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
OP_DEF(cas_w)
{
	uint n = ir & 0x3f;

	if (n == 0x3c) {
		// CAS2.W Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
		ir2 = fetch_2();
		uint32 ir3 = fetch_2();
		uint c1 = ir2 & 7;
		uint u1 = (ir2 >> 6) & 7;
		uint r1 = ir2 >> 12;
		uint c2 = ir3 & 7;
		uint u2 = (ir3 >> 6) & 7;
		uint r2 = ir3 >> 12;
		uint32 dc1 = reg.D[c1] & 0xffff;
		uint32 du1 = reg.D[u1] & 0xffff;
		uint32 ea1 = reg.R[r1];
		uint32 dc2 = reg.D[c2] & 0xffff;
		uint32 du2 = reg.D[u2] & 0xffff;
		uint32 ea2 = reg.R[r2];

		uint32 dst1 = read_2(ea1);
		uint32 dst2 = read_2(ea2);
		ACC.cmp_16(dc1, dst1);
		if (CCR.IsZ()) {
			ACC.cmp_16(dc2, dst2);
			if (CCR.IsZ()) {
				// 更新オペランド -> デスティネーション
				CYCLE2(0, 2);	// これは成功時の追加分
				write_2(ea1, du1);
				write_2(ea2, du2);
			}
		}
		// デスティネーション -> 比較オペランド
		CYCLE(24);	// 本当はこれは最大値
		reg.D[c1] = (reg.D[c1] & 0xffff0000) | dst1;
		reg.D[c2] = (reg.D[c2] & 0xffff0000) | dst2;
	} else {
		// CAS.W Dc,Du,<ea>
		ir2 = fetch_2();
		uint c = ir2 & 7;
		uint u = (ir2 >> 6) & 7;
		uint32 dc = reg.D[c] & 0xffff;
		uint32 du = reg.D[u] & 0xffff;
		uint ea = cea_data_2();
		uint32 dst = read_2(ea);

		ACC.cmp_16(dc, dst);
		if (CCR.IsZ()) {
			// 等しければ、Du -> dst
			CYCLE(13);
			write_2(ea, du);
		} else {
			// そうでなければ、dst -> Dc
			CYCLE(11);
			reg.D[c] = (reg.D[c] & 0xffff0000) | dst;
		}
	}
}

// %0000_111000_mmmrrr	MOVES.B <ea>,Rn
// %0000_111000_mmmrrr	MOVES.B Rn,<ea>
OP_DEF(moves_b)
{
	SUPERVISOR_OP;

	ir2 = fetch_2();
	uint n = ir2 >> 12;
	uint ea;
	uint32 data;

	if ((ir & 0x3f) < 16) {
		op_illegal();
		return;
	}

	ea = cea_data_1();
	if ((ir2 & 0x0800) == 0) {
		// <ea>,Rn
		CYCLE(7);
		busaddr addr = busaddr(ea) | reg.sfc | BusAddr::Size1;
		data = read_data(addr);
		if (n < 8) {	// Dn
			reg.D[n] = (reg.D[n] & 0xffffff00) | data;
		} else {		// An
			reg.R[n] = (int32)(int8)data;
		}
	} else {
		// Rn,<ea>
		CYCLE2(5, 6);
		busaddr addr = busaddr(ea) | reg.dfc | BusAddr::Size1;
		data = reg.R[n] & 0xff;
		write_data(addr, data);
	}
}

// %0000_111001_mmmrrr	MOVES.W <ea>,Rn
// %0000_111001_mmmrrr	MOVES.W Rn,<ea>
OP_DEF(moves_w)
{
	SUPERVISOR_OP;

	ir2 = fetch_2();
	uint n = ir2 >> 12;
	uint ea;
	uint32 data;

	if ((ir & 0x3f) < 16) {
		op_illegal();
		return;
	}

	ea = cea_data_2();
	if ((ir2 & 0x0800) == 0) {
		// <ea>,Rn
		CYCLE(7);
		busaddr addr = busaddr(ea) | reg.sfc | BusAddr::Size2;
		data = read_data(addr);
		if (n < 8) {	// Dn
			reg.D[n] = (reg.D[n] & 0xffff0000) | data;
		} else {		// An
			reg.R[n] = (int32)(int16)data;
		}
	} else {
		// Rn,<ea>
		CYCLE2(5, 6);
		busaddr addr = busaddr(ea) | reg.dfc | BusAddr::Size2;
		data = reg.R[n] & 0xffff;
		write_data(addr, data);
	}
}

// %0000_111010_mmmrrr	MOVES.L <ea>,Rn
// %0000_111010_mmmrrr	MOVES.L Rn,<ea>
OP_DEF(moves_l)
{
	SUPERVISOR_OP;

	ir2 = fetch_2();
	uint n = ir2 >> 12;
	uint ea;
	uint32 data;

	if ((ir & 0x3f) < 16) {
		op_illegal();
		return;
	}

	ea = cea_data_4();
	if ((ir2 & 0x0800) == 0) {
		// <ea>,Rn
		CYCLE(7);
		busaddr addr = busaddr(ea) | reg.sfc | BusAddr::Size4;
		data = read_data(addr);
		reg.R[n] = data;
	} else {
		// Rn,<ea>
		CYCLE2(5, 6);
		busaddr addr = busaddr(ea) | reg.dfc | BusAddr::Size4;
		data = reg.R[n];
		write_data(addr, data);
	}
}

// %0000_111011_mmmrrr	CAS.L Dc,Du,<ea>
// %0000_111011_111100	CAS2.L Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
OP_DEF(cas_l)
{
	uint n = ir & 0x3f;

	if (n == 0x3c) {
		// CAS2.L Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
		ir2 = fetch_2();
		uint32 ir3 = fetch_2();
		uint c1 = ir2 & 7;
		uint u1 = (ir2 >> 6) & 7;
		uint r1 = ir2 >> 12;
		uint c2 = ir3 & 7;
		uint u2 = (ir3 >> 6) & 7;
		uint r2 = ir3 >> 12;
		uint32 dc1 = reg.D[c1];
		uint32 du1 = reg.D[u1];
		uint32 ea1 = reg.R[r1];
		uint32 dc2 = reg.D[c2];
		uint32 du2 = reg.D[u2];
		uint32 ea2 = reg.R[r2];

		uint32 dst1 = read_4(ea1);
		uint32 dst2 = read_4(ea2);
		ACC.cmp_32(dc1, dst1);
		if (CCR.IsZ()) {
			ACC.cmp_32(dc2, dst2);
			if (CCR.IsZ()) {
				// 更新オペランド -> デスティネーション
				CYCLE2(0, 2);	// これは成功時の追加分
				write_4(ea1, du1);
				write_4(ea2, du2);
			}
		}
		// デスティネーション -> 比較オペランド
		CYCLE(24);	// 本当はこれは最大値
		reg.D[c1] = dst1;
		reg.D[c2] = dst2;
	} else {
		// CAS.L Dc,Du,<ea>
		ir2 = fetch_2();
		uint c = ir2 & 7;
		uint u = (ir2 >> 6) & 7;
		uint32 dc = reg.D[c];
		uint32 du = reg.D[u];
		uint ea = cea_data_4();
		uint32 dst = read_4(ea);

		ACC.cmp_32(dc, dst);
		if (CCR.IsZ()) {
			// 等しければ、Du -> dst
			CYCLE(13);
			write_4(ea, du);
		} else {
			// そうでなければ、dst -> Dc
			CYCLE(11);
			reg.D[c] = dst;
		}
	}
}

// %0001_xxx000_mmmrrr	MOVE.B <ea>,Dx
OP_DEF(move_b_ea_dn)
{
	CYCLE(2);
	uint32 data = fea_all_1();
	ACC.move_8(data);
	RegDX = (RegDX & 0xffffff00) | data;
}

// %0001_xxx010_mmmrrr	MOVE.B <ea>,(Ax)
OP_DEF(move_b_ea_anin)
{
	// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_1();
	uint32 ea = cea_anin(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx011_mmmrrr	MOVE.B <ea>,(Ax)+
OP_DEF(move_b_ea_anpi)
{
	// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_1();
	// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
	save_reg_pi_if(RegIRX);
	uint32 ea = cea_anpi_1(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx100_mmmrrr	MOVE.B <ea>,-(Ax)
OP_DEF(move_b_ea_anpd)
{
	// 実際にはソースがレジスタなら (4, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_1();
	// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
	save_reg_pd_if(RegIRX);
	uint32 ea = cea_anpd_1(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx101_mmmrrr	MOVE.B <ea>,d16(Ax)
OP_DEF(move_b_ea_andi)
{
	CYCLE2(4, 5);
	uint32 data = fea_all_1();
	uint32 ea = cea_andi(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx110_mmmrrr	MOVE.B <ea>,(Ax,IX)
OP_DEF(move_b_ea_anix)
{
	// XXX 実際にはdstのフォーマットによって(8,9)-(20,23)
	CYCLE2(16, 18);
	uint32 data = fea_all_1();
	uint32 ea = cea_anix(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_000111_mmmrrr	MOVE.B <ea>,Abs.W
OP_DEF(move_b_ea_absw)
{
	CYCLE2(4, 5);
	uint32 data = fea_all_1();
	uint32 ea = cea_absw();
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_001111_mmmrrr	MOVE.B <ea>,Abs.L
OP_DEF(move_b_ea_absl)
{
	CYCLE2(6, 7);
	uint32 data = fea_all_1();
	uint32 ea = cea_absl();
	ACC.move_8(data);
	write_1(ea, data);
}

// %0010_xxx000_mmmrrr	MOVE.L <ea>,Dx
OP_DEF(move_l_ea_dn)
{
	CYCLE(2);
	uint32 data = fea_all_4();
	ACC.move_32(data);
	RegDX = data;
}

// %0010_xxx001_mmmrrr	MOVEA.L <ea>,Ax
OP_DEF(movea_l)
{
	CYCLE(2);
	uint32 data = fea_all_4();
	RegAX = data;
}

// %0010_xxx010_mmmrrr	MOVE.L <ea>,(Ax)
OP_DEF(move_l_ea_anin)
{
	// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_4();
	uint32 ea = cea_anin(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx011_mmmrrr	MOVE.L <ea>,(Ax)+
OP_DEF(move_l_ea_anpi)
{
	// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_4();
	// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
	save_reg_pi_if(RegIRX);
	uint32 ea = cea_anpi_4(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx100_mmmrrr	MOVE.L <ea>,-(Ax)
OP_DEF(move_l_ea_anpd)
{
	// 実際にはソースがレジスタなら (4, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_4();
	// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
	save_reg_pd_if(RegIRX);
	uint32 ea = cea_anpd_4(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx101_mmmrrr	MOVE.L <ea>,d16(Ax)
OP_DEF(move_l_ea_andi)
{
	CYCLE2(4, 5);
	uint32 data = fea_all_4();
	uint32 ea = cea_andi(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx110_mmmrrr	MOVE.L <ea>,(Ax,IX)
OP_DEF(move_l_ea_anix)
{
	// XXX 実際にはdstのフォーマットによって(8,9)-(20,23)
	CYCLE2(16, 18);
	uint32 data = fea_all_4();
	uint32 ea = cea_anix(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_000111_mmmrrr	MOVE.L <ea>,Abs.W
OP_DEF(move_l_ea_absw)
{
	CYCLE2(4, 5);
	uint32 data = fea_all_4();
	uint32 ea = cea_absw();
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_001111_mmmrrr	MOVE.L <ea>,Abs.L
OP_DEF(move_l_ea_absl)
{
	CYCLE2(6, 7);
	uint32 data = fea_all_4();
	uint32 ea = cea_absl();
	ACC.move_32(data);
	write_4(ea, data);
}

// %0011_xxx000_mmmrrr	MOVE.W <ea>,Dx
OP_DEF(move_w_ea_dn)
{
	CYCLE(2);
	uint32 data = fea_all_2();
	ACC.move_16(data);
	RegDX = (RegDX & 0xffff0000) | data;
}

// %0011_xxx001_mmmrrr	MOVEA.W <ea>,Ax
OP_DEF(movea_w)
{
	CYCLE(2);
	uint32 data = (int32)(int16)fea_all_2();
	RegAX = data;
}

// %0011_xxx010_mmmrrr	MOVE.W <ea>,(Ax)
OP_DEF(move_w_ea_anin)
{
	// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_2();
	uint32 ea = cea_anin(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx011_mmmrrr	MOVE.W <ea>,(Ax)+
OP_DEF(move_w_ea_anpi)
{
	// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_2();
	// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
	save_reg_pi_if(RegIRX);
	uint32 ea = cea_anpi_2(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx100_mmmrrr	MOVE.W <ea>,-(Ax)
OP_DEF(move_w_ea_anpd)
{
	// 実際にはソースがレジスタなら (4, 4)、メモリなら (4, 5)
	CYCLE2(4, 5);
	uint32 data = fea_all_2();
	// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
	save_reg_pd_if(RegIRX);
	uint32 ea = cea_anpd_2(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx101_mmmrrr	MOVE.W <ea>,d16(Ax)
OP_DEF(move_w_ea_andi)
{
	CYCLE2(4, 5);
	uint32 data = fea_all_2();
	uint32 ea = cea_andi(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx110_mmmrrr	MOVE.W <ea>,(Ax,IX)
OP_DEF(move_w_ea_anix)
{
	// XXX 実際にはdstのフォーマットによって(8,9)-(20,23)
	CYCLE2(16, 18);
	uint32 data = fea_all_2();
	uint32 ea = cea_anix(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_000111_mmmrrr	MOVE.W <ea>,Abs.W
OP_DEF(move_w_ea_absw)
{
	CYCLE2(4, 5);
	uint32 data = fea_all_2();
	uint32 ea = cea_absw();
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_001111_mmmrrr	MOVE.W <ea>,Abs.L
OP_DEF(move_w_ea_absl)
{
	CYCLE2(6, 7);
	uint32 data = fea_all_2();
	uint32 ea = cea_absl();
	ACC.move_16(data);
	write_2(ea, data);
}

// %0100_000000_mmmrrr	NEGX.B <ea>
OP_DEF(negx_b)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEGX.B Dn
		CYCLE(2);
		uint32 data = reg.D[n] & 0xff;
		data = ACC.subx_8(data, 0);
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
	} else if (n < 16) {
		op_illegal();
	} else {
		// NEGX.B <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.subx_8(data, 0);
		write_1(ea, data);
	}
}

// %0100_000001_mmmrrr	NEGX.W <ea>
OP_DEF(negx_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEGX.W Dn
		CYCLE(2);
		uint32 data = reg.D[n] & 0xffff;
		data = ACC.subx_16(data, 0);
		reg.D[n] = (reg.D[n] & 0xffff0000) | data;
	} else if (n < 16) {
		op_illegal();
	} else {
		// NEGX.W <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.subx_16(data, 0);
		write_2(ea, data);
	}
}

// %0100_000010_mmmrrr	NEGX.L <ea>
OP_DEF(negx_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEGX.L Dn
		CYCLE(2);
		reg.D[n] = ACC.subx_32(reg.D[n], 0);
	} else if (n < 16) {
		op_illegal();
	} else {
		// NEGX.L <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.subx_32(data, 0);
		write_4(ea, data);
	}
}

// %0100_000011_mmmrrr	MOVE.W SR,<ea>
OP_DEF(move_sr_ea)
{
	SUPERVISOR_OP;

	uint n = ir & 0x3f;
	if (n < 8) {
		// MOVE.W SR,Dn
		CYCLE(4);
		reg.D[n] = (reg.D[n] & 0xffff0000) | GetSR();
	} else {
		// MOVE.W SR,<ea>
		CYCLE2(4, 5);
		uint32 ea = cea_data_2();
		write_2(ea, GetSR());
	}
}

// %0100_xxx100_mmmrrr	CHK.L <ea>,Dx
OP_DEF(chk_l)
{
	uint32 dst = RegDX;
	ACC.move_32(dst);
	if (CCR.IsN()) {
		// これは最大値で次の条件式が成立した時の値なので、
		// 実際にはこれより小さい確定した値のはずだけど。
		CYCLE2(28, 30);
		Exception(M68K::EXCEP_CHK);
		return;
	}
	// 本当はこうじゃないけど、とりあえず
	uint32 src = fea_data_4();
	if ((int32)dst > (int32)src) {
		CYCLE2(28, 30);
		CCR.SetN(false);
		Exception(M68K::EXCEP_CHK);
		return;
	}
	CYCLE(8);
}

// %0100_xxx110_mmmrrr	CHK.W <ea>,Dx
OP_DEF(chk_w)
{
	uint32 dst = RegDX & 0xffff;
	ACC.move_16(dst);
	if (CCR.IsN()) {
		// これは最大値で次の条件式が成立した時の値なので、
		// 実際にはこれより小さい確定した値のはずだけど。
		CYCLE2(28, 30);
		Exception(M68K::EXCEP_CHK);
		return;
	}
	// 本当はこうじゃないけど、とりあえず
	uint32 src = fea_data_2();
	if ((int16)dst > (int16)src) {
		CYCLE2(28, 30);
		CCR.SetN(false);
		Exception(M68K::EXCEP_CHK);
		return;
	}
	CYCLE(8);
}

// %0100_xxx111_mmmrrr	LEA.L <ea>,Ax
// %0100_100111_000yyy	EXTB.L Dy
OP_DEF(lea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EXTB.L Dy
		CYCLE(4);
		RegDY = (int32)(int8)(RegDY & 0xff);
		ACC.move_32(RegDY);
	} else {
		// LEA.L <ea>,Ax
		CYCLE(2);
		RegAX = cea_ctrl();
	}
}

// %0100_001000_mmmrrr	CLR.B <ea>
OP_DEF(clr_b)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// CLR.B Dn
		CYCLE(2);
		RegDY &= 0xffffff00;
		ACC.move_8(0);
	} else {
		// CLR.B <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		ACC.move_8(0);
		write_1(ea, 0);
	}
}

// %0100_001001_mmmrrr	CLR.W <ea>
OP_DEF(clr_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// CLR.W Dn
		CYCLE(2);
		RegDY &= 0xffff0000;
		ACC.move_16(0);
	} else {
		// CLR.W <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		ACC.move_16(0);
		write_2(ea, 0);
	}
}

// %0100_001010_mmmrrr	CLR.L <ea>
OP_DEF(clr_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// CLR.L Dn
		CYCLE(2);
		RegDY = 0;
		ACC.move_32(0);
	} else {
		// CLR.L <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		ACC.move_32(0);
		write_4(ea, 0);
	}
}

// %0100_001011_mmmrrr	MOVE.W CCR,<ea>
OP_DEF(move_ccr_ea)
{
	uint n = ir & 0x3f;

	// 転送は16ビットで行われ、上位バイトと未実装ビットは %0 になる。
	if (n < 8) {
		// MOVE.W CCR,Dn
		CYCLE(4);
		reg.D[n] = (reg.D[n] & 0xffff0000) | CCR.Get();
	} else if (n < 16) {
		// MOVE.W CCR,An はない
		op_illegal();
	} else {
		// MOVE.W CCR,<ea>
		CYCLE2(4, 5);
		uint32 ea = cea_data_2();
		write_2(ea, CCR.Get());
	}
}

// %0100_010000_mmmrrr	NEG.B <ea>
OP_DEF(neg_b)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEG.B Dn
		CYCLE(2);
		uint32 data = ACC.sub_8(reg.D[n] & 0xff, 0);
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
	} else {
		// NEG.B <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.sub_8(data, 0);
		write_1(ea, data);
	}
}

// %0100_010001_mmmrrr	NEG.W <ea>
OP_DEF(neg_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEG.W Dn
		CYCLE(2);
		uint32 data = ACC.sub_16(reg.D[n] & 0xffff, 0);
		reg.D[n] = (reg.D[n] & 0xffff0000) | data;
	} else {
		// NEG.W <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.sub_16(data, 0);
		write_2(ea, data);
	}
}

// %0100_010010_mmmrrr	NEG.L <ea>
OP_DEF(neg_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEG.L Dn
		CYCLE(2);
		reg.D[n] = ACC.sub_32(reg.D[n], 0);
	} else {
		// NEG.L <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.sub_32(data, 0);
		write_4(ea, data);
	}
}

// %0100_010011_mmmrrr	MOVE.W <ea>,CCR
OP_DEF(move_ea_ccr)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// MOVE.W Dn,CCR
		CYCLE(4);
		uint32 data = reg.D[n] & 0xff;
		CCR.Set(data);
	} else if (n < 16) {
		// MOVE.W An,CCR はない
		op_illegal();
	} else {
		// MOVE.W <ea>,CCR
		CYCLE(4);
		uint32 data = fea_data_2();
		CCR.Set(data);
	}
}

// %0100_011000_mmmrrr	NOT.B <ea>
OP_DEF(not_b)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NOT.B Dn
		CYCLE(2);
		uint32 data = (~reg.D[n]) & 0xff;
		ACC.move_8(data);
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
	} else {
		// NOT.B <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = (~data) & 0xff;
		ACC.move_8(data);
		write_1(ea, data);
	}
}

// %0100_011001_mmmrrr	NOT.W <ea>
OP_DEF(not_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NOT.W Dn
		CYCLE(2);
		uint32 data = (~reg.D[n]) & 0xffff;
		ACC.move_16(data);
		reg.D[n] = (reg.D[n] & 0xffff0000) | data;
	} else {
		// NOT.W <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = (~data) & 0xffff;
		ACC.move_16(data);
		write_2(ea, data);
	}
}

// %0100_011010_mmmrrr	NOT.L <ea>
OP_DEF(not_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NOT.L Dn
		CYCLE(2);
		reg.D[n] = ~reg.D[n];
		ACC.move_32(reg.D[n]);
	} else {
		// NOT.L <ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ~data;
		ACC.move_32(data);
		write_4(ea, data);
	}
}

// %0100_011011_mmmrrr	MOVE.W <ea>,SR
OP_DEF(move_ea_sr)
{
	SUPERVISOR_OP;

	CYCLE2(8, 10);
	uint16 data = fea_data_2();
	SetSR(data);
}

// %0100_100000_mmmrrr	NBCD.B <ea>
// %0100_100000_001yyy	LINK.L Ay,#<imm>
OP_DEF(nbcd)
{
	uint n = ir & 0x3f;
	int32 imm;

	if (n < 8) {
		// NBCD.B Dn
		CYCLE(6);
		uint32 dst = RegDY & 0xff;
		dst = ACC.sbcd_8(dst, 0);
		RegDY = (RegDY & 0xffffff00) | dst;
	} else if (n == 0x0e) {
		// LINK.L A6,#<imm>
		CYCLE2(6, 7);
		// レジスタやスタックを変更する前にフェッチしないと、
		// ページフォルトで再実行できなくなる
		imm = fetch_4();
		// ページフォルトに備えて保存する
		save_reg_pd(7);
		push_4(reg.A[6]);
		reg.A[6] = reg.A[7];
		reg.A[7] += imm;
	} else if (n < 16) {
		// LINK.L An,#<imm>
		CYCLE2(6, 7);
		// レジスタやスタックを変更する前にフェッチしないと、
		// ページフォルトで再実行できなくなる
		imm = fetch_4();
		// ページフォルトに備えて保存する
		save_reg_pd(7);
		push_4(RegAY);
		RegAY = reg.A[7];
		reg.A[7] += imm;
	} else {
		// NBCD.B <ea>
		CYCLE(6);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst = ACC.sbcd_8(dst, 0);
		write_1(ea, dst);
	}
}

// %0100_100001_000yyy	SWAP.W Dy
// %0100_100001_001nnn	BKPT #<imm>
// %0100_100001_mmmrrr	PEA.L <ea>
OP_DEF(pea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// SWAP.W Dy
		CYCLE(4);
		reg.D[n] = (reg.D[n] << 16) | (reg.D[n] >> 16);
		ACC.move_32(reg.D[n]);
	} else if (n < 16) {
		// BKPT #<imm>
		// ブレークポイント・アクノリッジサイクルに応答するデバイスはないので
		// 常に不当命令にする。
		CYCLE(9);	// ?
		op_illegal();
	} else {
		// PEA.L <ea>
		CYCLE(4);
		uint32 ea = cea_ctrl();
		// ページフォルトに備えて保存する
		save_reg_pd(7);
		push_4(ea);
	}
}

// MOVEM.[WL] <list>,<ea> の共通部分。
// bytesize は1レジスタ分のサイズ、.Wなら2、.Lなら4。
// 本当はテンプレートにしたい。
void
MPU680x0Device::ops_movem_list_ea(int bytesize)
{
	uint32 ea;
	int regcount;

	// 不当な第1ワードを弾く
#define INVALID(x)	(0xffULL << (56 - ((x) * 8)))
	const uint64 valid =
		INVALID(0)	// Dn
	  | INVALID(1)	// An
	  | INVALID(3)	// (An)+
	  | 0x3fL;		// (PC)...
	if ((int64)(valid << (ir & 0x3f)) < 0) {
		op_illegal();
		return;
	}

	// 第2ワードは EA が正当な場合のみ EA より先にフェッチ
	ir2 = fetch_2();

	// EA 取得。MOVEM だけ別対応
	// |  M -WXZ  | MOVEM list,<ea>
	// だが、不当 EA はすでに弾いてあるので cea_data でいい
	if (bytesize == 2) {
		ea = cea_data_2();
	} else {
		ea = cea_data_4();
	}

	regcount = 0;
	uint list = ir2;
	if (eamode(ir) == 4/*-(An)*/) {
		// -(An) の場合 reglist の格納順が逆(転送順は LSB から)
		// bit15                                      bit0
		// D0 D1 D2 D3 D4 D5 D6 D7 A0 A1 A2 A3 A4 A5 A6 A7
		while (list) {
			int ctz = __builtin_ctz(list);
			if (bytesize == 2) {
				write_2(ea, reg.R[15 - ctz] & 0xffff);
			} else {
				write_4(ea, reg.R[15 - ctz]);
			}
			ea -= bytesize;
			regcount++;
			// 処理した最下位ビットを落とす
			list &= list - 1;
		}
		// ea は一つ行き過ぎるので補正
		RegAY = ea + bytesize;
	} else {
		// LSB 側から転送
		// bit15                                      bit0
		// A7 A6 A5 A4 A4 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
		while (list) {
			int ctz = __builtin_ctz(list);
			if (bytesize == 2) {
				write_2(ea, reg.R[ctz] & 0xffff);
			} else {
				write_4(ea, reg.R[ctz]);
			}
			ea += bytesize;
			regcount++;
			// 処理した最下位ビットを落とす
			list &= list - 1;
		}
	}

	CYCLE(4 + 2 * regcount);
}

// %0100_100010_000yyy	EXT.W Dy
// %0100_100010_mmmrrr	MOVEM.W <list>,<ea>
OP_DEF(movem_w_mem)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EXT.W Dy
		CYCLE(4);
		uint16 data = (int16)(int8)(RegDY & 0xff);
		ACC.move_16(data);
		RegDY = (RegDY & 0xffff0000) | data;
	} else {
		// MOVEM.W <list>,<ea>
		ops_movem_list_ea(2);
	}
}

// %0100_100011_000yyy	EXT.L Dy
// %0100_100011_mmmrrr	MOVEM.L <list>,<ea>
OP_DEF(movem_l_mem)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EXT.L Dy
		CYCLE(4);
		RegDY = (int32)(int16)(RegDY & 0x0000ffff);
		ACC.move_32(RegDY);
	} else {
		// MOVEM.L <list>,<ea>
		ops_movem_list_ea(4);
	}
}

// %0100_101000_mmmrrr	TST.B <ea>
OP_DEF(tst_b)
{
	CYCLE(2);
	uint32 data = fea_all_1();
	ACC.move_8(data);
}

// %0100_101001_mmmrrr	TST.W <ea>
OP_DEF(tst_w)
{
	CYCLE(2);
	uint32 data = fea_all_2();
	ACC.move_16(data);
}

// %0100_101010_mmmrrr	TST.L <ea>
OP_DEF(tst_l)
{
	CYCLE(2);
	uint32 data = fea_all_4();
	ACC.move_32(data);
}

// %0100_101011_mmmrrr	TAS.B <ea>
// %0100_101011_111100	ILLEGAL
OP_DEF(tas)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// TAS.B Dn
		// リード・モディファイ・ライトという概念はない
		CYCLE(4);
		uint32 data = reg.D[n];
		ACC.move_8(data);
		reg.D[n] |= 0x80;
	} else if (n == 0x3c) {
		// ILLEGAL
		op_illegal();
	} else {
		// TAS.B <ea>
		// リード・モディファイ・ライトという概念はない
		CYCLE(12);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		ACC.move_8(data);
		write_1(ea, (data | 0x80));
	}
}

// %0100_110000_mmmrrr	MUL{U,S}.L <ea>,Dl
OP_DEF(mul)
{
	// 2ワード目
	// %0LLL_Ss0000_000HHH
	//   +++ ||        +++- Dh
	//    |  |+------------ %1:64bit, %0:32bit
	//    |  +------------- %1:MULS, %0:MULU
	//    +---------------- Dl
	ir2 = fetch_2();
	uint h = ir2 & 7;
	uint l = (ir2 >> 12) & 7;

	CYCLE(44);	// XXX これは本当は最大値だけど
	switch ((ir2 >> 10) & 3) {
	 case 0:
	 {
		// MULU.L <ea>,Dl
		uint32 src = fea_data_4();
		uint32 dst = reg.D[l];
		reg.D[l] = ACC.mulu_32(src, dst);
		break;
	 }

	 case 1:
	 {
		// MULU.L <ea>,Dh:Dl
		uint32 src = fea_data_4();
		uint32 dst = reg.D[l];
		uint64 res = ACC.mulu_64(src, dst);
		// h == l の時は未定義なので考えない。
		reg.D[h] = res >> 32;
		reg.D[l] = res;
		break;
	 }

	 case 2:
	 {
		// MULS.L <ea>,Dl
		uint32 src = fea_data_4();
		uint32 dst = reg.D[l];
		reg.D[l] = ACC.muls_32(src, dst);
		break;
	 }

	 case 3:
	 {
		// MULS.L <ea>,Dh:Dl
		uint32 src = fea_data_4();
		uint32 dst = reg.D[l];
		uint64 res = ACC.muls_64(src, dst);
		// h == l の時は未定義なので考えない。
		reg.D[h] = res >> 32;
		reg.D[l] = res;
		break;
	 }

	 default:
		__unreachable();
	}
}

// DIVU.L <ea>,Dq
// DIVUL.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divu_32_32(uint r, uint q)
{
	CYCLE(78);	// XXX これは本当は最大値だけど

	uint32 src = fea_data_4();
	uint32 dst = reg.D[q];

	if (src == 0) {
		// ゼロ除算の場合、
		// X は変化しない
		// C は常にクリア
		// N,Z,V は未定義
		CCR.SetC(false);
		Exception(M68K::EXCEP_ZERODIV);
		return;
	}
	uint32 quo = dst / src;
	uint32 rem = dst % src;
	// このケースでオーバーフローは起きないはず

	// 正常の場合、
	// X は変化しない
	// V, C はクリア
	// N, Z は quo の結果。
	// r == q の場合 quo が残るので、rem を先に書く
	reg.D[r] = rem;
	reg.D[q] = quo;
	ACC.move_32(quo);
}

// DIVU.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divu_64_32(uint r, uint q)
{
	CYCLE(78);	// XXX これは本当は最大値だけど

	uint32 src = fea_data_4();
	uint64 dst = (((uint64)reg.D[r]) << 32) | reg.D[q];

	if (src == 0) {
		// ゼロ除算の場合、
		// X は変化しない
		// C は常にクリア
		// N,Z,V は未定義
		CCR.SetC(false);
		Exception(M68K::EXCEP_ZERODIV);
		return;
	}
	uint64 q64 = dst / src;
	if (q64 > 0xffffffffUL) {
		// オーバーフローの場合、
		// X は変化しない
		// N,Z は未定義
		// V はセット
		// C は常にクリア
		CCR.SetV(true);
		CCR.SetC(false);
		return;
	}
	uint32 quo = q64;
	uint32 rem = dst % src;

	// 正常の場合、
	// X は変化しない
	// V, C はクリア
	// N, Z は quo の結果。
	// r == q の場合 quo が残るので、rem を先に書く
	reg.D[r] = rem;
	reg.D[q] = quo;
	ACC.move_32(quo);
}

// DIVS.L <ea>,Dq
// DIVSL.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divs_32_32(uint r, uint q)
{
	CYCLE(90);	// XXX これは本当は最大値だけど

	uint32 src = fea_data_4();
	uint32 dst = reg.D[q];

	if (src == 0) {
		// ゼロ除算の場合、
		// X は変化しない
		// C は常にクリア
		// N,Z,V は未定義
		CCR.SetC(false);
		Exception(M68K::EXCEP_ZERODIV);
		return;
	}

	// ホストでオーバーフローが起きるのはこのケースのみ
	if (dst == INT32_MIN && src == -1) {
		// オーバーフローの場合、
		// X は変化しない
		// N,Z は未定義
		// V はセット
		// C は常にクリア
		CCR.SetV(true);
		CCR.SetC(false);
		return;
	}

	uint32 quo = (int32)dst / (int32)src;
	uint32 rem = (int32)dst % (int32)src;
	// ここでオーバーフローは起きない

	// 正常の場合、
	// X は変化しない
	// V, C はクリア
	// N, Z は quo の結果。
	// r == q の場合 quo が残るので、rem を先に書く
	reg.D[r] = rem;
	reg.D[q] = quo;
	ACC.move_32(quo);
}

// DIVSL.L
void
MPU680x0Device::ops_divs_64_32(uint r, uint q)
{
	CYCLE(90);	// XXX これは本当は最大値だけど

	uint32 src = fea_data_4();
	uint64 dst = (((uint64)reg.D[r]) << 32) | reg.D[q];

	if (src == 0) {
		// ゼロ除算の場合、
		// X は変化しない
		// C は常にクリア
		// N,Z,V は未定義
		CCR.SetC(false);
		Exception(M68K::EXCEP_ZERODIV);
		return;
	}

	// ホストでオーバーフローが起きるのはこのケースのみ
	if (dst == INT64_MIN && src == -1) {
		// オーバーフローの場合、
		// X は変化しない
		// N,Z は未定義
		// V はセット
		// C は常にクリア
		CCR.SetV(true);
		CCR.SetC(false);
		return;
	}

	int64 sq64 = (int64)dst / (int32)src;
	if ((int32)sq64 != sq64) {
		// オーバーフロー
		CCR.SetV(true);
		CCR.SetC(false);
		return;
	}
	uint32 quo = (uint32)sq64;
	uint32 rem = (int64)dst % (int32)src;

	// 正常の場合、
	// X は変化しない
	// V, C はクリア
	// N, Z は quo の結果。
	// r == q の場合 quo が残るので、rem を先に書く
	reg.D[r] = rem;
	reg.D[q] = quo;
	ACC.move_32(quo);
}

// %0100_110001_mmmrrr	DIVU.L <ea>,Dq
// %0100_110001_mmmrrr	DIVU.L <ea>,Dr:Dq
// %0100_110001_mmmrrr	DIVUL.L <ea>,Dr:Dq
// %0100_110001_mmmrrr	DIVS.L <ea>,Dq
// %0100_110001_mmmrrr	DIVS.L <ea>,Dr:Dq
// %0100_110001_mmmrrr	DIVSL.L <ea>,Dr:Dq
OP_DEF(div)
{
	// 2ワード目
	// %0QQQ_Ss0000_000RRR
	//   +++ ||        +++- Dr
	//    |  |+------------ %1:64bit, %0:32bit
	//    |  +------------- %1:DIVS, %0:DIVU
	//    +---------------- Dq
	ir2 = fetch_2();
	uint r = ir2 & 7;
	uint q = (ir2 >> 12) & 7;

	switch ((ir2 >> 10) & 3) {
	 case 0:
		ops_divu_32_32(r, q);
		break;
	 case 1:
		ops_divu_64_32(r, q);
		break;
	 case 2:
		ops_divs_32_32(r, q);
		break;
	 case 3:
		ops_divs_64_32(r, q);
		break;
	 default:
		__unreachable();
	}
}

void
MPU680x0Device::ops_movem_ea_list(int bytesize)
{
	uint32 ea;
	int regcount;
	bool anpi = false;

	ir2 = fetch_2();

	// EA 取得。MOVEM だけ別対応
	// |  M+ WXZP | MOVEM <ea>,list
	switch (eamode(ir)) {
	 case 2:	// (An)
		ea = cea_anin(eanum(ir));
		break;
	 case 3:	// (An)+
		save_reg_pi(eanum(ir));
		if (bytesize == 2) {
			ea = cea_anpi_2(eanum(ir));
		} else {
			ea = cea_anpi_4(eanum(ir));
		}
		anpi = true;
		break;
	 case 5:	// d16(An)
		ea = cea_andi(eanum(ir));
		break;
	 case 6:	// (An,IX)
		ea = cea_anix(eanum(ir));
		break;
	 case 7:
		switch (eanum(ir)) {
		 case 0:	// Abs.W
			ea = cea_absw();
			break;
		 case 1:	// Abs.L
			ea = cea_absl();
			break;
		 case 2:	// d16(PC)
			ea = cea_pcdi();
			break;
		 case 3:	// (PC,IX)
			ea = cea_pcix();
			break;
		 default:
			op_illegal();
			return;
		}
		break;
	 default:
		op_illegal();
		return;
	}

	// XXX レジスタリストに表れて、ea オペランドに出てくる
	// レジスタは Dn、IX も含めて全部保存しておく必要がある。

	regcount = 0;
	uint list = ir2;
	while (list) {
		uint32 data;
		if (bytesize == 2) {
			data = (int32)(int16)read_2(ea);
		} else {
			data = read_4(ea);
		}
		ea += bytesize;
		regcount++;
		int ctz = __builtin_ctz(list);
		reg.R[ctz] = data;
		// clear LSB bits
		list &= ((~1U) << ctz);
	}
	// (An)+ なら An を更新
	if (anpi) {
		RegAY = ea;
	}

	CYCLE(8 + 4 * regcount);
}

// %0100_110010_mmmrrr	MOVEM.W <ea>,<list>
OP_DEF(movem_w)
{
	ops_movem_ea_list(2);
}

// %0100_110011_mmmrrr	MOVEM.L <ea>,<list>
OP_DEF(movem_l)
{
	ops_movem_ea_list(4);
}

// MOVEC.L Rc,Rn
void
MPU680x0Device::ops_movec_rc_rn()
{
	SUPERVISOR_OP;

	CYCLE(6);
	ir2 = fetch_2();
	uint n = ir2 >> 12;
	uint c = ir2 & 0xfff;
	switch (c) {
	 case 0x000:
		reg.R[n] = reg.GetSFC();
		return;
	 case 0x001:
		reg.R[n] = reg.GetDFC();
		return;
	 case 0x002:
		reg.R[n] = reg.cacr;
		return;
	 case 0x800:
		reg.R[n] = reg.usp;
		return;
	 case 0x801:
		reg.R[n] = reg.vbr;
		return;
	 case 0x802:
		reg.R[n] = reg.caar;
		return;
	 case 0x803:
		if (reg.m) {
			reg.R[n] = reg.A[7];
		} else {
			reg.R[n] = reg.msp;
		}
		return;
	 case 0x804:
		if (reg.m) {
			reg.R[n] = reg.isp;
		} else {
			reg.R[n] = reg.A[7];
		}
		return;
	 default:
		break;
	}
	op_illegal();
}

// MOVEC.L Rn,Rc
void
MPU680x0Device::ops_movec_rn_rc()
{
	SUPERVISOR_OP;

	ir2 = fetch_2();
	uint n = ir2 >> 12;
	uint c = ir2 & 0xfff;
	switch (c) {
	 case 0x000:
		CYCLE(12);
		reg.sfc = busaddr::FC(reg.R[n] & 7) | BusAddr::R;
		return;
	 case 0x001:
		CYCLE(12);
		reg.dfc = busaddr::FC(reg.R[n] & 7) | BusAddr::W;
		return;
	 case 0x002:
		CYCLE(12);
		SetCACR(reg.R[n]);
		return;
	 case 0x800:
		CYCLE(6);
		reg.usp = reg.R[n];
		return;
	 case 0x801:
		CYCLE(6);
		reg.vbr = reg.R[n];
		return;
	 case 0x802:
		CYCLE(6);
		reg.caar = reg.R[n];
		return;
	 case 0x803:
		CYCLE(6);
		if (reg.m) {
			reg.A[7] = reg.R[n];
		} else {
			reg.msp = reg.R[n];
		}
		return;
	 case 0x804:
		CYCLE(6);
		if (reg.m) {
			reg.isp = reg.R[n];
		} else {
			reg.A[7] = reg.R[n];
		}
		return;
	 default:
		break;
	}
	op_illegal();
}

// %0100_111001_00nnnn	TRAP #<vector>
// %0100_111001_010yyy	LINK.W Ay,#<imm>
// %0100_111001_011yyy	UNLK Ay
// %0100_111001_100yyy	MOVE.L Ay,USP
// %0100_111001_101yyy	MOVE.L USP,Ay
// %0100_111001_110000	RESET
// %0100_111001_110001	NOP
// %0100_111001_110010	STOP #<imm>
// %0100_111001_110011	RTE
// %0100_111001_110100	RTD #<imm>
// %0100_111001_110101	RTS
// %0100_111001_110110	TRAPV
// %0100_111001_110111	RTR
// %0100_111001_111010	MOVEC.L Rc,Rn
// %0100_111001_111011	MOVEC.L Rn,Rc
OP_DEF(trap)
{
	uint n = ir & 0x3f;
	int32 imm;

	switch (n) {
	 case 0x00 ... 0x0e:// TRAP #<vector>
		CYCLE2(18, 20);
		// TRAP#N 例外
		Exception(M68K::EXCEP_TRAP0 + n);
		return;

	 case 0x0f:			// TRAP #15
		CYCLE2(18, 20);
		// TRAP#15 例外 (IOCS コール表示のためこれだけ別処理)
		ExceptionTrap15();
		return;

	 case 0x10:
	 case 0x11:
	 case 0x12:
	 case 0x13:
	 case 0x14:
	 case 0x15:
	 case 0x17:			// LINK.W Ay,#<imm>
		CYCLE2(4, 5);
		// レジスタやスタックを変更する前にフェッチとセーブをしないと、
		// ページフォルトで再実行できなくなる
		imm = (int32)(int16)fetch_2();
		save_reg_pd(7);
		push_4(RegAY);
		RegAY = reg.A[7];
		reg.A[7] += imm;
		return;
	 case 0x16:			// LINK.W A6,#<imm>
		// LINK はほぼ A6 なのでこいつだけ展開してみる
		CYCLE2(4, 5);
		// レジスタやスタックを変更する前にフェッチとセーブをしないと、
		// ページフォルトで再実行できなくなる
		imm = (int32)(int16)fetch_2();
		save_reg_pd(7);
		push_4(reg.A[6]);
		reg.A[6] = reg.A[7];
		reg.A[7] += imm;
		return;

	 case 0x18:
	 case 0x19:
	 case 0x1a:
	 case 0x1b:
	 case 0x1c:
	 case 0x1d:
	 case 0x1f:			// UNLK Ay
		CYCLE(5);
		// ページフォルトに備えて保存する
		save_reg_pi(7);
		reg.A[7] = RegAY;
		RegAY = pop_4();
		return;
	 case 0x1e:			// UNLK A6
		// UNLK はほぼ A6 なのでこいつだけ展開してみる
		CYCLE(5);
		// ページフォルトに備えて保存する
		save_reg_pi(7);
		reg.A[7] = reg.A[6];
		reg.A[6] = pop_4();
		return;

	 case 0x20:
	 case 0x21:
	 case 0x22:
	 case 0x23:
	 case 0x24:
	 case 0x25:
	 case 0x26:
	 case 0x27:			// MOVE.L Ay,USP
		SUPERVISOR_OP;
		CYCLE(4);
		reg.usp = RegAY;
		return;

	 case 0x28:
	 case 0x29:
	 case 0x2a:
	 case 0x2b:
	 case 0x2c:
	 case 0x2d:
	 case 0x2e:
	 case 0x2f:			// MOVE.L USP,Ay
		SUPERVISOR_OP;
		CYCLE(4);
		RegAY = reg.usp;
		return;

	 case 0x30:			// RESET
		CYCLE(518);
		ops_reset();
		return;

	 case 0x31:			// NOP
		CYCLE(2);
		// XXX ほんとは何かするらしいけど
		return;

	 case 0x32:			// STOP #<imm>
		SUPERVISOR_OP;
		CYCLE(8);
		ops_stop();
		return;

	 case 0x33:			// RTE
		SUPERVISOR_OP;
		ops_rte();
		return;

	 case 0x34:			// RTD #<imm>
	 {
		CYCLE2(10, 12);
		// ページフォルトに備えて保存する
		save_reg_pi(7);
		uint32 disp = fetch_2();
		Jump(pop_4());
		reg.A[7] += (int32)(int16)disp;
		return;
	 }

	 case 0x35:			// RTS
		CYCLE2(9, 11);
		// ページフォルトに備えて保存する
		save_reg_pi(7);
		Jump(pop_4());
		return;

	 case 0x36:			// TRAPV
		if (CCR.IsV()) {
			CYCLE2(22, 24);
			Exception(M68K::EXCEP_TRAPV);
		} else {
			CYCLE(4);
		}
		return;

	 case 0x37:			// RTR
		CYCLE2(12, 14);
		// ページフォルトに備えて保存する
		save_reg_pi(7);
		CCR.Set(pop_2());
		Jump(pop_4());
		return;

	 case 0x3a:			// MOVEC.L Rc,Rn
		ops_movec_rc_rn();
		return;

	 case 0x3b:			// MOVEC.L Rn,Rc
		ops_movec_rn_rc();
		return;

	 default:
		op_illegal();
		return;
	}
}

// %0100_111010_mmmrrr	JSR <ea>
OP_DEF(jsr)
{
	CYCLE2(4, 7);
	uint32 ea = cea_ctrl();
	// ページフォルトに備えて保存する
	save_reg_pd(7);
	push_4(reg.pc);
	Jump(ea);
}

// %0100_111011_mmmrrr	JMP <ea>
OP_DEF(jmp)
{
	CYCLE2(4, 6);
	// 実際には CEA ではなく JEA の実行時間を足すんだがまあいいか
	uint32 ea = cea_ctrl();
	Jump(ea);
}

// %0101_qqq000_mmmrrr	ADDQ.B #qqq,<ea>
OP_DEF(addq_b)
{
	uint n = ir & 0x3f;

	uint32 src = RegIRX;
	src = (src == 0) ? 8 : src;
	if (n < 8) {
		// ADDQ.B #qqq,Dn
		CYCLE(2);
		uint32 data = ACC.add_8(src, reg.D[n] & 0xff);
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
	} else {
		// ADDQ.B #qqq,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.add_8(src, data);
		write_1(ea, data);
	}
}

// %0101_qqq001_mmmrrr	ADDQ.W #qqq,<ea>
// %0101_qqq001_001yyy	ADDQ.W #qqq,Ay (.Lと等価)
OP_DEF(addq_w)
{
	uint n = ir & 0x3f;

	uint32 src = RegIRX;
	src = (src == 0) ? 8 : src;
	if (n < 8) {
		// ADDQ.W #qqq,Dn
		CYCLE(2);
		uint32 data = ACC.add_16(src, reg.D[n] & 0xffff);
		reg.D[n] = (reg.D[n] & 0xffff0000) | data;
	} else if (n < 16) {
		// ADDQ.W #qqq,An は ADDQ.L と等価
		// フラグは変化しない
		CYCLE(2);
		reg.R[n] += src;
	} else {
		// ADDQ.W #qqq,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.add_16(src, data);
		write_2(ea, data);
	}
}

// %0101_qqq010_mmmrrr	ADDQ.L #qqq,<ea>
// %0101_qqq010_001yyy	ADDQ.L #qqq,Ay
OP_DEF(addq_l)
{
	uint n = ir & 0x3f;

	uint32 src = RegIRX;
	src = (src == 0) ? 8 : src;
	if (n < 8) {
		// ADDQ.L #qqq,Dn
		CYCLE(2);
		reg.D[n] = ACC.add_32(src, reg.D[n]);
	} else if (n < 16) {
		// ADDQ.L #qqq,An
		// フラグは変化しない
		CYCLE(2);
		reg.R[n] += src;
	} else {
		// ADDQ.L #qqq,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.add_32(src, data);
		write_4(ea, data);
	}
}

// TRAPcc の共通部分。
void
MPU680x0Device::ops_trapcc(uint cond)
{
	// 条件成立すれば例外。成立しなければ何もしない。
	// いずれの場合もオペランドありの形態なら事前に読み飛ばしておくこと。
	if (CCR.Cond(cond)) {
		CYCLE2(22, 24);
		Exception(M68K::EXCEP_TRAPV);
	} else {
		// サイクルを消費するだけ
		CYCLE(4);
	}
}

// %0101_cccc11_mmmrrr	Scc.B <ea>
// %0101_cccc11_001yyy	DBcc.W Dy,<label>
// %0101_cccc11_111010	TRAPcc.W #<imm>
// %0101_cccc11_111011	TRAPcc.L #<imm>
// %0101_cccc11_111100	TRAPcc
// %0101_000111_001yyy	DBRA.W Dy,<label>
OP_DEF(scc)
{
	uint n = ir & 0x3f;
	uint cond = (ir >> 8) & 0x0f;

	switch (n) {
	 case 0b000000 ... 0b000111:	// Scc.B Dn
		CYCLE(4);
		if (CCR.Cond(cond)) {
			RegDY |= 0xff;
		} else {
			RegDY &= ~0xff;
		}
		return;

	 case 0b001000 ... 0b001111:	// DBcc.W Dy,<label>
		if (CCR.Cond(cond)) {
			// 真なら何もしない。disp を読み飛ばして次へ。
			CYCLE2(6, 8);
			fetch_2();
		} else {
			// 偽の場合

			// Dy.W を減算して(下位ワードに)書き戻し、Dy.W が -1 だったら
			// ループ終了。だが最適化のため、減算前の Dy.W が 0 の時は
			// 下位ワードを 0xffff にしてループ終了、そうでなければ Dy.L を
			// 減算するだけでいいはず。

			uint16 data = RegDY;
			if (data == 0) {
				// ループ終了。disp を読み飛ばす
				CYCLE2(10, 13);
				RegDY |= 0x0000ffff;
				fetch_2();
			} else {
				CYCLE2(6, 8);
				RegDY--;
				uint32 origin = reg.pc;
				int32 disp = (int32)(int16)fetch_2();
				Jump(origin + disp);
			}
		}
		return;

	 case 0b010000 ... 0b010111:	// Scc.B <ea>
	 case 0b011000 ... 0b011111:	// Scc.B <ea>
	 case 0b100000 ... 0b100111:	// Scc.B <ea>
	 case 0b101000 ... 0b101111:	// Scc.B <ea>
	 case 0b110000 ... 0b110111:	// Scc.B <ea>
	 case 0b111000:					// Scc.B <ea>
	 case 0b111001:					// Scc.B <ea>
	 {
		CYCLE(5);
		// 条件成立可否に関わらず EA は取得しないといけない
		uint32 ea = cea_data_1();
		uint32 data;
		if (CCR.Cond(cond)) {
			data = 0xff;
		} else {
			data = 0;
		}
		write_1(ea, data);
		return;
	 }

	 case 0b111010:		// TRAPcc.W #<imm>
		// オペランドなしTRAPccに比べてすべてのケースで2サイクル多い
		CYCLE(2);
		fetch_2();
		ops_trapcc(cond);
		return;

	 case 0b111011:		// TRAPcc.L #<imm>
		// オペランドなしTRAPccに比べてすべてのケースで4サイクル多い
		CYCLE(4);
		fetch_4();
		ops_trapcc(cond);
		return;

	 case 0b111100:		// TRAPcc
		ops_trapcc(cond);
		return;

	 default:
		OP_FUNC(illegal);
		return;
	}
}

// %0101_qqq100_mmmrrr	SUBQ.B #qqq,<ea>
OP_DEF(subq_b)
{
	uint n = ir & 0x3f;

	uint32 src = RegIRX;
	src = (src == 0) ? 8 : src;
	if (n < 8) {
		// SUBQ.B #qqq,Dn
		CYCLE(2);
		uint32 data = ACC.sub_8(src, reg.D[n] & 0xff);
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
	} else {
		// SUBQ.B #qqq,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.sub_8(src, data);
		write_1(ea, data);
	}
}

// %0101_qqq101_mmmrrr	SUBQ.W #qqq,<ea>
// %0101_qqq101_001yyy	SUBQ.W #qqq,Ay (.Lと等価)
OP_DEF(subq_w)
{
	uint n = ir & 0x3f;

	uint32 src = RegIRX;
	src = (src == 0) ? 8 : src;
	if (n < 8) {
		// SUBQ.W #qqq,Dn
		CYCLE(2);
		uint32 data = ACC.sub_16(src, reg.D[n] & 0xffff);
		reg.D[n] = (reg.D[n] & 0xffff0000) | data;
	} else if (n < 16) {
		// SUBQ.W #qqq,An は SUBQ.L と等価
		// フラグは変化しない
		CYCLE(2);
		reg.R[n] -= src;
	} else {
		// SUBQ.W #qqq,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.sub_16(src, data);
		write_2(ea, data);
	}
}

// %0101_qqq110_mmmrrr	SUBQ.L #qqq,<ea>
// %0101_qqq110_001yyy	SUBQ.L #qqq,Ay
OP_DEF(subq_l)
{
	uint n = ir & 0x3f;

	uint32 src = RegIRX;
	src = (src == 0) ? 8 : src;
	if (n < 8) {
		// SUBQ.L #qqq,Dn
		CYCLE(2);
		reg.D[n] = ACC.sub_32(src, reg.D[n]);
	} else if (n < 16) {
		// SUBQ.L #qqq,An
		// フラグは変化しない
		CYCLE(2);
		reg.R[n] -= src;
	} else {
		// SUBQ.L #qqq,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.sub_32(src, data);
		write_4(ea, data);
	}
}

inline void
MPU680x0Device::ops_bra()
{
	CYCLE2(6, 8);

	uint32 origin = reg.pc;
	int32 disp = (int32)(int8)(ir & 0xff);
	if (disp == -1) {
		// Bcc.L
		disp = (int32)fetch_4();
	} else if (disp == 0) {
		// Bcc.W
		disp = (int32)(int16)fetch_2();
	}
	Jump(origin + disp);
}

// %0110_000000_000000	BRA.W <label>
// %0110_0000nn_nnnnnn	BRA.B <label>
// %0110_000011_111111	BRA.L <label>
OP_DEF(bra)
{
	ops_bra();
}

// %0110_000100_000000	BSR.W <label>
// %0110_0001nn_nnnnnn	BSR.B <label>
// %0110_000111_111111	BSR.L <label>
OP_DEF(bsr)
{
	CYCLE2(6, 9);
	uint32 origin = reg.pc;
	int32 disp = (int32)(int8)(ir & 0xff);
	if (disp == -1) {
		// BSR.L <label>
		disp = (int32)fetch_4();
	} else if (disp == 0) {
		// BSR.W <label>
		disp = (int32)(int16)fetch_2();
	}
	// ページフォルトに備えて保存する
	save_reg_pd(7);
	push_4(reg.pc);
	Jump(origin + disp);
}

// %0110_cccc00_000000	Bcc.W <label>
// %0110_ccccnn_nnnnnn	Bcc.B <label>
// %0110_cccc11_111111	Bcc.L <label>
OP_DEF(bcc)
{
	// ブランチするかどうかでサイクルが変わるので先に条件を調べる
	uint cond = (ir >> 8) & 0x0f;
	if (CCR.Cond(cond)) {
		// Bcc (taken)
		ops_bra();
	} else {
		int32 disp = (int32)(int8)(ir & 0xff);
		if (disp == -1) {
			// Bcc.L (not taken)
			CYCLE(8);
			fetch_4();
		} else if (disp == 0) {
			// Bcc.W (not taken)
			CYCLE(6);
			fetch_2();
		} else {
			// Bcc.B (not taken)
			CYCLE(4);
		}
	}
}

// %0111_xxx0nn_nnnnnn	MOVEQ.L #<imm>,Dx
OP_DEF(moveq)
{
	CYCLE(2);
	RegDX = (int32)(int8)(ir & 0xff);
	ACC.move_32(RegDX);
}

// %1000_xxx000_mmmrrr	OR.B <ea>,Dx
OP_DEF(or_b_ea_dn)
{
	uint n = ir & 0x3f;

	CYCLE(2);
	uint x = RegIRX;
	if (n < 8) {
		// OR.B Dn,Dx
		uint32 data = (reg.D[x] | reg.D[n]) & 0xff;
		ACC.move_8(data);
		reg.D[x] = (reg.D[x] & 0xffffff00) | data;
	} else {
		// OR.B <ea>,Dx
		uint32 src = fea_data_1();
		uint32 data = (reg.D[x] | src) & 0xff;
		ACC.move_8(data);
		reg.D[x] = (reg.D[x] & 0xffffff00) | data;
	}
}

// %1000_xxx001_mmmrrr	OR.W <ea>,Dx
OP_DEF(or_w_ea_dn)
{
	uint n = ir & 0x3f;

	CYCLE(2);
	uint x = RegIRX;
	if (n < 8) {
		// OR.W Dn,Dx
		uint32 data = (reg.D[x] | reg.D[n]) & 0xffff;
		ACC.move_16(data);
		reg.D[x] = (reg.D[x] & 0xffff0000) | data;
	} else {
		// OR.W <ea>,Dx
		uint32 src = fea_data_2();
		uint32 data = (reg.D[x] | src) & 0xffff;
		ACC.move_16(data);
		reg.D[x] = (reg.D[x] & 0xffff0000) | data;
	}
}

// %1000_xxx010_mmmrrr	OR.L <ea>,Dx
OP_DEF(or_l_ea_dn)
{
	uint n = ir & 0x3f;

	CYCLE(2);
	uint x = RegIRX;
	if (n < 8) {
		// OR.L Dn,Dx
		reg.D[x] |= reg.D[n];
		ACC.move_32(reg.D[x]);
	} else {
		// OR.L <ea>,Dx
		uint32 src = fea_data_4();
		uint32 data = reg.D[x] | src;
		ACC.move_32(data);
		reg.D[x] = data;
	}
}

// %1000_xxx011_mmmrrr	DIVU.W <ea>,Dx
OP_DEF(divu_w)
{
	CYCLE(44);	// XXX これは本当は最大値だけど

	uint16 src = fea_data_2();
	uint32 dst = RegDX;

	if (src == 0) {
		// ゼロ除算の場合、
		// X は変化しない
		// C は常にクリア
		// N,Z,V は未定義
		CCR.SetC(false);
		Exception(M68K::EXCEP_ZERODIV);
		return;
	}

	uint32 quo = dst / src;
	uint32 rem = dst % src;
	if (quo > 0xffff) {
		// オーバーフローの場合、
		// X は変化しない
		// N,Z は未定義
		// V はセット
		// C は常にクリア
		CCR.SetV(true);
		CCR.SetC(false);
		return;
	}

	// 正常の場合、
	// X は変化しない
	// V, C はクリア
	// N, Z は quo の結果。
	RegDX = (rem << 16) | quo;
	ACC.move_16(quo);
}

// %1000_xxx100_000yyy	SBCD.B Dy,Dx
// %1000_xxx100_001yyy	SBCD.B -(Ay),-(Ax)
// %1000_xxx100_mmmrrr	OR.B Dx,<ea>
OP_DEF(or_b_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// SBCD.B Dy,Dx
		CYCLE(4);
		uint32 src = RegDY & 0xff;
		uint32 dst = RegDX & 0xff;
		dst = ACC.sbcd_8(src, dst);
		RegDX &= 0xffffff00;
		RegDX |= dst;
	} else if (n < 16) {
		// SBCD.B -(Ay),-(Ax)
		CYCLE2(13, 14);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_1(RegIRY);
		uint32 dstea = internal_ea_anpd_1(RegIRX);
		uint32 src = read_1(srcea);
		uint32 dst = read_1(dstea);
		dst = ACC.sbcd_8(src, dst);
		write_1(dstea, dst);
	} else {
		// OR.B Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint8 data = read_1(ea);
		data |= RegDX;
		ACC.move_8(data);
		write_1(ea, data);
	}
}

// %1000_xxx101_000yyy	PACK Dy,Dx,#<imm>
// %1000_xxx101_001yyy	PACK -(Ay),-(Ax),#<imm>
// %1000_xxx101_mmmrrr	OR.W Dx,<ea>
OP_DEF(or_w_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// PACK Dy,Dx,#<imm>
		CYCLE(6);
		uint32 imm = fetch_2();
		uint32 src = RegDY + imm;
		RegDX = (RegDX & 0xffffff00) | ((src >> 4) & 0x00f0) | (src & 0x000f);
	} else if (n < 16) {
		// PACK -(Ay),-(Ax),#<imm>
		CYCLE(11);
		uint32 imm = fetch_2();
		uint32 srcea;
		uint32 src;
		// -(Ay) を2回行う
		save_reg_pd(RegIRY);
		srcea = internal_ea_anpd_1(RegIRY);
		src = read_1(srcea);
		srcea = internal_ea_anpd_1(RegIRY);
		src |= (read_1(srcea) << 8);
		src += imm;
		uint32 dst = ((src >> 4) & 0x00f0) | (src & 0x000f);
		save_reg_pd_if(RegIRX);
		uint32 dstea = internal_ea_anpd_1(RegIRX);
		write_1(dstea, dst);
	} else {
		// OR.W Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint16 data = read_2(ea);
		data |= RegDX;
		ACC.move_16(data);
		write_2(ea, data);
	}
}

// %1000_xxx110_000yyy	UNPK Dy,Dx,#<imm>
// %1000_xxx110_001yyy	UNPK -(Ay),-(Ax),#<imm>
// %1000_xxx110_mmmrrr	OR.L Dx,<ea>
OP_DEF(or_l_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// UNPK Dy,Dx,#<imm>
		CYCLE(8);
		uint32 imm = fetch_2();
		uint16 src = RegDY;
		src = ((src & 0x00f0) << 4) | (src & 0x000f);
		src += imm;
		RegDX = (RegDX & 0xffff0000) | src;
	} else if (n < 16) {
		// UNPK -(Ay),-(Ax),#<imm>
		CYCLE(11);
		uint32 imm = fetch_2();
		save_reg_pd(RegIRY);
		uint32 srcea = internal_ea_anpd_1(RegIRY);
		uint16 src = read_1(srcea);
		src = ((src & 0x00f0) << 4) | (src & 0x000f);
		src += imm;
		// -(Ax) を2回行う
		save_reg_pd_if(RegIRX);
		uint32 dstea;
		dstea = internal_ea_anpd_1(RegIRX);
		write_1(dstea, (src & 0xff));
		dstea = internal_ea_anpd_1(RegIRX);
		write_1(dstea, src >> 8);
	} else {
		// OR.L Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data |= RegDX;
		ACC.move_32(data);
		write_4(ea, data);
	}
}

// %1000_xxx111_mmmrrr	DIVS.W <ea>,Dx
OP_DEF(divs_w)
{
	CYCLE(56);	// XXX これは本当は最大値だけど

	uint16 src = fea_data_2();
	uint32 dst = RegDX;

	if (src == 0) {
		// ゼロ除算の場合、
		// X は変化しない
		// C は常にクリア
		// N,Z,V は未定義
		CCR.SetC(false);
		Exception(M68K::EXCEP_ZERODIV);
		return;
	}

	// ホストでオーバーフローが起きるのはこのケースのみ
	if (dst == 0x80000000 && src == 0xffff) {
		// オーバーフローの場合、
		// X は変化しない
		// N,Z は未定義
		// V はセット
		// C は常にクリア
		CCR.SetV(true);
		CCR.SetC(false);
		return;
	}

	int32 squo = (int32)dst / (int32)(int16)src;
	int32 srem = (int32)dst % (int32)(int16)src;
	if ((int16)squo != squo) {
		// オーバーフローの場合
		CCR.SetV(true);
		CCR.SetC(false);
		return;
	}
	// 正常の場合、
	// X は変化しない
	// V, C はクリア
	// N, Z は quo の結果。
	uint32 quo = (uint32)squo & 0xffff;
	uint32 rem = (uint32)srem & 0xffff;
	RegDX = (rem << 16) | quo;
	ACC.move_16(quo);
}

// %1001_xxx000_mmmrrr	SUB.B <ea>,Dx
OP_DEF(sub_b_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_all_1();
	uint32 data = ACC.sub_8(src, RegDX & 0xff);
	RegDX = (RegDX & 0xffffff00) | data;
}

// %1001_xxx001_mmmrrr	SUB.W <ea>,Dx
OP_DEF(sub_w_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_all_2();
	uint32 data = ACC.sub_16(src, RegDX & 0xffff);
	RegDX = (RegDX & 0xffff0000) | data;
}

// %1001_xxx010_mmmrrr	SUB.L <ea>,Dx
OP_DEF(sub_l_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_all_4();
	RegDX = ACC.sub_32(src, RegDX);
}

// %1001_xxx011_mmmrrr	SUBA.W <ea>,Ax
OP_DEF(suba_w)
{
	CYCLE(4);
	uint32 src = (int32)(int16)fea_all_2();
	RegAX -= src;
}

// %1001_xxx100_000yyy	SUBX.B Dy,Dx
// %1001_xxx100_001yyy	SUBX.B -(Ay),-(Ax)
// %1001_xxx100_mmmrrr	SUB.B Dx,<ea>
OP_DEF(sub_b_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// SUBX.B Dy,Dx
		CYCLE(2);
		uint32 src = RegDY & 0xff;
		uint32 dst = RegDX & 0xff;
		dst = ACC.subx_8(src, dst);
		RegDX = (RegDX & 0xffffff00) | dst;
	} else if (n < 16) {
		// SUBX.B -(Ay),-(Ax)
		CYCLE2(9, 10);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_1(RegIRY);
		uint32 dstea = internal_ea_anpd_1(RegIRX);
		uint32 src = read_1(srcea);
		uint32 dst = read_1(dstea);
		dst = ACC.subx_8(src, dst);
		write_1(dstea, dst);
	} else {
		// SUB.B Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.sub_8(RegDX & 0xff, data);
		write_1(ea, data);
	}
}

// %1001_xxx101_000yyy	SUBX.W Dy,Dx
// %1001_xxx101_001yyy	SUBX.W -(Ay),-(Ax)
// %1001_xxx101_mmmrrr	SUB.W Dx,<ea>
OP_DEF(sub_w_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// SUBX.W Dy,Dx
		CYCLE(2);
		uint32 src = RegDY & 0xffff;
		uint32 dst = RegDX & 0xffff;
		dst = ACC.subx_16(src, dst);
		RegDX = (RegDX & 0xffff0000) | dst;
	} else if (n < 16) {
		// SUBX.W -(Ay),-(Ax)
		CYCLE2(9, 10);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_2(RegIRY);
		uint32 dstea = internal_ea_anpd_2(RegIRX);
		uint32 src = read_2(srcea);
		uint32 dst = read_2(dstea);
		dst = ACC.subx_16(src, dst);
		write_2(dstea, dst);
	} else {
		// SUB.W Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.sub_16(RegDX & 0xffff, data);
		write_2(ea, data);
	}
}

// %1001_xxx110_000yyy	SUBX.L Dy,Dx
// %1001_xxx110_001yyy	SUBX.L -(Ay),-(Ax)
// %1001_xxx110_mmmrrr	SUB.L Dx,<ea>
OP_DEF(sub_l_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// SUBX.L Dy,Dx
		CYCLE(2);
		uint32 src = RegDY;
		uint32 dst = RegDX;
		RegDX = ACC.subx_32(src, dst);
	} else if (n < 16) {
		// SUBX.L -(Ay),-(Ax)
		CYCLE2(9, 10);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_4(RegIRY);
		uint32 dstea = internal_ea_anpd_4(RegIRX);
		uint32 src = read_4(srcea);
		uint32 dst = read_4(dstea);
		dst = ACC.subx_32(src, dst);
		write_4(dstea, dst);
	} else {
		// SUB.L Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.sub_32(RegDX, data);
		write_4(ea, data);
	}
}

// %1001_xxx111_mmmrrr	SUBA.L <ea>,Ax
OP_DEF(suba_l)
{
	CYCLE(2);
	uint32 src = fea_all_4();
	RegAX -= src;
}

// %1010_nnnnnn_nnnnnn	A-Line
OP_DEF(aline)
{
	if (aline_callback) {
		if (aline_callback(this, aline_arg)) {
			return;
		}
	}
	// A系列命令例外
	Exception(M68K::EXCEP_ALINE);
}

// %1011_xxx000_mmmrrr	CMP.B <ea>,Dx
OP_DEF(cmp_b)
{
	CYCLE(2);
	uint32 src = fea_all_1();
	uint32 dst = RegDX & 0xff;
	ACC.cmp_8(src, dst);
}

// %1011_xxx001_mmmrrr	CMP.W <ea>,Dx
OP_DEF(cmp_w)
{
	CYCLE(2);
	uint32 src = fea_all_2();
	uint32 dst = RegDX & 0xffff;
	ACC.cmp_16(src, dst);
}

// %1011_xxx010_mmmrrr	CMP.L <ea>,Dx
OP_DEF(cmp_l)
{
	CYCLE(2);
	uint32 src = fea_all_4();
	ACC.cmp_32(src, RegDX);
}

// %1011_xxx011_mmmrrr	CMPA.W <ea>,Ax
OP_DEF(cmpa_w)
{
	CYCLE(4);
	uint32 src = (uint32)(int32)(int16)fea_all_2();
	ACC.cmp_32(src, RegAX);
}

// %1011_xxx100_mmmrrr	EOR.B Dx,<ea>
// %1011_xxx100_001yyy	CMPM.B (Ay)+,(Ax)+
OP_DEF(eor_b)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EOR.B Dx,Dy
		CYCLE(2);
		uint32 data = (reg.D[n] ^ RegDX) & 0xff;
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
		ACC.move_8(data);
	} else if (n < 16) {
		// CMPM.B (Ay)+,(Ax)+
		CYCLE(8);
		save_reg_pi_if(RegIRY);
		save_reg_pi_if(RegIRX);
		uint32 srcea = internal_ea_anpi_1(RegIRY);
		uint32 dstea = internal_ea_anpi_1(RegIRX);
		uint32 src = read_1(srcea);
		uint32 dst = read_1(dstea);
		ACC.cmp_8(src, dst);
	} else {
		// EOR.B Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data ^= (RegDX & 0xff);
		write_1(ea, data);
		ACC.move_8(data);
	}
}

// %1011_xxx101_mmmrrr	EOR.W Dx,<ea>
// %1011_xxx101_001yyy	CMPM.W (Ay)+,(Ax)+
OP_DEF(eor_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EOR.W Dx,Dy
		CYCLE(2);
		uint32 data = (reg.D[n] ^ RegDX) & 0xffff;
		reg.D[n] = (reg.D[n] & 0xffff0000) | data;
		ACC.move_16(data);
	} else if (n < 16) {
		// CMPM.W (Ay)+,(Ax)+
		CYCLE(8);
		save_reg_pi_if(RegIRY);
		save_reg_pi_if(RegIRX);
		uint32 srcea = internal_ea_anpi_2(RegIRY);
		uint32 dstea = internal_ea_anpi_2(RegIRX);
		uint32 src = read_2(srcea);
		uint32 dst = read_2(dstea);
		ACC.cmp_16(src, dst);
	} else {
		// EOR.W Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data ^= (RegDX & 0xffff);
		write_2(ea, data);
		ACC.move_16(data);
	}
}

// %1011_xxx110_mmmrrr	EOR.L Dx,<ea>
// %1011_xxx110_001yyy	CMPM.L (Ay)+,(Ax)+
OP_DEF(eor_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EOR.L Dx,Dy
		CYCLE(2);
		reg.D[n] ^= RegDX;
		ACC.move_32(reg.D[n]);
	} else if (n < 16) {
		// CMPM.L (Ay)+,(Ax)+
		CYCLE(8);
		save_reg_pi_if(RegIRY);
		save_reg_pi_if(RegIRX);
		uint32 srcea = internal_ea_anpi_4(RegIRY);
		uint32 dstea = internal_ea_anpi_4(RegIRX);
		uint32 src = read_4(srcea);
		uint32 dst = read_4(dstea);
		ACC.cmp_32(src, dst);
	} else {
		// EOR.L Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data ^= RegDX;
		write_4(ea, data);
		ACC.move_32(data);
	}
}

// %1011_xxx111_mmmrrr	CMPA.L <ea>,Ax
OP_DEF(cmpa_l)
{
	CYCLE(4);
	uint32 src = fea_all_4();
	ACC.cmp_32(src, RegAX);
}

// %1100_xxx000_mmmrrr	AND.B <ea>,Dx
OP_DEF(and_b_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_data_1();
	uint32 dst = (RegDX & 0x000000ff) & src;
	ACC.move_8(dst);
	RegDX = (RegDX & 0xffffff00) | dst;
}

// %1100_xxx001_mmmrrr	AND.W <ea>,Dx
OP_DEF(and_w_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_data_2();
	uint32 dst = (RegDX & 0x0000ffff) & src;
	ACC.move_16(dst);
	RegDX = (RegDX & 0xffff0000) | dst;
}

// %1100_xxx010_mmmrrr	AND.L <ea>,Dx
OP_DEF(and_l_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_data_4();
	RegDX = RegDX & src;
	ACC.move_32(RegDX);
}

// %1100_xxx011_mmmrrr	MULU.W <ea>,Dx
OP_DEF(mulu_w)
{
	CYCLE(28);	// 実際にはこれは最大値
	uint32 src = fea_data_2();
	uint32 dst = RegDX & 0xffff;
	RegDX = ACC.mulu_16(src, dst);
}

// %1100_xxx100_000yyy	ABCD.B Dy,Dx
// %1100_xxx100_001yyy	ABCD.B -(Ay),-(Ax)
// %1100_xxx100_mmmrrr	AND.B Dx,<ea>
OP_DEF(and_b_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// ABCD.B Dy,Dx
		CYCLE(4);
		uint32 src = RegDY & 0xff;
		uint32 dst = RegDX & 0xff;
		dst = ACC.abcd_8(src, dst);
		RegDX &= 0xffffff00;
		RegDX |= dst;
		return;
	} else if (n < 16) {
		// ABCD.B -(Ay),-(Ax)
		CYCLE2(13, 14);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_1(RegIRY);
		uint32 dstea = internal_ea_anpd_1(RegIRX);
		uint32 src = read_1(srcea);
		uint32 dst = read_1(dstea);
		dst = ACC.abcd_8(src, dst);
		write_1(dstea, dst);
		return;
	} else {
		// AND.B Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst &= RegDX & 0xff;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

// %1100_xxx101_000yyy	EXG.L Dx,Dy
// %1100_xxx101_001yyy	EXG.L Ax,Ay
// %1100_xxx101_mmmrrr	AND.W Dx,<ea>
OP_DEF(and_w_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// EXG.L Dx,Dy
		CYCLE(4);
		uint x = RegIRX;
		uint y = n;
		uint32 tmp = reg.D[x];
		reg.D[x] = reg.D[y];
		reg.D[y] = tmp;
		return;
	} else if (n < 16) {
		// EXG.L Ax,Ay
		// ここでは x は 0..7 で A(x)、y は 8..15 で R(y)
		CYCLE(4);
		uint x = RegIRX;
		uint y = n;
		uint32 tmp = reg.A[x];
		reg.A[x] = reg.R[y];
		reg.R[y] = tmp;
		return;
	} else {
		// AND.W Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst &= RegDX & 0xffff;
		ACC.move_16(dst);
		write_2(ea, dst);
	}
}

// %1100_xxx110_001yyy	EXG.L Dx,Ay
// %1100_xxx110_mmmrrr	AND.L Dx,<ea>
OP_DEF(and_l_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		op_illegal();
		return;
	} else if (n < 16) {
		// EXG.L Dx,Ay
		// ここでは x は 0..7 で D(x)、y は 8..15 で R(y)
		CYCLE(4);
		uint x = RegIRX;
		uint y = n;
		uint32 tmp = reg.D[x];
		reg.D[x] = reg.R[y];
		reg.R[y] = tmp;
		return;
	} else {
		// AND.L Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 dst = read_4(ea);
		dst &= RegDX;
		ACC.move_32(dst);
		write_4(ea, dst);
	}
}

// %1100_xxx111_mmmrrr	MULS.W <ea>,Dx
OP_DEF(muls_w)
{
	CYCLE(28);	// 実際にはこれは最大値
	uint32 src = fea_data_2();
	uint32 dst = RegDX & 0xffff;
	RegDX = ACC.muls_16(src, dst);
}

// %1101_xxx000_mmmrrr	ADD.B <ea>,Dx
OP_DEF(add_b_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_all_1();
	uint32 data = ACC.add_8(src, RegDX & 0xff);
	RegDX = (RegDX & 0xffffff00) | data;
}

// %1101_xxx001_mmmrrr	ADD.W <ea>,Dx
OP_DEF(add_w_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_all_2();
	uint32 data = ACC.add_16(src, RegDX & 0xffff);
	RegDX = (RegDX & 0xffff0000) | data;
}

// %1101_xxx010_mmmrrr	ADD.L <ea>,Dx
OP_DEF(add_l_ea_dn)
{
	CYCLE(2);
	uint32 src = fea_all_4();
	RegDX = ACC.add_32(src, RegDX);
}

// %1101_xxx011_mmmrrr	ADDA.W <ea>,Ax
OP_DEF(adda_w)
{
	CYCLE(4);
	uint32 src = (int32)(int16)fea_all_2();
	RegAX += src;
}

// %1101_xxx100_000yyy	ADDX.B Dy,Dx
// %1101_xxx100_001yyy	ADDX.B -(Ay),-(Ax)
// %1101_xxx100_mmmrrr	ADD.B Dx,<ea>
OP_DEF(add_b_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// ADDX.B Dy,Dx
		CYCLE(2);
		uint32 src = RegDY & 0xff;
		uint32 dst = RegDX & 0xff;
		dst = ACC.addx_8(src, dst);
		RegDX = (RegDX & 0xffffff00) | dst;
	} else if (n < 16) {
		// ADDX.B -(Ay),-(Ax)
		CYCLE2(9, 10);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_1(RegIRY);
		uint32 dstea = internal_ea_anpd_1(RegIRX);
		uint32 src = read_1(srcea);
		uint32 dst = read_1(dstea);
		dst = ACC.addx_8(src, dst);
		write_1(dstea, dst);
	} else {
		// ADD.B Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.add_8(RegDX & 0xff, data);
		write_1(ea, data);
	}
}

// %1101_xxx101_000yyy	ADDX.W Dy,Dx
// %1101_xxx101_001yyy	ADDX.W -(Ay),-(Ax)
// %1101_xxx101_mmmrrr	ADD.W Dx,<ea>
OP_DEF(add_w_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// ADDX.W Dy,Dx
		CYCLE(2);
		uint32 src = RegDY & 0xffff;
		uint32 dst = RegDX & 0xffff;
		dst = ACC.addx_16(src, dst);
		RegDX = (RegDX & 0xffff0000) | dst;
	} else if (n < 16) {
		// ADDX.W -(Ay),-(Ax)
		CYCLE2(9, 10);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_2(RegIRY);
		uint32 dstea = internal_ea_anpd_2(RegIRX);
		uint32 src = read_2(srcea);
		uint32 dst = read_2(dstea);
		dst = ACC.addx_16(src, dst);
		write_2(dstea, dst);
	} else {
		// ADD.W Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.add_16(RegDX & 0xffff, data);
		write_2(ea, data);
	}
}

// %1101_xxx110_000yyy	ADDX.L Dy,Dx
// %1101_xxx110_001yyy	ADDX.L -(Ay),-(Ax)
// %1101_xxx110_mmmrrr	ADD.L Dx,<ea>
OP_DEF(add_l_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// ADDX.L Dy,Dx
		CYCLE(2);
		uint32 src = RegDY;
		uint32 dst = RegDX;
		RegDX = ACC.addx_32(src, dst);
	} else if (n < 16) {
		// ADDX.L -(Ay),-(Ax)
		CYCLE2(9, 10);
		save_reg_pd_if(RegIRY);
		save_reg_pd_if(RegIRX);
		uint32 srcea = internal_ea_anpd_4(RegIRY);
		uint32 dstea = internal_ea_anpd_4(RegIRX);
		uint32 src = read_4(srcea);
		uint32 dst = read_4(dstea);
		dst = ACC.addx_32(src, dst);
		write_4(dstea, dst);
	} else {
		// ADD.L Dx,<ea>
		CYCLE2(3, 4);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.add_32(RegDX, data);
		write_4(ea, data);
	}
}

// %1101_xxx111_mmmrrr	ADDA.L <ea>,Ax
OP_DEF(adda_l)
{
	CYCLE(2);
	uint32 src = fea_all_4();
	RegAX += src;
}

// %1110_qqq000_000yyy	ASR.B #qqq,Dy
// %1110_qqq000_001yyy	LSR.B #qqq,Dy
// %1110_qqq000_010yyy	ROXR.B #qqq,Dy
// %1110_qqq000_011yyy	ROR.B #qqq,Dy
// %1110_xxx000_100yyy	ASR.B Dx,Dy
// %1110_xxx000_101yyy	LSR.B Dx,Dy
// %1110_xxx000_110yyy	ROXR.B Dx,Dy
// %1110_xxx000_111yyy	ROR.B Dx,Dy
OP_DEF(asr_b_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASR.B #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.asr_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 1:	// LSR.B #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.lsr_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 2:	// ROXR.B #qqq,Dy
		CYCLE(12);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.roxr_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 3:	// ROR.B #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.ror_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 4:	// ASR.B Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 8 ? 6 : 10);
		__assume(0 <= count && count < 64);
		data = ACC.asr_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 5:	// LSR.B Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 8 ? 6 : 8);
		__assume(0 <= count && count < 64);
		data = ACC.lsr_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 6:	// ROXR.B Dx,Dy
		CYCLE(12);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.roxr_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 7:	// ROR.B Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.ror_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	}
}

// %1110_qqq001_000yyy	ASR.W #qqq,Dy
// %1110_qqq001_001yyy	LSR.W #qqq,Dy
// %1110_qqq001_010yyy	ROXR.W #qqq,Dy
// %1110_qqq001_011yyy	ROR.W #qqq,Dy
// %1110_xxx001_100yyy	ASR.W Dx,Dy
// %1110_xxx001_101yyy	LSR.W Dx,Dy
// %1110_xxx001_110yyy	ROXR.W Dx,Dy
// %1110_xxx001_111yyy	ROR.W Dx,Dy
OP_DEF(asr_w_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASR.W #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.asr_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 1:	// LSR.W #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.lsr_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 2:	// ROXR.W #qqq,Dy
		CYCLE(12);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.roxr_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 3:	// ROR.W #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.ror_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 4:	// ASR.W Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 16 ? 6 : 10);
		__assume(0 <= count && count < 64);
		data = ACC.asr_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 5:	// LSR.W Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 16 ? 6 : 8);
		__assume(0 <= count && count < 64);
		data = ACC.lsr_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 6:	// ROXR.W Dx,Dy
		CYCLE(12);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.roxr_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 7:	// ROR.W Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.ror_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	}
}

// %1110_qqq010_000yyy	ASR.L #qqq,Dy
// %1110_qqq010_001yyy	LSR.L #qqq,Dy
// %1110_qqq010_010yyy	ROXR.L #qqq,Dy
// %1110_qqq010_011yyy	ROR.L #qqq,Dy
// %1110_xxx010_100yyy	ASR.L Dx,Dy
// %1110_xxx010_101yyy	LSR.L Dx,Dy
// %1110_xxx010_110yyy	ROXR.L Dx,Dy
// %1110_xxx010_111yyy	ROR.L Dx,Dy
OP_DEF(asr_l_imm)
{
	int count;
	switch (eamode(ir)) {
	 case 0:	// ASR.L #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.asr_32(RegDY, count);
		return;
	 case 1:	// LSR.L #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.lsr_32(RegDY, count);
		return;
	 case 2:	// ROXR.L #qqq,Dy
		CYCLE(12);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.roxr_32(RegDY, count);
		return;
	 case 3:	// ROR.L #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.ror_32(RegDY, count);
		return;
	 case 4:	// ASR.L Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 32 ? 6 : 10);
		__assume(0 <= count && count < 64);
		RegDY = ACC.asr_32(RegDY, count);
		return;
	 case 5:	// LSR.L Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 32 ? 6 : 8);
		__assume(0 <= count && count < 64);
		RegDY = ACC.lsr_32(RegDY, count);
		return;
	 case 6:	// ROXR.L Dx,Dy
		CYCLE(12);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.roxr_32(RegDY, count);
		return;
	 case 7:	// ROR.L Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.ror_32(RegDY, count);
		return;
	}
}

// %1110_000011_mmmrrr	ASR.W <ea>
OP_DEF(asr_w)
{
	CYCLE(4);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.asr_16(data, 1);
	write_2(ea, data);
}

// %1110_qqq100_000yyy	ASL.B #qqq,Dy
// %1110_qqq100_001yyy	LSL.B #qqq,Dy
// %1110_qqq100_010yyy	ROXL.B #qqq,Dy
// %1110_qqq100_011yyy	ROL.B #qqq,Dy
// %1110_xxx100_100yyy	ASL.B Dx,Dy
// %1110_xxx100_101yyy	LSL.B Dx,Dy
// %1110_xxx100_110yyy	ROXL.B Dx,Dy
// %1110_xxx100_111yyy	ROL.B Dx,Dy
OP_DEF(asl_b_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASL.B #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.asl_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 1:	// LSL.B #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.lsl_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 2:	// ROXL.B #qqq,Dy
		CYCLE(12);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.roxl_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 3:	// ROL.B #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.rol_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 4:	// ASL.B Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.asl_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 5:	// LSL.B Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 8 ? 6 : 8);
		__assume(0 <= count && count < 64);
		data = ACC.lsl_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 6:	// ROXL.B Dx,Dy
		CYCLE(12);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.roxl_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 7:	// ROL.B Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.rol_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	}
}

// %1110_qqq101_000yyy	ASL.W #qqq,Dy
// %1110_qqq101_001yyy	LSL.W #qqq,Dy
// %1110_qqq101_010yyy	ROXL.W #qqq,Dy
// %1110_qqq101_011yyy	ROL.W #qqq,Dy
// %1110_xxx101_100yyy	ASL.W Dx,Dy
// %1110_xxx101_101yyy	LSL.W Dx,Dy
// %1110_xxx101_110yyy	ROXL.W Dx,Dy
// %1110_xxx101_111yyy	ROL.W Dx,Dy
OP_DEF(asl_w_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASL.W #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.asl_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 1:	// LSL.W #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.lsl_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 2:	// ROXL.W #qqq,Dy
		CYCLE(12);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.roxl_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 3:	// ROL.W #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		data = ACC.rol_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 4:	// ASL.W Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.asl_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 5:	// LSL.W Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 16 ? 6 : 8);
		__assume(0 <= count && count < 64);
		data = ACC.lsl_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 6:	// ROXL.W Dx,Dy
		CYCLE(12);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.roxl_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 7:	// ROL.W Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.rol_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	}
}

// %1110_qqq110_000yyy	ASL.L #qqq,Dy
// %1110_qqq110_001yyy	LSL.L #qqq,Dy
// %1110_qqq110_010yyy	ROXL.L #qqq,Dy
// %1110_qqq110_011yyy	ROL.L #qqq,Dy
// %1110_xxx110_100yyy	ASL.L Dx,Dy
// %1110_xxx110_101yyy	LSL.L Dx,Dy
// %1110_xxx110_110yyy	ROXL.L Dx,Dy
// %1110_xxx110_111yyy	ROL.L Dx,Dy
OP_DEF(asl_l_imm)
{
	int count;
	switch (eamode(ir)) {
	 case 0:	// ASL.L #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.asl_32(RegDY, count);
		return;
	 case 1:	// LSL.L #qqq,Dy
		CYCLE(4);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.lsl_32(RegDY, count);
		return;
	 case 2:	// ROXL.L #qqq,Dy
		CYCLE(12);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.roxl_32(RegDY, count);
		return;
	 case 3:	// ROL.L #qqq,Dy
		CYCLE(6);
		count = RegIRX;
		count = (count == 0) ? 8 : count;
		__assume(1 <= count && count <= 8);
		RegDY = ACC.rol_32(RegDY, count);
		return;
	 case 4:	// ASL.L Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.asl_32(RegDY, count);
		return;
	 case 5:	// LSL.L Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		CYCLE(count <= 32 ? 6 : 8);
		__assume(0 <= count && count < 64);
		RegDY = ACC.lsl_32(RegDY, count);
		return;
	 case 6:	// ROXL.L Dx,Dy
		CYCLE(12);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.roxl_32(RegDY, count);
		return;
	 case 7:	// ROL.L Dx,Dy
		CYCLE(8);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.rol_32(RegDY, count);
		return;
	}
}

// %1110_000111_mmmrrr	ASL.W <ea>
OP_DEF(asl_w)
{
	CYCLE(6);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.asl_16(data, 1);
	write_2(ea, data);
}

// %1110_001011_mmmrrr	LSR.W <ea>
OP_DEF(lsr_w)
{
	CYCLE(4);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.lsr_16(data, 1);
	write_2(ea, data);
}

// %1110_001111_mmmrrr	LSL.W <ea>
OP_DEF(lsl_w)
{
	CYCLE(4);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.lsl_16(data, 1);
	write_2(ea, data);
}

// %1110_010011_mmmrrr	ROXR.W <ea>
OP_DEF(roxr_w)
{
	CYCLE(4);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.roxr_16(data, 1);
	write_2(ea, data);
}

// %1110_010111_mmmrrr	ROXL.W <ea>
OP_DEF(roxl_w)
{
	CYCLE(4);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.roxl_16(data, 1);
	write_2(ea, data);
}

// %1110_011011_mmmrrr	ROR.W <ea>
OP_DEF(ror_w)
{
	CYCLE(6);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.ror_16(data, 1);
	write_2(ea, data);
}

// %1110_011111_mmmrrr	ROL.W <ea>
OP_DEF(rol_w)
{
	CYCLE(6);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.rol_16(data, 1);
	write_2(ea, data);
}

// %1110_100011_mmmrrr	BFTST <ea>{#o:#w}
OP_DEF(bftst)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();

	acc_bf bf(this);
	if (n < 8) {
		// BFTST Dn{#o:#w}
		bf.LoadReg(n);
	} else {
		// BFTST <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	ACC.move_32(bf.data);
}

// %1110_100111_mmmrrr	BFEXTU <ea>{#o:#w},Dn
OP_DEF(bfextu)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();
	uint dn = ir2 >> 12;

	acc_bf bf(this);
	if (n < 8) {
		// BFEXTU Dn{#o:#w},Dn
		bf.LoadReg(n);
	} else {
		// BFEXTU <ea>{#o:#w},Dn
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	// 符号なしシフト
	reg.D[dn] = bf.data >> (32 - bf.width);
}

// %1110_101011_mmmrrr	BFCHG <ea>{#o:#w}
OP_DEF(bfchg)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();

	acc_bf bf(this);
	if (n < 8) {
		// BFCHG Dn{#o:#w}
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFCHG <ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFCHG <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.data = ~bf.data;
	bf.Store(n);
}

// %1110_101111_mmmrrr	BFEXTS <ea>{#o:#w},Dn
OP_DEF(bfexts)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();
	uint dn = ir2 >> 12;

	acc_bf bf(this);
	if (n < 8) {
		// BFEXTS Dn{#o:#w},Dn
		bf.LoadReg(n);
	} else {
		// BFEXTS <ea>{#o:#w},Dn
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	// 符号付きシフト
	// XXX 負数の右シフト
	reg.D[dn] = ((int32)bf.data) >> (32 - bf.width);
}

// %1110_110011_mmmrrr	BFCLR <ea>{#o:#w}
OP_DEF(bfclr)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();

	acc_bf bf(this);
	if (n < 8) {
		// BFCLR Dn{#o:#w}
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFCLR <ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFCLR <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.data = 0;
	bf.Store(n);
}

// %1110_110111_mmmrrr	BFFFO <ea>{#o:#w},Dn
OP_DEF(bfffo)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();
	uint dn = ir2 >> 12;

	acc_bf bf(this);
	if (n < 8) {
		// BFFFO Dn{#o:#w},Dn
		bf.LoadReg(n);
	} else {
		// BFFFO <ea>{#o:#w},Dn
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	// 1 になっているビットを探す
	for (; (int)bf.width-- > 0 && (int32)bf.data >= 0; bf.data <<= 1) {
		bf.offset++;
	}
	reg.D[dn] = bf.offset;
}

// %1110_111011_mmmrrr	BFSET <ea>{#o:#w}
OP_DEF(bfset)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();

	acc_bf bf(this);
	if (n < 8) {
		// BFSET Dn{#o:#w}
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFSET <ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFSET <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.data = 0xffffffff;
	bf.Store(n);
}

// %1110_111111_mmmrrr	BFINS Dn,<ea>{#o:#w}
OP_DEF(bfins)
{
	uint n = ir & 0x3f;
	ir2 = fetch_2();
	uint dn = ir2 >> 12;

	acc_bf bf(this);
	if (n < 8) {
		// BFINS Dm,Dn{#o:#w}
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFINS Dn,<ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFINS Dn,<ea>{#o:#w}
		uint32 ea = cea_ctrl();
		bf.LoadMem(ea);
	}
	bf.data = reg.D[dn] << (32 - bf.width);
	// BFINS のみ CCR は操作後のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.Store(n);
}

// %1111_000nnn_nnnnnn	MMU_OP
OP_DEF(mmuop)
{
	ir2 = fetch_2();
	switch ((ir2 >> 8) & 0xff) {
	 case (0x0800 >> 8):
	 case (0x0900 >> 8):
	 case (0x0c00 >> 8):
	 case (0x0d00 >> 8):
	 // %000_01n00_000_00000	PMOVE.L <ea>,TTn
	 // %000_01n01_000_00000	PMOVEFD.L <ea>,TTn
	 {
		CYCLE2(12, 14);
		uint32 ea = cea_copro();
		uint32 data = read_4(ea);
		uint n = (ir2 >> 10) & 1;
		SetTT(n, data);
		if ((ir2 & 0x0100) == 0)
			atc.flush();
		break;
	 }
	 case (0x0a00 >> 8):
	 case (0x0e00 >> 8):
	 // %000_01n10_000_00000	PMOVE.L TTn,<ea>
	 {
		CYCLE(8);
		uint32 ea = cea_copro();
		uint n = (ir2 >> 10) & 1;
		write_4(ea, GetTT(n));
		break;
	 }
	 case (0x2000 >> 8):
	 // %001_00000_000_00000	PLOADW SFC,<ea>
	 // %001_00000_000_00001	PLOADW DFC,<ea>
	 // %001_00000_000_01yyy	PLOADW Dy,<ea>
	 // %001_00000_000_10nnn	PLOADW #<imm>,<ea>
	 {
putlog(0, "ploadw");
		mmu_op_pload();
		break;
	 }
	 case (0x2200 >> 8):
	 // %001_00010_000_00000	PLOADR SFC,<ea>
	 // %001_00010_000_00001	PLOADR DFC,<ea>
	 // %001_00010_000_01yyy	PLOADR Dy,<ea>
	 // %001_00010_000_10nnn	PLOADR #<imm>,<ea>
	 {
putlog(0, "ploadr");
		mmu_op_pload();
		break;
	 }
	 case (0x2400 >> 8):
	 // %001_00100_000_00000	PFLUSHA
	 {
		CYCLE2(12, 14);
		atc.flush();
		break;
	 }
	 case (0x3000 >> 8):
	 // %001_10000_nnn_00000	PFLUSH SFC,#<mask>
	 // %001_10000_nnn_00001	PFLUSH DFC,#<mask>
	 // %001_10000_nnn_01yyy	PFLUSH Dy,#<mask>
	 // %001_10000_nnn_10nnn	PFLUSH #<imm>,#<mask>
	 {
		mmu_op_pflush();
		break;
	 }
	 case (0x3800 >> 8):
	 // %001_11000_nnn_00000	PFLUSH SFC,#<mask>,<ea>
	 // %001_11000_nnn_00001	PFLUSH DFC,#<mask>,<ea>
	 // %001_11000_nnn_01yyy	PFLUSH Dy,#<mask>,<ea>
	 // %001_11000_nnn_10nnn	PFLUSH #<imm>,#<mask>,<ea>
	 {
		mmu_op_pflush_ea();
		break;
	 }
	 case (0x4000 >> 8):
	 case (0x4100 >> 8):
	 // %010_00000_000_00000	PMOVE.L <ea>,TC
	 // %010_00001_000_00000	PMOVEFD.L <ea>,TC
	 {
		// たぶん
		// 無効→有効が (38, 40)
		// 有効→無効が (56, 58)
		// 無効→無効が (14, 16) ってことだと思うんだけど。
		CYCLE2(14, 16);
		uint32 ea = cea_copro();
		uint32 data = read_4(ea);
		if (SetTC(data) == false) {
			Exception(M68K::EXCEP_MMU_CONFIG);
			break;
		}
		if ((ir2 & 0x0100) == 0)
			atc.flush();
		break;
	 }
	 case (0x4200 >> 8):
	 // %010_00010_000_00000	PMOVE.L TC,<ea>
	 {
		CYCLE2(4, 5);
		uint32 ea = cea_copro();
		write_4(ea, GetTC());
		break;
	 }
	 case (0x4800 >> 8):
	 case (0x4900 >> 8):
	 // %010_01000_000_00000	PMOVE.Q <ea>,SRP
	 // %010_01001_000_00000	PMOVEFD.Q <ea>,SRP
	 {
		// たぶん有効になる時が (12, 14)
		// それ以外が (28, 30) ってことかな。
		CYCLE2(28, 30);
		uint32 ea = cea_copro();
		uint32 h = read_4(ea);
		uint32 l = read_4(ea + 4);
		if (SetSRP(h, l) == false) {
			Exception(M68K::EXCEP_MMU_CONFIG);
			break;
		}
		if ((ir2 & 0x0100) == 0)
			atc.flush();
		break;
	 }
	 case (0x4a00 >> 8):
	 // %010_01010_000_00000	PMOVE.Q SRP,<ea>
	 {
		CYCLE2(4, 5);
		uint32 ea = cea_copro();
		write_4(ea,     GetSRPh());
		write_4(ea + 4, GetSRPl());
		break;
	 }
	 case (0x4c00 >> 8):
	 case (0x4d00 >> 8):
	 // %010_01100_000_00000	PMOVE.Q <ea>,CRP
	 // %010_01101_000_00000	PMOVEFD.Q <ea>,CRP
	 {
		// たぶん有効になる時が (12, 14)
		// それ以外が (28, 30) ってことかな。
		CYCLE2(28, 30);
		uint32 ea = cea_copro();
		uint32 h = read_4(ea);
		uint32 l = read_4(ea + 4);
		if (SetCRP(h, l) == false) {
			Exception(M68K::EXCEP_MMU_CONFIG);
			break;
		}
		if ((ir2 & 0x0100) == 0)
			atc.flush();
		break;
	 }
	 case (0x4e00 >> 8):
	 // %010_01110_000_00000	PMOVE.Q CRP,<ea>
	 {
		CYCLE2(4, 5);
		uint32 ea = cea_copro();
		write_4(ea,     GetCRPh());
		write_4(ea + 4, GetCRPl());
		break;
	 }
	 case (0x6000 >> 8):
	 // %011_00000_000_00000	PMOVE.W <ea>,MMUSR
	 {
		CYCLE(6);
		uint32 ea = cea_copro();
		uint16 data = read_2(ea);
		SetMMUSR(data);
		break;
	 }
	 case (0x6200 >> 8):
	 // %011_00010_000_00000	PMOVE.W MMUSR,<ea>
	 {
		CYCLE2(4, 5);
		uint32 ea = cea_copro();
		write_2(ea, GetMMUSR());
		break;
	 }
	 case (0x8000 >> 8):
	 case (0x8400 >> 8):
	 case (0x8800 >> 8):
	 case (0x8c00 >> 8):
	 case (0x9000 >> 8):
	 case (0x9400 >> 8):
	 case (0x9800 >> 8):
	 case (0x9c00 >> 8):
	 // %100_nnn00_000_00000	PTESTW SFC,<ea>,#<level>
	 // %100_nnn00_000_00001	PTESTW DFC,<ea>,#<level>
	 // %100_nnn00_000_01yyy	PTESTW Dy,<ea>,#<level>
	 // %100_nnn00_000_10nnn	PTESTW #<imm>,<ea>,#<level>
	 {
		mmu_op_ptest();
		break;
	 }
	 case (0x8100 >> 8):
	 case (0x8500 >> 8):
	 case (0x8900 >> 8):
	 case (0x8d00 >> 8):
	 case (0x9100 >> 8):
	 case (0x9500 >> 8):
	 case (0x9900 >> 8):
	 case (0x9d00 >> 8):
	 // %100_nnn01_nnn_00000	PTESTW SFC,<ea>,#<level>,An
	 // %100_nnn01_nnn_00001	PTESTW DFC,<ea>,#<level>,An
	 // %100_nnn01_nnn_01yyy	PTESTW Dy,<ea>,#<level>,An
	 // %100_nnn01_nnn_10nnn	PTESTW #<imm>,<ea>,#<level>,An
	 {
		mmu_op_ptest();
		break;
	 }
	 case (0x8200 >> 8):
	 case (0x8600 >> 8):
	 case (0x8a00 >> 8):
	 case (0x8e00 >> 8):
	 case (0x9200 >> 8):
	 case (0x9600 >> 8):
	 case (0x9a00 >> 8):
	 case (0x9e00 >> 8):
	 // %100_nnn10_000_00000	PTESTR SFC,<ea>,#<level>
	 // %100_nnn10_000_00001	PTESTR DFC,<ea>,#<level>
	 // %100_nnn10_000_01yyy	PTESTR Dy,<ea>,#<level>
	 // %100_nnn10_000_10nnn	PTESTR #<imm>,<ea>,#<level>
	 {
		mmu_op_ptest();
		break;
	 }
	 case (0x8300 >> 8):
	 case (0x8700 >> 8):
	 case (0x8b00 >> 8):
	 case (0x8f00 >> 8):
	 case (0x9300 >> 8):
	 case (0x9700 >> 8):
	 case (0x9b00 >> 8):
	 case (0x9f00 >> 8):
	 // %100_nnn11_nnn_00000	PTESTR SFC,<ea>,#<level>,An
	 // %100_nnn11_nnn_00001	PTESTR DFC,<ea>,#<level>,An
	 // %100_nnn11_nnn_01yyy	PTESTR Dy,<ea>,#<level>,An
	 // %100_nnn11_nnn_10nnn	PTESTR #<imm>,<ea>,#<level>,An
	 {
		mmu_op_ptest();
		break;
	 }
	 default:
		OP_FUNC(illegal);
		break;
	}
}

// %1111_001000_nnnnnn	FPGEN
OP_DEF(fpgen)
{
	if (has_fpu == 0) {
		op_fline();
		return;
	}

	fpu_op_start();

	ir2 = fetch_2();
	switch (ir2 >> 13) {
	 case 0:
		fpu_op_fgen_reg();
		break;
	 case 1:
		fpu_op_illg();
		break;
	 case 2:
		fpu_op_fgen_mem();
		break;
	 case 3:
	 {
		// FMOVE reg,<ea> はサイズごとに分岐
		uint size = (ir2 >> 10) & 7;
		switch (size) {
		 case SIZE_B:
			fpu_op_fmove_b_mem();
			break;
		 case SIZE_W:
			fpu_op_fmove_w_mem();
			break;
		 case SIZE_L:
			fpu_op_fmove_l_mem();
			break;
		 case SIZE_S:
			fpu_op_fmove_s_mem();
			break;
		 case SIZE_D:
			fpu_op_fmove_d_mem();
			break;
		 case SIZE_X:
			fpu_op_fmove_x_mem();
			break;
		 case SIZE_P:
		 case 7:
			fpu_op_fmove_p_mem();
			break;
		}
		break;
	 }
	 case 4:
		fpu_op_fmovem_ea2ctl();
		break;
	 case 5:
		fpu_op_fmovem_ctl2ea();
		break;
	 case 6:
		fpu_op_fmovem_ea2reg();
		break;
	 case 7:
		fpu_op_fmovem_reg2ea();
		break;
	}
}

// %1111_001001_nnnnnn	FScc.B <ea>
// %1111_001001_001yyy	FDBcc Dy,<label>
// %1111_001001_111010	FTRAPcc.W #<imm>
// %1111_001001_111011	FTRAPcc.L #<imm>
// %1111_001001_111100	FTRAPcc
OP_DEF(fxcc)
{
	if (has_fpu == 0) {
		op_fline();
		return;
	}

	fpu_op_start();

	ir2 = fetch_2();
	switch (eamode(ir)) {
	 case 1:
		fpu_op_fdbcc();
		return;
	 case 7:
		switch (ir & 7) {
		 case 0:
		 case 1:
			fpu_op_fscc();
			return;
		 case 2:
			fpu_op_ftrapcc_w();
			return;
		 case 3:
			fpu_op_ftrapcc_l();
			return;
		 case 4:
			fpu_op_ftrapcc();
			return;
		 default:
			break;
		}
		break;
	 default:
		fpu_op_fscc();
		return;
	}
}

// %1111_001010_nnnnnn	FBcc.W <label>
OP_DEF(fbcc_w)
{
	if (has_fpu == 0) {
		op_fline();
		return;
	}

	fpu_op_start();

	fpu_op_fbcc_w();
}

// %1111_001011_nnnnnn	FBcc.L <label>
OP_DEF(fbcc_l)
{
	if (has_fpu == 0) {
		op_fline();
		return;
	}

	fpu_op_start();

	fpu_op_fbcc_l();
}

// %1111_001100_mmmrrr	FSAVE <ea>
OP_DEF(fsave)
{
	if (has_fpu == 0) {
		op_fline();
		return;
	}

	SUPERVISOR_OP;

	fpu_op_fsave();
}

// %1111_001101_mmmrrr	FRESTORE <ea>
OP_DEF(frestore)
{
	if (has_fpu == 0) {
		op_fline();
		return;
	}

	SUPERVISOR_OP;

	fpu_op_frestore();
}

// %1111_nnnnnn_nnnnnn	F-Line
OP_DEF(fline)
{
	CYCLE2(18, 20);

	if (fline_callback) {
		if (fline_callback(this, fline_arg)) {
			return;
		}
	}
	// F系列命令例外
	Exception(M68K::EXCEP_FLINE);
}

// illegal instructions
OP_DEF(illegal)
{
	CYCLE2(18, 20);
	// 不当命令例外
	Exception(M68K::EXCEP_ILLEGAL);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.