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

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

#include "mpu680x0.h"
#include "m680x0acc.h"
#include "m680x0bitfield.h"
#include "m680x0cycle.h"
#include "m68040mmu.h"

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

#define CCR reg.ccr
#define ACC (*(m680x0ACC*)&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]

// (エミュレータ的)未実装命令
#define op_unimpl(cpu)	\
	PANIC("unimplemented instruction! %s()", __FUNCTION__)

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

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

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// ORI.B #<imm>,Dn
		CYCLE3(ori_dn);
		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
		CYCLE3(ori_ccr);
		CCR.Set(CCR.Get() | src);
	} else {
		// ORI.B #<imm>,<ea>
		CYCLE3(ori_ea);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst |= src;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

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

	if (n < 8) {
		// ORI.W #<imm>,Dn
		CYCLE3(ori_dn);
		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;
		CYCLE3(ori_sr);
		uint32 src = fetch_2();
		SetSR(GetSR() | src);
	} else {
		// ORI.W #<imm>,<ea>
		CYCLE3(ori_ea);
		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 d.m+-rxw.. 034	ORI.L #<imm>,<ea>
OP_DEF(ori_l)
{
	uint n = ir & 0x3f;

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

// %0000_000011_mmmrrr ..m..rxwp. -34	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()) {
			CYCLE3(chk2_excep_max);
			Exception(M68K::EXCEP_CHK);
		} else {
			CYCLE3(chk2);
		}
	} else {
		// CMP2
		CYCLE3(cmp2_max);
	}
}

// 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);

	CYCLE3(movep);

	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_mmmrrr ..m+-rxwpi 034	BTST.B Dx,<ea>
// %0000_xxx100_000yyy .......... 034	BTST.L Dx,Dy
// %0000_xxx100_001yyy .......... 034	MOVEP.W (d,Ay),Dx
OP_DEF(btst_dn_ea)
{
	uint n = ir & 0x3f;

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

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

	if (n < 8) {
		// BCHG.L Dx,Dy
		CYCLE3(bchg_dn);
		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>
		CYCLE3(bchg_dn);
		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_mmmrrr ..m+-rxw.. 034	BCLR.B Dx,<ea>
// %0000_xxx110_000yyy .......... 034	BCLR.L Dx,Dy
// %0000_xxx110_001yyy .......... 034	MOVEP.W Dx,(d,Ay)
OP_DEF(bclr_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BCLR.L Dx,Dy
		CYCLE3(bclr_dn);
		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>
		CYCLE3(bclr_dn);
		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_mmmrrr ..m+-rxw.. 034	BSET.B Dx,<ea>
// %0000_xxx111_000yyy .......... 034	BSET.L Dx,Dy
// %0000_xxx111_001yyy .......... 034	MOVEP.L Dx,(d,Ay)
OP_DEF(bset_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BSET.L Dx,Dy
		CYCLE3(bset_dn);
		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>
		CYCLE3(bset_dn);
		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 d.m+-rxw.. 034	ANDI.B #<imm>,<ea>
// %0000_001000_111100 .......... 034	ANDI.B #<imm>,CCR
OP_DEF(andi_b)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// ANDI.B #<imm>,Dn
		CYCLE3(andi_dn);
		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
		CYCLE3(andi_ccr);
		CCR.Set(CCR.Get() & src);
	} else {
		// ANDI.B #<imm>,<ea>
		CYCLE3(andi_ea);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst &= src;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

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

	if (n < 8) {
		// ANDI.W #<imm>,Dn
		CYCLE3(andi_dn);
		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;
		CYCLE3(andi_sr);
		uint32 src = fetch_2();
		SetSR(GetSR() & src);
	} else {
		// ANDI.W #<imm>,<ea>
		CYCLE3(andi_ea);
		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 d.m+-rxw.. 034	ANDI.L #<imm>,<ea>
OP_DEF(andi_l)
{
	uint n = ir & 0x3f;

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

// %0000_001011_mmmrrr ..m..rxwp. -34	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()) {
			CYCLE3(chk2_excep_max);
			Exception(M68K::EXCEP_CHK);
		} else {
			CYCLE3(chk2);
		}
	} else {
		// CMP2
		CYCLE3(cmp2_max);
	}
}

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

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// SUBI.B #<imm>,Dn
		CYCLE3(subi_dn);
		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>
		CYCLE3(subi_ea);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst = ACC.sub_8(src, dst);
		write_1(ea, dst);
	}
}

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

	uint32 src = fetch_2();
	if (n < 8) {
		// SUBI.W #<imm>,Dn
		CYCLE3(subi_dn);
		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>
		CYCLE3(subi_ea);
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst = ACC.sub_16(src, dst);
		write_2(ea, dst);
	}
}

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

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

// %0000_010011_mmmrrr ..m..rxwp. -34	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()) {
			CYCLE3(chk2_excep_max);
			Exception(M68K::EXCEP_CHK);
		} else {
			CYCLE3(chk2);
		}
	} else {
		// CMP2
		CYCLE3(cmp2_max);
	}
}

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

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// ADDI.B #<imm>,Dn
		CYCLE3(addi_dn);
		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>
		CYCLE3(addi_ea);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst = ACC.add_8(src, dst);
		write_1(ea, dst);
	}
}

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

	uint32 src = fetch_2();
	if (n < 8) {
		// ADDI.W #<imm>,Dn
		CYCLE3(addi_dn);
		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>
		CYCLE3(addi_ea);
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst = ACC.add_16(src, dst);
		write_2(ea, dst);
	}
}

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

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

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

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

	if (n < 8) {
		// BTST.L #<imm>,Dy
		CYCLE3(btst_imm);
		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>
		CYCLE3(btst_imm);
		uint bit = fetch_2() & 7;
		uint32 data = fea_data_1();
		ACC.btst(data, bit);
	}
}

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

	if (n < 8) {
		// BCHG.L #<imm>,Dy
		CYCLE3(bchg_imm);
		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>
		CYCLE3(bchg_imm);
		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_mmmrrr ..m+-rxw.. 034	BCLR.B #<imm>,<ea>
// %0000_100010_000yyy .......... 034	BCLR.L #<imm>,Dy
OP_DEF(bclr_imm_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BCLR.L #<imm>,Dy
		CYCLE3(bclr_imm);
		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>
		CYCLE3(bclr_imm);
		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_mmmrrr ..m+-rxw.. 034	BSET.B #<imm>,<ea>
// %0000_100011_000yyy .......... 034	BSET.L #<imm>,Dy
OP_DEF(bset_imm_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// BSET.L #<imm>,Dy
		CYCLE3(bset_imm);
		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>
		CYCLE3(bset_imm);
		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 d.m+-rxw.. 034	EORI.B #<imm>,<ea>
// %0000_101000_111100 .......... 034	EORI.B #<imm>,CCR
OP_DEF(eori_b)
{
	uint n = ir & 0x3f;

	uint32 src = fetch_2() & 0xff;
	if (n < 8) {
		// EORI.B #<imm>,Dn
		CYCLE3(eori_dn);
		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
		CYCLE3(eori_ccr);
		CCR.Set(CCR.Get() ^ src);
	} else {
		// EORI.B #<imm>,<ea>
		CYCLE3(eori_ea);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst ^= src;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

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

	if (n < 8) {
		// EORI.W #<imm>,Dn
		CYCLE3(eori_dn);
		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;
		CYCLE3(eori_sr);
		uint32 src = fetch_2();
		SetSR(GetSR() ^ src);
	} else {
		// EORI.W #<imm>,<ea>
		CYCLE3(eori_ea);
		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 d.m+-rxw.. 034	EORI.L #<imm>,<ea>
OP_DEF(eori_l)
{
	uint n = ir & 0x3f;

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

// %0000_101011_mmmrrr ..m+-rxw.. -34	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
		CYCLE3(cas_eq);
		write_1(ea, du);
	} else {
		// そうでなければ、dst -> Dc
		CYCLE3(cas_ne);
		reg.D[c] = (reg.D[c] & 0xffffff00) | dst;
	}
}

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

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

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

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

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

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

// %0000_110011_mmmrrr ..m+-rxw.. -34	CAS.W Dc,Du,<ea>
// %0000_110011_111100 .......... -34	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()) {
				// 更新オペランド -> デスティネーション
				CYCLE3(cas2_true_inc);	// これは成功時の追加分
				write_2(ea1, du1);
				write_2(ea2, du2);
			}
		}
		// デスティネーション -> 比較オペランド
		CYCLE3(cas2_max);
		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
			CYCLE3(cas_eq);
			write_2(ea, du);
		} else {
			// そうでなければ、dst -> Dc
			CYCLE3(cas_ne);
			reg.D[c] = (reg.D[c] & 0xffff0000) | dst;
		}
	}
}

// 68040 は MOVES でのプログラム空間アクセスをデータ空間アクセスに読み替える。
// バスエラーで報告されるのも読み替え後の FC なので、ここで差し替える。
// MC68040UM.pdf, p3-22。
// 68000PRM.pdf, p.6-26 の記述は逆に読めるが、誤りだと思われる。
busaddr
MPU680x0Device::translate_fc40(busaddr xfc)
{
	if (mpu_type == m680x0MPUType::M68040) {
		uint32 fc = xfc.GetFC();
		if (fc == 2) {
			xfc.ChangeFC(1);
		} else if (fc == 6) {
			xfc.ChangeFC(5);
		}
	}
	return xfc;
}

// %0000_111000_mmmrrr ..m+-rxw.. -34	MOVES.B <ea>,Rn
// %0000_111000_mmmrrr ..m+-rxw.. -34	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
		busaddr sfc = translate_fc40(reg.sfc);
		busaddr addr = busaddr(ea) | sfc | BusAddr::Size1;
		data = read_data(addr);
		if (n < 8) {	// Dn
			reg.D[n] = (reg.D[n] & 0xffffff00) | data;
			CYCLE3(moves_ea_dn);
		} else {		// An
			reg.R[n] = (int32)(int8)data;
			CYCLE3(moves_ea_an);
		}
	} else {
		// Rn,<ea>
		CYCLE3(moves_rn_ea);
		busaddr dfc = translate_fc40(reg.dfc);
		busaddr addr = busaddr(ea) | dfc | BusAddr::Size1;
		data = reg.R[n] & 0xff;
		write_data(addr, data);
	}
}

// %0000_111001_mmmrrr ..m+-rxw.. -34	MOVES.W <ea>,Rn
// %0000_111001_mmmrrr ..m+-rxw.. -34	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
		busaddr sfc = translate_fc40(reg.sfc);
		busaddr addr = busaddr(ea) | sfc | BusAddr::Size2;
		data = read_data(addr);
		if (n < 8) {	// Dn
			reg.D[n] = (reg.D[n] & 0xffff0000) | data;
			CYCLE3(moves_ea_dn);
		} else {		// An
			reg.R[n] = (int32)(int16)data;
			CYCLE3(moves_ea_an);
		}
	} else {
		// Rn,<ea>
		CYCLE3(moves_rn_ea);
		busaddr dfc = translate_fc40(reg.dfc);
		busaddr addr = busaddr(ea) | dfc | BusAddr::Size2;
		data = reg.R[n] & 0xffff;
		write_data(addr, data);
	}
}

// %0000_111010_mmmrrr ..m+-rxw.. -34	MOVES.L <ea>,Rn
// %0000_111010_mmmrrr ..m+-rxw.. -34	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
		busaddr sfc = translate_fc40(reg.sfc);
		busaddr addr = busaddr(ea) | sfc | BusAddr::Size4;
		data = read_data(addr);
		reg.R[n] = data;
		if (n < 8) {
			CYCLE3(moves_ea_dn);
		} else {
			CYCLE3(moves_ea_an);
		}
	} else {
		// Rn,<ea>
		CYCLE3(moves_rn_ea);
		busaddr dfc = translate_fc40(reg.dfc);
		busaddr addr = busaddr(ea) | dfc | BusAddr::Size4;
		data = reg.R[n];
		write_data(addr, data);
	}
}

// %0000_111011_mmmrrr ..m+-rxw.. -34	CAS.L Dc,Du,<ea>
// %0000_111011_111100 .......... -34	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()) {
				// 更新オペランド -> デスティネーション
				CYCLE3(cas2_true_inc);	// これは成功時の追加分
				write_4(ea1, du1);
				write_4(ea2, du2);
			}
		}
		// デスティネーション -> 比較オペランド
		CYCLE3(cas2_max);
		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
			CYCLE3(cas_eq);
			write_4(ea, du);
		} else {
			// そうでなければ、dst -> Dc
			CYCLE3(cas_ne);
			reg.D[c] = dst;
		}
	}
}

// %0001_xxx000_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,Dx
OP_DEF(move_b_ea_dn)
{
	CYCLE3(move_ea_dn);
	uint32 data = fea_all_1();
	ACC.move_8(data);
	RegDX = (RegDX & 0xffffff00) | data;
}

// %0001_xxx010_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,(Ax)
OP_DEF(move_b_ea_anin)
{
	// dst 分込み。
	CYCLE3(move_ea_anin);
	uint32 data = fea_all_1();
	uint32 ea = internal_ea_anin(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx011_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,(Ax)+
OP_DEF(move_b_ea_anpi)
{
	// dst 分込み。
	CYCLE3(move_ea_anpi);
	uint32 data = fea_all_1();
	// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
	save_reg_pi_if(RegIRX);
	uint32 ea = internal_ea_anpi_1(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx100_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,-(Ax)
OP_DEF(move_b_ea_anpd)
{
	// dst 分込み。
	CYCLE3(move_ea_anpd);
	uint32 data = fea_all_1();
	// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
	save_reg_pd_if(RegIRX);
	uint32 ea = internal_ea_anpd_1(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx101_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,d16(Ax)
OP_DEF(move_b_ea_andi)
{
	// dst 分込み。
	CYCLE3(move_ea_andi);
	uint32 data = fea_all_1();
	uint32 ea = internal_ea_andi(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_xxx110_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,(Ax,IX)
OP_DEF(move_b_ea_anix)
{
	// dst 分込み。
	CYCLE3(move_ea_anix);
	uint32 data = fea_all_1();
	uint32 ea = internal_ea_anix(RegIRX);
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_000111_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,Abs.W
OP_DEF(move_b_ea_absw)
{
	// dst 分込み。
	CYCLE3(move_ea_absw);
	uint32 data = fea_all_1();
	uint32 ea = internal_ea_absw();
	ACC.move_8(data);
	write_1(ea, data);
}

// %0001_001111_mmmrrr d.m+-rxwpi 034	MOVE.B <ea>,Abs.L
OP_DEF(move_b_ea_absl)
{
	// dst 分込み。
	CYCLE3(move_ea_absl);
	uint32 data = fea_all_1();
	uint32 ea = internal_ea_absl();
	ACC.move_8(data);
	write_1(ea, data);
}

// %0010_xxx000_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,Dx
OP_DEF(move_l_ea_dn)
{
	CYCLE3(move_ea_dn);
	uint32 data = fea_all_4();
	ACC.move_32(data);
	RegDX = data;
}

// %0010_xxx001_mmmrrr dam+-rxwpi 034	MOVEA.L <ea>,Ax
OP_DEF(movea_l)
{
	CYCLE3(movea_l);
	uint32 data = fea_all_4();
	RegAX = data;
}

// %0010_xxx010_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,(Ax)
OP_DEF(move_l_ea_anin)
{
	// dst 分込み。
	CYCLE3(move_ea_anin);
	uint32 data = fea_all_4();
	uint32 ea = internal_ea_anin(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx011_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,(Ax)+
OP_DEF(move_l_ea_anpi)
{
	// dst 分込み。
	CYCLE3(move_ea_anpi);
	uint32 data = fea_all_4();
	// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
	save_reg_pi_if(RegIRX);
	uint32 ea = internal_ea_anpi_4(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx100_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,-(Ax)
OP_DEF(move_l_ea_anpd)
{
	// dst 分込み。
	CYCLE3(move_ea_anpd);
	uint32 data = fea_all_4();
	// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
	save_reg_pd_if(RegIRX);
	uint32 ea = internal_ea_anpd_4(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx101_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,d16(Ax)
OP_DEF(move_l_ea_andi)
{
	// dst 分込み。
	CYCLE3(move_ea_andi);
	uint32 data = fea_all_4();
	uint32 ea = internal_ea_andi(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_xxx110_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,(Ax,IX)
OP_DEF(move_l_ea_anix)
{
	// dst 分込み。
	CYCLE3(move_ea_anix);
	uint32 data = fea_all_4();
	uint32 ea = internal_ea_anix(RegIRX);
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_000111_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,Abs.W
OP_DEF(move_l_ea_absw)
{
	// dst 分込み。
	CYCLE3(move_ea_absw);
	uint32 data = fea_all_4();
	uint32 ea = internal_ea_absw();
	ACC.move_32(data);
	write_4(ea, data);
}

// %0010_001111_mmmrrr dam+-rxwpi 034	MOVE.L <ea>,Abs.L
OP_DEF(move_l_ea_absl)
{
	// dst 分込み。
	CYCLE3(move_ea_absl);
	uint32 data = fea_all_4();
	uint32 ea = internal_ea_absl();
	ACC.move_32(data);
	write_4(ea, data);
}

// %0011_xxx000_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,Dx
OP_DEF(move_w_ea_dn)
{
	CYCLE3(move_ea_dn);
	uint32 data = fea_all_2();
	ACC.move_16(data);
	RegDX = (RegDX & 0xffff0000) | data;
}

// %0011_xxx001_mmmrrr dam+-rxwpi 034	MOVEA.W <ea>,Ax
OP_DEF(movea_w)
{
	CYCLE3(movea_w);
	uint32 data = (int32)(int16)fea_all_2();
	RegAX = data;
}

// %0011_xxx010_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,(Ax)
OP_DEF(move_w_ea_anin)
{
	// dst 分込み。
	CYCLE3(move_ea_anin);
	uint32 data = fea_all_2();
	uint32 ea = internal_ea_anin(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx011_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,(Ax)+
OP_DEF(move_w_ea_anpi)
{
	// dst 分込み。
	CYCLE3(move_ea_anpi);
	uint32 data = fea_all_2();
	// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
	save_reg_pi_if(RegIRX);
	uint32 ea = internal_ea_anpi_2(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx100_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,-(Ax)
OP_DEF(move_w_ea_anpd)
{
	// dst 分込み。
	CYCLE3(move_ea_anpd);
	uint32 data = fea_all_2();
	// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
	save_reg_pd_if(RegIRX);
	uint32 ea = internal_ea_anpd_2(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx101_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,d16(Ax)
OP_DEF(move_w_ea_andi)
{
	// dst 分込み。
	CYCLE3(move_ea_andi);
	uint32 data = fea_all_2();
	uint32 ea = internal_ea_andi(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_xxx110_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,(Ax,IX)
OP_DEF(move_w_ea_anix)
{
	// dst 分込み。
	CYCLE3(move_ea_anix);
	uint32 data = fea_all_2();
	uint32 ea = internal_ea_anix(RegIRX);
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_000111_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,Abs.W
OP_DEF(move_w_ea_absw)
{
	// dst 分込み。
	CYCLE3(move_ea_absw);
	uint32 data = fea_all_2();
	uint32 ea = internal_ea_absw();
	ACC.move_16(data);
	write_2(ea, data);
}

// %0011_001111_mmmrrr dam+-rxwpi 034	MOVE.W <ea>,Abs.L
OP_DEF(move_w_ea_absl)
{
	// dst 分込み。
	CYCLE3(move_ea_absl);
	uint32 data = fea_all_2();
	uint32 ea = internal_ea_absl();
	ACC.move_16(data);
	write_2(ea, data);
}

// %0100_000000_mmmrrr d.m+-rxw.. 034	NEGX.B <ea>
OP_DEF(negx_b)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEGX.B Dn
		CYCLE3(negx_dn);
		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>
		CYCLE3(negx_ea);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.subx_8(data, 0);
		write_1(ea, data);
	}
}

// %0100_000001_mmmrrr d.m+-rxw.. 034	NEGX.W <ea>
OP_DEF(negx_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEGX.W Dn
		CYCLE3(negx_dn);
		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>
		CYCLE3(negx_ea);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.subx_16(data, 0);
		write_2(ea, data);
	}
}

// %0100_000010_mmmrrr d.m+-rxw.. 034	NEGX.L <ea>
OP_DEF(negx_l)
{
	uint n = ir & 0x3f;

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

// %0100_000011_mmmrrr d.m+-rxw.. -34	MOVE.W SR,<ea>
OP_DEF(move_sr_ea)
{
	SUPERVISOR_OP;

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

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

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

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

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

// %0100_001000_mmmrrr d.m+-rxw.. 034	CLR.B <ea>
OP_DEF(clr_b)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// CLR.B Dn
		CYCLE3(clr_dn);
		RegDY &= 0xffffff00;
		ACC.move_8(0);
	} else {
		// CLR.B <ea>
		CYCLE3(clr_ea);
		uint32 ea = cea_data_1();
		ACC.move_8(0);
		write_1(ea, 0);
	}
}

// %0100_001001_mmmrrr d.m+-rxw.. 034	CLR.W <ea>
OP_DEF(clr_w)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// CLR.W Dn
		CYCLE3(clr_dn);
		RegDY &= 0xffff0000;
		ACC.move_16(0);
	} else {
		// CLR.W <ea>
		CYCLE3(clr_ea);
		uint32 ea = cea_data_2();
		ACC.move_16(0);
		write_2(ea, 0);
	}
}

// %0100_001010_mmmrrr d.m+-rxw.. 034	CLR.L <ea>
OP_DEF(clr_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// CLR.L Dn
		CYCLE3(clr_dn);
		RegDY = 0;
		ACC.move_32(0);
	} else {
		// CLR.L <ea>
		CYCLE3(clr_ea);
		uint32 ea = cea_data_4();
		ACC.move_32(0);
		write_4(ea, 0);
	}
}

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

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

// %0100_010000_mmmrrr d.m+-rxw.. 034	NEG.B <ea>
OP_DEF(neg_b)
{
	uint n = ir & 0x3f;

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

// %0100_010001_mmmrrr d.m+-rxw.. 034	NEG.W <ea>
OP_DEF(neg_w)
{
	uint n = ir & 0x3f;

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

// %0100_010010_mmmrrr d.m+-rxw.. 034	NEG.L <ea>
OP_DEF(neg_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NEG.L Dn
		CYCLE3(neg_dn);
		reg.D[n] = ACC.sub_32(reg.D[n], 0);
	} else {
		// NEG.L <ea>
		CYCLE3(neg_ea);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.sub_32(data, 0);
		write_4(ea, data);
	}
}

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

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

// %0100_011000_mmmrrr d.m+-rxw.. 034	NOT.B <ea>
OP_DEF(not_b)
{
	uint n = ir & 0x3f;

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

// %0100_011001_mmmrrr d.m+-rxw.. 034	NOT.W <ea>
OP_DEF(not_w)
{
	uint n = ir & 0x3f;

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

// %0100_011010_mmmrrr d.m+-rxw.. 034	NOT.L <ea>
OP_DEF(not_l)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NOT.L Dn
		CYCLE3(not_dn);
		reg.D[n] = ~reg.D[n];
		ACC.move_32(reg.D[n]);
	} else {
		// NOT.L <ea>
		CYCLE3(not_ea);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ~data;
		ACC.move_32(data);
		write_4(ea, data);
	}
}

// %0100_011011_mmmrrr d.m+-rxwpi 034	MOVE.W <ea>,SR
OP_DEF(move_ea_sr)
{
	SUPERVISOR_OP;

	CYCLE3(move_ea_sr);
	uint16 data = fea_data_2();
	SetSR(data);
}

// LINK.W, LINK.L は即値の取り出しが違うだけ。
void
MPU680x0Device::ops_link(int32 imm)
{
	// ページフォルトに備えて保存する。
	save_reg_pd(7);
	push_4(RegAY);
	RegAY = reg.A[7];
	reg.A[7] += imm;
}

// %0100_100000_mmmrrr d.m+-rxw.. 034	NBCD.B <ea>
// %0100_100000_001yyy .......... -34	LINK.L Ay,#<imm>
OP_DEF(nbcd)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// NBCD.B Dn
		CYCLE3(nbcd);
		uint32 dst = RegDY & 0xff;
		dst = ACC.sbcd_8(dst, 0);
		RegDY = (RegDY & 0xffffff00) | dst;
	} else if (n < 16) {
		// LINK.L An,#<imm>
		CYCLE3(link_l);
		// レジスタやスタックを変更する前にフェッチしないと、
		// ページフォルトで再実行できなくなる
		int32 imm = fetch_4();
		ops_link(imm);
	} else {
		// NBCD.B <ea>
		CYCLE3(nbcd);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst = ACC.sbcd_8(dst, 0);
		write_1(ea, dst);
	}
}

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

	if (n < 8) {
		// SWAP.W Dy
		CYCLE3(swap);
		reg.D[n] = (reg.D[n] << 16) | (reg.D[n] >> 16);
		ACC.move_32(reg.D[n]);
	} else if (n < 16) {
		// BKPT #<imm>
		// ブレークポイント・アクノリッジサイクルに応答するデバイスはないので
		// 常に不当命令にする。
		CYCLE3(bkpt);	// ?
		op_illegal();
	} else {
		// PEA.L <ea>
		CYCLE3(pea);
		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;
		}
	}

	// 040 では実際は、転送するデータレジスタの数が0なら1個として
	// (Dn + An) * 1 を加算なのだが、そこはもう省略。(68040UM.pdf p.10-23)
	CYCLE3(movem_list_ea);
	CYCLE3(movem_list_ea_n) * regcount;	// 副作用上等!
}

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

	if (n < 8) {
		// EXT.W Dy
		CYCLE3(ext);
		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_mmmrrr ..m.-rxw.. 034	MOVEM.L <list>,<ea>
// %0100_100011_000yyy .......... 034	EXT.L Dy
OP_DEF(movem_l_mem)
{
	uint n = ir & 0x3f;

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

// %0100_101000_mmmrrr dam+-rxwpi -34	TST.B <ea>
OP_DEF(tst_b)
{
	CYCLE3(tst);
	uint32 data = fea_all_1();
	ACC.move_8(data);
}

// %0100_101001_mmmrrr dam+-rxwpi -34	TST.W <ea>
OP_DEF(tst_w)
{
	CYCLE3(tst);
	uint32 data = fea_all_2();
	ACC.move_16(data);
}

// %0100_101010_mmmrrr dam+-rxwpi -34	TST.L <ea>
OP_DEF(tst_l)
{
	CYCLE3(tst);
	uint32 data = fea_all_4();
	ACC.move_32(data);
}

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

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

// %0100_110000_mmmrrr d.m+-rxwpi -34	MULS.L <ea>,Dl
// %0100_110000_mmmrrr d.m+-rxwpi -34	MULS.L <ea>,Dh:Dl
// %0100_110000_mmmrrr d.m+-rxwpi -34	MULU.L <ea>,Dl
// %0100_110000_mmmrrr d.m+-rxwpi -34	MULU.L <ea>,Dh: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;

	switch ((ir2 >> 10) & 3) {
	 case 0:
	 {
		// MULU.L <ea>,Dl
		CYCLE3(mulu_l_max);
		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
		CYCLE3(mulu_l_max);
		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
		CYCLE3(muls_l_max);
		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
		CYCLE3(muls_l_max);
		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)
{
	CYCLE3(divu_l_max);

	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)
{
	CYCLE3(divu_l_max);

	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)
{
	CYCLE3(divs_l_max);

	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)
{
	CYCLE3(divs_l_max);

	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 d.m+-rxwpi -34	DIVS.L <ea>,Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34	DIVS.L <ea>,Dr:Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34	DIVSL.L <ea>,Dr:Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34	DIVU.L <ea>,Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34	DIVU.L <ea>,Dr:Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34	DIVUL.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;
	}

	// 040 では実際は、転送するデータレジスタの数が0なら1個として
	// (Dn + An) * 1 を加算なのだが、そこはもう省略。(68040UM.pdf p.10-23)
	CYCLE3(movem_ea_list);
	CYCLE3(movem_ea_list_n) * regcount;	// 副作用上等!
}

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

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

// 制御レジスタ:
//				MPU
// $000 SFC		234
// $001 DFC		234
// $002 CACR	234
// $003 TC		--4
// $004 ITT0	--4
// $005 ITT1	--4
// $006 DTT0	--4
// $007 DTT1	--4
// $800 USP		234
// $801 VBR		234
// $802 CAAR	23-
// $803 MSP		234
// $804 ISP		234
// $805 MMUSR	--4
// $806 URP		--4
// $807 SRP		--4

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

	CYCLE3(movec_rc_rn);
	ir2 = fetch_2();
	uint n = ir2 >> 12;
	uint c = ir2 & 0xfff;

	// まず CPU 固有レジスタを試す。
	if (ops_movec_rc_rn_cpu(c, n)) {
		return;
	}

	// なければ共通レジスタを試す。
	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 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 Rc,Rn (68030 固有)
bool
MPU68030Device::ops_movec_rc_rn_cpu(uint c, uint n)
{
	switch (c) {
	 case 0x802:
		reg.R[n] = reg.caar;
		return true;
	 default:
		break;
	}
	return false;
}

// MOVEC.L Rc,Rn (68040 固有)
bool
MPU68040Device::ops_movec_rc_rn_cpu(uint c, uint n)
{
	switch (c) {
	 case 0x003:
		reg.R[n] = reg.tc40;
		return true;
	 case 0x004:
		reg.R[n] = reg.itt[0];
		return true;
	 case 0x005:
		reg.R[n] = reg.itt[1];
		return true;
	 case 0x006:
		reg.R[n] = reg.dtt[0];
		return true;
	 case 0x007:
		reg.R[n] = reg.dtt[1];
		return true;
	 case 0x805:
		reg.R[n] = reg.mmusr40;
		return true;
	 case 0x806:
		reg.R[n] = reg.urp40;
		return true;
	 case 0x807:
		reg.R[n] = reg.srp40;
		return true;
	 default:
		break;
	}
	return false;
}

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

	ir2 = fetch_2();
	uint n = ir2 >> 12;
	uint c = ir2 & 0xfff;

	// まず CPU 固有レジスタを試す。
	if (ops_movec_rn_rc_cpu(c, n)) {
		return;
	}

	// なければ共通レジスタを試す。
	switch (c) {
	 case 0x000:
		CYCLE3(movec_rn_rcb);
		reg.sfc = busaddr::FC(reg.R[n] & 7) | BusAddr::R;
		return;
	 case 0x001:
		CYCLE3(movec_rn_rcb);
		reg.dfc = busaddr::FC(reg.R[n] & 7) | BusAddr::W;
		return;
	 case 0x002:
		CYCLE3(movec_rn_rcb);
		SetCACR(reg.R[n]);
		return;
	 case 0x800:
		CYCLE3(movec_rn_rca);
		reg.usp = reg.R[n];
		return;
	 case 0x801:
		CYCLE3(movec_rn_rca);
		reg.vbr = reg.R[n];
		return;
	 case 0x803:
		CYCLE3(movec_rn_rca);
		if (reg.m) {
			reg.A[7] = reg.R[n];
		} else {
			reg.msp = reg.R[n];
		}
		return;
	 case 0x804:
		CYCLE3(movec_rn_rca);
		if (reg.m) {
			reg.isp = reg.R[n];
		} else {
			reg.A[7] = reg.R[n];
		}
		return;
	 default:
		break;
	}
	op_illegal();
}

// MOVEC.L Rn,Rc (68030 固有)
bool
MPU68030Device::ops_movec_rn_rc_cpu(uint c, uint n)
{
	switch (c) {
	 case 0x802:
		CYCLE3(movec_rn_rca);
		reg.caar = reg.R[n];
		return true;
	 default:
		break;
	}
	return false;
}

// MOVEC.L Rn,Rc (68040 固有)
bool
MPU68040Device::ops_movec_rn_rc_cpu(uint c, uint n)
{
	switch (c) {
	 case 0x003:
		SetTC(reg.R[n]);
		return true;
	 case 0x004:
		SetTT(mmu_itt[0].get(), reg.R[n]);
		return true;
	 case 0x005:
		SetTT(mmu_itt[1].get(), reg.R[n]);
		return true;
	 case 0x006:
		SetTT(mmu_dtt[0].get(), reg.R[n]);
		return true;
	 case 0x007:
		SetTT(mmu_dtt[1].get(), reg.R[n]);
		return true;
	 case 0x805:
		// 書き込める?
		//SetMMUSR(reg.R[n]);
		OP_FUNC(unimpl);
		return true;
	 case 0x806:
		SetURP(reg.R[n]);
		return true;
	 case 0x807:
		SetSRP(reg.R[n]);
		return true;
	 default:
		break;
	}
	return false;
}

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

	switch (n) {
	 case 0x00:			// TRAP #0
		CYCLE3(trap);
		// TRAP#0 例外 (NetBSD システムコール表示のため別処理)
		ExceptionTrap0();
		return;

	 case 0x01 ... 0x0e:// TRAP #<vector>
		CYCLE3(trap);
		// TRAP#N 例外
		Exception(M68K::EXCEP_TRAP0 + n);
		return;

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

	 case 0x10:
	 case 0x11:
	 case 0x12:
	 case 0x13:
	 case 0x14:
	 case 0x15:
	 case 0x16:
	 case 0x17:			// LINK.W Ay,#<imm>
	 {
		CYCLE3(link_w);
		// レジスタやスタックを変更する前にフェッチとセーブをしないと、
		// ページフォルトで再実行できなくなる
		int32 imm = (int32)(int16)fetch_2();
		ops_link(imm);
		return;
	 }

	 case 0x18:
	 case 0x19:
	 case 0x1a:
	 case 0x1b:
	 case 0x1c:
	 case 0x1d:
	 case 0x1e:
	 case 0x1f:			// UNLK Ay
		CYCLE3(unlk);
		// ページフォルトに備えて保存する
		save_reg_pi(7);
		reg.A[7] = RegAY;
		RegAY = 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;
		CYCLE3(move_an_usp);
		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;
		CYCLE3(move_usp_an);
		RegAY = reg.usp;
		return;

	 case 0x30:			// RESET
		// CYCLE3() は int8 なので。
		CYCLE(518);
		ops_reset();
		return;

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

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

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

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

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

	 case 0x36:			// TRAPV
		if (CCR.IsV()) {
			CYCLE3(trapv_excep);
			Exception(M68K::EXCEP_TRAPV);
		} else {
			CYCLE3(trapv);
		}
		return;

	 case 0x37:			// RTR
		CYCLE3(rtr);
		// ページフォルトに備えて保存する
		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 ..m..rxwp. 034	JSR <ea>
OP_DEF(jsr)
{
	CYCLE3(jsr);
	uint32 ea = cea_ctrl();
	uint32 return_addr = reg.pc;

	// ページフォルトに備えて保存する。
	save_reg_pd(7);
	push_4(return_addr);
	Jump(ea);
}

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

// %0101_qqq000_mmmrrr d.m+-rxw.. 034	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
		CYCLE3(addq_rn);
		uint32 data = ACC.add_8(src, reg.D[n] & 0xff);
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
	} else {
		// ADDQ.B #qqq,<ea>
		CYCLE3(addq_ea);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.add_8(src, data);
		write_1(ea, data);
	}
}

// %0101_qqq001_mmmrrr d.m+-rxw.. 034	ADDQ.W #qqq,<ea>
// %0101_qqq001_001yyy .a........ 034	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
		CYCLE3(addq_rn);
		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 と等価
		// フラグは変化しない
		CYCLE3(addq_rn);
		reg.R[n] += src;
	} else {
		// ADDQ.W #qqq,<ea>
		CYCLE3(addq_ea);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.add_16(src, data);
		write_2(ea, data);
	}
}

// %0101_qqq010_mmmrrr d.m+-rxw.. 034	ADDQ.L #qqq,<ea>
// %0101_qqq010_001yyy .a........ 034	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
		CYCLE3(addq_rn);
		reg.D[n] = ACC.add_32(src, reg.D[n]);
	} else if (n < 16) {
		// ADDQ.L #qqq,An
		// フラグは変化しない
		CYCLE3(addq_rn);
		reg.R[n] += src;
	} else {
		// ADDQ.L #qqq,<ea>
		CYCLE3(addq_ea);
		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)) {
		CYCLE3(trapcc_excep);
		Exception(M68K::EXCEP_TRAPV);
	} else {
		// サイクルを消費するだけ
		CYCLE3(trapcc);
	}
}

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

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

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

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

			uint16 data = RegDY;
			if (data == 0) {
				// ループ終了。disp を読み飛ばす
				CYCLE3(dbcc_done);
				RegDY |= 0x0000ffff;
				fetch_2();
			} else {
				CYCLE3(dbcc_jmp);
				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>
	 {
		CYCLE3(scc_ea);
		// 条件成立可否に関わらず 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サイクル多い
		CYCLE3(trapcc_w_inc);
		fetch_2();
		ops_trapcc(cond);
		return;

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

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

	 default:
		break;
	}
	OP_FUNC(illegal);
}

// %0101_qqq100_mmmrrr d.m+-rxw.. 034	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
		CYCLE3(subq_rn);
		uint32 data = ACC.sub_8(src, reg.D[n] & 0xff);
		reg.D[n] = (reg.D[n] & 0xffffff00) | data;
	} else {
		// SUBQ.B #qqq,<ea>
		CYCLE3(subq_ea);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.sub_8(src, data);
		write_1(ea, data);
	}
}

// %0101_qqq101_mmmrrr d.m+-rxw.. 034	SUBQ.W #qqq,<ea>
// %0101_qqq101_001yyy .a........ 034	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
		CYCLE3(subq_rn);
		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 と等価
		// フラグは変化しない
		CYCLE3(subq_rn);
		reg.R[n] -= src;
	} else {
		// SUBQ.W #qqq,<ea>
		CYCLE3(subq_ea);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.sub_16(src, data);
		write_2(ea, data);
	}
}

// %0101_qqq110_mmmrrr d.m+-rxw.. 034	SUBQ.L #qqq,<ea>
// %0101_qqq110_001yyy .a........ 034	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
		CYCLE3(subq_rn);
		reg.D[n] = ACC.sub_32(src, reg.D[n]);
	} else if (n < 16) {
		// SUBQ.L #qqq,An
		// フラグは変化しない
		CYCLE3(subq_rn);
		reg.R[n] -= src;
	} else {
		// SUBQ.L #qqq,<ea>
		CYCLE3(subq_ea);
		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()
{
	CYCLE3(bra);

	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_0000nn_nnnnnn .......... 034	BRA.B <label>
// %0110_000000_000000 .......... 034	BRA.W <label>
// %0110_000011_111111 .......... -34	BRA.L <label>
OP_DEF(bra)
{
	ops_bra();
}

// %0110_0001nn_nnnnnn .......... 034	BSR.B <label>
// %0110_000100_000000 .......... 034	BSR.W <label>
// %0110_000111_111111 .......... -34	BSR.L <label>
OP_DEF(bsr)
{
	CYCLE3(bsr);
	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_ccccnn_nnnnnn .......... 034	Bcc.B <label>
// %0110_cccc00_000000 .......... 034	Bcc.W <label>
// %0110_cccc11_111111 .......... -34	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)
			CYCLE3(bcc_l_not);
			fetch_4();
		} else if (disp == 0) {
			// Bcc.W (not taken)
			CYCLE3(bcc_w_not);
			fetch_2();
		} else {
			// Bcc.B (not taken)
			CYCLE3(bcc_b_not);
		}
	}
}

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

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

	CYCLE3(or_ea_dn);
	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 d.m+-rxwpi 034	OR.W <ea>,Dx
OP_DEF(or_w_ea_dn)
{
	uint n = ir & 0x3f;

	CYCLE3(or_ea_dn);
	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 d.m+-rxwpi 034	OR.L <ea>,Dx
OP_DEF(or_l_ea_dn)
{
	uint n = ir & 0x3f;

	CYCLE3(or_ea_dn);
	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 d.m+-rxwpi 034	DIVU.W <ea>,Dx
OP_DEF(divu_w)
{
	CYCLE3(divu_w_max);

	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_mmmrrr ..m+-rxw.. 034	OR.B Dx,<ea>
// %1000_xxx100_000yyy .......... 034	SBCD.B Dy,Dx
// %1000_xxx100_001yyy .......... 034	SBCD.B -(Ay),-(Ax)
OP_DEF(or_b_dn_ea)
{
	uint n = ir & 0x3f;

	if (n < 8) {
		// SBCD.B Dy,Dx
		CYCLE3(sbcd_dn);
		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)
		CYCLE3(sbcd_an);
		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>
		CYCLE3(or_dn_ea);
		uint32 ea = cea_data_1();
		uint8 data = read_1(ea);
		data |= RegDX;
		ACC.move_8(data);
		write_1(ea, data);
	}
}

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

	if (n < 8) {
		// PACK Dy,Dx,#<imm>
		CYCLE3(pack_dn);
		uint32 imm = fetch_2();
		uint32 src = RegDY + imm;
		RegDX = (RegDX & 0xffffff00) | ((src >> 4) & 0x00f0) | (src & 0x000f);
	} else if (n < 16) {
		// PACK -(Ay),-(Ax),#<imm>
		CYCLE3(pack_an);
		uint32 imm = fetch_2();
		save_reg_pd(RegIRY);
		uint32 srcea = internal_ea_anpd_2(RegIRY);
		uint32 src = read_2(srcea);
		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>
		CYCLE3(or_dn_ea);
		uint32 ea = cea_data_2();
		uint16 data = read_2(ea);
		data |= RegDX;
		ACC.move_16(data);
		write_2(ea, data);
	}
}

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

	if (n < 8) {
		// UNPK Dy,Dx,#<imm>
		CYCLE3(unpk_dn);
		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>
		CYCLE3(unpk_an);
		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;
		save_reg_pd_if(RegIRX);
		uint32 dstea = internal_ea_anpd_2(RegIRX);
		write_2(dstea, src);
	} else {
		// OR.L Dx,<ea>
		CYCLE3(or_dn_ea);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data |= RegDX;
		ACC.move_32(data);
		write_4(ea, data);
	}
}

// %1000_xxx111_mmmrrr d.m+-rxwpi 034	DIVS.W <ea>,Dx
OP_DEF(divs_w)
{
	CYCLE3(divs_w_max);

	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 dam+-rxwpi 034	SUB.B <ea>,Dx
OP_DEF(sub_b_ea_dn)
{
	CYCLE3(sub_ea_dn);
	uint32 src = fea_all_1();
	uint32 data = ACC.sub_8(src, RegDX & 0xff);
	RegDX = (RegDX & 0xffffff00) | data;
}

// %1001_xxx001_mmmrrr dam+-rxwpi 034	SUB.W <ea>,Dx
OP_DEF(sub_w_ea_dn)
{
	CYCLE3(sub_ea_dn);
	uint32 src = fea_all_2();
	uint32 data = ACC.sub_16(src, RegDX & 0xffff);
	RegDX = (RegDX & 0xffff0000) | data;
}

// %1001_xxx010_mmmrrr dam+-rxwpi 034	SUB.L <ea>,Dx
OP_DEF(sub_l_ea_dn)
{
	CYCLE3(sub_ea_dn);
	uint32 src = fea_all_4();
	RegDX = ACC.sub_32(src, RegDX);
}

// %1001_xxx011_mmmrrr dam+-rxwpi 034	SUBA.W <ea>,Ax
OP_DEF(suba_w)
{
	CYCLE3(suba_w);
	uint32 src = (int32)(int16)fea_all_2();
	RegAX -= src;
}

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

	if (n < 8) {
		// SUBX.B Dy,Dx
		CYCLE3(subx_dn);
		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)
		CYCLE3(subx_an);
		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>
		CYCLE3(sub_dn_ea);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.sub_8(RegDX & 0xff, data);
		write_1(ea, data);
	}
}

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

	if (n < 8) {
		// SUBX.W Dy,Dx
		CYCLE3(subx_dn);
		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)
		CYCLE3(subx_an);
		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>
		CYCLE3(sub_dn_ea);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.sub_16(RegDX & 0xffff, data);
		write_2(ea, data);
	}
}

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

	if (n < 8) {
		// SUBX.L Dy,Dx
		CYCLE3(subx_dn);
		uint32 src = RegDY;
		uint32 dst = RegDX;
		RegDX = ACC.subx_32(src, dst);
	} else if (n < 16) {
		// SUBX.L -(Ay),-(Ax)
		CYCLE3(subx_an);
		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>
		CYCLE3(sub_dn_ea);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.sub_32(RegDX, data);
		write_4(ea, data);
	}
}

// %1001_xxx111_mmmrrr dam+-rxwpi 034	SUBA.L <ea>,Ax
OP_DEF(suba_l)
{
	CYCLE3(suba_l);
	uint32 src = fea_all_4();
	RegAX -= src;
}

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

// %1011_xxx000_mmmrrr d.m+-rxwpi 034	CMP.B <ea>,Dx
OP_DEF(cmp_b)
{
	CYCLE3(cmp);
	uint32 src = fea_all_1();
	uint32 dst = RegDX & 0xff;
	ACC.cmp_8(src, dst);
}

// %1011_xxx001_mmmrrr d.m+-rxwpi 034	CMP.W <ea>,Dx
OP_DEF(cmp_w)
{
	CYCLE3(cmp);
	uint32 src = fea_all_2();
	uint32 dst = RegDX & 0xffff;
	ACC.cmp_16(src, dst);
}

// %1011_xxx010_mmmrrr d.m+-rxwpi 034	CMP.L <ea>,Dx
OP_DEF(cmp_l)
{
	CYCLE3(cmp);
	uint32 src = fea_all_4();
	ACC.cmp_32(src, RegDX);
}

// %1011_xxx011_mmmrrr dam+-rxwpi 034	CMPA.W <ea>,Ax
OP_DEF(cmpa_w)
{
	CYCLE3(cmpa);
	uint32 src = (uint32)(int32)(int16)fea_all_2();
	ACC.cmp_32(src, RegAX);
}

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

	if (n < 8) {
		// EOR.B Dx,Dy
		CYCLE3(eor_dn_dn);
		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)+
		CYCLE3(cmpm);
		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>
		CYCLE3(eor_dn_ea);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data ^= (RegDX & 0xff);
		ACC.move_8(data);
		write_1(ea, data);
	}
}

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

	if (n < 8) {
		// EOR.W Dx,Dy
		CYCLE3(eor_dn_dn);
		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)+
		CYCLE3(cmpm);
		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>
		CYCLE3(eor_dn_ea);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data ^= (RegDX & 0xffff);
		ACC.move_16(data);
		write_2(ea, data);
	}
}

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

	if (n < 8) {
		// EOR.L Dx,Dy
		CYCLE3(eor_dn_dn);
		reg.D[n] ^= RegDX;
		ACC.move_32(reg.D[n]);
	} else if (n < 16) {
		// CMPM.L (Ay)+,(Ax)+
		CYCLE3(cmpm);
		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>
		CYCLE3(eor_dn_ea);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data ^= RegDX;
		ACC.move_32(data);
		write_4(ea, data);
	}
}

// %1011_xxx111_mmmrrr dam+-rxwpi 034	CMPA.L <ea>,Ax
OP_DEF(cmpa_l)
{
	CYCLE3(cmpa);
	uint32 src = fea_all_4();
	ACC.cmp_32(src, RegAX);
}

// %1100_xxx000_mmmrrr d.m+-rxwpi 034	AND.B <ea>,Dx
OP_DEF(and_b_ea_dn)
{
	CYCLE3(and_ea_dn);
	uint32 src = fea_data_1();
	uint32 dst = (RegDX & 0x000000ff) & src;
	ACC.move_8(dst);
	RegDX = (RegDX & 0xffffff00) | dst;
}

// %1100_xxx001_mmmrrr d.m+-rxwpi 034	AND.W <ea>,Dx
OP_DEF(and_w_ea_dn)
{
	CYCLE3(and_ea_dn);
	uint32 src = fea_data_2();
	uint32 dst = (RegDX & 0x0000ffff) & src;
	ACC.move_16(dst);
	RegDX = (RegDX & 0xffff0000) | dst;
}

// %1100_xxx010_mmmrrr d.m+-rxwpi 034	AND.L <ea>,Dx
OP_DEF(and_l_ea_dn)
{
	CYCLE3(and_ea_dn);
	uint32 src = fea_data_4();
	RegDX = RegDX & src;
	ACC.move_32(RegDX);
}

// %1100_xxx011_mmmrrr d.m+-rxwpi 034	MULU.W <ea>,Dx
OP_DEF(mulu_w)
{
	CYCLE3(mulu_w_max);
	uint32 src = fea_data_2();
	uint32 dst = RegDX & 0xffff;
	RegDX = ACC.mulu_16(src, dst);
}

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

	if (n < 8) {
		// ABCD.B Dy,Dx
		CYCLE3(abcd_dn);
		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)
		CYCLE3(abcd_an);
		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>
		CYCLE3(and_ea_dn);
		uint32 ea = cea_data_1();
		uint32 dst = read_1(ea);
		dst &= RegDX & 0xff;
		ACC.move_8(dst);
		write_1(ea, dst);
	}
}

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

	if (n < 8) {
		// EXG.L Dx,Dy
		CYCLE3(exg);
		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)
		CYCLE3(exg);
		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>
		CYCLE3(and_dn_ea);
		uint32 ea = cea_data_2();
		uint32 dst = read_2(ea);
		dst &= RegDX & 0xffff;
		ACC.move_16(dst);
		write_2(ea, dst);
	}
}

// %1100_xxx110_mmmrrr ..m+-rxw.. 034	AND.L Dx,<ea>
// %1100_xxx110_001yyy .......... 034	EXG.L Dx,Ay
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)
		CYCLE3(exg);
		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>
		CYCLE3(and_dn_ea);
		uint32 ea = cea_data_4();
		uint32 dst = read_4(ea);
		dst &= RegDX;
		ACC.move_32(dst);
		write_4(ea, dst);
	}
}

// %1100_xxx111_mmmrrr d.m+-rxwpi 034	MULS.W <ea>,Dx
OP_DEF(muls_w)
{
	CYCLE3(muls_w_max);
	uint32 src = fea_data_2();
	uint32 dst = RegDX & 0xffff;
	RegDX = ACC.muls_16(src, dst);
}

// %1101_xxx000_mmmrrr dam+-rxwpi 034	ADD.B <ea>,Dx
OP_DEF(add_b_ea_dn)
{
	CYCLE3(add_ea_dn);
	uint32 src = fea_all_1();
	uint32 data = ACC.add_8(src, RegDX & 0xff);
	RegDX = (RegDX & 0xffffff00) | data;
}

// %1101_xxx001_mmmrrr dam+-rxwpi 034	ADD.W <ea>,Dx
OP_DEF(add_w_ea_dn)
{
	CYCLE3(add_ea_dn);
	uint32 src = fea_all_2();
	uint32 data = ACC.add_16(src, RegDX & 0xffff);
	RegDX = (RegDX & 0xffff0000) | data;
}

// %1101_xxx010_mmmrrr dam+-rxwpi 034	ADD.L <ea>,Dx
OP_DEF(add_l_ea_dn)
{
	CYCLE3(add_ea_dn);
	uint32 src = fea_all_4();
	RegDX = ACC.add_32(src, RegDX);
}

// %1101_xxx011_mmmrrr dam+-rxwpi 034	ADDA.W <ea>,Ax
OP_DEF(adda_w)
{
	CYCLE3(adda_w);
	uint32 src = (int32)(int16)fea_all_2();
	RegAX += src;
}

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

	if (n < 8) {
		// ADDX.B Dy,Dx
		CYCLE3(addx_dn);
		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)
		CYCLE3(addx_an);
		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>
		CYCLE3(add_dn_ea);
		uint32 ea = cea_data_1();
		uint32 data = read_1(ea);
		data = ACC.add_8(RegDX & 0xff, data);
		write_1(ea, data);
	}
}

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

	if (n < 8) {
		// ADDX.W Dy,Dx
		CYCLE3(addx_dn);
		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)
		CYCLE3(addx_an);
		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>
		CYCLE3(add_dn_ea);
		uint32 ea = cea_data_2();
		uint32 data = read_2(ea);
		data = ACC.add_16(RegDX & 0xffff, data);
		write_2(ea, data);
	}
}

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

	if (n < 8) {
		// ADDX.L Dy,Dx
		CYCLE3(addx_dn);
		uint32 src = RegDY;
		uint32 dst = RegDX;
		RegDX = ACC.addx_32(src, dst);
	} else if (n < 16) {
		// ADDX.L -(Ay),-(Ax)
		CYCLE3(addx_an);
		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>
		CYCLE3(add_dn_ea);
		uint32 ea = cea_data_4();
		uint32 data = read_4(ea);
		data = ACC.add_32(RegDX, data);
		write_4(ea, data);
	}
}

// %1101_xxx111_mmmrrr dam+-rxwpi 034	ADDA.L <ea>,Ax
OP_DEF(adda_l)
{
	CYCLE3(adda_l);
	uint32 src = fea_all_4();
	RegAX += src;
}

// %1110_qqq000_000yyy .......... 034	ASR.B #qqq,Dy
// %1110_qqq000_001yyy .......... 034	LSR.B #qqq,Dy
// %1110_qqq000_010yyy .......... 034	ROXR.B #qqq,Dy
// %1110_qqq000_011yyy .......... 034	ROR.B #qqq,Dy
// %1110_xxx000_100yyy .......... 034	ASR.B Dx,Dy
// %1110_xxx000_101yyy .......... 034	LSR.B Dx,Dy
// %1110_xxx000_110yyy .......... 034	ROXR.B Dx,Dy
// %1110_xxx000_111yyy .......... 034	ROR.B Dx,Dy
OP_DEF(asr_b_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASR.B #qqq,Dy
		CYCLE3(asr_imm_dn);
		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
		CYCLE3(lsd_imm_dn);
		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
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_imm_dn);
		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;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 8) {
			CYCLE3(asr_dn_dn_less);
		} else {
			CYCLE3(asr_dn_dn_over);
		}
		__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;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 8) {
			CYCLE3(lsd_dn_dn_less);
		} else {
			CYCLE3(lsd_dn_dn_over);
		}
		__assume(0 <= count && count < 64);
		data = ACC.lsr_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 6:	// ROXR.B Dx,Dy
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_dn_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.ror_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	}
}

// %1110_qqq001_000yyy .......... 034	ASR.W #qqq,Dy
// %1110_qqq001_001yyy .......... 034	LSR.W #qqq,Dy
// %1110_qqq001_010yyy .......... 034	ROXR.W #qqq,Dy
// %1110_qqq001_011yyy .......... 034	ROR.W #qqq,Dy
// %1110_xxx001_100yyy .......... 034	ASR.W Dx,Dy
// %1110_xxx001_101yyy .......... 034	LSR.W Dx,Dy
// %1110_xxx001_110yyy .......... 034	ROXR.W Dx,Dy
// %1110_xxx001_111yyy .......... 034	ROR.W Dx,Dy
OP_DEF(asr_w_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASR.W #qqq,Dy
		CYCLE3(asr_imm_dn);
		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
		CYCLE3(lsd_imm_dn);
		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
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_imm_dn);
		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;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 16) {
			CYCLE3(asr_dn_dn_less);
		} else {
			CYCLE3(asr_dn_dn_over);
		}
		__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;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 16) {
			CYCLE3(lsd_dn_dn_less);
		} else {
			CYCLE3(lsd_dn_dn_over);
		}
		__assume(0 <= count && count < 64);
		data = ACC.lsr_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 6:	// ROXR.W Dx,Dy
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_dn_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.ror_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	}
}

// %1110_qqq010_000yyy .......... 034	ASR.L #qqq,Dy
// %1110_qqq010_001yyy .......... 034	LSR.L #qqq,Dy
// %1110_qqq010_010yyy .......... 034	ROXR.L #qqq,Dy
// %1110_qqq010_011yyy .......... 034	ROR.L #qqq,Dy
// %1110_xxx010_100yyy .......... 034	ASR.L Dx,Dy
// %1110_xxx010_101yyy .......... 034	LSR.L Dx,Dy
// %1110_xxx010_110yyy .......... 034	ROXR.L Dx,Dy
// %1110_xxx010_111yyy .......... 034	ROR.L Dx,Dy
OP_DEF(asr_l_imm)
{
	int count;
	switch (eamode(ir)) {
	 case 0:	// ASR.L #qqq,Dy
		CYCLE3(asr_imm_dn);
		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
		CYCLE3(lsd_imm_dn);
		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
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_imm_dn);
		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;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 32) {
			CYCLE3(asr_dn_dn_less);
		} else {
			CYCLE3(asr_dn_dn_over);
		}
		__assume(0 <= count && count < 64);
		RegDY = ACC.asr_32(RegDY, count);
		return;
	 case 5:	// LSR.L Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 32) {
			CYCLE3(lsd_dn_dn_less);
		} else {
			CYCLE3(lsd_dn_dn_over);
		}
		__assume(0 <= count && count < 64);
		RegDY = ACC.lsr_32(RegDY, count);
		return;
	 case 6:	// ROXR.L Dx,Dy
		CYCLE3(roxd_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.roxr_32(RegDY, count);
		return;
	 case 7:	// ROR.L Dx,Dy
		CYCLE3(rod_dn_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.ror_32(RegDY, count);
		return;
	}
}

// %1110_000011_mmmrrr ..m+-rxw.. 034	ASR.W <ea>
OP_DEF(asr_w)
{
	CYCLE3(asr_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.asr_16(data, 1);
	write_2(ea, data);
}

// %1110_qqq100_000yyy .......... 034	ASL.B #qqq,Dy
// %1110_qqq100_001yyy .......... 034	LSL.B #qqq,Dy
// %1110_qqq100_010yyy .......... 034	ROXL.B #qqq,Dy
// %1110_qqq100_011yyy .......... 034	ROL.B #qqq,Dy
// %1110_xxx100_100yyy .......... 034	ASL.B Dx,Dy
// %1110_xxx100_101yyy .......... 034	LSL.B Dx,Dy
// %1110_xxx100_110yyy .......... 034	ROXL.B Dx,Dy
// %1110_xxx100_111yyy .......... 034	ROL.B Dx,Dy
OP_DEF(asl_b_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASL.B #qqq,Dy
		CYCLE3(asl_imm_dn);
		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
		CYCLE3(lsd_imm_dn);
		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
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_imm_dn);
		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
		CYCLE3(asl_dn_dn);
		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;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 8) {
			CYCLE3(lsd_dn_dn_less);
		} else {
			CYCLE3(lsd_dn_dn_over);
		}
		__assume(0 <= count && count < 64);
		data = ACC.lsl_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	 case 6:	// ROXL.B Dx,Dy
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_dn_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.rol_8(RegDY & 0xff, count);
		RegDY = (RegDY & 0xffffff00) | data;
		return;
	}
}

// %1110_qqq101_000yyy .......... 034	ASL.W #qqq,Dy
// %1110_qqq101_001yyy .......... 034	LSL.W #qqq,Dy
// %1110_qqq101_010yyy .......... 034	ROXL.W #qqq,Dy
// %1110_qqq101_011yyy .......... 034	ROL.W #qqq,Dy
// %1110_xxx101_100yyy .......... 034	ASL.W Dx,Dy
// %1110_xxx101_101yyy .......... 034	LSL.W Dx,Dy
// %1110_xxx101_110yyy .......... 034	ROXL.W Dx,Dy
// %1110_xxx101_111yyy .......... 034	ROL.W Dx,Dy
OP_DEF(asl_w_imm)
{
	int count;
	uint32 data;
	switch (eamode(ir)) {
	 case 0:	// ASL.W #qqq,Dy
		CYCLE3(asl_imm_dn);
		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
		CYCLE3(lsd_imm_dn);
		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
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_imm_dn);
		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
		CYCLE3(asl_dn_dn);
		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;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 16) {
			CYCLE3(lsd_dn_dn_less);
		} else {
			CYCLE3(lsd_dn_dn_over);
		}
		__assume(0 <= count && count < 64);
		data = ACC.lsl_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	 case 6:	// ROXL.W Dx,Dy
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_dn_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		data = ACC.rol_16(RegDY & 0xffff, count);
		RegDY = (RegDY & 0xffff0000) | data;
		return;
	}
}

// %1110_qqq110_000yyy .......... 034	ASL.L #qqq,Dy
// %1110_qqq110_001yyy .......... 034	LSL.L #qqq,Dy
// %1110_qqq110_010yyy .......... 034	ROXL.L #qqq,Dy
// %1110_qqq110_011yyy .......... 034	ROL.L #qqq,Dy
// %1110_xxx110_100yyy .......... 034	ASL.L Dx,Dy
// %1110_xxx110_101yyy .......... 034	LSL.L Dx,Dy
// %1110_xxx110_110yyy .......... 034	ROXL.L Dx,Dy
// %1110_xxx110_111yyy .......... 034	ROL.L Dx,Dy
OP_DEF(asl_l_imm)
{
	int count;
	switch (eamode(ir)) {
	 case 0:	// ASL.L #qqq,Dy
		CYCLE3(asl_imm_dn);
		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
		CYCLE3(lsd_imm_dn);
		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
		CYCLE3(roxd_dn);
		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
		CYCLE3(rod_imm_dn);
		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
		CYCLE3(asl_dn_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.asl_32(RegDY, count);
		return;
	 case 5:	// LSL.L Dx,Dy
		count = RegDX & 63;
		// シフト数がデータサイズを越えるかどうかでサイクルが違う
		if (count <= 32) {
			CYCLE3(lsd_dn_dn_less);
		} else {
			CYCLE3(lsd_dn_dn_over);
		}
		__assume(0 <= count && count < 64);
		RegDY = ACC.lsl_32(RegDY, count);
		return;
	 case 6:	// ROXL.L Dx,Dy
		CYCLE3(roxd_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.roxl_32(RegDY, count);
		return;
	 case 7:	// ROL.L Dx,Dy
		CYCLE3(rod_dn_dn);
		count = RegDX & 63;
		__assume(0 <= count && count < 64);
		RegDY = ACC.rol_32(RegDY, count);
		return;
	}
}

// %1110_000111_mmmrrr ..m+-rxw.. 034	ASL.W <ea>
OP_DEF(asl_w)
{
	CYCLE3(asl_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.asl_16(data, 1);
	write_2(ea, data);
}

// %1110_001011_mmmrrr ..m+-rxw.. 034	LSR.W <ea>
OP_DEF(lsr_w)
{
	CYCLE3(lsd_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.lsr_16(data, 1);
	write_2(ea, data);
}

// %1110_001111_mmmrrr ..m+-rxw.. 034	LSL.W <ea>
OP_DEF(lsl_w)
{
	CYCLE3(lsd_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.lsl_16(data, 1);
	write_2(ea, data);
}

// %1110_010011_mmmrrr ..m+-rxw.. 034	ROXR.W <ea>
OP_DEF(roxr_w)
{
	CYCLE3(roxd_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.roxr_16(data, 1);
	write_2(ea, data);
}

// %1110_010111_mmmrrr ..m+-rxw.. 034	ROXL.W <ea>
OP_DEF(roxl_w)
{
	CYCLE3(roxd_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.roxl_16(data, 1);
	write_2(ea, data);
}

// %1110_011011_mmmrrr ..m+-rxw.. 034	ROR.W <ea>
OP_DEF(ror_w)
{
	CYCLE3(rod_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.ror_16(data, 1);
	write_2(ea, data);
}

// %1110_011111_mmmrrr ..m+-rxw.. 034	ROL.W <ea>
OP_DEF(rol_w)
{
	CYCLE3(rod_w);
	uint32 ea = cea_data_2();
	uint32 data = read_2(ea);
	data = ACC.rol_16(data, 1);
	write_2(ea, data);
}

// %1110_100011_mmmrrr d.m..rxwp. -34	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}
		CYCLE3(bftst_dn);
		bf.LoadReg(n);
	} else {
		// BFTST <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bftst_ea_less);
		} else {
			CYCLE3(bftst_ea_over);
		}
	}
	ACC.move_32(bf.data);
}

// %1110_100111_mmmrrr d.m..rxwp. -34	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
		CYCLE3(bfext_dn);
		bf.LoadReg(n);
	} else {
		// BFEXTU <ea>{#o:#w},Dn
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bfext_ea_less);
		} else {
			CYCLE3(bfext_ea_over);
		}
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	// 符号なしシフト
	reg.D[dn] = bf.data >> (32 - bf.width);
}

// %1110_101011_mmmrrr d.m..rxw.. -34	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}
		CYCLE3(bfchg_dn);
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFCHG <ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFCHG <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bfchg_ea_less);
		} else {
			CYCLE3(bfchg_ea_over);
		}
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.data = ~bf.data;
	bf.Store(n);
}

// %1110_101111_mmmrrr d.m..rxwp. -34	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
		CYCLE3(bfext_dn);
		bf.LoadReg(n);
	} else {
		// BFEXTS <ea>{#o:#w},Dn
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bfext_ea_less);
		} else {
			CYCLE3(bfext_ea_over);
		}
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	// 符号付きシフト
	// XXX 負数の右シフト
	reg.D[dn] = ((int32)bf.data) >> (32 - bf.width);
}

// %1110_110011_mmmrrr d.m..rxw.. -34	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}
		CYCLE3(bfclr_dn);
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFCLR <ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFCLR <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bfclr_ea_less);
		} else {
			CYCLE3(bfclr_ea_over);
		}
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.data = 0;
	bf.Store(n);
}

// %1110_110111_mmmrrr d.m..rxwp. -34	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
		CYCLE3(bfffo_dn);
		bf.LoadReg(n);
	} else {
		// BFFFO <ea>{#o:#w},Dn
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bfffo_ea_less);
		} else {
			CYCLE3(bfffo_ea_over);
		}
	}
	// 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 d.m..rxw.. -34	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}
		CYCLE3(bfset_dn);
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFSET <ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFSET <ea>{#o:#w}
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bfset_ea_less);
		} else {
			CYCLE3(bfset_ea_over);
		}
	}
	// CCR は操作前のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.data = 0xffffffff;
	bf.Store(n);
}

// %1110_111111_mmmrrr d.m..rxw.. -34	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}
		CYCLE3(bfins_dn);
		bf.LoadReg(n);
	} else if (n >= 0x3a) {
		// BFINS Dn,<ea> に PC 相対(と #imm) はない
		op_illegal();
	} else {
		// BFINS Dn,<ea>{#o:#w}
		uint32 ea = cea_ctrl();
		if (__predict_true(bf.LoadMem(ea))) {
			CYCLE3(bfins_ea_less);
		} else {
			CYCLE3(bfins_ea_over);
		}
	}
	bf.data = reg.D[dn] << (32 - bf.width);
	// BFINS のみ CCR は操作後のビットフィールドに対して
	ACC.move_32(bf.data);
	bf.Store(n);
}

// %1111_000nnn_nnnnnn .......... -3-	MMU30_OP
OP_DEF(mmu30)
{
	// CPU ごとの virtual 関数になっている。
	ops_mmu30();
}

// 68030 MMU 命令跡地は 68040 では全部 F ライン例外。
void
MPU68040Device::ops_mmu30()
{
	op_illegal();
}

// 68030 MMU 命令。
void
MPU68030Device::ops_mmu30()
{
	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
	 {
		CYCLE3(pmove_ea_tt);
		uint32 ea = cea_copro();
		uint32 data = read_4(ea);
		uint n = (ir2 >> 10) & 1;
		SetTT(n, data);
		if ((ir2 & 0x0100) == 0) {
			atc.FlushAll();
		}
		return;
	 }
	 case (0x0a00 >> 8):
	 case (0x0e00 >> 8):
	 // %000_01n10_000_00000	PMOVE.L TTn,<ea>
	 {
		CYCLE3(pmove_tt_ea);
		uint32 ea = cea_copro();
		uint n = (ir2 >> 10) & 1;
		write_4(ea, GetTT(n));
		return;
	 }
	 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>
	 {
		CYCLE3(pload);
putlog(0, "ploadw");
		ops_mmu30_pload();
		return;
	 }
	 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>
	 {
		CYCLE3(pload);
putlog(0, "ploadr");
		ops_mmu30_pload();
		return;
	 }
	 case (0x2400 >> 8):
	 // %001_00100_000_00000	PFLUSHA
	 {
		CYCLE3(pflusha);
		ops_mmu30_pflusha();
		return;
	 }
	 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>
	 {
		CYCLE3(pflush);
		ops_mmu30_pflush();
		return;
	 }
	 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>
	 {
		CYCLE3(pflush);
		ops_mmu30_pflush_ea();
		return;
	 }
	 case (0x4000 >> 8):
	 case (0x4100 >> 8):
	 // %010_00000_000_00000	PMOVE.L <ea>,TC
	 // %010_00001_000_00000	PMOVEFD.L <ea>,TC
	 {
		CYCLE3(pmove_ea_tc);
		uint32 ea = cea_copro();
		uint32 data = read_4(ea);
		if (SetTC(data)) {
			if ((ir2 & 0x0100) == 0) {
				atc.FlushAll();
			}
		} else {
			Exception(M68K::EXCEP_MMU_CONFIG);
		}
		return;
	 }
	 case (0x4200 >> 8):
	 // %010_00010_000_00000	PMOVE.L TC,<ea>
	 {
		CYCLE3(pmove_tc_ea);
		uint32 ea = cea_copro();
		write_4(ea, GetTC());
		return;
	 }
	 case (0x4800 >> 8):
	 case (0x4900 >> 8):
	 // %010_01000_000_00000	PMOVE.Q <ea>,SRP
	 // %010_01001_000_00000	PMOVEFD.Q <ea>,SRP
	 {
		CYCLE3(pmove_ea_xrp);
		uint32 ea = cea_copro();
		uint32 h = read_4(ea);
		uint32 l = read_4(ea + 4);
		if (SetSRP(h, l)) {
			if ((ir2 & 0x0100) == 0) {
				atc.FlushAll();
			}
		} else {
			Exception(M68K::EXCEP_MMU_CONFIG);
		}
		return;
	 }
	 case (0x4a00 >> 8):
	 // %010_01010_000_00000	PMOVE.Q SRP,<ea>
	 {
		CYCLE3(pmove_xrp_ea);
		uint32 ea = cea_copro();
		write_4(ea,     GetSRPh());
		write_4(ea + 4, GetSRPl());
		return;
	 }
	 case (0x4c00 >> 8):
	 case (0x4d00 >> 8):
	 // %010_01100_000_00000	PMOVE.Q <ea>,CRP
	 // %010_01101_000_00000	PMOVEFD.Q <ea>,CRP
	 {
		CYCLE3(pmove_ea_xrp);
		uint32 ea = cea_copro();
		uint32 h = read_4(ea);
		uint32 l = read_4(ea + 4);
		if (SetCRP(h, l)) {
			if ((ir2 & 0x0100) == 0) {
				atc.FlushAll();
			}
		} else {
			Exception(M68K::EXCEP_MMU_CONFIG);
		}
		return;
	 }
	 case (0x4e00 >> 8):
	 // %010_01110_000_00000	PMOVE.Q CRP,<ea>
	 {
		CYCLE3(pmove_xrp_ea);
		uint32 ea = cea_copro();
		write_4(ea,     GetCRPh());
		write_4(ea + 4, GetCRPl());
		return;
	 }
	 case (0x6000 >> 8):
	 // %011_00000_000_00000	PMOVE.W <ea>,MMUSR
	 {
		CYCLE3(pmove_ea_mmusr);
		uint32 ea = cea_copro();
		uint16 data = read_2(ea);
		SetMMUSR(data);
		return;
	 }
	 case (0x6200 >> 8):
	 // %011_00010_000_00000	PMOVE.W MMUSR,<ea>
	 {
		CYCLE3(pmove_mmusr_ea);
		uint32 ea = cea_copro();
		write_2(ea, GetMMUSR());
		return;
	 }
	 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>
	 {
		ops_mmu30_ptest();
		return;
	 }
	 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
	 {
		ops_mmu30_ptest();
		return;
	 }
	 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>
	 {
		ops_mmu30_ptest();
		return;
	 }
	 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
	 {
		ops_mmu30_ptest();
		return;
	 }
	 default:
		break;
	}
	OP_FUNC(illegal);
}

// 現在の 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 命令以外で変更されることはないはず。
#define INIT_FE()	do {	\
	fe.fe_fpcr = RegFPCR;	\
	fe.fe_fpsr = RegFPSR;	\
} while (0)

// ステートを (NULL なら) IDLE に変える。
// 6888x では非条件命令、条件命令どちらでも IDLE になる。
// 68040 では非条件命令でだけ IDLE になる。
// 非条件命令はここでは1ワード目の opclass が 1,2,3 の命令。
#define SET_IDLE()	do {	\
	if (fpu_state == FPU_STATE_NULL)	\
		fpu_state = FPU_STATE_IDLE;	\
} while (0)

// %1111_001000_nnnnnn .......... -34	FPGEN
OP_DEF(fpgen)
{
	if (GetFPUType().IsNoFPU()) {
		op_illegal();
		return;
	}

	INIT_FE();
	SET_IDLE();

	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:
		fpu_op_fmove_to_mem();
		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_mmmrrr d.m+-rxw.. -34	FScc.B <ea>
// %1111_001001_001yyy .......... -34	FDBcc Dy,<label>
// %1111_001001_111010 .......... -34	FTRAPcc.W #<imm>
// %1111_001001_111011 .......... -34	FTRAPcc.L #<imm>
// %1111_001001_111100 .......... -34	FTRAPcc
OP_DEF(fxcc)
{
	if (GetFPUType().IsNoFPU()) {
		op_illegal();
		return;
	}

	if ((ir & 077) >= 075) {
		op_illegal();
		return;
	}

	INIT_FE();
	if (GetFPUType().Is6888x()) {
		SET_IDLE();
	}

	// ここまで来ると共通で ir2 に cc が来る。
	ir2 = fetch_2();
	switch (ir & 077) {
	 case 010 ... 017:	// FDBcc
		fpu_op_fdbcc();
		break;
	 case 000 ... 007:	// FScc
	 case 020 ... 027:
	 case 030 ... 037:
	 case 040 ... 047:
	 case 050 ... 057:
	 case 060 ... 067:
	 case 070 ... 071:
		fpu_op_fscc();
		break;
	 case 072:			// FTRAPcc.W
		fpu_op_ftrapcc_w();
		break;
	 case 073:			// FTRAPcc.L
		fpu_op_ftrapcc_l();
		break;
	 case 074:			// FTRAPcc
		fpu_op_ftrapcc();
		break;
	 default:
		__unreachable();
	}
}

// %1111_001010_nnnnnn .......... -34	FBcc.W <label>
OP_DEF(fbcc_w)
{
	if (GetFPUType().IsNoFPU()) {
		op_illegal();
		return;
	}

	INIT_FE();
	if (GetFPUType().Is6888x()) {
		SET_IDLE();
	}

	fpu_op_fbcc_w();
}

// %1111_001011_nnnnnn .......... -34	FBcc.L <label>
OP_DEF(fbcc_l)
{
	if (GetFPUType().IsNoFPU()) {
		op_illegal();
		return;
	}

	INIT_FE();
	if (GetFPUType().Is6888x()) {
		SET_IDLE();
	}

	fpu_op_fbcc_l();
}

// %1111_001100_mmmrrr ..m.-rxw.. -34	FSAVE <ea>
OP_DEF(fsave)
{
	if (GetFPUType().IsNoFPU()) {
		op_illegal();
		return;
	}

	SUPERVISOR_OP;

	fpu_op_fsave();
}

// %1111_001101_mmmrrr ..m+.rxw.. -34	FRESTORE <ea>
OP_DEF(frestore)
{
	if (GetFPUType().IsNoFPU()) {
		op_illegal();
		return;
	}

	SUPERVISOR_OP;

	fpu_op_frestore();
}

// %1111_0100nn_001yyy .......... --4	CINVL <caches>,(Ay)
// %1111_0100nn_010yyy .......... --4	CINVP <caches>,(Ay)
// %1111_0100nn_011000 .......... --4	CINVA <caches>
// %1111_0100nn_101yyy .......... --4	CPUSHL <caches>,(Ay)
// %1111_0100nn_110yyy .......... --4	CPUSHP <caches>,(Ay)
// %1111_0100nn_111000 .......... --4	CPUSHA <caches>
OP_DEF(cinv)
{
	if (mpu_type != m680x0MPUType::M68040) {
		op_illegal();
		return;
	}
//	putlog(1, "cinv*/cpush* (NOT IMPLEMENTED)");
}

// %1111_010100_mmmrrr ..m.-rxw.. 23-	cpSAVE
// %1111_010100_000yyy .......... --4	PFLUSHN (Ay)
// %1111_010100_001yyy .......... --4	PFLUSH (Ay)
// %1111_010100_010000 .......... --4	PFLUSHAN
// %1111_010100_011000 .......... --4	PFLUSHA
OP_DEF(pflush)
{
	// CPU ごとの virtual 関数になっている。
	ops_mmu40_pflush();
}

// 68030 では 68040 MMU 命令の位置は全部 cpSAVE。
void
MPU68030Device::ops_mmu40_pflush()
{
	op_cpsave();
}

// 68040 MMU 命令。
void
MPU68040Device::ops_mmu40_pflush()
{
	SUPERVISOR_OP;

	// DFC は 1,2,5,6 の場合のみ有効で、0,3,4,7 なら動作不定。
	// 68000PRM.pdf, p6-35。
	// ここでは FC2 だけで判定する。

	switch (ir & 077) {
	 case 000 ... 007:	// PFLUSHN (Ay)
	 {
		CYCLE(11);
		busaddr addr = busaddr(RegAY) | reg.dfc;
		atc_inst->Flush(addr, true);
		atc_data->Flush(addr, true);
		return;
	 }

	 case 010 ... 017:	// PFLUSH (Ay)
	 {
		CYCLE(11);
		busaddr addr = busaddr(RegAY) | reg.dfc;
		atc_inst->Flush(addr, false);
		atc_data->Flush(addr, false);
		return;
	 }

	 case 020:			// PFLUSHAN
	 {
		CYCLE(27);
		bool s = reg.dfc.IsSuper();
		atc_inst->Flush(s, true);
		atc_data->Flush(s, true);
		return;
	 }

	 case 030:			// PFLUSHA
	 {
		CYCLE3(pflusha);
		bool s = reg.dfc.IsSuper();
		atc_inst->Flush(s, false);
		atc_data->Flush(s, false);
		return;
	 }

	 default:
		break;
	}
	op_illegal();
}

// %1111_010101_mmmrrr ..m+.rxwp. 23-	cpRESTORE
// %1111_010101_001yyy .......... --4	PTESTW (Ay)
// %1111_010101_101yyy .......... --4	PTESTR (Ay)
OP_DEF(ptest)
{
	if (mpu_type != m680x0MPUType::M68040) {
		op_cprestore();
		return;
	}
	//CYCLE(25);
	OP_FUNC(unimpl);
}

// %1111_011000_000yyy .......... --4	MOVE16 (Ay)+,xxx.L
// %1111_011000_001yyy .......... --4	MOVE16 xxx.L,(Ay)+
// %1111_011000_010yyy .......... --4	MOVE16 (Ay),xxx.L
// %1111_011000_011yyy .......... --4	MOVE16 xxx.L,(Ay)
// %1111_011000_100yyy .......... --4	MOVE16 (Ay)+,(An)+
OP_DEF(move16)
{
	if (mpu_type != m680x0MPUType::M68040) {
		op_illegal();
		return;
	}
	OP_FUNC(unimpl);
}

// %1111_011100_mmmrrr ..m.-rxw.. 23-	cpSAVE
// %1111_100100_mmmrrr ..m.-rxw.. 23-	cpSAVE
// %1111_101100_mmmrrr ..m.-rxw.. 23-	cpSAVE
// %1111_110100_mmmrrr ..m.-rxw.. 23-	cpSAVE
// %1111_111100_mmmrrr ..m.-rxw.. 23-	cpSAVE
OP_DEF(cpsave)
{
	// 020/030 では、(第1ワードが?) 有効な命令パターンの場合
	// まず特権チェックを行う。
	// cpSAVE の場合先に CIR で問い合わせて、その後 EA を評価すると書いて
	// あるように読める (68020 本 p.104) ので、コプロセッサがいない場合は
	// EA は評価しなさそう。
	// -(An) はコプロセッサがいなければ変化しないような気がする。
	// EA のパターンが無効なら F ライン例外になる。
	// cpID=6,7 はユーザ用とあるが cpSAVE は影響を受けるかどうか。
	// 040 ではコプロセッサプロトコル自体ないので全部 F ライン例外になる?
	//
	// ただし、Human68k モードではその特権判定よりも先んじて不当命令に
	// ならなければいけない。
	// Human68k モードでは F ライン命令は例外を起こすのではなく、命令内部で
	// 直接ホストのコールバックを実行しているため、ゲスト側の特権違反ハンドラ
	// に来たものを F ライン例外へ回すというような処理は出来ないため。
	if (fline_callback == NULL && mpu_type == m680x0MPUType::M68030) {
		switch (ir & 077) {
		 case 020 ... 027:	// m:(An)
		 case 040 ... 047:	// -:-(An)
		 case 050 ... 057:	// r:d16(An)
		 case 060 ... 067:	// x:d8(An,IX)
		 case 070 ... 071:	// w:Abs
			SUPERVISOR_OP;
			// コプロセッサがいないので EA をフェッチせず終了のはず。
			break;
		 default:
			break;
		}
	}
	op_illegal();
}

// %1111_011101_mmmrrr ..m+.rxwp. 23-	cpRESTORE
// %1111_100101_mmmrrr ..m+.rxwp. 23-	cpRESTORE
// %1111_101101_mmmrrr ..m+.rxwp. 23-	cpRESTORE
// %1111_110101_mmmrrr ..m+.rxwp. 23-	cpRESTORE
// %1111_111101_mmmrrr ..m+.rxwp. 23-	cpRESTORE
OP_DEF(cprestore)
{
	// すぐ上の cpsave 内のコメント参照。
	// cpRESTORE の場合先に1ロングワード読んでみて、その後コプロセッサに
	// 通信するので、コプロセッサがいなくても読み込みは発生する。
	// See XEiJ/misc/flinebuserror.x
	if (fline_callback == NULL && mpu_type == m680x0MPUType::M68030) {
		switch (ir & 077) {
		 case 020 ... 027:	// m:(An)
		 case 030 ... 037:	// +:(An)+
		 case 050 ... 057:	// r:d16(An)
		 case 060 ... 067:	// x:d8(An,IX)
		 case 070 ... 071:	// w:Abs
		 case 072 ... 073:	// p:d8(PC,IX)
		 {
			SUPERVISOR_OP;
			uint32 ea = cea_fpu(4);
			read_4(ea);
			break;
		 }
		 default:
			break;
		}
	}
	op_illegal();
}

// %1111_010110_001nnn .......... --6	PLPAW (An)
// %1111_010111_001nnn .......... --6	PLPAR (An)
OP_DEF(plpa)
{
	op_illegal();
}

// %1111_100000_000000 .......... --6	LPSTOP
OP_DEF(lpstop)
{
	op_illegal();
}

// illegal (or not-assigned) instructions
OP_DEF(illegal)
{
	// ILLEGAL 命令と F ライン命令と不当命令パターンがすべてここに来る。
	// catch 内からも呼ばれるので、ここで C++ の例外をスローしてはいけない。

	if ((ir & 0xf000) == 0xf000) {
		// F系列命令
		CYCLE3(fline);
		if (fline_callback) {
			if (fline_callback(this, fline_arg)) {
				return;
			}
		}
		ExceptionFLine();
	} else {
		// 不当命令
		CYCLE3(illegal);
		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.