File:  [Isaki's NoNo m68k/m88k emulator] / nono / m680x0 / disasm.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:04:28 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v002, v001, HEAD
nono 0.0.1

//
// nono
// Copyright (C) 2017 [email protected]
//

#include "header.h"
#include "m68030.h"
#include "disasm.h"
#include "bus.h"
#include "mystring.h"

// コンストラクタ
Disasm::Disasm()
{
	init();
}

// デストラクタ
Disasm::~Disasm()
{
}

// 逆アセンブル
std::string
Disasm::Disassemble(uint32 laddr, uint32 paddr)
{
	init();

	pc = laddr;
	pc0 = pc;
	phys_pc = paddr;

	switch (fetch16() >> 6) {
#include "m68030switch.h"
	 default:
		__unreachable();
	}

	std::string s = name + size_str[size];

	if (!src.empty() || !dst.empty()) {
		// オペランドが片方でもあればインデントする
		int sl = s.length();
		if (sl < 8) {
			s += std::string(8 - sl, ' ');
		} else {
			s += ' ';
		}

		// src があれば src を追加
		if (!src.empty()) {
			s += src;
		}
		// 両方あればカンマで区切る
		if (!src.empty() && !dst.empty()) {
			s += ",";
		}
		// dst があれば dst を追加
		if (!dst.empty()) {
			s += dst;
		}
	}

	return s;
}

// 逆アセンブル + ダンプ
std::string
Disasm::DisassembleWithDump(uint32 laddr, uint32 paddr)
{
	// 逆アセンブル
	std::string s = Disassemble(laddr, paddr);

	// ダンプ
	std::string dump;
	for (const auto & i : ir) {
		dump += string_format("%04x ", i);
	}
	if (ir.size() < 5) {
		dump += std::string(25 - ir.size() * 5, ' ');
	}

	return dump + s;
}

// 1行逆アセンブル前の初期化
void
Disasm::init()
{
	ir.clear();
	name.clear();
	size = Size::None;
	src.clear();
	dst.clear();
}

// ワードピーク (PCを進めずワードを取得する)
uint32
Disasm::peek16()
{
	// 物理空間から読み込む
	uint16 data;
	data = m68030_phys_peek_8(phys_pc) << 8;
	data |= m68030_phys_peek_8(phys_pc + 1);
	return data;
}

// ワードフェッチ
uint32
Disasm::fetch16()
{
	uint16 data = peek16();
	// IR に入れて PC を進める
	ir.push_back(data);
	pc += 2;
	phys_pc += 2;
	return data;
}

// ロングワードフェッチ
uint32
Disasm::fetch32()
{
	uint32 data;
	data = fetch16() << 16;
	data |= fetch16();
	return data;
}

// 符号なし8ビット16進数を文字列にして返す
std::string
Disasm::hex8(uint32 val)
{
	return string_format("$%02x", val);
}

// 符号なし16ビット16進数を文字列にして返す
std::string
Disasm::hex16(uint32 val)
{
	return string_format("$%04x", val);
}

// 符号なし32ビット16進数を文字列にして返す
std::string
Disasm::hex32(uint32 val)
{
	return string_format("$%08x", val);
}

// 符号つき8ビット16進数を文字列にして返す
// 負数はマイナスを前置して表す。
std::string
Disasm::shex8(uint32 val)
{
	if ((int8)val < 0) {
		return string_format("-$%02x", -(int8)val);
	} else {
		return string_format("$%02x", val);
	}
}

// 符号つき16ビット16進数を文字列にして返す
// 負数はマイナスを前置して表す。
std::string
Disasm::shex16(uint32 val)
{
	if ((int16)val < 0) {
		return string_format("-$%04x", -(int16)val);
	} else {
		return string_format("$%04x", val);
	}
}

// 符号つき32ビット16進数を文字列にして返す
// 負数はマイナスを前置して表す。
std::string
Disasm::shex32(uint32 val)
{
	if ((int32)val < 0) {
		return string_format("-$%08x", (uint32)(-(int64)(int32)val));
	} else {
		return string_format("$%08x", val);
	}
}

// EA を示す文字列を返す。ir[0] の mmmrrr の部分固定。
std::string
Disasm::make_ea()
{
	return make_ea(ir[0]);
}

// mmrr に対して EA を示す文字列を返す。
std::string
Disasm::make_ea(uint mmrr)
{
	std::string s;
	uint rr;

	mmrr &= 0x3f;
	rr = mmrr & 7;

	switch (mmrr) {
	 case 0x00 ... 0x07:	// 0
		s = make_dn(rr);
		break;
	 case 0x08 ... 0x0f:	// 1
		s = make_an(rr);
		break;
	 case 0x10 ... 0x17:	// 2
		s = make_anin(rr);
		break;
	 case 0x18 ... 0x1f:	// 3
		s = make_anpi(rr);
		break;
	 case 0x20 ... 0x27:	// 4
		s = make_anpd(rr);
		break;
	 case 0x28 ... 0x2f:	// 5
		s = disp16() + make_anin(rr);
		break;
	 case 0x30 ... 0x37:	// 6
		s = make_eaix(make_an(rr));
		break;
	 case 0x38:			// Abs.W
		s = addr16();
		break;
	 case 0x39:			// Abs.L
		s = addr32();
		break;
	 case 0x3a:			// d16(pc)
		s = addr32(pc + (int32)(int16)fetch16()) +
			"(" + make_reg(Reg::PC) + ")";
		break;
	 case 0x3b:			// d8(pc,IX)
		s = make_eaix(make_reg(Reg::PC));
		break;
	 case 0x3c:			// imm
		switch (size) {
		 case Size::B:
			s = imm8();
			break;
		 case Size::W:
			s = imm16();
			break;
		 case Size::L:
		 case Size::S:
			s = imm32();
			break;
		 case Size::D:
			s = imm32();
			s += string_format("_%08x", fetch32());
			break;
		 case Size::X:
		 case Size::P:
			s = imm32();
			s += string_format("_%08x", fetch32());
			s += string_format("_%08x", fetch32());
			break;
		 default:
			s = "(invalid ea size?)";
			break;
		}
		break;
	 default:
		s = "(invalid ea?)";
		break;
	}
	return s;
}

std::string
Disasm::make_eaix(std::string basereg)
{
	static const char * const scalestr[] = {
		"", "*2", "*4", "*8",
	};
	uint16 ext = fetch16();
	bool full = (ext & 0x0100);
	uint rn = (ext >> 12);
	bool wl = (ext & 0x0800);
	uint scale = (ext >> 9) & 3;
	std::string idx;
	std::string s;

	// インデックスレジスタ
	Size sz = wl ? Size::L : Size::W;
	idx = ",";
	idx += make_rn(rn);		// Rn
	idx += size_str[sz];	// .[WL]
	idx += scalestr[scale];	// *{2/4/8}

	if (full == false) {
		// 短縮フォーマット
		uint8 disp = ext & 0xff;
		if (disp == 0) {
			// $00 は省略する
		} else {
			s = shex8(disp);
		}
		s += '(';
		s += basereg;
		s += idx;
		s += ')';
	} else {
		// フルフォーマット
		bool bs = (ext & 0x0080);
		bool is = (ext & 0x0040);
		uint bdsize = (ext >> 4) & 3;
		uint iis = (ext & 7);
		std::string bd;
		std::string od;

		// ベースレジスタ・サプレス
		if (bs) {
			basereg = "z" + basereg;
		}

		// ベース・ディスプレースメント
		switch (bdsize) {
		 case 0:	// 予約
			return "<invalid EA(bdsize 0)>";
		 case 1:	// ベースはヌル
			break;
		 case 2:	// ベース.W
			bd = disp16();
			bd += ",";
			break;
		 case 3:	// ベース.L
			bd = disp32();
			bd += ",";
			break;
		}

		// アウター・ディスプレースメント
		switch (iis & 3) {
		 case 0:	// 不要?
		 case 1:	// アウターはヌル
			break;
		 case 2:	// アウター.W
			od = ",";
			od += disp16();
			break;
		 case 3:	// アウター.L
			od = ",";
			od += disp32();
			break;
		}

		if (is == 0) {
			switch (iis) {
			 case 0:	// no memory indirection
				// (bd,base,idx)
				s = "(";
				s += bd;
				s += basereg;
				s += idx;
				s += ")";
				break;
			 case 1:	// indirect pre-index with null outer
				// ([bd,base,idx])
			 case 2:	// indirect pre-index with word outer
			 case 3:	// indirect pre-index with long outer
				// ([bd,base,idx],od)
				s = "([";
				s += bd;
				s += basereg;
				s += idx;
				s += "]";
				s += od;
				s += ")";
				break;

			 case 4:
				return "<invalid EA(iis=4)>";

			 case 5:	// indirect post-index with null outer
				// ([bd,base],idx)
			 case 6:	// indirect post-index with word outer
			 case 7:	// indirect post-index with long outer
				// ([bd,base],idx,od)
				s = "([";
				s += bd;
				s += basereg;
				s += "]";
				s += idx;
				s += od;
				s += ")";
				break;
			 default:
				__unreachable();
			}
		} else {
			switch (iis) {
			 case 0:	// no memory indirection
				// (bd,base)
				s = "(";
				s += bd;
				s += basereg;
				s += ")";
				break;
			 case 1:	// memory indirect with null outer
				// ([bd,base])
			 case 2:	// memory indirect with word outer
			 case 3:	// memory indirect with long outer
				// ([bd,base],od)
				s += "([";
				s += bd;
				s += basereg;
				s += "]";
				s += od;
				s += ")";
				break;
			 default:
				return string_format("<invalid EA(is=1,iis=%d)>", iis);
			}
		}
	}

	return s;
}

// addr をワードアドレスとした時の文字列を返す
std::string
Disasm::addr16(uint32 addr)
{
	return hex16(addr & 0xffff);
}

// addr をロングワードアドレスとした時の文字列を返す
std::string
Disasm::addr32(uint32 addr)
{
	return hex32(addr);
}

// フェッチした値をワードアドレスとして文字列を返す
std::string
Disasm::addr16()
{
	return addr16(fetch16());
}

// フェッチした値をロングワードアドレスとして文字列を返す
std::string
Disasm::addr32()
{
	return addr32(fetch32());
}

// フェッチした値をワードディスプレースメントとして文字列を返す
std::string
Disasm::disp16()
{
	return shex16(fetch16());
}

// フェッチした値をロングワードディスプレースメントとして文字列を返す
std::string
Disasm::disp32()
{
	return shex32(fetch32());
}

// バイト即値 imm を文字列にして返す
std::string
Disasm::imm8()
{
	return "#" + hex8(fetch16() & 0xff);
}

// ワード即値 imm を文字列にして返す
std::string
Disasm::imm16()
{
	return "#" + hex16(fetch16());
}

// ロングワード即値 imm を文字列にして返す
std::string
Disasm::imm32()
{
	return "#" + hex32(fetch32());
}

// Dn を文字列にして返す。n の上位ビットは無視する。
std::string
Disasm::make_dn(uint n)
{
	n = (n & 7) + '0';
	std::string s;
	s = 'd';
	s += n;
	return s;
}

// An を文字列にして返す。n の上位ビットは無視する。
std::string
Disasm::make_an(uint n)
{
	n = (n & 7) + '0';
	std::string s;
	s = 'a';
	s += n;
	return s;
}

// Rn (Dn/An) を文字列にして返す。n の上位ビットは無視する。
std::string
Disasm::make_rn(uint n)
{
	n &= 0x0f;
	if (n < 8) {
		return make_dn(n);
	} else {
		return make_an(n - 8);
	}
}

// (An) を文字列にして返す。n の上位ビットは無視する。
std::string
Disasm::make_anin(uint n)
{
	std::string s;
	s = '(';
	s += make_an(n);
	s += ')';
	return s;
}

// (An)+ を文字列にして返す。n の上位ビットは無視する。
std::string
Disasm::make_anpi(uint n)
{
	std::string s;
	s = make_anin(n);
	s += '+';
	return s;
}

// -(An) を文字列にして返す。n の上位ビットは無視する。
std::string
Disasm::make_anpd(uint n)
{
	std::string s;
	s = '-';
	s += make_anin(n);
	return s;
}

// #qqq を文字列にして返す。ir[0] のいつものところにあると仮定する。
std::string
Disasm::make_q8()
{
	uint q = (ir[0] >> 9) & 7;
	if (q == 0) {
		q = 8;
	}
	return string_format("#%d", q);
}

// regno で示されるレジスタ名を返す
std::string
Disasm::make_reg(Reg reg)
{
	return reg_names[reg];
}

// MOVEM のレジスタリスト文字列を返す。
// 第2ワードのフェッチは呼び出し側で行っておくこと。
// プリデクリメントかどうかの判断はこちらで行う。
std::string
Disasm::make_reglist()
{
	uint16 mask = ir[1];
	uint mm = (ir[0] >> 3) & 7;
	std::string s;

	// 制御モード・ポストインクリメントモードなら、ビット順を入れ替える。
	if (mm != 4) {
		//mask = bitrev16(mask);
		mask = ((mask & 0x5555) << 1) | ((mask >> 1) & 0x5555);
		mask = ((mask & 0x3333) << 2) | ((mask >> 2) & 0x3333);
		mask = ((mask & 0x0f0f) << 4) | ((mask >> 4) & 0x0f0f);
		mask = (mask >> 8) | (mask << 8);
	}

	// これでどちらのモードでも 16ビット内に上から順に並んでいる。
	// Bit: 15 14 ...  1  0
	// Reg: D0 D1 ... A6 A7

	make_reglist_half(s, "d", mask & 0xff00);
	make_reglist_half(s, "a", mask << 8);
	if (s.empty()) {
		s = "noregs";
	}
	return s;
}

// データレジスタもしくはアドレスレジスタの8ビット分だけを処理する。
// FPn からも使うようになったので名前がいまいちか。
// mask は以下のように上位8ビットに上から下に向かって並ぶように渡すこと。
// ビット7 は番兵のため %0 にすること。
//
//  15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
//  R0 R1 R2 R3 R4 R5 R6 R7 <-------- %0 --------->
//
void
Disasm::make_reglist_half(std::string& s, const char *reg, uint16 mask)
{
	int top = -1;

	// 番兵を含めてループするため1つ多く回る
	for (int i = 0; i < 9; i++, mask <<= 1) {
		if ((int16)mask < 0) {
			// このビットは表示するレジスタ
			if (top < 0) {
				// 非表示中ならこのレジスタを出力する。
				// 初回以外は区切りを先に出力する。
				if (s.length() != 0) {
					s += '/';
				}
				s += reg;
				s += '0' + i;
				top = i;
			}
		} else {
			// このビットは表示しない
			if (top >= 0) {
				// 表示中ならこの一つ前のレジスタで終端
				int last = i - 1;
				if (top != last) {
					// 表示が複数にまたがっていた
					s += '-';
					s += reg;
					s += '0' + last;
				}
				top = -1;
			}
		}
	}
}

// ビットフィールド欄を文字列にして返す。
// 第2ワードのフェッチは呼び出し側で行っておくこと。
std::string
Disasm::make_bf()
{
	uint16 ext = ir[1];
	uint od = (ext & 0x0800);
	uint offset = (ext >> 6) & 0x1f;
	uint wd = (ext & 0x0020);
	uint width = ext & 0x1f;
	std::string s = "{";

	// offset
	if (od) {
		if (offset < 8) {
			s += make_dn(offset);
		} else {
			s += string_format("<invalid regno %d>", offset);
		}
	} else {
		// オフセットは 0..31
		s += string_format("#%d", offset);
	}

	s += ":";

	// width
	if (wd) {
		if (width < 8) {
			s += make_dn(width);
		} else {
			s += string_format("<invalid regno %d>", width); 
		}
	} else {
		// 幅は 0 なら 32 を意味する
		if (width == 0) {
			width = 32;
		}
		s += string_format("#%d", width);
	}

	s += "}";
	return s;
}

// ファンクションコードフィールドを文字列にして返す。
// MMU の拡張ワードは呼び出し側で取得済みのはず。
std::string
Disasm::make_fc()
{
	uint fc = ir[1] & 0x1f;

	switch (fc) {
	 case 0:
		return make_reg(Reg::SFC);
	 case 1:
		return make_reg(Reg::DFC);
	 case 0x08 ... 0x0f:
		return make_dn(fc);
	 case 0x10 ... 0x17:
		return string_format("#%d", fc & 7);
	 default:
		return string_format("<invalid fc %d>", fc);
	}
}

// MOVEC の制御レジスタを返す。
std::string
Disasm::make_movec()
{
	uint n = ir[1] & 0x0fff;
	Reg reg;

	switch (n) {
	 case 0x000:	reg = Reg::SFC;		break;
	 case 0x001:	reg = Reg::DFC;		break;
	 case 0x002:	reg = Reg::CACR;	break;
	 case 0x800:	reg = Reg::USP;		break;
	 case 0x801:	reg = Reg::VBR;		break;
	 case 0x802:	reg = Reg::CAAR;	break;
	 case 0x803:	reg = Reg::MSP;		break;
	 case 0x804:	reg = Reg::ISP;		break;

	 // 040
	 // TC, MMUSR, SRP は名前が同じだが 030 MMU のではない
	 case 0x003:	reg = Reg::TC;		break;
	 case 0x004:	reg = Reg::ITT0;	break;	// EC040 なら IACR0
	 case 0x005:	reg = Reg::ITT1;	break;	// EC040 なら IACR1
	 case 0x006:	reg = Reg::DTT0;	break;	// EC040 なら DACR0
	 case 0x007:	reg = Reg::DTT1;	break;	// EC040 なら DACR1
	 case 0x805:	reg = Reg::MMUSR;	break;
	 case 0x806:	reg = Reg::URP;		break;
	 case 0x807:	reg = Reg::SRP;		break;

	 default:
		return string_format("<invalid ctrl reg %03x>", n);
	}
	return make_reg(reg);
}

// FPgen 関数名を返す
// mode が適切でなければ "" を返す。
std::string
Disasm::make_fpgen()
{
	uint mode = ir[1] & 0x7f;

	if (mode < countof(fpgen_names)) {
		return fpgen_names[mode];
	}
	return "";
}

// FPn を文字列にして返す。n の上位ビットは無視する。
std::string
Disasm::make_fpn(uint n)
{
	n = (n & 7) + '0';
	std::string s;
	s = "fp";
	s += n;
	return s;
}

// FPU の condition 文字列を返す。
// word には condition が入ったワードを指定すること。
// 不要な上位ビットはこちらでマスクする。
std::string
Disasm::make_fpcc(uint16 word)
{
	uint cc = word & 0x3f;
	if (cc > 0x1f) {
		return string_format("<invalid fpcc $%x>", cc);
	}
	return fpconditions[cc];
}

// FMOVEM 用の FPctls を文字列にして s に返す。
// 戻り値は指定された制御レジスタの個数。
uint
Disasm::make_fpctls(std::string& s)
{
	uint n = 0;
	uint list = ir[1] >> 10;

	s.clear();
	if ((list & 4)) {
		s += make_reg(Reg::FPCR);
		n++;
	}
	if ((list & 2)) {
		if (!s.empty()) {
			s += "/";
		}
		s += make_reg(Reg::FPSR);
		n++;
	}
	if ((list & 1)) {
		if (!s.empty()) {
			s += "/";
		}
		s += make_reg(Reg::FPIAR);
		n++;
	}

	if (n == 0)
		s = "nofpc";

	return n;
}

// FMOVEM のレジスタリスト文字列を返す。
// 第2ワードのフェッチはすでに行ってあるはず。
// プリデクリメントかどうかの判断はこちらで行う。
std::string
Disasm::make_fpnlist()
{
	uint16 mask = ir[1] & 0x00ff;
	std::string s;

	// プリデクリメントモードなら、ビット順を入れ替える。
	// An/Dn の時とは逆なので注意。てかなんでだよ。
	// <ea> のモードと食い違ってたらその時は知らん…。
	if ((ir[1] & 0x0800)) {
		//mask = bitrev8(mask);
		mask = ((mask & 0x55) << 1) | ((mask >> 1) & 0x55);
		mask = ((mask & 0x33) << 2) | ((mask >> 2) & 0x33);
		mask = ((mask & 0x0f) << 4) | ((mask >> 4) & 0x0f);
	}

	// これで、レジスタは常に上から順に並んでいる。
	//   7   6   5 ..   1   0
	// FP0 FP1 FP2 .. FP6 FP7

	make_reglist_half(s, "fp", mask << 8);
	if (s.empty()) {
		s = "nofpn";
	}
	return s;
}

/*static*/ const char * const Disasm::reg_names[] = {
	"ccr",
	"sr",
	"pc",
	"usp",

	"msp",
	"isp",
	"vbr",
	"sfc",
	"dfc",
	"cacr",
	"caar",

	"tc",
	"mmusr",
	"srp",
	"crp",
	"tt0",
	"tt1",

	"fpcr",
	"fpsr",
	"fpiar",
};

/*static*/ const char * const Disasm::size_str[] = {
	".l",
	".s",
	".x",
	".p",
	".w",
	".d",
	".b",
	".p",	// dynamic k-factor
	".q",
	"",		// None
};

/*static*/ const char * const Disasm::conditions[] = {
	"t",  "f",  "hi", "ls", "cc", "cs", "ne", "eq",
	"vc", "vs", "pl", "mi", "ge", "lt", "gt", "le",
};

/*static*/ const char * const Disasm::fpconditions[] = {
	"f",	// 000000
	"eq",	// 000001
	"ogt",	// 000010
	"oge",	// 000011
	"olt",	// 000100
	"ole",	// 000101
	"ogl",	// 000110
	"or",	// 000111
	"un",	// 001000
	"ueq",	// 001001
	"ugt",	// 001010
	"uge",	// 001011
	"ult",	// 001100
	"ule",	// 001101
	"ne",	// 001110
	"?",	// 001111

	"sf",	// 010000
	"seq",	// 010001
	"ge",	// 010010
	"ge",	// 010011
	"lt",	// 010100
	"le",	// 010101
	"gl",	// 010110
	"gle",	// 010111
	"ngle",	// 011000
	"ngl",	// 011001
	"nle",	// 011010
	"nlt",	// 011011
	"nge",	// 011100
	"ngt",	// 011101
	"sne",	// 011110
	"st",	// 011111
};

/*static*/ const char * const Disasm::btst_names[] = {
	"btst",
	"bchg",
	"bclr",
	"bset",
};

/*static*/ const char * const Disasm::fpgen_names[] = {
	"fmove",	// $00
	"fint",		// $01
	"fsinh",	// $02
	"fintrz",	// $03
	"fsqrt",	// $04
	"",			// $05
	"flognp1",	// $06
	"",			// $07
	"fetoxm1",	// $08
	"ftanh",	// $09
	"fatan",	// $0a
	"",			// $0b
	"fasin",	// $0c
	"fatanh",	// $0d
	"fsin",		// $0e
	"ftan",		// $0f
	"fetox",	// $10
	"ftwotox",	// $11
	"ftentox",	// $12
	"",			// $13
	"flogn",	// $14
	"flog10",	// $15
	"flog2",	// $16
	"",			// $17
	"fabs",		// $18
	"fcosh",	// $19
	"fneg",		// $1a
	"",			// $1b
	"facos",	// $1c
	"fcos",		// $1d
	"fgetexp",	// $1e
	"fgetman",	// $1f
	"fdiv",		// $20
	"fmod",		// $21
	"fadd",		// $22
	"fmul",		// $23
	"fsgldiv",	// $24
	"frem",		// $25
	"fscale",	// $26
	"fsglmul",	// $27
	"fsub",		// $28
	"",			// $29
	"",			// $2a
	"",			// $2b
	"",			// $2c
	"",			// $2d
	"",			// $2e
	"",			// $2f
	"",			// $30 (fsincos)
	"",			// $31 (fsincos)
	"",			// $32 (fsincos)
	"",			// $33 (fsincos)
	"",			// $34 (fsincos)
	"",			// $35 (fsincos)
	"",			// $36 (fsincos)
	"",			// $37 (fsincos)
	"fcmp",		// $38
	"",			// $39
	"ftst",		// $3a
};

/*static*/ const char * const Disasm::fmovecr_text[] = {
	"<log10(2)>",	// [0] $0b
	"<e>",			// [1] $0c
	"<log2(e)>",	// [2] $0d
	"<log10(e)>",	// [3] $0e
	"<0>",			// [4] $0f
	"<ln(2)>",		// $30
	"<ln(10)>",		// $31
	"<1>",			// $32
	"<10>",			// $33
	"<1e2>",		// $34
	"<1e4>",		// $35
	"<1e8>",		// $36
	"<1e16>",		// $37
	"<1e32>",		// $38
	"<1e64>",		// $39
	"<1e128>",		// $3a
	"<1e256>",		// $3b
	"<1e512>",		// $3c
	"<1e1024>",		// $3d
	"<1e2048>",		// $3e
	"<1e4096>",		// $3f
};

/*static*/ const char *const Disasm::x68k_doscall[256] = {
	"_EXIT",		// ff00
	"_GETCHAR",		// ff01
	"_PUTCHAR",		// ff02
	"_COMINP",		// ff03
	"_COMOUT",		// ff04
	"_PRNOUT",		// ff05
	"_INPOUT",		// ff06
	"_INKEY",		// ff07
	"_GETC",		// ff08
	"_PRINT",		// ff09
	"_GETS",		// ff0a
	"_KEYSNS",		// ff0b
	"_KFLUSH",		// ff0c
	"_FFLUSH",		// ff0d
	"_CHGDRV",		// ff0e
	"_DRVCTRL",		// ff0f

	"_CONSNS",		// ff10
	"_PRNSNS",		// ff11
	"_CINSNS",		// ff12
	"_COUTSNS",		// ff13
	NULL,			// ff14
	NULL,			// ff15
	NULL,			// ff16
	"_FATCHK",		// ff17
	"_HENDSP",		// ff18
	"_CURDRV",		// ff19
	"_GETSS",		// ff1a
	"_FGETC",		// ff1b
	"_FGETS",		// ff1c
	"_FPUTC",		// ff1d
	"_FPUTS",		// ff1e
	"_ALLCLOSE",	// ff1f

	"_SUPER",		// ff20
	"_FNCKEY",		// ff21
	"_KNJCTRL",		// ff22
	"_CONCTRL",		// ff23
	"_KEYCTRL",		// ff24
	"_INTVCS",		// ff25
	"_PSPSET",		// ff26
	"_GETTIM2",		// ff27
	"_SETTIM2",		// ff28
	"_NAMESTS",		// ff29
	"_GETDATE",		// ff2a
	"_SETDATE",		// ff2b
	"_GETTIME",		// ff2c
	"_SETTIME",		// ff2d
	"_VERIFY",		// ff2e
	"_DUP0",		// ff2f

	"_VERNUM",		// ff30
	"_KEEPPR",		// ff31
	"_GETDPB",		// ff32
	"_BREAKCK",		// ff33
	"_DRVXCHG",		// ff34
	"_INTVCG",		// ff35
	"_DSKFRE",		// ff36
	"_NAMECK",		// ff37
	NULL,			// ff38
	"_MKDIR",		// ff39
	"_RMDIR",		// ff3a
	"_CHDIR",		// ff3b
	"_CREATE",		// ff3c
	"_OPEN",		// ff3d
	"_CLOSE",		// ff3e
	"_READ",		// ff3f

	"_WRITE",		// ff40
	"_DELETE",		// ff41
	"_SEEK",		// ff42
	"_CHMOD",		// ff43
	"_IOCTRL",		// ff44
	"_DUP",			// ff45
	"_DUP2",		// ff46
	"_CURDIR",		// ff47
	"_MALLOC",		// ff48
	"_MFREE",		// ff49
	"_SETBLOCK",	// ff4a
	"_EXEC",		// ff4b
	"_EXIT2",		// ff4c
	"_WAIT",		// ff4d
	"_FILES",		// ff4e
	"_NFILES",		// ff4f

	"_SETPDB",		// ff50 (Human68k ver.2)
	"_GETPDB",		// ff51 (Human68k ver.2)
	"_SETENV",		// ff52 (Human68k ver.2)
	"_GETENV",		// ff53 (Human68k ver.2)
	"_VERIFYG",		// ff54 (Human68k ver.2)
	"_COMMON",		// ff55 (Human68k ver.2)
	"_RENAME",		// ff56 (Human68k ver.2)
	"_FILEDATE",	// ff57 (Human68k ver.2)
	"_MALLOC2",		// ff58 (Human68k ver.2)
	NULL,			// ff59
	"_MAKETMP",		// ff5a (Human68k ver.2)
	"_NEWFILE",		// ff5b (Human68k ver.2)
	"_LOCK",		// ff5c (Human68k ver.2)
	NULL,			// ff5d
	NULL,			// ff5e
	"_ASSIGN",		// ff5f (Human68k ver.2)

	NULL,			// ff60
	NULL,			// ff61
	NULL,			// ff62
	NULL,			// ff63
	NULL,			// ff64
	NULL,			// ff65
	NULL,			// ff66
	NULL,			// ff67
	NULL,			// ff68
	NULL,			// ff69
	NULL,			// ff6a
	NULL,			// ff6b
	NULL,			// ff6c
	NULL,			// ff6d
	NULL,			// ff6e
	NULL,			// ff6f

	NULL,			// ff70
	NULL,			// ff71
	NULL,			// ff72
	NULL,			// ff73
	NULL,			// ff74
	NULL,			// ff75
	NULL,			// ff76
	NULL,			// ff77
	NULL,			// ff78
	NULL,			// ff79
	"_FFLUSH_SET",	// ff7a (Human68k ver.2)
	"_OS_PATCH",	// ff7b (Human68k ver.2)
	"_GETFCB",		// ff7c (Human68k ver.2)
	"_S_MALLOC",	// ff7d (Human68k ver.2)
	"_S_MFREE",		// ff7e (Human68k ver.2)
	"_S_PROCESS",	// ff7f (Human68k ver.2)

	"_SETPDB",		// ff80
	"_GETPDB",		// ff81
	"_SETENV",		// ff82
	"_GETENV",		// ff83
	"_VERIFYG",		// ff84
	"_COMMON",		// ff85
	"_RENAME",		// ff86
	"_FILEDATE",	// ff87
	"_MALLOC2",		// ff88
	NULL,			// ff89
	"_MAKETMP",		// ff8a
	"_NEWFILE",		// ff8b
	"_LOCK",		// ff8c
	NULL,			// ff8d
	NULL,			// ff8e
	"_ASSIGN",		// ff8f

	NULL,			// ff90
	NULL,			// ff91
	NULL,			// ff92
	NULL,			// ff93
	NULL,			// ff94
	NULL,			// ff95
	NULL,			// ff96
	NULL,			// ff97
	NULL,			// ff98
	NULL,			// ff99
	NULL,			// ff9a
	NULL,			// ff9b
	NULL,			// ff9c
	NULL,			// ff9d
	NULL,			// ff9e
	NULL,			// ff9f

	NULL,			// ffa0
	NULL,			// ffa1
	NULL,			// ffa2
	NULL,			// ffa3
	NULL,			// ffa4
	NULL,			// ffa5
	NULL,			// ffa6
	NULL,			// ffa7
	NULL,			// ffa8
	NULL,			// ffa9
	"_FFLUSH_SET",	// ffaa
	"_OS_PATCH",	// ffab
	"_GETFCB",		// ffac
	"_S_MALLOC",	// ffad
	"_S_MFREE",		// ffae
	"_S_PROCESS",	// ffaf

	NULL,			// ffb0
	NULL,			// ffb1
	NULL,			// ffb2
	NULL,			// ffb3
	NULL,			// ffb4
	NULL,			// ffb5
	NULL,			// ffb6
	NULL,			// ffb7
	NULL,			// ffb8
	NULL,			// ffb9
	NULL,			// ffba
	NULL,			// ffbb
	NULL,			// ffbc
	NULL,			// ffbd
	NULL,			// ffbe
	NULL,			// ffbf

	NULL,			// ffc0
	NULL,			// ffc1
	NULL,			// ffc2
	NULL,			// ffc3
	NULL,			// ffc4
	NULL,			// ffc5
	NULL,			// ffc6
	NULL,			// ffc7
	NULL,			// ffc8
	NULL,			// ffc9
	NULL,			// ffca
	NULL,			// ffcb
	NULL,			// ffcc
	NULL,			// ffcd
	NULL,			// ffce
	NULL,			// ffcf

	NULL,			// ffd0
	NULL,			// ffd1
	NULL,			// ffd2
	NULL,			// ffd3
	NULL,			// ffd4
	NULL,			// ffd5
	NULL,			// ffd6
	NULL,			// ffd7
	NULL,			// ffd8
	NULL,			// ffd9
	NULL,			// ffda
	NULL,			// ffdb
	NULL,			// ffdc
	NULL,			// ffdd
	NULL,			// ffde
	NULL,			// ffdf

	NULL,			// ffe0
	NULL,			// ffe1
	NULL,			// ffe2
	NULL,			// ffe3
	NULL,			// ffe4
	NULL,			// ffe5
	NULL,			// ffe6
	NULL,			// ffe7
	NULL,			// ffe8
	NULL,			// ffe9
	NULL,			// ffea
	NULL,			// ffeb
	NULL,			// ffec
	NULL,			// ffed
	NULL,			// ffee
	NULL,			// ffef

	"_EXITVC",		// fff0
	"_CTRLVC",		// fff1
	"_ERRJVC",		// fff2
	"_DISKRED",		// fff3
	"_DISKWRT",		// fff4
	"_INDOSFLG",	// fff5
	"_SUPER_JSR",	// fff6
	"_BUS_ERR",		// fff7
	"_OPEN_PR",		// fff8
	"_KILL_PR",		// fff9
	"_GET_PR",		// fffa
	"_SUSPEND_PR",	// fffb
	"_SLEEP_PR",	// fffc
	"_SEND_PR",		// fffd
	"_TIME_PR",		// fffe
	"_CHANGE_PR",	// ffff
};

/*static*/ const char * const Disasm::x68k_fpcall[256] = {
	"__LMUL",		// fe00
	"__LDIV",		// fe01
	"__LMOD",		// fe02
	NULL,			// fe03
	"__UMUL",		// fe04
	"__UDIV",		// fe05
	"__UMOD",		// fe06
	NULL,			// fe07
	"__IMUL",		// fe08
	"__IDIV",		// fe09
	NULL,			// fe0a
	NULL,			// fe0b
	"__RANDOMIZE",	// fe0c
	"__SRAND",		// fe0d
	"__RAND",		// fe0e
	NULL,			// fe0f

	"__STOL",		// fe10
	"__LTOS",		// fe11
	"__STOH",		// fe12
	"__HTOS",		// fe13
	"__STOO",		// fe14
	"__OTOS",		// fe15
	"__STOB",		// fe16
	"__BTOS",		// fe17
	"__IUSING",		// fe18
	NULL,			// fe19
	"__LTOD",		// fe1a
	"__DTOL",		// fe1b
	"__LTOF",		// fe1c
	"__FTOL",		// fe1d
	"__FTOD",		// fe1e
	"__DTOF",		// fe1f

	"__VAL",		// fe20
	"__USING",		// fe21
	"__STOD",		// fe22
	"__DTOS",		// fe23
	"__ECVT",		// fe24
	"__FCVT",		// fe25
	"__GCVT",		// fe26
	NULL,			// fe27
	"__DTST",		// fe28
	"__DCMP",		// fe29
	"__DNEG",		// fe2a
	"__DADD",		// fe2b
	"__DSUB",		// fe2c
	"__DMUL",		// fe2d
	"__DDIV",		// fe2e
	"__DMOD",		// fe2f

	"__DABS",		// fe30
	"__DCEIL",		// fe31
	"__DFIX",		// fe32
	"__DFLOOR",		// fe33
	"__DFRAC",		// fe34
	"__DSGN",		// fe35
	"__SIN",		// fe36
	"__COS",		// fe37
	"__TAN",		// fe38
	"__ATAN",		// fe39
	"__LOG",		// fe3a
	"__EXP",		// fe3b
	"__SQR",		// fe3c
	"__PI",			// fe3d
	"__NPI",		// fe3e
	"__POWER",		// fe3f

	"__RND",		// fe40
	"__SINH",		// fe41
	"__COSH",		// fe42
	"__TANH",		// fe43
	"__ATANH",		// fe44
	"__ASIN",		// fe45
	"__ACOS",		// fe46
	"__LOG10",		// fe47
	"__LOG2",		// fe48
	"__DFREXP",		// fe49
	"__DLDEXP",		// fe4a
	"__DADDONE",	// fe4b
	"__DSUBONE",	// fe4c
	"__DDIVTWO",	// fe4d
	"__DIEECNV",	// fe4e
	"__IEEDCNV",	// fe4f

	"__FVAL",		// fe50
	"__FUSING",		// fe51
	"__STOF",		// fe52
	"__FTOS",		// fe53
	"__FECVT",		// fe54
	"__FFCVT",		// fe55
	"__FGCVT",		// fe56
	NULL,			// fe57
	"__FTST",		// fe58
	"__FCMP",		// fe59
	"__FNEG",		// fe5a
	"__FADD",		// fe5b
	"__FSUB",		// fe5c
	"__FMUL",		// fe5d
	"__FDIV",		// fe5e
	"__FMOD",		// fe5f

	"__FABS",		// fe60
	"__FCEIL",		// fe61
	"__FFIX",		// fe62
	"__FFLOOR",		// fe63
	"__FFRAC",		// fe64
	"__FSGN",		// fe65
	"__FSIN",		// fe66
	"__FCOS",		// fe67
	"__FTAN",		// fe68
	"__FATAN",		// fe69
	"__FLOG",		// fe6a
	"__FEXP",		// fe6b
	"__FSQR",		// fe6c
	"__FPI",		// fe6d
	"__FNPI",		// fe6e
	"__FPOWER",		// fe6f

	"__FRND",		// fe70
	"__FSINH",		// fe71
	"__FCOSH",		// fe72
	"__FTANH",		// fe73
	"__FATANH",		// fe74
	"__FASIN",		// fe75
	"__FACOS",		// fe76
	"__FLOG10",		// fe77
	"__FLOG2",		// fe78
	"__FFREXP",		// fe79
	"__FLDEXP",		// fe7a
	"__FADDONE",	// fe7b
	"__FSUBONE",	// fe7c
	"__FDIVTWO",	// fe7d
	"__FIEECNV",	// fe7e
	"__IEEFCNV",	// fe7f

	NULL,			// fe80
	NULL,			// fe81
	NULL,			// fe82
	NULL,			// fe83
	NULL,			// fe84
	NULL,			// fe85
	NULL,			// fe86
	NULL,			// fe87
	NULL,			// fe88
	NULL,			// fe89
	NULL,			// fe8a
	NULL,			// fe8b
	NULL,			// fe8c
	NULL,			// fe8d
	NULL,			// fe8e
	NULL,			// fe8f

	NULL,			// fe90
	NULL,			// fe91
	NULL,			// fe92
	NULL,			// fe93
	NULL,			// fe94
	NULL,			// fe95
	NULL,			// fe96
	NULL,			// fe97
	NULL,			// fe98
	NULL,			// fe99
	NULL,			// fe9a
	NULL,			// fe9b
	NULL,			// fe9c
	NULL,			// fe9d
	NULL,			// fe9e
	NULL,			// fe9f

	NULL,			// fea0
	NULL,			// fea1
	NULL,			// fea2
	NULL,			// fea3
	NULL,			// fea4
	NULL,			// fea5
	NULL,			// fea6
	NULL,			// fea7
	NULL,			// fea8
	NULL,			// fea9
	NULL,			// feaa
	NULL,			// feab
	NULL,			// feac
	NULL,			// fead
	NULL,			// feae
	NULL,			// feaf

	NULL,			// feb0
	NULL,			// feb1
	NULL,			// feb2
	NULL,			// feb3
	NULL,			// feb4
	NULL,			// feb5
	NULL,			// feb6
	NULL,			// feb7
	NULL,			// feb8
	NULL,			// feb9
	NULL,			// feba
	NULL,			// febb
	NULL,			// febc
	NULL,			// febd
	NULL,			// febe
	NULL,			// febf

	NULL,			// fec0
	NULL,			// fec1
	NULL,			// fec2
	NULL,			// fec3
	NULL,			// fec4
	NULL,			// fec5
	NULL,			// fec6
	NULL,			// fec7
	NULL,			// fec8
	NULL,			// fec9
	NULL,			// feca
	NULL,			// fecb
	NULL,			// fecc
	NULL,			// fecd
	NULL,			// fece
	NULL,			// fecf

	NULL,			// fed0
	NULL,			// fed1
	NULL,			// fed2
	NULL,			// fed3
	NULL,			// fed4
	NULL,			// fed5
	NULL,			// fed6
	NULL,			// fed7
	NULL,			// fed8
	NULL,			// fed9
	NULL,			// feda
	NULL,			// fedb
	NULL,			// fedc
	NULL,			// fedd
	NULL,			// fede
	NULL,			// fedf

	"__CLMUL",		// fee0
	"__CLDIV",		// fee1
	"__CLMOD",		// fee2
	"__CUMUL",		// fee3
	"__CUDIV",		// fee4
	"__CUMOD",		// fee5
	"__CLTOD",		// fee6
	"__CDTOL",		// fee7
	"__CLTOF",		// fee8
	"__CFTOL",		// fee9
	"__CFTOD",		// feea
	"__CDTOF",		// feeb
	"__CDCMP",		// feec
	"__CDADD",		// feed
	"__CDSUB",		// feee
	"__CDMUL",		// feef

	"__CDDIV",		// fef0
	"__CDMOD",		// fef1
	"__CFCMP",		// fef2
	"__CFADD",		// fef3
	"__CFSUB",		// fef4
	"__CFMUL",		// fef5
	"__CFDIV",		// fef6
	"__CFMOD",		// fef7
	"__CDTST",		// fef8
	"__CFTST",		// fef9
	"__CDINC",		// fefa
	"__CFINC",		// fefb
	"__CDDEC",		// fefc
	"__CFDEC",		// fefd
	"__FEVARG",		// fefe
	"__FEVECS",		// feff

};

/*static*/ const char * const Disasm::x68k_iocscall[256] = {
	"_B_KEYINP",	// 7000
	"_B_KEYSNS",	// 7001
	"_B_SFTSNS",	// 7002
	"_KEY_INIT",	// 7003
	"_BITSNS",		// 7004
	"_SKEYSET",		// 7005
	"_LEDCTRL",		// 7006
	"_LEDSET",		// 7007
	"_KEYDLY",		// 7008
	"_KEYREP",		// 7009
	NULL,			// 700a
	NULL,			// 700b
	"_TVCTRL",		// 700c
	"_LEDMOD",		// 700d
	"_TGUSEMD",		// 700e
	"_DEFCHR",		// 700f

	"_CRTMOD",		// 7010
	"_CONTRAST",	// 7011
	"_HSVTORGB",	// 7012
	"_TPALET",		// 7013
	"_TPALET2",		// 7014
	"_TCOLOR",		// 7015
	"_FNTADR",		// 7016
	"_VRAMGET",		// 7017
	"_VRAMPUT",		// 7018
	"_FNTGET",		// 7019
	"_TEXTGET",		// 701a
	"_TEXTPUT",		// 701b
	"_CLIPPUT",		// 701c
	"_SCROLL",		// 701d
	"_B_CURON",		// 701e
	"_B_CUROFF",	// 701f

	"_B_PUTC",		// 7020
	"_B_PRINT",		// 7021
	"_B_COLOR",		// 7022
	"_B_LOCATE",	// 7023
	"_B_DOWN_S",	// 7024
	"_B_UP_S",		// 7025
	"_B_UP",		// 7026
	"_B_DOWN",		// 7027
	"_B_RIGHT",		// 7028
	"_B_LEFT",		// 7029
	"_B_CLR_ST",	// 702a
	"_B_ERA_ST",	// 702b
	"_B_INS",		// 702c
	"_B_DEL",		// 702d
	"_B_CONSOL",	// 702e
	"_B_PUTMES",	// 702f

	"_SET232C",		// 7030
	"_LOF232C",		// 7031
	"_INP232C",		// 7032
	"_ISNS232C",	// 7033
	"_OSNS232C",	// 7034
	"_OUT232C",		// 7035
	NULL,			// 7036
	NULL,			// 7037
	"_SETFNTADR",	// 7038
	NULL,			// 7039
	NULL,			// 703a
	"_JOYGET",		// 703b
	"_INIT_PRN",	// 703c
	"_SNSPRN",		// 703d
	"_OUTLPT",		// 703e
	"_OUTPRN",		// 703f

	"_B_SEEK",		// 7040
	"_B_VERIFY",	// 7041
	"_B_READDI",	// 7042
	"_B_DSKINI",	// 7043
	"_B_DRVSNS",	// 7044
	"_B_WRITE",		// 7045
	"_B_READ",		// 7046
	"_B_RECALI",	// 7047
	"_B_ASSIGN",	// 7048
	"_B_WRITED",	// 7049
	"_B_READID",	// 704a
	"_B_BADFMT",	// 704b
	"_B_READDL",	// 704c
	"_B_FORMAT",	// 704d
	"_B_DRVCHK",	// 704e
	"_B_EJECT",		// 704f

	"_DATEBCD",		// 7050
	"_DATESET",		// 7051
	"_TIMEBCD",		// 7052
	"_TIMESET",		// 7053
	"_DATEGET",		// 7054
	"_DATEBIN",		// 7055
	"_TIMEGET",		// 7056
	"_TIMEBIN",		// 7057
	"_DATECNV",		// 7058
	"_TIMECNV",		// 7059
	"_DATEASC",		// 705a
	"_TIMEASC",		// 705b
	"_DAYASC",		// 705c
	"_ALARMMOD",	// 705d
	"_ALARMSET",	// 705e
	"_ALARMGET",	// 705f

	"_ADPCMOUT",	// 7060
	"_ADPCMINP",	// 7061
	"_ADPCMAOT",	// 7062
	"_ADPCMAIN",	// 7063
	"_ADPCMLOT",	// 7064
	"_ADPCMLIN",	// 7065
	"_ADPCMSNS",	// 7066
	"_ADPCMMOD",	// 7067
	"_OPMSET",		// 7068
	"_OPMSNS",		// 7069
	"_OPMINTST",	// 706a
	"_TIMERDST",	// 706b
	"_VDISPST",		// 706c
	"_CRTCRAS",		// 706d
	"_HSYNCST",		// 706e
	"_PRNINTST",	// 706f

	"_MS_INIT",		// 7070
	"_MS_CURON",	// 7071
	"_MS_CUROF",	// 7072
	"_MS_STAT",		// 7073
	"_MS_GETDT",	// 7074
	"_MS_CURGT",	// 7075
	"_MS_CURST",	// 7076
	"_MS_LIMIT",	// 7077
	"_MS_OFFTM",	// 7078
	"_MS_ONTM",		// 7079
	"_MS_PATST",	// 707a
	"_MS_SEL",		// 707b
	"_MS_SEL2",		// 707c
	"_SKEY_MOD",	// 707d
	"_DENSNS",		// 707e
	"_ONTIME",		// 707f

	"_B_INTVCS",	// 7080
	"_B_SUPER",		// 7081
	"_B_BPEEK",		// 7082
	"_B_WPEEK",		// 7083
	"_B_LPEEK",		// 7084
	"_B_MEMSTR",	// 7085
	"_B_BPOKE",		// 7086
	"_B_WPOKE",		// 7087
	"_B_LPOKE",		// 7088
	"_B_MEMSET",	// 7089
	"_DMAMOVE",		// 708a
	"_DMAMOV_A",	// 708b
	"_DMAMOV_L",	// 708c
	"_DMAMODE",		// 708d
	"_BOOTINF",		// 708e
	"_ROMVER",		// 708f

	"_G_CLR_ON",	// 7090
	NULL,			// 7091
	NULL,			// 7092
	NULL,			// 7093
	"_GPALET",		// 7094
	NULL,			// 7095
	NULL,			// 7096
	NULL,			// 7097
	NULL,			// 7098
	NULL,			// 7099
	NULL,			// 709a
	NULL,			// 709b
	NULL,			// 709c
	NULL,			// 709d
	NULL,			// 709e
	NULL,			// 709f

	"_SFTJIS",		// 70a0
	"_JISSFT",		// 70a1
	"_AKCONV",		// 70a2
	"_RMACNV",		// 70a3
	"_DAKJOB",		// 70a4
	"_HANJOB",		// 70a5
	NULL,			// 70a6
	NULL,			// 70a7
	NULL,			// 70a8
	NULL,			// 70a9
	NULL,			// 70aa
	NULL,			// 70ab
	"_SYS_STAT",	// 70ac
	"_B_CONMOD",	// 70ad
	"_OS_CURON",	// 70ae
	"_OS_CUROF",	// 70af

	"_DRAWMODE",	// 70b0
	"_APAGE",		// 70b1
	"_VPAGE",		// 70b2
	"_HOME",		// 70b3
	"_WINDOW",		// 70b4
	"_WIPE",		// 70b5
	"_PSET",		// 70b6
	"_POINT",		// 70b7
	"_LINE",		// 70b8
	"_BOX",			// 70b9
	"_FILL",		// 70ba
	"_CIRCLE",		// 70bb
	"_PAINT",		// 70bc
	"_SYMBOL",		// 70bd
	"_GETGRM",		// 70be
	"_PUTGRM",		// 70bf

	"_SP_INIT",		// 70c0
	"_SP_ON",		// 70c1
	"_SP_OFF",		// 70c2
	"_SP_CGCLR",	// 70c3
	"_SP_DEFCG",	// 70c4
	"_SP_GTPCG",	// 70c5
	"_SP_REGST",	// 70c6
	"_SP_REGGT",	// 70c7
	"_BGSCRLST",	// 70c8
	"_BGSCRLGT",	// 70c9
	"_BGCTRLST",	// 70ca
	"_BGCTRLGT",	// 70cb
	"_BGTEXTCL",	// 70cc
	"_BGTEXTST",	// 70cd
	"_BGTEXTGT",	// 70ce
	"_SPALET",		// 70cf

	NULL,			// 70d0
	NULL,			// 70d1
	NULL,			// 70d2
	"_TXXLINE",		// 70d3
	"_TXYLINE",		// 70d4
	"_TXLINE",		// 70d5
	"_TXBOX",		// 70d6
	"_TXFILL",		// 70d7
	"_TXREV",		// 70d8
	NULL,			// 70d9
	NULL,			// 70da
	NULL,			// 70db
	NULL,			// 70dc
	NULL,			// 70dd
	NULL,			// 70de
	"_TXRASCPY",	// 70df

	NULL,			// 70e0
	NULL,			// 70e1
	NULL,			// 70e2
	NULL,			// 70e3
	NULL,			// 70e4
	NULL,			// 70e5
	NULL,			// 70e6
	NULL,			// 70e7
	NULL,			// 70e8
	NULL,			// 70e9
	NULL,			// 70ea
	NULL,			// 70eb
	NULL,			// 70ec
	NULL,			// 70ed
	NULL,			// 70ee
	NULL,			// 70ef

	"_OPMDRV",		// 70f0
	"_RSDRV",		// 70f1
	"_A_JOYGET",	// 70f2
	"_MUSICDRV",	// 70f3
	NULL,			// 70f4
	"_SCSIDRV",		// 70f5
	NULL,			// 70f6
	NULL,			// 70f7
	NULL,			// 70f8
	NULL,			// 70f9
	NULL,			// 70fa
	NULL,			// 70fb
	NULL,			// 70fc
	"_ABORTRST",	// 70fd
	"_IPLERR",		// 70fe
	"_ABORTJOB",	// 70ff
};

// ここから命令

// %0000_000000_mmmrrr	ORI.B #<imm>,<ea>
// %0000_000000_111100	ORI.B #<imm>,CCR
OP_DEF(ori_b)
{
	name = "ori";
	size = Size::B;
	src = imm8();
	if ((ir[0] & 0x3f) == 0x3c) {
		dst = make_reg(Reg::CCR);
	} else {
		dst = make_ea();
	}
}

// %0000_000001_mmmrrr	ORI.W #<imm>,<ea>
// %0000_000001_111100	ORI.W #<imm>,SR
OP_DEF(ori_w)
{
	name = "ori";
	size = Size::W;
	src = imm16();
	if ((ir[0] & 0x3f) == 0x3c) {
		dst = make_reg(Reg::SR);
	} else {
		dst = make_ea();
	}
}

// %0000_000010_mmmrrr	ORI.L #<imm>,<ea>
OP_DEF(ori_l)
{
	name = "ori";
	size = Size::L;
	src = imm32();
	dst = make_ea();
}

void
Disasm::ops_cmp2chk2(Disasm::Size sz)
{
	fetch16();
	if ((ir[1] & 0x0800) == 0) {
		// CMP2.[BWL] <ea>,Rn
		name = "cmp2";
	} else {
		// CHK2.[BWL] <ea>,Rn
		name = "chk2";
	}
	size = sz;
	src = make_ea();
	dst = make_rn(ir[1] >> 12);
}

// %0000_000011_mmmrrr	CMP2/CHK2.B <ea>,Rn
OP_DEF(cmp2chk2_b)
{
	ops_cmp2chk2(Size::B);
}

// B{TST,CHG,CLR,SET} と MOVEP のメイン部分
void
Disasm::ops_btst_movep()
{
	uint mr = (ir[0] >> 3) & 7;
	uint op = (ir[0] >> 6) & 3;

	if (mr == 0) {
		// B***.L Dx,Dy
		name = btst_names[op];
		size = Size::L;
		src = make_dn(ir[0] >> 9);
		dst = make_dn(ir[0]);
	} else if (mr == 1) {
		// MOVEP
		ops_movep();
	} else {
		// B***.B Dx,<ea>
		name = btst_names[op];
		size = Size::B;
		src = make_dn(ir[0] >> 9);
		dst = make_ea();
	}
}

// MOVEP
void
Disasm::ops_movep()
{
	name = "movep";
	uint mode = (ir[0] >> 6) & 3;
	__assume(mode <= 3);
	switch (mode) {
	 case 0:	// MOVEP.W (d,Ay),Dx
		size = Size::W;
		src = "(" + addr16() + "," + make_an(ir[0]) + ")";
		dst = make_dn(ir[0] >> 9);
		break;
	 case 1:	// MOVEP.L (d,Ay),Dx
		size = Size::L;
		src = "(" + addr16() + "," + make_an(ir[0]) + ")";
		dst = make_dn(ir[0] >> 9);
		break;
	 case 2:	// MOVEP.W Dx,(d,Ay)
		size = Size::W;
		src = make_dn(ir[0] >> 9);
		dst = "(" + addr16() + "," + make_an(ir[0]) + ")";
		break;
	 case 3:	// MOVEP.L Dx,(d,Ay)
		size = Size::L;
		src = make_dn(ir[0] >> 9);
		dst = "(" + addr16() + "," + make_an(ir[0]) + ")";
		break;
	}
}

// %0000_xxx100_000yyy	BTST.L Dx,Dy
// %0000_xxx100_001yyy	MOVEP.W (d,Ay),Dx
// %0000_xxx100_mmmrrr	BTST.B Dx,<ea>
OP_DEF(btst_dn_ea)
{
	ops_btst_movep();
}

// %0000_xxx101_000yyy	BCHG.L Dx,Dy
// %0000_xxx101_001yyy	MOVEP.L (d,Ay),Dx
// %0000_xxx101_mmmrrr	BCHG.B Dx,<ea>
OP_DEF(bchg_dn_ea)
{
	ops_btst_movep();
}

// %0000_xxx110_000yyy	BCLR.L Dx,Dy
// %0000_xxx110_001yyy	MOVEP.W Dx,(d,Ay)
// %0000_xxx110_mmmrrr	BCLR.B Dx,<ea>
OP_DEF(bclr_dn_ea)
{
	ops_btst_movep();
}

// %0000_xxx111_000yyy	BSET.L Dx,Dy
// %0000_xxx111_001yyy	MOVEP.L Dx,(d,Ay)
// %0000_xxx111_mmmrrr	BSET.B Dx,<ea>
OP_DEF(bset_dn_ea)
{
	ops_btst_movep();
}

// %0000_001000_mmmrrr	ANDI.B #<imm>,<ea>
// %0000_001000_111100	ANDI.B #<imm>,CCR
OP_DEF(andi_b)
{
	name = "andi";
	size = Size::B;
	src = imm8();
	if ((ir[0] & 0x3f) == 0x3c) {
		dst = make_reg(Reg::CCR);
	} else {
		dst = make_ea();
	}
}

// %0000_001001_mmmrrr	ANDI.W #<imm>,<ea>
// %0000_001001_111100	ANDI.W #<imm>,SR
OP_DEF(andi_w)
{
	name = "andi";
	size = Size::W;
	src = imm16();
	if ((ir[0] & 0x3f) == 0x3c) {
		dst = make_reg(Reg::SR);
	} else {
		dst = make_ea();
	}
}

// %0000_001010_mmmrrr	ANDI.L #<imm>,<ea>
OP_DEF(andi_l)
{
	name = "andi";
	size = Size::L;
	src = imm32();
	dst = make_ea();
}

// %0000_001011_mmmrrr	CMP2/CHK2.W <ea>,Rn
OP_DEF(cmp2chk2_w)
{
	ops_cmp2chk2(Size::W);
}

// %0000_010000_mmmrrr	SUBI.B #<imm>,<ea>
OP_DEF(subi_b)
{
	name = "subi";
	size = Size::B;
	src = imm8();
	dst = make_ea();
}

// %0000_010001_mmmrrr	SUBI.W #<imm>,<ea>
OP_DEF(subi_w)
{
	name = "subi";
	size = Size::W;
	src = imm16();
	dst = make_ea();
}

// %0000_010010_mmmrrr	SUBI.L #<imm>,<ea>
OP_DEF(subi_l)
{
	name = "subi";
	size = Size::L;
	src = imm32();
	dst = make_ea();
}

// %0000_010011_mmmrrr	CMP2/CHK2.L <ea>,Rn
OP_DEF(cmp2chk2_l)
{
	ops_cmp2chk2(Size::L);
}

// %0000_011000_mmmrrr	ADDI.B #<imm>,<ea>
OP_DEF(addi_b)
{
	name = "addi";
	size = Size::B;
	src = imm8();
	dst = make_ea();
}

// %0000_011001_mmmrrr	ADDI.W #<imm>,<ea>
OP_DEF(addi_w)
{
	name = "addi";
	size = Size::W;
	src = imm16();
	dst = make_ea();
}

// %0000_011010_mmmrrr	ADDI.L #<imm>,<ea>
OP_DEF(addi_l)
{
	name = "addi";
	size = Size::L;
	src = imm32();
	dst = make_ea();
}

// BTST,BCHG,BCLR,BSET #<imm>,<ea> の共通部分。
void
Disasm::ops_btst_imm_ea()
{
	uint n = ir[0] & 0x3f;
	uint op = (ir[0] >> 6) & 3;

	fetch16();
	name = btst_names[op];
	if (n < 8) {
		size = Size::L;
		src = string_format("#%d", ir[1] & 31);
		dst = make_dn(n);
	} else {
		size = Size::B;
		src = string_format("#%d", ir[1] & 7);
		dst = make_ea();
	}
}

// %0000_100000_000yyy	BTST.L #<imm>,Dy
// %0000_100000_mmmrrr	BTST.B #<imm>,<ea>
OP_DEF(btst_imm_ea)
{
	ops_btst_imm_ea();
}

// %0000_100001_000yyy	BCHG.L #<imm>,Dy
// %0000_100001_mmmrrr	BCHG.B #<imm>,<ea>
OP_DEF(bchg_imm_ea)
{
	ops_btst_imm_ea();
}

// %0000_100010_000yyy	BCLR.L #<imm>,Dy
// %0000_100010_mmmrrr	BCLR.B #<imm>,<ea>
OP_DEF(bclr_imm_ea)
{
	ops_btst_imm_ea();
}

// %0000_100011_000yyy	BSET.L #<imm>,Dy
// %0000_100011_mmmrrr	BSET.B #<imm>,<ea>
OP_DEF(bset_imm_ea)
{
	ops_btst_imm_ea();
}

// %0000_101000_mmmrrr	EORI.B #<imm>,<ea>
// %0000_101000_111100	EORI.B #<imm>,CCR
OP_DEF(eori_b)
{
	name = "eori";
	size = Size::B;
	src = imm8();
	if ((ir[0] & 0x3f) == 0x3c) {
		dst = make_reg(Reg::CCR);
	} else {
		dst = make_ea();
	}
}

// %0000_101001_mmmrrr	EORI.W #<imm>,<ea>
// %0000_101001_111100	EORI.W #<imm>,SR
OP_DEF(eori_w)
{
	name = "eori";
	size = Size::W;
	src = imm16();
	if ((ir[0] & 0x3f) == 0x3c) {
		dst = make_reg(Reg::SR);
	} else {
		dst = make_ea();
	}
}

// %0000_101010_mmmrrr	EORI.L #<imm>,<ea>
OP_DEF(eori_l)
{
	name = "eori";
	size = Size::L;
	src = imm32();
	dst = make_ea();
}

// CAS の共通部分
void
Disasm::ops_cas(Disasm::Size sz)
{
	fetch16();

	name = "cas";
	size = sz;
	uint dc = ir[1];
	uint du = ir[1] >> 6;
	src = make_dn(dc) + "," + make_dn(du);
	dst = make_ea();
}

// CAS2 の共通部分
void
Disasm::ops_cas2(Disasm::Size sz)
{
	name = "cas2";
	size = sz;
	fetch16();
	uint dc1 = ir[1] & 7;
	uint du1 = ir[1] >> 6;
	uint rn1 = ir[1] >> 12;
	fetch16();
	uint dc2 = ir[2] & 7;
	uint du2 = ir[2] >> 6;
	uint rn2 = ir[2] >> 12;
	src = make_dn(dc1) + ":" + make_dn(dc2) + ","
	    + make_dn(du1) + ":" + make_dn(du2);
	dst = "(" + make_rn(rn1) + "):(" + make_rn(rn2) + ")";
}

// %0000_101011_mmmrrr	CAS.B Dc,Du,<ea>
OP_DEF(cas_b)
{
	ops_cas(Size::B);
}

// %0000_110000_mmmrrr	CMPI.B #<imm>,<ea>
OP_DEF(cmpi_b)
{
	name = "cmpi";
	size = Size::B;
	src = imm8();
	dst = make_ea();
}

// %0000_110001_mmmrrr	CMPI.W #<imm>,<ea>
OP_DEF(cmpi_w)
{
	name = "cmpi";
	size = Size::W;
	src = imm16();
	dst = make_ea();
}

// %0000_110010_mmmrrr	CMPI.L #<imm>,<ea>
OP_DEF(cmpi_l)
{
	name = "cmpi";
	size = Size::L;
	src = imm32();
	dst = make_ea();
}

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

	if (n == 0x3c) {
		// CAS2.W Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
		ops_cas2(Size::W);
	} else {
		// CAS.W Dc,Du,<ea>
		ops_cas(Size::W);
	}
}

// MOVES の共通部分
void
Disasm::ops_moves(Disasm::Size sz)
{
	fetch16();

	name = "moves";
	size = sz;
	if ((ir[1] & 0x0800) == 0) {
		// MOVES <ea>,Rn
		src = make_ea();
		dst = make_rn(ir[1] >> 12);
	} else {
		// MOVES Rn,<ea>
		src = make_rn(ir[1] >> 12);
		dst = make_ea();
	}
}

// %0000_111000_mmmrrr	MOVES.B <ea>,Rn
OP_DEF(moves_b)
{
	ops_moves(Size::B);
}

// %0000_111001_mmmrrr	MOVES.W <ea>,Rn
OP_DEF(moves_w)
{
	ops_moves(Size::W);
}

// %0000_111010_mmmrrr	MOVES.L <ea>,Rn
OP_DEF(moves_l)
{
	ops_moves(Size::L);
}

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

	if (n == 0x3c) {
		// CAS2.L Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
		ops_cas2(Size::L);
	} else {
		// CAS.L Dc,Du,<ea>
		ops_cas(Size::L);
	}
}

// MOVE.{BWL} <src>,<dst> の共通部分
void
Disasm::ops_move(Disasm::Size sz)
{
	name = "move";
	size = sz;
	src = make_ea();
	uint dstea = ((ir[0] >> 9) & 7) | ((ir[0] >> 3) & 0x38);
	dst = make_ea(dstea);
}

// %0001_xxx000_mmmrrr	MOVE.B <ea>,Dx
OP_DEF(move_b_ea_dn)
{
	ops_move(Size::B);
}

// %0001_xxx010_mmmrrr	MOVE.B <ea>,(Ax)
OP_DEF(move_b_ea_anin)
{
	ops_move(Size::B);
}

// %0001_xxx011_mmmrrr	MOVE.B <ea>,(Ax)+
OP_DEF(move_b_ea_anpi)
{
	ops_move(Size::B);
}

// %0001_xxx100_mmmrrr	MOVE.B <ea>,-(Ax)
OP_DEF(move_b_ea_anpd)
{
	ops_move(Size::B);
}

// %0001_xxx101_mmmrrr	MOVE.B <ea>,d16(Ax)
OP_DEF(move_b_ea_andi)
{
	ops_move(Size::B);
}

// %0001_xxx110_mmmrrr	MOVE.B <ea>,(Ax,IX)
OP_DEF(move_b_ea_anix)
{
	ops_move(Size::B);
}

// %0001_000111_mmmrrr	MOVE.B <ea>,Abs.W
OP_DEF(move_b_ea_absw)
{
	ops_move(Size::B);
}

// %0001_001111_mmmrrr	MOVE.B <ea>,Abs.L
OP_DEF(move_b_ea_absl)
{
	ops_move(Size::B);
}

// %0010_xxx000_mmmrrr	MOVE.L <ea>,Dx
OP_DEF(move_l_ea_dn)
{
	ops_move(Size::L);
}

// %0010_xxx001_mmmrrr	MOVEA.L <ea>,Ax
OP_DEF(movea_l)
{
	name = "movea";
	size = Size::L;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

// %0010_xxx010_mmmrrr	MOVE.L <ea>,(Ax)
OP_DEF(move_l_ea_anin)
{
	ops_move(Size::L);
}

// %0010_xxx011_mmmrrr	MOVE.L <ea>,(Ax)+
OP_DEF(move_l_ea_anpi)
{
	ops_move(Size::L);
}

// %0010_xxx100_mmmrrr	MOVE.L <ea>,-(Ax)
OP_DEF(move_l_ea_anpd)
{
	ops_move(Size::L);
}

// %0010_xxx101_mmmrrr	MOVE.L <ea>,d16(Ax)
OP_DEF(move_l_ea_andi)
{
	ops_move(Size::L);
}

// %0010_xxx110_mmmrrr	MOVE.L <ea>,(Ax,IX)
OP_DEF(move_l_ea_anix)
{
	ops_move(Size::L);
}

// %0010_000111_mmmrrr	MOVE.L <ea>,Abs.W
OP_DEF(move_l_ea_absw)
{
	ops_move(Size::L);
}

// %0010_001111_mmmrrr	MOVE.L <ea>,Abs.L
OP_DEF(move_l_ea_absl)
{
	ops_move(Size::L);
}

// %0011_xxx000_mmmrrr	MOVE.W <ea>,Dx
OP_DEF(move_w_ea_dn)
{
	ops_move(Size::W);
}

// %0011_xxx001_mmmrrr	MOVEA.W <ea>,Ax
OP_DEF(movea_w)
{
	name = "movea";
	size = Size::W;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

// %0011_xxx010_mmmrrr	MOVE.W <ea>,(Ax)
OP_DEF(move_w_ea_anin)
{
	ops_move(Size::W);
}

// %0011_xxx011_mmmrrr	MOVE.W <ea>,(Ax)+
OP_DEF(move_w_ea_anpi)
{
	ops_move(Size::W);
}

// %0011_xxx100_mmmrrr	MOVE.W <ea>,-(Ax)
OP_DEF(move_w_ea_anpd)
{
	ops_move(Size::W);
}

// %0011_xxx101_mmmrrr	MOVE.W <ea>,d16(Ax)
OP_DEF(move_w_ea_andi)
{
	ops_move(Size::W);
}

// %0011_xxx110_mmmrrr	MOVE.W <ea>,(Ax,IX)
OP_DEF(move_w_ea_anix)
{
	ops_move(Size::W);
}

// %0011_000111_mmmrrr	MOVE.W <ea>,Abs.W
OP_DEF(move_w_ea_absw)
{
	ops_move(Size::W);
}

// %0011_001111_mmmrrr	MOVE.W <ea>,Abs.L
OP_DEF(move_w_ea_absl)
{
	ops_move(Size::W);
}

// %0100_000000_mmmrrr	NEGX.B <ea>
OP_DEF(negx_b)
{
	name = "negx";
	size = Size::B;
	src = make_ea();
}

// %0100_000001_mmmrrr	NEGX.W <ea>
OP_DEF(negx_w)
{
	name = "negx";
	size = Size::W;
	src = make_ea();
}

// %0100_000010_mmmrrr	NEGX.L <ea>
OP_DEF(negx_l)
{
	name = "negx";
	size = Size::L;
	src = make_ea();
}

// %0100_000011_mmmrrr	MOVE.W SR,<ea>
OP_DEF(move_sr_ea)
{
	name = "move";
	size = Size::W;
	src = make_reg(Reg::SR);
	dst = make_ea();
}

// %0100_xxx100_mmmrrr	CHK.L <ea>,Dx
OP_DEF(chk_l)
{
	name = "chk";
	size = Size::L;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %0100_xxx110_mmmrrr	CHK.W <ea>,Dx
OP_DEF(chk_w)
{
	name = "chk";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %0100_xxx111_mmmrrr	LEA.L <ea>,Ax
// %0100_100111_000yyy	EXTB.L Dy
OP_DEF(lea)
{
	uint n = ir[0] & 0x3f;
	uint x = (ir[0] >> 9) & 7;
	if (n < 8) {
		if (x == 4) {
			// EXTB.L Dy
			name = "extb";
			size = Size::L;
			src = make_dn(ir[0]);
		} else {
			OP_FUNC(illegal);
		}
	} else {
		// LEA.L <ea>,Ax
		name = "lea";
		size = Size::L;
		src = make_ea();
		dst = make_an(x);
	}
}

// %0100_001000_mmmrrr	CLR.B <ea>
OP_DEF(clr_b)
{
	name = "clr";
	size = Size::B;
	src = make_ea();
}

// %0100_001001_mmmrrr	CLR.W <ea>
OP_DEF(clr_w)
{
	name = "clr";
	size = Size::W;
	src = make_ea();
}

// %0100_001010_mmmrrr	CLR.L <ea>
OP_DEF(clr_l)
{
	name = "clr";
	size = Size::L;
	src = make_ea();
}

// %0100_001011_mmmrrr	MOVE.W CCR,<ea>
OP_DEF(move_ccr_ea)
{
	// MOVE to/from CCR のサイズは .W
	name = "move";
	size = Size::W;
	src = make_reg(Reg::CCR);
	dst = make_ea();
}

// %0100_010000_mmmrrr	NEG.B <ea>
OP_DEF(neg_b)
{
	name = "neg";
	size = Size::B;
	src = make_ea();
}

// %0100_010001_mmmrrr	NEG.W <ea>
OP_DEF(neg_w)
{
	name = "neg";
	size = Size::W;
	src = make_ea();
}

// %0100_010010_mmmrrr	NEG.L <ea>
OP_DEF(neg_l)
{
	name = "neg";
	size = Size::L;
	src = make_ea();
}

// %0100_010011_mmmrrr	MOVE.W <ea>,CCR
OP_DEF(move_ea_ccr)
{
	// MOVE to/from CCR のサイズは .W
	name = "move";
	size = Size::W;
	src = make_ea();
	dst = make_reg(Reg::CCR);
}

// %0100_011000_mmmrrr	NOT.B <ea>
OP_DEF(not_b)
{
	name = "not";
	size = Size::B;
	src = make_ea();
}

// %0100_011001_mmmrrr	NOT.W <ea>
OP_DEF(not_w)
{
	name = "not";
	size = Size::W;
	src = make_ea();
}

// %0100_011010_mmmrrr	NOT.L <ea>
OP_DEF(not_l)
{
	name = "not";
	size = Size::L;
	src = make_ea();
}

// %0100_011011_mmmrrr	MOVE.W <ea>,SR
OP_DEF(move_ea_sr)
{
	name = "move";
	size = Size::W;
	src = make_ea();
	dst = make_reg(Reg::SR);
}

// %0100_100000_mmmrrr	NBCD.B <ea>
// %0100_100000_001yyy	LINK.L Ay,#<imm>
OP_DEF(nbcd)
{
	uint mm = (ir[0] >> 3) & 7;

	if (mm == 1) {
		// LINK.L Ay,#<imm>
		name = "link";
		size = Size::L;
		src = make_an(ir[0]);
		dst = "#" + disp32();
	} else {
		// NBCD.B <ea>
		name = "nbcd";
		size = Size::B;
		src = make_ea();
	}
}

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

	if (n < 8) {
		// SWAP.W Dy
		name = "swap";
		size = Size::W;
		src = make_dn(n);
	} else if (n < 16) {
		// BKPT #<imm>
		name = "bkpt";
		src = string_format("#%d", ir[0] & 7);
	} else {
		// PEA.L <ea>
		name = "pea";
		size = Size::L;
		src = make_ea();
	}
}

// MOVEM/EXT の共通部分
void
Disasm::ops_movem_ext(Disasm::Size sz)
{
	uint n = ir[0] & 0x3f;

	size = sz;
	if (n < 8) {
		// EXT.W Dy
		name = "ext";
		src = make_dn(ir[0]);
	} else {
		// MOVEM.W <list>,<ea>
		fetch16();
		name = "movem";
		src = make_reglist();
		dst = make_ea();
	}
}

// %0100_100010_000yyy	EXT.W Dy
// %0100_100010_mmmrrr	MOVEM.W <list>,<ea>
OP_DEF(movem_w_mem)
{
	ops_movem_ext(Size::W);
}

// %0100_100011_000yyy	EXT.L Dy
// %0100_100011_mmmrrr	MOVEM.L <list>,<ea>
OP_DEF(movem_l_mem)
{
	ops_movem_ext(Size::L);
}

// %0100_101000_mmmrrr	TST.B <ea>
OP_DEF(tst_b)
{
	name = "tst";
	size = Size::B;
	src = make_ea();
}

// %0100_101001_mmmrrr	TST.W <ea>
OP_DEF(tst_w)
{
	name = "tst";
	size = Size::W;
	src = make_ea();
}

// %0100_101010_mmmrrr	TST.L <ea>
OP_DEF(tst_l)
{
	name = "tst";
	size = Size::L;
	src = make_ea();
}

// %0100_101011_mmmrrr	TAS.B <ea>
// %0100_101011_111100	ILLEGAL
OP_DEF(tas)
{
	uint n = ir[0] & 0x3f;
	if (n == 0x3c) {
		// ILLEGAL
		name = "illegal";
	} else {
		// TAS.B <ea>
		name = "tas";
		size = Size::B;
		src = make_ea();
	}
}

// %0100_110000_mmmrrr	MUL{U,S}.L <ea>,Dl
OP_DEF(mul)
{
	fetch16();

	if ((ir[1] & 0x0800) == 0) {
		name = "mulu";
	} else {
		name = "muls";
	}
	size = Size::L;
	src = make_ea();
	if ((ir[1] & 0x0400) == 0) {
		dst = make_dn(ir[1] >> 12);
	} else {
		dst = make_dn(ir[1]) + ":" + make_dn(ir[1] >> 12);
	}
}

// %0100_110001_mmmrrr	DIV{U,UL,S,SL}.L <ea>,Dq
OP_DEF(div)
{
	fetch16();

	if ((ir[1] & 0x0800) == 0) {
		name = "divu";
	} else {
		name = "divs";
	}
	size = Size::L;
	src = make_ea();
	uint dr = ir[1] & 7;
	uint dq = (ir[1] >> 12) & 7;
	if ((ir[1] & 0x0400) == 0) {
		if (dr == dq) {
			dst = make_dn(dr);
		} else {
			dst = make_dn(dr) + ":" + make_dn(dq);
		}
	} else {
		name += "l";
		dst = make_dn(dr) + ":" + make_dn(dq);
	}
}

// %0100_110010_mmmrrr	MOVEM.W <ea>,<list>
OP_DEF(movem_w)
{
	fetch16();
	name = "movem";
	size = Size::W;
	src = make_ea();
	dst = make_reglist();
}

// %0100_110011_mmmrrr	MOVEM.L <ea>,<list>
OP_DEF(movem_l)
{
	fetch16();
	name = "movem";
	size = Size::L;
	src = make_ea();
	dst = make_reglist();
}

// %0100_111001_00nnnn	TRAP #<vector>
// %0100_111001_010yyy	LINK.W Ay,#<imm>
// %0100_111001_011yyy	UNLK Ay
// %0100_111001_100yyy	MOVE.L Ay,USP
// %0100_111001_101yyy	MOVE.L USP,Ay
// %0100_111001_110000	RESET
// %0100_111001_110001	NOP
// %0100_111001_110010	STOP #<imm>
// %0100_111001_110011	RTE
// %0100_111001_110100	RTD #<imm>
// %0100_111001_110101	RTS
// %0100_111001_110110	TRAPV
// %0100_111001_110111	RTR
// %0100_111001_111010	MOVEC.L Rc,Rn
// %0100_111001_111011	MOVEC.L Rn,Rc
OP_DEF(trap)
{
	uint n = ir[0] & 0x3f;
	switch (n) {
	 case 0x00 ... 0x0f:	// TRAP #<vector>
		name = "trap";
		src = string_format("#%d", n);
		break;
	 case 0x10 ... 0x17:	// LINK.W Ay,#<imm>
		name = "link";
		size = Size::W;
		src = make_an(ir[0]);
		dst = "#" + disp16();
		break;
	 case 0x18 ... 0x1f:	// UNLK Ay
		name = "unlk";
		src = make_an(ir[0]);
		break;
	 case 0x20 ... 0x27:	// MOVE.L Ay,USP
		name = "move";
		size = Size::L;
		src = make_an(ir[0]);
		dst = make_reg(Reg::USP);
		break;
	 case 0x28 ... 0x2f:	// MOVE.L USP,Ay
		name = "move";
		size = Size::L;
		src = make_reg(Reg::USP);
		dst = make_an(ir[0]);
		break;
	 case 0x30:				// RESET
		name = "reset";
		break;
	 case 0x31:				// NOP
		name = "nop";
		break;
	 case 0x32:				// STOP #<imm>
		name = "stop";
		src = imm16();
		break;
	 case 0x33:				// RTE
		name = "rte";
		break;
	 case 0x34:				// RTD #<imm>
		name = "rtd";
		src = imm16();
		break;
	 case 0x35:				// RTS
		name = "rts";
		break;
	 case 0x36:				// TRAPV
		name = "trapv";
		break;
	 case 0x37:				// RTR
		name = "rtr";
		break;
	 case 0x3a:				// MOVEC.L Rc,Rn
		fetch16();
		name = "movec";
		size = Size::L;
		src = make_movec();
		dst = make_rn(ir[1] >> 12);
		break;
	 case 0x3b:				// MOVEC.L Rn,Rc
		fetch16();
		name = "movec";
		size = Size::L;
		src = make_rn(ir[1] >> 12);
		dst = make_movec();
		break;
	 default:
		OP_FUNC(illegal);
		break;
	}
}

// %0100_111010_mmmrrr	JSR <ea>
OP_DEF(jsr)
{
	name = "jsr";
	src = make_ea();
}

// %0100_111011_mmmrrr	JMP <ea>
OP_DEF(jmp)
{
	name = "jmp";
	src = make_ea();
}

// %0101_qqq000_mmmrrr	ADDQ.B #qqq,<ea>
OP_DEF(addq_b)
{
	name = "addq";
	size = Size::B;
	src = make_q8();
	dst = make_ea();
}

// %0101_qqq001_mmmrrr	ADDQ.W #qqq,<ea>
// %0101_qqq001_001yyy	ADDQ.W #qqq,Ay (.Lと等価)
OP_DEF(addq_w)
{
	// ニーモニック上は ADDQ.W #q,Ay を分ける必要はない
	name = "addq";
	size = Size::W;
	src = make_q8();
	dst = make_ea();
}

// %0101_qqq010_mmmrrr	ADDQ.L #qqq,<ea>
// %0101_qqq010_001yyy	ADDQ.L #qqq,Ay
OP_DEF(addq_l)
{
	// ニーモニック上は ADDQ.L #q,Ay を分ける必要はない
	name = "addq";
	size = Size::L;
	src = make_q8();
	dst = make_ea();
}

// Scc/SF のメイン部分。
void
Disasm::ops_scc()
{
	uint n = ir[0] & 0x3f;
	uint cc = (ir[0] >> 8) & 15;
	switch (n) {
	 case 0x00 ... 0x07:	// Scc.B Dn
	 case 0x10 ... 0x39:	// Scc.B <ea>
		name = "s";
		name += conditions[cc];
		size = Size::B;
		src = make_ea();
		break;
	 case 0x08 ... 0x0f:	// DBcc.W Dy,<label>
		if (cc == 1) {
			name = "dbra";
		} else {
			name = "db";
			name += conditions[cc];
		}
		size = Size::W;
		src = make_dn(ir[0]);
		dst = addr32(pc0 + 2 + (int32)(int16)fetch16());
		break;
	 case 0x3a:				// TRAPcc.W #<imm>
		name = "trap";
		name += conditions[cc];
		size = Size::W;
		src = imm16();
		break;
	 case 0x3b:				// TRAPcc.L #<imm>
		name = "trap";
		name += conditions[cc];
		size = Size::L;
		src = imm32();
		break;
	 case 0x3c:				// TRAPcc
		name = "trap";
		name += conditions[cc];
		break;

	 default:
		OP_FUNC(illegal);
		break;
	}
}

// %0101_000011_mmmrrr	ST.B <ea>
// %0101_000011_001yyy	DBT.W Dy,<label>
// %0101_000011_111010	TRAPT.W #<imm>
// %0101_000011_111011	TRAPT.L #<imm>
// %0101_000011_111100	TRAPT
OP_DEF(st)
{
	ops_scc();
}

// %0101_qqq100_mmmrrr	SUBQ.B #qqq,<ea>
OP_DEF(subq_b)
{
	name = "subq";
	size = Size::B;
	src = make_q8();
	dst = make_ea();
}

// %0101_qqq101_mmmrrr	SUBQ.W #qqq,<ea>
// %0101_qqq101_001yyy	SUBQ.W #qqq,Ay (.Lと等価)
OP_DEF(subq_w)
{
	// ニーモニック上は SUBQ.W #q,Ay を分ける必要はない
	name = "subq";
	size = Size::W;
	src = make_q8();
	dst = make_ea();
}

// %0101_qqq110_mmmrrr	SUBQ.L #qqq,<ea>
// %0101_qqq110_001yyy	SUBQ.L #qqq,Ay
OP_DEF(subq_l)
{
	// ニーモニック上は SUBQ.L #q,Ay を分ける必要はない
	name = "subq";
	size = Size::L;
	src = make_q8();
	dst = make_ea();
}

// %0101_000111_mmmrrr	SF.B <ea>
// %0101_000111_001yyy	DBRA.W Dy,<label>
// %0101_000111_111010	TRAPF.W #<imm>
// %0101_000111_111011	TRAPF.L #<imm>
// %0101_000111_111100	TRAPF
OP_DEF(sf)
{
	ops_scc();
}

// %0101_001011_mmmrrr	SHI.B <ea>
// %0101_001011_001yyy	DBHI.W Dy,<label>
// %0101_001011_111010	TRAPHI.W #<imm>
// %0101_001011_111011	TRAPHI.L #<imm>
// %0101_001011_111100	TRAPHI
OP_DEF(shi)
{
	ops_scc();
}

// %0101_001111_mmmrrr	SLS.B <ea>
// %0101_001111_001yyy	DBLS.W Dy,<label>
// %0101_001111_111010	TRAPLS.W #<imm>
// %0101_001111_111011	TRAPLS.L #<imm>
// %0101_001111_111100	TRAPLS
OP_DEF(sls)
{
	ops_scc();
}

// %0101_010011_mmmrrr	SCC.B <ea>
// %0101_010011_001yyy	DBCC.W Dy,<label>
// %0101_010011_111010	TRAPCC.W #<imm>
// %0101_010011_111011	TRAPCC.L #<imm>
// %0101_010011_111100	TRAPCC
OP_DEF(scc)
{
	ops_scc();
}

// %0101_010111_mmmrrr	SCS.B <ea>
// %0101_010111_001yyy	DBCS.W Dy,<label>
// %0101_010111_111010	TRAPCS.W #<imm>
// %0101_010111_111011	TRAPCS.L #<imm>
// %0101_010111_111100	TRAPCS
OP_DEF(scs)
{
	ops_scc();
}

// %0101_011011_mmmrrr	SNE.B <ea>
// %0101_011011_001yyy	DBNE.W Dy,<label>
// %0101_011011_111010	TRAPNE.W #<imm>
// %0101_011011_111011	TRAPNE.L #<imm>
// %0101_011011_111100	TRAPNE
OP_DEF(sne)
{
	ops_scc();
}

// %0101_011111_mmmrrr	SEQ.B <ea>
// %0101_011111_001yyy	DBEQ.W Dy,<label>
// %0101_011111_111010	TRAPEQ.W #<imm>
// %0101_011111_111011	TRAPEQ.L #<imm>
// %0101_011111_111100	TRAPEQ
OP_DEF(seq)
{
	ops_scc();
}

// %0101_100011_mmmrrr	SVC.B <ea>
// %0101_100011_001yyy	DBVC.W Dy,<label>
// %0101_100011_111010	TRAPVC.W #<imm>
// %0101_100011_111011	TRAPVC.L #<imm>
// %0101_100011_111100	TRAPVC
OP_DEF(svc)
{
	ops_scc();
}

// %0101_100111_mmmrrr	SVS.B <ea>
// %0101_100111_001yyy	DBVS.W Dy,<label>
// %0101_100111_111010	TRAPVS.W #<imm>
// %0101_100111_111011	TRAPVS.L #<imm>
// %0101_100111_111100	TRAPVS
OP_DEF(svs)
{
	ops_scc();
}

// %0101_101011_mmmrrr	SPL.B <ea>
// %0101_101011_001yyy	DBPL.W Dy,<label>
// %0101_101011_111010	TRAPPL.W #<imm>
// %0101_101011_111011	TRAPPL.L #<imm>
// %0101_101011_111100	TRAPPL
OP_DEF(spl)
{
	ops_scc();
}

// %0101_101111_mmmrrr	SMI.B <ea>
// %0101_101111_001yyy	DBMI.W Dy,<label>
// %0101_101111_111010	TRAPMI.W #<imm>
// %0101_101111_111011	TRAPMI.L #<imm>
// %0101_101111_111100	TRAPMI
OP_DEF(smi)
{
	ops_scc();
}

// %0101_110011_mmmrrr	SGE.B <ea>
// %0101_110011_001yyy	DBGE.W Dy,<label>
// %0101_110011_111010	TRAPGE.W #<imm>
// %0101_110011_111011	TRAPGE.L #<imm>
// %0101_110011_111100	TRAPGE
OP_DEF(sge)
{
	ops_scc();
}

// %0101_110111_mmmrrr	SLT.B <ea>
// %0101_110111_001yyy	DBLT.W Dy,<label>
// %0101_110111_111010	TRAPLT.W #<imm>
// %0101_110111_111011	TRAPLT.L #<imm>
// %0101_110111_111100	TRAPLT
OP_DEF(slt)
{
	ops_scc();
}

// %0101_111011_mmmrrr	SGT.B <ea>
// %0101_111011_001yyy	DBGT.W Dy,<label>
// %0101_111011_111010	TRAPGT.W #<imm>
// %0101_111011_111011	TRAPGT.L #<imm>
// %0101_111011_111100	TRAPGT
OP_DEF(sgt)
{
	ops_scc();
}

// %0101_111111_mmmrrr	SLE.B <ea>
// %0101_111111_001yyy	DBLE.W Dy,<label>
// %0101_111111_111010	TRAPLE.W #<imm>
// %0101_111111_111011	TRAPLE.L #<imm>
// %0101_111111_111100	TRAPLE
OP_DEF(sle)
{
	ops_scc();
}


// BRA/BSR/Bcc の共通部分。
void
Disasm::ops_bcc()
{
	uint cond = (ir[0] >> 8) & 0x0f;
	uint32 disp = ir[0] & 0xff;

	switch (cond) {
	 case 0:	name = "bra";	break;
	 case 1:	name = "bsr";	break;
	 default:
		name = "b";
		name += conditions[cond];
		break;
	}

	if (disp == 0) {
		// Bxx.W <label>
		size = Size::W;
		disp = (int32)(int16)fetch16();
	} else if (disp == 0xff) {
		// Bxx.L <label>
		size = Size::L;
		disp = (int32)fetch32();
	} else {
		// Bxx.B <label>
		size = Size::B;
		disp = (int32)(int8)disp;
	}
	src = addr32(pc0 + 2 + disp);
}

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

// %0110_000100_000000	BSR.W <label>
// %0110_0001nn_nnnnnn	BSR.B <label>
// %0110_000111_111111	BSR.L <label>
OP_DEF(bsr)
{
	ops_bcc();
}

// %0110_001000_000000	BHI.W <label>
// %0110_0010nn_nnnnnn	BHI.B <label>
// %0110_001011_111111	BHI.L <label>
OP_DEF(bhi)
{
	ops_bcc();
}

// %0110_001100_000000	BLS.W <label>
// %0110_0011nn_nnnnnn	BLS.B <label>
// %0110_001111_111111	BLS.L <label>
OP_DEF(bls)
{
	ops_bcc();
}

// %0110_010000_000000	BCC.W <label>
// %0110_0100nn_nnnnnn	BCC.B <label>
// %0110_010011_111111	BCC.L <label>
OP_DEF(bcc)
{
	ops_bcc();
}

// %0110_010100_000000	BCS.W <label>
// %0110_0101nn_nnnnnn	BCS.B <label>
// %0110_010111_111111	BCS.L <label>
OP_DEF(bcs)
{
	ops_bcc();
}

// %0110_011000_000000	BNE.W <label>
// %0110_0110nn_nnnnnn	BNE.B <label>
// %0110_011011_111111	BNE.L <label>
OP_DEF(bne)
{
	ops_bcc();
}

// %0110_011100_000000	BEQ.W <label>
// %0110_0111nn_nnnnnn	BEQ.B <label>
// %0110_011111_111111	BEQ.L <label>
OP_DEF(beq)
{
	ops_bcc();
}

// %0110_100000_000000	BVC.W <label>
// %0110_1000nn_nnnnnn	BVC.B <label>
// %0110_100011_111111	BVC.L <label>
OP_DEF(bvc)
{
	ops_bcc();
}

// %0110_100100_000000	BVS.W <label>
// %0110_1001nn_nnnnnn	BVS.B <label>
// %0110_100111_111111	BVS.L <label>
OP_DEF(bvs)
{
	ops_bcc();
}

// %0110_101000_000000	BPL.W <label>
// %0110_1010nn_nnnnnn	BPL.B <label>
// %0110_101011_111111	BPL.L <label>
OP_DEF(bpl)
{
	ops_bcc();
}

// %0110_101100_000000	BMI.W <label>
// %0110_1011nn_nnnnnn	BMI.B <label>
// %0110_101111_111111	BMI.L <label>
OP_DEF(bmi)
{
	ops_bcc();
}

// %0110_110000_000000	BGE.W <label>
// %0110_1100nn_nnnnnn	BGE.B <label>
// %0110_110011_111111	BGE.L <label>
OP_DEF(bge)
{
	ops_bcc();
}

// %0110_110100_000000	BLT.W <label>
// %0110_1101nn_nnnnnn	BLT.B <label>
// %0110_110111_111111	BLT.L <label>
OP_DEF(blt)
{
	ops_bcc();
}

// %0110_111000_000000	BGT.W <label>
// %0110_1110nn_nnnnnn	BGT.B <label>
// %0110_111011_111111	BGT.L <label>
OP_DEF(bgt)
{
	ops_bcc();
}

// %0110_111100_000000	BLE.W <label>
// %0110_1111nn_nnnnnn	BLE.B <label>
// %0110_111111_111111	BLE.L <label>
OP_DEF(ble)
{
	ops_bcc();
}

// %0111_xxx0nn_nnnnnn	MOVEQ.L #<imm>,Dx
OP_DEF(moveq)
{
	uint8 val = ir[0] & 0xff;

	// IOCS コールを表示する。XXX 機種判定はまだしてない
	// IOCS コールは大抵
	//  70NN moveq.l #nn,d0
	//  4e4f trap #15
	// という命令列になっているので、これを検出する。
	uint16 next = peek16();
	if (next == 0x4e4f) {
		// IOCS コールと確定したら TRAP のワードも取り出しておく
		fetch16();
		name = "IOCS";
		src = x68k_iocscall[(uint)val] ?: "<undefined>";
		return;
	}

	name = "moveq";
	size = Size::L;
	// 負数なら 32bit で書いてみるか
	if ((val & 0x80)) {
		src = "#" + hex32((int32)(int8)val);
	} else {
		src = "#" + hex8(val);
	}
	dst = make_dn(ir[0] >> 9);
}

// %1000_xxx000_mmmrrr	OR.B <ea>,Dx
OP_DEF(or_b_ea_dn)
{
	name = "or";
	size = Size::B;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1000_xxx001_mmmrrr	OR.W <ea>,Dx
OP_DEF(or_w_ea_dn)
{
	name = "or";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1000_xxx010_mmmrrr	OR.L <ea>,Dx
OP_DEF(or_l_ea_dn)
{
	name = "or";
	size = Size::L;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1000_xxx011_mmmrrr	DIVU.W <ea>,Dx
OP_DEF(divu_w)
{
	name = "divu";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

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

	if (n < 8) {
		// SBCD.B Dy,Dx
		name = "sbcd";
		size = Size::B;
		src = make_dn(n);
		dst = make_dn(x);
	} else if (n < 16) {
		// SBCD.B -(Ay),-(An)
		name = "sbcd";
		size = Size::B;
		src = make_anpd(n);
		dst = make_anpd(x);
	} else {
		// OR.B Dx,<ea>
		name = "or";
		size = Size::B;
		src = make_dn(x);
		dst = make_ea();
	}
}

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

	if (n < 8) {
		name = "pack";
		src = make_dn(n) + "," + make_dn(x);
		dst = imm16();
	} else if (n < 16) {
		name = "pack";
		src = make_anpd(n) + "," + make_anpd(x);
		dst = imm16();
	} else {
		// OR.W Dx,<ea>
		name = "or";
		size = Size::W;
		src = make_dn(x);
		dst = make_ea();
	}
}

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

	if (n < 8) {
		name = "unpk";
		src = make_dn(n) + "," + make_dn(x);
		dst = imm16();
	} else if (n < 16) {
		name = "unpk";
		src = make_anpd(n) + "," + make_anpd(x);
		dst = imm16();
	} else {
		// OR.L Dx,<ea>
		name = "or";
		size = Size::L;
		src = make_dn(x);
		dst = make_ea();
	}
}

// %1000_xxx111_mmmrrr	DIVS.W <ea>,Dx
OP_DEF(divs_w)
{
	name = "divs";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1001_xxx000_mmmrrr	SUB.B <ea>,Dx
OP_DEF(sub_b_ea_dn)
{
	name = "sub";
	size = Size::B;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1001_xxx001_mmmrrr	SUB.W <ea>,Dx
OP_DEF(sub_w_ea_dn)
{
	name = "sub";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1001_xxx010_mmmrrr	SUB.L <ea>,Dx
OP_DEF(sub_l_ea_dn)
{
	name = "sub";
	size = Size::L;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1001_xxx011_mmmrrr	SUBA.W <ea>,Ax
OP_DEF(suba_w)
{
	name = "suba";
	size = Size::W;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

// SUB の共通部分
void
Disasm::ops_sub(Disasm::Size sz)
{
	uint n = ir[0] & 0x3f;
	uint x = ir[0] >> 9;

	size = sz;
	if (n < 8) {
		// SUBX.B Dy,Dx
		name = "subx";
		src = make_dn(n);
		dst = make_dn(x);
	} else if (n < 16) {
		// SUBX.B -(Ay),-(Ax)
		name = "subx";
		src = make_anpd(n);
		dst = make_anpd(x);
	} else {
		// SUB.B Dx,<ea>
		name = "sub";
		src = make_dn(x);
		dst = make_ea();
	}
}

// %1001_xxx100_000yyy	SUBX.B Dy,Dx
// %1001_xxx100_001yyy	SUBX.B -(Ay),-(Ax)
// %1001_xxx100_mmmrrr	SUB.B Dx,<ea>
OP_DEF(sub_b_dn_ea)
{
	ops_sub(Size::B);
}

// %1001_xxx101_000yyy	SUBX.W Dy,Dx
// %1001_xxx101_001yyy	SUBX.W -(Ay),-(Ax)
// %1001_xxx101_mmmrrr	SUB.W Dx,<ea>
OP_DEF(sub_w_dn_ea)
{
	ops_sub(Size::W);
}

// %1001_xxx110_000yyy	SUBX.L Dy,Dx
// %1001_xxx110_001yyy	SUBX.L -(Ay),-(Ax)
// %1001_xxx110_mmmrrr	SUB.L Dx,<ea>
OP_DEF(sub_l_dn_ea)
{
	ops_sub(Size::L);
}

// %1001_xxx111_mmmrrr	SUBA.L <ea>,Ax
OP_DEF(suba_l)
{
	name = "suba";
	size = Size::L;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

// %1010_nnnnnn_nnnnnn	A-Line
OP_DEF(aline)
{
	name = "<unknown A-Line trap>";
}

// %1011_xxx000_mmmrrr	CMP.B <ea>,Dx
OP_DEF(cmp_b)
{
	name = "cmp";
	size = Size::B;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1011_xxx001_mmmrrr	CMP.W <ea>,Dx
OP_DEF(cmp_w)
{
	name = "cmp";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1011_xxx010_mmmrrr	CMP.L <ea>,Dx
OP_DEF(cmp_l)
{
	name = "cmp";
	size = Size::L;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1011_xxx011_mmmrrr	CMPA.W <ea>,Ax
OP_DEF(cmpa_w)
{
	name = "cmpa";
	size = Size::W;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

void
Disasm::ops_eor_cmpm(Disasm::Size sz)
{
	size = sz;

	uint mm = (ir[0] >> 3) & 7;
	if (mm == 1) {
		// CMPM.x (Ay)+,(Ax)+
		name = "cmpm";
		src = make_anpi(ir[0]);
		dst = make_anpi(ir[0] >> 9);
	} else {
		// EOR.x Dx,<ea>
		name = "eor";
		src = make_dn(ir[0] >> 9);
		dst = make_ea();
	}
}

// %1011_xxx100_mmmrrr	EOR.B Dx,<ea>
// %1011_xxx100_001yyy	CMPM.B (Ay)+,(Ax)+
OP_DEF(eor_b)
{
	ops_eor_cmpm(Size::B);
}

// %1011_xxx101_mmmrrr	EOR.W Dx,<ea>
// %1011_xxx101_001yyy	CMPM.W (Ay)+,(Ax)+
OP_DEF(eor_w)
{
	ops_eor_cmpm(Size::W);
}

// %1011_xxx110_mmmrrr	EOR.L Dx,<ea>
// %1011_xxx110_001yyy	CMPM.L (Ay)+,(Ax)+
OP_DEF(eor_l)
{
	ops_eor_cmpm(Size::L);
}

// %1011_xxx111_mmmrrr	CMPA.L <ea>,Ax
OP_DEF(cmpa_l)
{
	name = "cmpa";
	size = Size::L;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

// %1100_xxx000_mmmrrr	AND.B <ea>,Dx
OP_DEF(and_b_ea_dn)
{
	name = "and";
	size = Size::B;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1100_xxx001_mmmrrr	AND.W <ea>,Dx
OP_DEF(and_w_ea_dn)
{
	name = "and";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1100_xxx010_mmmrrr	AND.L <ea>,Dx
OP_DEF(and_l_ea_dn)
{
	name = "and";
	size = Size::L;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1100_xxx011_mmmrrr	MULU.W <ea>,Dx
OP_DEF(mulu_w)
{
	name = "mulu";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

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

	if (n < 8) {
		// ABCD.B Dy,Dx
		name = "abcd";
		size = Size::B;
		src = make_dn(n);
		dst = make_dn(x);
	} else if (n < 16) {
		// ABCD.B -(Ay),-(Ax)
		name = "abcd";
		size = Size::B;
		src = make_anpd(n);
		dst = make_anpd(x);
	} else {
		// AND.B Dx,<ea>
		name = "and";
		size = Size::B;
		src = make_dn(x);
		dst = make_ea();
	}
}

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

	if (n < 8) {
		// EXG.L Dx,Dy
		name = "exg";
		size = Size::L;
		src = make_dn(x);
		dst = make_dn(n);
	} else if (n < 16) {
		// EXG.L Ax,Ay
		name = "exg";
		size = Size::L;
		src = make_an(x);
		dst = make_an(n);
	} else {
		// AND.W Dx,<ea>
		name = "and";
		size = Size::W;
		src = make_dn(x);
		dst = make_ea();
	}
}

// %1100_xxx110_001yyy	EXG.L Dx,Ay
// %1100_xxx110_mmmrrr	AND.L Dx,<ea>
OP_DEF(and_l_dn_ea)
{
	uint mm = (ir[0] >> 3) & 7;

	if (mm == 1) {
		// EXG.L Dx,Ay
		name = "exg";
		size = Size::L;
		src = make_dn(ir[0] >> 9);
		dst = make_an(ir[0]);
	} else {
		// AND.L Dx,<ea>
		name = "and";
		size = Size::L;
		src = make_dn(ir[0] >> 9);
		dst = make_ea();
	}
}

// %1100_xxx111_mmmrrr	MULS.W <ea>,Dx
OP_DEF(muls_w)
{
	name = "muls";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1101_xxx000_mmmrrr	ADD.B <ea>,Dx
OP_DEF(add_b_ea_dn)
{
	name = "add";
	size = Size::B;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1101_xxx001_mmmrrr	ADD.W <ea>,Dx
OP_DEF(add_w_ea_dn)
{
	name = "add";
	size = Size::W;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1101_xxx010_mmmrrr	ADD.L <ea>,Dx
OP_DEF(add_l_ea_dn)
{
	name = "add";
	size = Size::L;
	src = make_ea();
	dst = make_dn(ir[0] >> 9);
}

// %1101_xxx011_mmmrrr	ADDA.W <ea>,Ax
OP_DEF(adda_w)
{
	name = "adda";
	size = Size::W;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

// ADD の共通部分
void
Disasm::ops_add(Disasm::Size sz)
{
	uint n = ir[0] & 0x3f;
	uint x = ir[0] >> 9;

	size = sz;
	if (n < 8) {
		// ADDX.B Dy,Dx
		name = "addx";
		src = make_dn(n);
		dst = make_dn(x);
	} else if (n < 16) {
		// ADDX.B -(Ay),-(Ax)
		name = "addx";
		src = make_anpd(n);
		dst = make_anpd(x);
	} else {
		// ADD.B Dx,<ea>
		name = "add";
		src = make_dn(x);
		dst = make_ea();
	}
}

// %1101_xxx100_000yyy	ADDX.B Dy,Dx
// %1101_xxx100_001yyy	ADDX.B -(Ay),-(Ax)
// %1101_xxx100_mmmrrr	ADD.B Dx,<ea>
OP_DEF(add_b_dn_ea)
{
	ops_add(Size::B);
}

// %1101_xxx101_000yyy	ADDX.W Dy,Dx
// %1101_xxx101_001yyy	ADDX.W -(Ay),-(Ax)
// %1101_xxx101_mmmrrr	ADD.W Dx,<ea>
OP_DEF(add_w_dn_ea)
{
	ops_add(Size::W);
}

// %1101_xxx110_000yyy	ADDX.L Dy,Dx
// %1101_xxx110_001yyy	ADDX.L -(Ay),-(Ax)
// %1101_xxx110_mmmrrr	ADD.L Dx,<ea>
OP_DEF(add_l_dn_ea)
{
	ops_add(Size::L);
}

// %1101_xxx111_mmmrrr	ADDA.L <ea>,Ax
OP_DEF(adda_l)
{
	name = "adda";
	size = Size::L;
	src = make_ea();
	dst = make_an(ir[0] >> 9);
}

// シフト・ローテート系の共通部分
void
Disasm::ops_rotate(std::string dir, Disasm::Size sz)
{
	uint xx = ir[0] >> 9;
	uint mm = (ir[0] >> 3) & 7;

	size = sz;
	dst = make_dn(ir[0]);
	switch (mm) {
	 case 0:		// AS* #qqq,Dy
		name = "as" + dir;
		src = make_q8();
		break;
	 case 1:		// LS* #qqq,Dy
		name = "ls" + dir;
		src = make_q8();
		break;
	 case 2:		// ROX* #qqq,Dy
		name = "rox" + dir;
		src = make_q8();
		break;
	 case 3:		// RO* #qqq,Dy
		name = "ro" + dir;
		src = make_q8();
		break;
	 case 4:		// AS* Dx,Dy
		name = "as" + dir;
		src = make_dn(xx);
		break;
	 case 5:		// LS* Dx,Dy
		name = "ls" + dir;
		src = make_dn(xx);
		break;
	 case 6:		// ROX* Dx,Dy
		name = "rox" + dir;
		src = make_dn(xx);
		break;
	 case 7:		// RO* Dx,Dy
		name = "ro" + dir;
		src = make_dn(xx);
		break;
	 default:
		__unreachable();
	}
}

// %1110_qqq000_000yyy	ASR.B #qqq,Dy
// %1110_qqq000_001yyy	LSR.B #qqq,Dy
// %1110_qqq000_010yyy	ROXR.B #qqq,Dy
// %1110_qqq000_011yyy	ROR.B #qqq,Dy
// %1110_xxx000_100yyy	ASR.B Dx,Dy
// %1110_xxx000_101yyy	LSR.B Dx,Dy
// %1110_xxx000_110yyy	ROXR.B Dx,Dy
// %1110_xxx000_111yyy	ROR.B Dx,Dy
OP_DEF(asr_b_imm)
{
	ops_rotate("r", Size::B);
}

// %1110_qqq001_000yyy	ASR.W #qqq,Dy
// %1110_qqq001_001yyy	LSR.W #qqq,Dy
// %1110_qqq001_010yyy	ROXR.W #qqq,Dy
// %1110_qqq001_011yyy	ROR.W #qqq,Dy
// %1110_xxx001_100yyy	ASR.W Dx,Dy
// %1110_xxx001_101yyy	LSR.W Dx,Dy
// %1110_xxx001_110yyy	ROXR.W Dx,Dy
// %1110_xxx001_111yyy	ROR.W Dx,Dy
OP_DEF(asr_w_imm)
{
	ops_rotate("r", Size::W);
}

// %1110_qqq010_000yyy	ASR.L #qqq,Dy
// %1110_qqq010_001yyy	LSR.L #qqq,Dy
// %1110_qqq010_010yyy	ROXR.L #qqq,Dy
// %1110_qqq010_011yyy	ROR.L #qqq,Dy
// %1110_xxx010_100yyy	ASR.L Dx,Dy
// %1110_xxx010_101yyy	LSR.L Dx,Dy
// %1110_xxx010_110yyy	ROXR.L Dx,Dy
// %1110_xxx010_111yyy	ROR.L Dx,Dy
OP_DEF(asr_l_imm)
{
	ops_rotate("r", Size::L);
}

// %1110_000011_mmmrrr	ASR.W <ea>
OP_DEF(asr_w)
{
	name = "asr";
	size = Size::W;
	src = make_ea();
}

// %1110_qqq100_000yyy	ASL.B #qqq,Dy
// %1110_qqq100_001yyy	LSL.B #qqq,Dy
// %1110_qqq100_010yyy	ROXL.B #qqq,Dy
// %1110_qqq100_011yyy	ROL.B #qqq,Dy
// %1110_xxx100_100yyy	ASL.B Dx,Dy
// %1110_xxx100_101yyy	LSL.B Dx,Dy
// %1110_xxx100_110yyy	ROXL.B Dx,Dy
// %1110_xxx100_111yyy	ROL.B Dx,Dy
OP_DEF(asl_b_imm)
{
	ops_rotate("l", Size::B);
}

// %1110_qqq101_000yyy	ASL.W #qqq,Dy
// %1110_qqq101_001yyy	LSL.W #qqq,Dy
// %1110_qqq101_010yyy	ROXL.W #qqq,Dy
// %1110_qqq101_011yyy	ROL.W #qqq,Dy
// %1110_xxx101_100yyy	ASL.W Dx,Dy
// %1110_xxx101_101yyy	LSL.W Dx,Dy
// %1110_xxx101_110yyy	ROXL.W Dx,Dy
// %1110_xxx101_111yyy	ROL.W Dx,Dy
OP_DEF(asl_w_imm)
{
	ops_rotate("l", Size::W);
}

// %1110_qqq110_000yyy	ASL.L #qqq,Dy
// %1110_qqq110_001yyy	LSL.L #qqq,Dy
// %1110_qqq110_010yyy	ROXL.L #qqq,Dy
// %1110_qqq110_011yyy	ROL.L #qqq,Dy
// %1110_xxx110_100yyy	ASL.L Dx,Dy
// %1110_xxx110_101yyy	LSL.L Dx,Dy
// %1110_xxx110_110yyy	ROXL.L Dx,Dy
// %1110_xxx110_111yyy	ROL.L Dx,Dy
OP_DEF(asl_l_imm)
{
	ops_rotate("l", Size::L);
}

// %1110_000111_mmmrrr	ASL.W <ea>
OP_DEF(asl_w)
{
	name = "asl";
	size = Size::W;
	src = make_ea();
}

// %1110_001011_mmmrrr	LSR.W <ea>
OP_DEF(lsr_w)
{
	name = "lsr";
	size = Size::W;
	src = make_ea();
}

// %1110_001111_mmmrrr	LSL.W <ea>
OP_DEF(lsl_w)
{
	name = "lsl";
	size = Size::W;
	src = make_ea();
}

// %1110_010011_mmmrrr	ROXR.W <ea>
OP_DEF(roxr_w)
{
	name = "roxr";
	size = Size::W;
	src = make_ea();
}

// %1110_010111_mmmrrr	ROXL.W <ea>
OP_DEF(roxl_w)
{
	name = "roxl";
	size = Size::W;
	src = make_ea();
}

// %1110_011011_mmmrrr	ROR.W <ea>
OP_DEF(ror_w)
{
	name = "ror";
	size = Size::W;
	src = make_ea();
}

// %1110_011111_mmmrrr	ROL.W <ea>
OP_DEF(rol_w)
{
	name = "rol";
	size = Size::W;
	src = make_ea();
}

// %1110_100011_mmmrrr	BFTST <ea>{#o:#w}
OP_DEF(bftst)
{
	fetch16();
	name = "bftst";
	src = make_ea() + make_bf();
}

// %1110_100111_mmmrrr	BFEXTU <ea>{#o:#w},Dn
OP_DEF(bfextu)
{
	fetch16();
	name = "bfextu";
	src = make_ea() + make_bf();
	dst = make_dn(ir[1] >> 12);
}

// %1110_101011_mmmrrr	BFCHG <ea>{#o:#w}
OP_DEF(bfchg)
{
	fetch16();
	name = "bfchg";
	src = make_ea() + make_bf();
}

// %1110_101111_mmmrrr	BFEXTS <ea>{#o:#w},Dn
OP_DEF(bfexts)
{
	fetch16();
	name = "bfexts";
	src = make_ea() + make_bf();
	dst = make_dn(ir[1] >> 12);
}

// %1110_110011_mmmrrr	BFCLR <ea>{#o:#w}
OP_DEF(bfclr)
{
	fetch16();
	name = "bfclr";
	src = make_ea() + make_bf();
}

// %1110_110111_mmmrrr	BFFFO <ea>{#o:#w},Dn
OP_DEF(bfffo)
{
	fetch16();
	name = "bfffo";
	src = make_ea() + make_bf();
	dst = make_dn(ir[1] >> 12);
}

// %1110_111011_mmmrrr	BFSET <ea>{#o:#w}
OP_DEF(bfset)
{
	fetch16();
	name = "bfset";
	src = make_ea() + make_bf();
}

// %1110_111111_mmmrrr	BFINS Dn,<ea>{#o:#w}
OP_DEF(bfins)
{
	fetch16();
	name = "bfins";
	dst = make_ea() + make_bf();
	src = make_dn(ir[1] >> 12);
}

// PMOVE* の共通部分
void
Disasm::ops_pmove(Reg reg, Disasm::Size sz)
{
	if ((ir[1] & 0x0100) == 0) {
		name = "pmove";
	} else {
		name = "pmovefd";
	}
	size = sz;
	if ((ir[1] & 0x0200) == 0) {
		src = make_ea();
		dst = make_reg(reg);
	} else {
		src = make_reg(reg);
		dst = make_ea();
	}
}

// %1111_000nnn_nnnnnn	MMU_OP
OP_DEF(mmuop)
{
	uint16 ext = fetch16();
	switch (ext >> 8) {
	 case 0x08:	// PMOVE.L   <ea>,TT0
	 case 0x09:	// PMOVEFD.L <ea>,TT0
	 case 0x0a:	// PMOVE.L   TT0,<ea>
		ops_pmove(Reg::TT0, Size::L);
		break;
	 case 0x0c: // PMOVE.L   <ea>,TT1
	 case 0x0d: // PMOVEFD.L <ea>,TT1
	 case 0x0e:	// PMOVE.L   TT1,<ea>
		ops_pmove(Reg::TT1, Size::L);
		break;
	 case 0x40: // PMOVE.L   <ea>,TC
	 case 0x41: // PMOVEFD.L <ea>,TC
	 case 0x42:	// PMOVE.L   TC,<ea>
		ops_pmove(Reg::TC, Size::L);
		break;
	 case 0x48:	// PMOVE.Q   <ea>,SRP
	 case 0x49:	// PMOVEFD.Q <ea>,SRP
	 case 0x4a:	// PMOVE.Q   SRP,<ea>
		ops_pmove(Reg::SRP, Size::Q);
		break;
	 case 0x4c: // PMOVE.Q   <ea>,CRP
	 case 0x4d: // PMOVEFD.Q <ea>,CRP
	 case 0x4e: // PMOVE.Q   CRP,<ea>
		ops_pmove(Reg::CRP, Size::Q);
		break;
	 case 0x60: // PMOVE.W   <ea>,MMUSR
	 case 0x61: // PMOVEFD.W <ea>,MMUSR
	 case 0x62:	// PMOVE.W   MMUSR,<ea>
		ops_pmove(Reg::MMUSR, Size::W);
		break;

	 case 0x20:	// PLOADW <fc>,<ea>
	 case 0x22:	// PLOADR <fc>,<ea>
		if ((ext & 0x0200) == 0) {
			name = "ploadw";
		} else {
			name = "ploadr";
		}
		src = make_fc();
		dst = make_ea();
		break;

	 case 0x24:	// PFLUSHA
		name = "pflusha";
		break;

	 case 0x38:	// PFLUSH <fc>,#<mask>,<ea>
		dst = make_ea();
		FALLTHROUGH;
	 case 0x30:	// PFLUSH <fc>,#<mask>
		name = "pflush";
		src = make_fc() + string_format(",#%d", (ir[1] >> 5) & 7);
		break;

	 case 0x81:	// PTESTW <fc>,<ea>,#0,An
	 case 0x85:	// PTESTW <fc>,<ea>,#1,An
	 case 0x89:	// PTESTW <fc>,<ea>,#2,An
	 case 0x8d:	// PTESTW <fc>,<ea>,#3,An
	 case 0x91:	// PTESTW <fc>,<ea>,#4,An
	 case 0x95:	// PTESTW <fc>,<ea>,#5,An
	 case 0x99:	// PTESTW <fc>,<ea>,#6,An
	 case 0x9d:	// PTESTW <fc>,<ea>,#7,An
	 case 0x83:	// PTESTR <fc>,<ea>,#0,An
	 case 0x87:	// PTESTR <fc>,<ea>,#1,An
	 case 0x8b:	// PTESTR <fc>,<ea>,#2,An
	 case 0x8f:	// PTESTR <fc>,<ea>,#3,An
	 case 0x93:	// PTESTR <fc>,<ea>,#4,An
	 case 0x97:	// PTESTR <fc>,<ea>,#5,An
	 case 0x9b:	// PTESTR <fc>,<ea>,#6,An
	 case 0x9f:	// PTESTR <fc>,<ea>,#7,An
		dst = make_an(ir[1] >> 5);
		FALLTHROUGH;
	 case 0x80:	// PTESTW <fc>,<ea>,#0
	 case 0x84:	// PTESTW <fc>,<ea>,#1
	 case 0x88:	// PTESTW <fc>,<ea>,#2
	 case 0x8c:	// PTESTW <fc>,<ea>,#3
	 case 0x90:	// PTESTW <fc>,<ea>,#4
	 case 0x94:	// PTESTW <fc>,<ea>,#5
	 case 0x98:	// PTESTW <fc>,<ea>,#6
	 case 0x9c:	// PTESTW <fc>,<ea>,#7
	 case 0x82:	// PTESTR <fc>,<ea>,#0
	 case 0x86:	// PTESTR <fc>,<ea>,#1
	 case 0x8a:	// PTESTR <fc>,<ea>,#2
	 case 0x8e:	// PTESTR <fc>,<ea>,#3
	 case 0x92:	// PTESTR <fc>,<ea>,#4
	 case 0x96:	// PTESTR <fc>,<ea>,#5
	 case 0x9a:	// PTESTR <fc>,<ea>,#6
	 case 0x9e:	// PTESTR <fc>,<ea>,#7
		if ((ext & 0x0200) == 0) {
			name = "ptestw";
		} else {
			name = "ptestr";
		}
		src = make_fc() + "," + make_ea()
		    + string_format(",#%d", (ext >> 10) & 7);
		break;

	 default:
		OP_FUNC(illegal);
		break;
	}
}

// %1111_001000_nnnnnn	FPGEN
OP_DEF(fpgen)
{
	uint16 ext = fetch16();

	switch (ext >> 13) {
	 case 0:
		ops_fpgen_fpn_fpn();
		break;
	 case 2:
		ops_fpgen_ea_fpn();
		break;
	 case 3:
		ops_fmove_fpn_ea();
		break;
	 case 4:
		ops_fmovem_ea_ctl();
		break;
	 case 5:
		ops_fmovem_ctl_ea();
		break;
	 case 6:
		ops_fmovem_ea_fpn();
		break;
	 case 7:
		ops_fmovem_fpn_ea();
		break;
	}
}

// FPgen <fpn>,<fpn>
void
Disasm::ops_fpgen_fpn_fpn()
{
	uint sn = (ir[1] >> 10) & 7;
	uint dn = (ir[1] >> 7) & 7;
	uint mode = ir[1] & 0x7f;

	// FSINCOS だけ形式が違うので先に処理
	if (0x30 <= mode && mode < 0x38) {
		name = "fsincos";
		size = Size::X;
		src = make_fpn(sn);
		dst = make_fpn(ir[1]) + ":" + make_fpn(dn);
		return;
	}

	// FSINCOS 以外は全部同じ書式
	name = fpgen_names[mode];
	if (name.empty()) {
		OP_FUNC(illegal);
		return;
	}
	size = Size::X;
	src = make_fpn(sn);
	// FSIN FPm,FPm のように src, dst が同じ場合は FSIN FPm と書くが、
	// FMOVE FPm,FPm は src, dst が同じであっても FMOVE FPm,FPm と表記する。
	if (mode == 0x00/*FMOVE*/ || sn != dn) {
		dst = make_fpn(dn);
	}
}

// FPgen <ea>,<reg>
void
Disasm::ops_fpgen_ea_fpn()
{
	uint sz = (ir[1] >> 10) & 7;
	uint dn = (ir[1] >> 7) & 7;
	uint mode = ir[1] & 0x7f;

	if (sz == 7) {
		// ここに FMOVECR
		ops_fmovecr();
		return;
	}

	name = fpgen_names[mode];
	if (name.empty()) {
		OP_FUNC(illegal);
		return;
	}
	size = (Size)sz;
	src = make_ea();
	dst = make_fpn(dn);
}

// FMOVECR
void
Disasm::ops_fmovecr()
{
	uint dn = (ir[1] >> 7) & 7;
	uint offset = ir[1] & 0x7f;
	std::string text;

	name = "fmovecr";
	size = Size::X;
	src = "#" + hex8(offset);
	// 定数だけじゃ分かりづらいので内容も表示も表示してみるのはどうか。
	switch (offset) {
	 case 0:
		src += "<pi>";
		break;
	 case 0x0b ... 0x0f:
		src += fmovecr_text[offset - 0x0b];
		break;
	 case 0x30 ... 0x3f:
		src += fmovecr_text[offset - 0x30 + 5];
		break;
	 default:
		break;
	}
	dst = make_fpn(dn);
}

// FMOVE <fpn>,<ea>
void
Disasm::ops_fmove_fpn_ea()
{
	uint sz = (ir[1] >> 10) & 7;
	uint sn = (ir[1] >> 7) & 7;
	uint mode = ir[1] & 0x7f;

	name = "fmove";
	size = (Size)sz;
	src = make_fpn(sn);
	dst = make_ea();
	if (sz == Size::P) {
		// static k-factor
		int k;
		// 7bit (符号なし)数を符号付き数に変える
		if ((mode & 0x40)) {
			k = (int8)(mode | 0x80);
		} else {
			k = mode;
		}
		dst += string_format("{#%d}", k);
	} else if (sz == Size::Pk) {
		// dynamic k-factor
		dst += "{" + make_dn(mode >> 4) + "}";
	}
}

void
Disasm::ops_fmovem_ea_ctl()
{
	uint n;

	n = make_fpctls(dst);
	if (n == 1) {
		name = "fmove";
	} else {
		name = "fmovem";
	}
	size = Size::L;

	src = make_ea();
	// #imm が複数ある場合
	if ((ir[0] & 0x3f) == 0x3c && n > 1) {
		for (int i = 1; i < n; i++) {
			src += "/";
			src += imm32();
		}
	}
}

void
Disasm::ops_fmovem_ctl_ea()
{
	uint n;

	n = make_fpctls(src);
	if (n == 1) {
		name = "fmove";
	} else {
		name = "fmovem";
	}
	size = Size::L;
	dst = make_ea();
}

void
Disasm::ops_fmovem_ea_fpn()
{
	name = "fmovem";
	size = Size::X;
	src = make_ea();
	if ((ir[1] & 0x1800) == 0x1800) {
		// dynamic list
		dst = make_dn(ir[1] >> 4);
	} else {
		dst = make_fpnlist();
	}
}

void
Disasm::ops_fmovem_fpn_ea()
{
	name = "fmovem";
	size = Size::X;
	if ((ir[1] & 0x1800) == 0x1800) {
		// dynamic list
		src = make_dn(ir[1] >> 4);
	} else {
		src = make_fpnlist();
	}
	dst = make_ea();
}

// %1111_001001_nnnnnn	FScc.B <ea>
// %1111_001001_001yyy	FDBcc Dy,<label>
// %1111_001001_111010	FTRAPcc.W #<imm>
// %1111_001001_111011	FTRAPcc.L #<imm>
// %1111_001001_111100	FTRAPcc
OP_DEF(fxcc)
{
	uint n = ir[0] & 0x3f;

	fetch16();
	switch (n) {
	 case 0x00 ... 0x07:	// FScc
	 case 0x10 ... 0x39:
		name = "fs" + make_fpcc(ir[1]);
		size = Size::B;
		src = make_ea();
		break;
	 case 0x08 ... 0x0f:	// FDBcc
		name = "fdb" + make_fpcc(ir[1]);
		src = make_dn(ir[0]);
		dst = addr32(pc0 + 2 + (int32)(int16)fetch16());
		break;
	 case 0x3a:				// FTRAPcc.W #<imm>
		name = "ftrap" + make_fpcc(ir[1]);
		size = Size::W;
		src = imm16();
		break;
	 case 0x3b:				// FTRAPcc.L #<imm>
		name = "ftrap" + make_fpcc(ir[1]);
		size = Size::L;
		src = imm32();
		break;
	 case 0x3c:				// FTRAPcc
		name = "ftrap" + make_fpcc(ir[1]);
		break;
	 default:
		OP_FUNC(illegal);
		break;
	}
}

// %1111_001010_nnnnnn	FBcc.W <label>
OP_DEF(fbcc_w)
{
	int32 disp = (int32)(int16)fetch16();

	if ((ir[0] & 0x3f) == 0 && disp == 0) {
		// FBF.W +$0000 のみ FNOP
		name = "fnop";
		return;
	}
	name = "fb" + make_fpcc(ir[0]);
	size = Size::W;
	src = addr32(pc0 + 2 + disp);
}

// %1111_001011_nnnnnn	FBcc.L <label>
OP_DEF(fbcc_l)
{
	name = "fb" + make_fpcc(ir[0]);
	size = Size::L;
	src = addr32(pc0 + 2 + (int32)fetch32());
}

// %1111_001100_nnnnnn	FSAVE <ea>
OP_DEF(fsave)
{
	name = "fsave";
	src = make_ea();
}

// %1111_001101_nnnnnn	FRESTORE <ea>
OP_DEF(frestore)
{
	name = "frestore";
	src = make_ea();
}

// %1111_nnnnnn_nnnnnn	F-Line
OP_DEF(fline)
{
	// XXX x68k/Human68k 判定するか
	if ((ir[0] & 0xff00) == 0xff00) {
		uint dosno = ir[0] & 0xff;
		name = "DOS";
		src = x68k_doscall[dosno] ?: "<undefined>";
	} else if ((ir[0] & 0xff00) == 0xfe00) {
		uint n = ir[0] & 0xff;
		name = "FPACK";
		src = x68k_fpcall[n] ?: "<undefined>";
	} else {
		name = "<unknown F-Line trap>";
	}
}

// illegal instructions
OP_DEF(illegal)
{
	name = "<illegal instruction>";
}

unix.superglobalmegacorp.com

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