|
|
nono 1.0.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
#include "mpu680x0.h"
#include "m68030acc.h"
#include "m68030bitfield.h"
#define OP_DEF(name) void __CONCAT(MPU680x0Device::op_,name)()
#define OP_FUNC(name) __CONCAT(op_,name)()
#define CCR reg.ccr
#define ACC (*(m68030acc*)®.ccr)
#define RegIRX ((ir >> 9) & 7)
#define RegIRY (ir & 7)
#define RegDX reg.D[RegIRX]
#define RegAX reg.A[RegIRX]
#define RegDY reg.D[RegIRY]
#define RegAY reg.A[RegIRY]
// 副作用のあるマクロ
// 特権違反例外のスタックに積む PC は違反を起こした命令先頭。
#define SUPERVISOR_OP do { \
if (!IsSuper()) { \
CYCLE2(18, 20); \
Exception(M68K::EXCEP_PRIV); \
return; \
} \
} while (0)
// FPU 命令の FSAVE/FRESTORE 以外のグループ全員で実行開始時に必要な処理
inline void
MPU680x0Device::fpu_op_start()
{
fpu_dirty = true;
// 現在の FPCR/FPSR を fe 構造体にコピー。
//
// fe.fe_{fpcr,fpsr} のほうはこの fpe 用の内部ワークなので破壊してよい。
// 命令実行の結果、FPSR レジスタの値を更新する際は fpu_upd_fpsr() を
// 呼ぶこと。これを使わず独自に更新する場合は fe.fe_fpframe->fpf_fpsr
// (こっちがレジスタ値) と fe.fe_fpsr (FPE 用) を同時に更新すること。
// FPCR のほうは FMOVE-to-FPCR 命令以外で変更されることはないはず。
fe.fe_fpcr = RegFPCR;
fe.fe_fpsr = RegFPSR;
}
// %0000_000000_mmmrrr ORI.B #<imm>,<ea>
// %0000_000000_111100 ORI.B #<imm>,CCR
OP_DEF(ori_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// ORI.B #<imm>,Dn
CYCLE(2);
uint32 dst = (reg.D[n] & 0xff) | src;
ACC.move_8(dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else if (n == 0b111100) {
// ORI.B #<imm>,CCR
CYCLE2(12, 14);
CCR.Set(CCR.Get() | src);
} else {
// ORI.B #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst |= src;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %0000_000001_mmmrrr ORI.W #<imm>,<ea>
// %0000_000001_111100 ORI.W #<imm>,SR
OP_DEF(ori_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// ORI.W #<imm>,Dn
CYCLE(2);
uint32 src = fetch_2();
uint32 dst = (reg.D[n] & 0xffff) | src;
ACC.move_16(dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else if (n == 0b111100) {
// ORI.W #<imm>,SR
SUPERVISOR_OP;
CYCLE2(12, 14);
uint32 src = fetch_2();
SetSR(GetSR() | src);
} else {
// ORI.W #<imm>,<ea>
CYCLE2(3, 4);
uint32 src = fetch_2();
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst |= src;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %0000_000010_mmmrrr ORI.L #<imm>,<ea>
OP_DEF(ori_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// ORI.L #<imm>,Dn
CYCLE(2);
reg.D[n] |= src;
ACC.move_32(reg.D[n]);
} else {
// ORI.L #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst |= src;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %0000_000011_mmmrrr CMP2/CHK2.B <ea>,Rn
OP_DEF(cmp2chk2_b)
{
ir2 = fetch_2();
uint32 compare;
uint32 ea = cea_ctrl();
uint32 lower;
uint32 upper;
if ((ir2 & 0x8000) == 0) {
// compare が Dn
compare = (int32)(int8)(reg.R[ir2 >> 12] & 0xff);
} else {
// compare が An
compare = reg.R[ir2 >> 12];
}
// 本当は PC 相対ならプログラム空間アクセス、
// それ以外はデータ空間アクセスだが、ここでは区別しない。
lower = (int32)(int8)read_1(ea);
upper = (int32)(int8)read_1(ea + 1);
ACC.chk2cmp2_32(compare, lower, upper);
// サイクル数はこれは実際には全部最大値
if ((ir2 & 0x0800)) {
// CHK2 で条件を満たしていれば例外
if (reg.ccr.CondCS()) {
CYCLE2(40, 42);
Exception(M68K::EXCEP_CHK);
} else {
CYCLE(18);
}
} else {
// CMP2
CYCLE(20);
}
}
// MOVEP.[WL] (d,Ay),Dx と
// MOVEP.[WL] Dx,(d,Ay) の共通部分。
void
MPU680x0Device::ops_movep()
{
uint32 disp = (int32)(int16)fetch_2();
uint32 ea = RegAY + disp;
bool size_long = ((ir & 0x40) != 0);
bool reg2mem = ((ir & 0x80) != 0);
CYCLE(14);
if (reg2mem) {
// Dx -> memory
uint32 dx = RegDX;
if (size_long) {
write_1(ea, (dx >> 24));
ea += 2;
write_1(ea, (dx >> 16) & 0xff);
ea += 2;
}
write_1(ea, (dx >> 8) & 0xff);
ea += 2;
write_1(ea, (dx & 0xff));
} else {
// memory -> Dx
uint32 dx = 0;
if (size_long) {
dx = read_1(ea);
dx <<= 8;
ea += 2;
dx |= read_1(ea);
dx <<= 8;
ea += 2;
}
// word
dx |= read_1(ea);
dx <<= 8;
ea += 2;
dx |= read_1(ea);
if (size_long) {
RegDX = dx;
} else {
RegDX = (RegDX & 0xffff0000) | (dx & 0xffff);
}
}
}
// %0000_xxx100_000yyy BTST.L Dx,Dy
// %0000_xxx100_001yyy MOVEP.W (d,Ay),Dx
// %0000_xxx100_mmmrrr BTST.B Dx,<ea>
OP_DEF(btst_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BTST.L Dx,Dy
CYCLE(4);
uint bit = (RegDX & 31);
ACC.btst(RegDY, bit);
} else if (n < 16) {
// MOVEP.W (d,Ay),Dx
ops_movep();
} else {
// BTST.B Dx,<ea>
CYCLE(4);
uint bit = (RegDX & 7);
uint32 data = fea_data_1();
ACC.btst(data, bit);
}
}
// %0000_xxx101_000yyy BCHG.L Dx,Dy
// %0000_xxx101_001yyy MOVEP.L (d,Ay),Dx
// %0000_xxx101_mmmrrr BCHG.B Dx,<ea>
OP_DEF(bchg_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCHG.L Dx,Dy
CYCLE(6);
uint bit = (RegDX & 31);
RegDY = ACC.bchg(RegDY, bit);
} else if (n < 16) {
// MOVEP.L (d,Ay),Dx
ops_movep();
} else {
// BCHG.B Dx,<ea>
CYCLE(6);
uint bit = (RegDX & 7);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bchg(data, bit);
write_1(ea, data);
}
}
// %0000_xxx110_000yyy BCLR.L Dx,Dy
// %0000_xxx110_001yyy MOVEP.W Dx,(d,Ay)
// %0000_xxx110_mmmrrr BCLR.B Dx,<ea>
OP_DEF(bclr_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCLR.L Dx,Dy
CYCLE(6);
uint bit = (RegDX & 31);
RegDY = ACC.bclr(RegDY, bit);
} else if (n < 16) {
// MOVEP.W Dx,(d,Ay)
ops_movep();
} else {
// BCLR.B Dx,<ea>
CYCLE(6);
uint bit = (RegDX & 7);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bclr(data, bit);
write_1(ea, data);
}
}
// %0000_xxx111_000yyy BSET.L Dx,Dy
// %0000_xxx111_001yyy MOVEP.L Dx,(d,Ay)
// %0000_xxx111_mmmrrr BSET.B Dx,<ea>
OP_DEF(bset_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BSET.L Dx,Dy
CYCLE(6);
uint bit = (RegDX & 31);
RegDY = ACC.bset(RegDY, bit);
} else if (n < 16) {
// MOVEP.L Dx,(d,Ay)
ops_movep();
} else {
// BSET.B Dx,<ea>
CYCLE(6);
uint bit = (RegDX & 7);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bset(data, bit);
write_1(ea, data);
}
}
// %0000_001000_mmmrrr ANDI.B #<imm>,<ea>
// %0000_001000_111100 ANDI.B #<imm>,CCR
OP_DEF(andi_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// ANDI.B #<imm>,Dn
CYCLE(2);
uint32 dst = reg.D[n] & 0xff;
dst &= src;
ACC.move_8(dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else if (n == 0b111100) {
// ANDI.B #<imm>,CCR
CYCLE2(12, 14);
CCR.Set(CCR.Get() & src);
} else {
// ANDI.B #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst &= src;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %0000_001001_mmmrrr ANDI.W #<imm>,<ea>
// %0000_001001_111100 ANDI.W #<imm>,SR
OP_DEF(andi_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// ANDI.W #<imm>,Dn
CYCLE(2);
uint32 src = fetch_2();
uint32 dst = reg.D[n] & 0xffff;
dst &= src;
ACC.move_16(dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else if (n == 0b111100) {
// ANDI.W #<imm>,SR
SUPERVISOR_OP;
CYCLE2(12, 14);
uint32 src = fetch_2();
SetSR(GetSR() & src);
} else {
// ANDI.W #<imm>,<ea>
CYCLE2(3, 4);
uint32 src = fetch_2();
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst &= src;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %0000_001010_mmmrrr ANDI.L #<imm>,<ea>
OP_DEF(andi_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// ANDI.L #<imm>,Dn
CYCLE(2);
reg.D[n] &= src;
ACC.move_32(reg.D[n]);
} else {
// ANDI.L #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst &= src;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %0000_001011_mmmrrr CMP2/CHK2.W <ea>,Rn
OP_DEF(cmp2chk2_w)
{
ir2 = fetch_2();
uint32 compare;
uint32 ea = cea_ctrl();
uint32 lower;
uint32 upper;
if ((ir2 & 0x8000) == 0) {
// compare が Dn
compare = (int32)(int16)(reg.R[ir2 >> 12] & 0xffff);
} else {
// compare が An
compare = reg.R[ir2 >> 12];
}
// 本当は PC 相対ならプログラム空間アクセス、
// それ以外はデータ空間アクセスだが、ここでは区別しない。
lower = (int32)(int16)read_2(ea);
upper = (int32)(int16)read_2(ea + 2);
ACC.chk2cmp2_32(compare, lower, upper);
// サイクル数はこれは実際には全部最大値
if ((ir2 & 0x0800)) {
// CHK2 で条件を満たしていれば例外
if (reg.ccr.CondCS()) {
CYCLE2(40, 42);
Exception(M68K::EXCEP_CHK);
} else {
CYCLE(18);
}
} else {
// CMP2
CYCLE(20);
}
}
// %0000_010000_mmmrrr SUBI.B #<imm>,<ea>
OP_DEF(subi_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// SUBI.B #<imm>,Dn
CYCLE(2);
uint32 dst = reg.D[n] & 0xff;
dst = ACC.sub_8(src, dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else {
// SUBI.B #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst = ACC.sub_8(src, dst);
write_1(ea, dst);
}
}
// %0000_010001_mmmrrr SUBI.W #<imm>,<ea>
OP_DEF(subi_w)
{
uint n = ir & 0x3f;
uint32 src = fetch_2();
if (n < 8) {
// SUBI.W #<imm>,Dn
CYCLE(2);
uint32 dst = reg.D[n] & 0xffff;
dst = ACC.sub_16(src, dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else {
// SUBI.W #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst = ACC.sub_16(src, dst);
write_2(ea, dst);
}
}
// %0000_010010_mmmrrr SUBI.L #<imm>,<ea>
OP_DEF(subi_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// SUBI.L #<imm>,Dn
CYCLE(2);
reg.D[n] = ACC.sub_32(src, reg.D[n]);
} else {
// SUBI.L #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst = ACC.sub_32(src, dst);
write_4(ea, dst);
}
}
// %0000_010011_mmmrrr CMP2/CHK2.L <ea>,Rn
OP_DEF(cmp2chk2_l)
{
ir2 = fetch_2();
uint32 compare = reg.R[ir2 >> 12];
uint32 ea = cea_ctrl();
uint32 lower;
uint32 upper;
// 本当は PC 相対ならプログラム空間アクセス、
// それ以外はデータ空間アクセスだが、ここでは区別しない。
lower = read_4(ea);
upper = read_4(ea + 4);
ACC.chk2cmp2_32(compare, lower, upper);
// サイクル数はこれは実際には全部最大値
if ((ir2 & 0x0800)) {
// CHK2 で条件を満たしていれば例外
if (reg.ccr.CondCS()) {
CYCLE2(40, 42);
Exception(M68K::EXCEP_CHK);
} else {
CYCLE(18);
}
} else {
// CMP2
CYCLE(20);
}
}
// %0000_011000_mmmrrr ADDI.B #<imm>,<ea>
OP_DEF(addi_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// ADDI.B #<imm>,Dn
CYCLE(2);
uint32 dst = reg.D[n] & 0xff;
dst = ACC.add_8(src, dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else {
// ADDI.B #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst = ACC.add_8(src, dst);
write_1(ea, dst);
}
}
// %0000_011001_mmmrrr ADDI.W #<imm>,<ea>
OP_DEF(addi_w)
{
uint n = ir & 0x3f;
uint32 src = fetch_2();
if (n < 8) {
// ADDI.W #<imm>,Dn
CYCLE(2);
uint32 dst = reg.D[n] & 0xffff;
dst = ACC.add_16(src, dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else {
// ADDI.W #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst = ACC.add_16(src, dst);
write_2(ea, dst);
}
}
// %0000_011010_mmmrrr ADDI.L #<imm>,<ea>
OP_DEF(addi_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// ADDI.L #<imm>,Dn
CYCLE(2);
reg.D[n] = ACC.add_32(src, reg.D[n]);
} else {
// ADDI.L #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst = ACC.add_32(src, dst);
write_4(ea, dst);
}
}
// %0000_011011_00nnnn RTM Rn
// %0000_011011_mmmrrr CALLM #<imm>,<ea>
OP_DEF(callm)
{
op_illegal();
}
// %0000_100000_000yyy BTST.L #<imm>,Dy
// %0000_100000_mmmrrr BTST.B #<imm>,<ea>
OP_DEF(btst_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BTST.L #<imm>,Dy
CYCLE(4);
uint bit = fetch_2() & 31;
ACC.btst(RegDY, bit);
} else if (n == 0x3c) {
// BTST.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BTST.B #<imm>,<ea>
CYCLE(4);
uint bit = fetch_2() & 7;
uint32 data = fea_data_1();
ACC.btst(data, bit);
}
}
// %0000_100001_000yyy BCHG.L #<imm>,Dy
// %0000_100001_mmmrrr BCHG.B #<imm>,<ea>
OP_DEF(bchg_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCHG.L #<imm>,Dy
CYCLE(6);
uint bit = fetch_2() & 31;
RegDY = ACC.bchg(RegDY, bit);
} else if (n == 0x3c) {
// BCHG.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BCHG.B #<imm>,<ea>
CYCLE(6);
uint bit = fetch_2() & 7;
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bchg(data, bit);
write_1(ea, data);
}
}
// %0000_100010_000yyy BCLR.L #<imm>,Dy
// %0000_100010_mmmrrr BCLR.B #<imm>,<ea>
OP_DEF(bclr_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCLR.L #<imm>,Dy
CYCLE(6);
uint bit = fetch_2() & 31;
RegDY = ACC.bclr(RegDY, bit);
} else if (n == 0x3c) {
// BCLR.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BCLR.B #<imm>,<ea>
CYCLE(6);
uint bit = fetch_2() & 7;
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bclr(data, bit);
write_1(ea, data);
}
}
// %0000_100011_000yyy BSET.L #<imm>,Dy
// %0000_100011_mmmrrr BSET.B #<imm>,<ea>
OP_DEF(bset_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BSET.L #<imm>,Dy
CYCLE(6);
uint bit = fetch_2() & 31;
RegDY = ACC.bset(RegDY, bit);
} else if (n == 0x3c) {
// BSET.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BSET.B #<imm>,<ea>
CYCLE(6);
uint bit = fetch_2() & 7;
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bset(data, bit);
write_1(ea, data);
}
}
// %0000_101000_mmmrrr EORI.B #<imm>,<ea>
// %0000_101000_111100 EORI.B #<imm>,CCR
OP_DEF(eori_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// EORI.B #<imm>,Dn
CYCLE(2);
uint32 dst = (reg.D[n] & 0xff) ^ src;
ACC.move_8(dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else if (n == 0b111100) {
// EORI.B #<imm>,CCR
CYCLE2(12, 14);
CCR.Set(CCR.Get() ^ src);
} else {
// EORI.B #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst ^= src;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %0000_101001_mmmrrr EORI.W #<imm>,<ea>
// %0000_101001_111100 EORI.W #<imm>,SR
OP_DEF(eori_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// EORI.W #<imm>,Dn
CYCLE(2);
uint32 src = fetch_2();
uint32 dst = (reg.D[n] & 0xffff) ^ src;
ACC.move_16(dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else if (n == 0b111100) {
// EORI.W #<imm>,SR
SUPERVISOR_OP;
CYCLE2(12, 14);
uint32 src = fetch_2();
SetSR(GetSR() ^ src);
} else {
// EORI.W #<imm>,<ea>
CYCLE2(3, 4);
uint32 src = fetch_2();
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst ^= src;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %0000_101010_mmmrrr EORI.L #<imm>,<ea>
OP_DEF(eori_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// EORI.L #<imm>,Dn
CYCLE(2);
reg.D[n] ^= src;
ACC.move_32(reg.D[n]);
} else {
// EORI.L #<imm>,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst ^= src;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %0000_101011_mmmrrr CAS.B Dc,Du,<ea>
OP_DEF(cas_b)
{
ir2 = fetch_2();
uint c = ir2 & 7;
uint u = (ir2 >> 6) & 7;
uint32 dc = reg.D[c] & 0xff;
uint32 du = reg.D[u] & 0xff;
uint ea = cea_data_1();
uint32 dst = read_1(ea);
ACC.cmp_8(dc, dst);
if (CCR.IsZ()) {
// 等しければ、Du -> dst
CYCLE(13);
write_1(ea, du);
} else {
// そうでなければ、dst -> Dc
CYCLE(11);
reg.D[c] = (reg.D[c] & 0xffffff00) | dst;
}
}
// %0000_110000_mmmrrr CMPI.B #<imm>,<ea>
OP_DEF(cmpi_b)
{
uint n = ir & 0x3f;
// CMPI はデータアドレッシングだが #imm がないことに注意
if (n == 0x3c) {
op_illegal();
return;
}
CYCLE(2);
uint32 src = fetch_2() & 0xff;
uint32 dst = fea_data_1();
ACC.cmp_8(src, dst);
}
// %0000_110001_mmmrrr CMPI.W #<imm>,<ea>
OP_DEF(cmpi_w)
{
uint n = ir & 0x3f;
// CMPI はデータアドレッシングだが #imm がないことに注意
if (n == 0x3c) {
op_illegal();
return;
}
CYCLE(2);
uint32 src = fetch_2();
uint32 dst = fea_data_2();
ACC.cmp_16(src, dst);
}
// %0000_110010_mmmrrr CMPI.L #<imm>,<ea>
OP_DEF(cmpi_l)
{
uint n = ir & 0x3f;
// CMPI はデータアドレッシングだが #imm がないことに注意
if (n == 0x3c) {
op_illegal();
return;
}
CYCLE(2);
uint32 src = fetch_4();
uint32 dst = fea_data_4();
ACC.cmp_32(src, dst);
}
// %0000_110011_mmmrrr CAS.W Dc,Du,<ea>
// %0000_110011_111100 CAS2.W Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
OP_DEF(cas_w)
{
uint n = ir & 0x3f;
if (n == 0x3c) {
// CAS2.W Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
ir2 = fetch_2();
uint32 ir3 = fetch_2();
uint c1 = ir2 & 7;
uint u1 = (ir2 >> 6) & 7;
uint r1 = ir2 >> 12;
uint c2 = ir3 & 7;
uint u2 = (ir3 >> 6) & 7;
uint r2 = ir3 >> 12;
uint32 dc1 = reg.D[c1] & 0xffff;
uint32 du1 = reg.D[u1] & 0xffff;
uint32 ea1 = reg.R[r1];
uint32 dc2 = reg.D[c2] & 0xffff;
uint32 du2 = reg.D[u2] & 0xffff;
uint32 ea2 = reg.R[r2];
uint32 dst1 = read_2(ea1);
uint32 dst2 = read_2(ea2);
ACC.cmp_16(dc1, dst1);
if (CCR.IsZ()) {
ACC.cmp_16(dc2, dst2);
if (CCR.IsZ()) {
// 更新オペランド -> デスティネーション
CYCLE2(0, 2); // これは成功時の追加分
write_2(ea1, du1);
write_2(ea2, du2);
}
}
// デスティネーション -> 比較オペランド
CYCLE(24); // 本当はこれは最大値
reg.D[c1] = (reg.D[c1] & 0xffff0000) | dst1;
reg.D[c2] = (reg.D[c2] & 0xffff0000) | dst2;
} else {
// CAS.W Dc,Du,<ea>
ir2 = fetch_2();
uint c = ir2 & 7;
uint u = (ir2 >> 6) & 7;
uint32 dc = reg.D[c] & 0xffff;
uint32 du = reg.D[u] & 0xffff;
uint ea = cea_data_2();
uint32 dst = read_2(ea);
ACC.cmp_16(dc, dst);
if (CCR.IsZ()) {
// 等しければ、Du -> dst
CYCLE(13);
write_2(ea, du);
} else {
// そうでなければ、dst -> Dc
CYCLE(11);
reg.D[c] = (reg.D[c] & 0xffff0000) | dst;
}
}
}
// %0000_111000_mmmrrr MOVES.B <ea>,Rn
// %0000_111000_mmmrrr MOVES.B Rn,<ea>
OP_DEF(moves_b)
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint ea;
uint32 data;
if ((ir & 0x3f) < 16) {
op_illegal();
return;
}
ea = cea_data_1();
if ((ir2 & 0x0800) == 0) {
// <ea>,Rn
CYCLE(7);
busaddr addr = busaddr(ea) | reg.sfc | BusAddr::Size1;
data = read_data(addr);
if (n < 8) { // Dn
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else { // An
reg.R[n] = (int32)(int8)data;
}
} else {
// Rn,<ea>
CYCLE2(5, 6);
busaddr addr = busaddr(ea) | reg.dfc | BusAddr::Size1;
data = reg.R[n] & 0xff;
write_data(addr, data);
}
}
// %0000_111001_mmmrrr MOVES.W <ea>,Rn
// %0000_111001_mmmrrr MOVES.W Rn,<ea>
OP_DEF(moves_w)
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint ea;
uint32 data;
if ((ir & 0x3f) < 16) {
op_illegal();
return;
}
ea = cea_data_2();
if ((ir2 & 0x0800) == 0) {
// <ea>,Rn
CYCLE(7);
busaddr addr = busaddr(ea) | reg.sfc | BusAddr::Size2;
data = read_data(addr);
if (n < 8) { // Dn
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else { // An
reg.R[n] = (int32)(int16)data;
}
} else {
// Rn,<ea>
CYCLE2(5, 6);
busaddr addr = busaddr(ea) | reg.dfc | BusAddr::Size2;
data = reg.R[n] & 0xffff;
write_data(addr, data);
}
}
// %0000_111010_mmmrrr MOVES.L <ea>,Rn
// %0000_111010_mmmrrr MOVES.L Rn,<ea>
OP_DEF(moves_l)
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint ea;
uint32 data;
if ((ir & 0x3f) < 16) {
op_illegal();
return;
}
ea = cea_data_4();
if ((ir2 & 0x0800) == 0) {
// <ea>,Rn
CYCLE(7);
busaddr addr = busaddr(ea) | reg.sfc | BusAddr::Size4;
data = read_data(addr);
reg.R[n] = data;
} else {
// Rn,<ea>
CYCLE2(5, 6);
busaddr addr = busaddr(ea) | reg.dfc | BusAddr::Size4;
data = reg.R[n];
write_data(addr, data);
}
}
// %0000_111011_mmmrrr CAS.L Dc,Du,<ea>
// %0000_111011_111100 CAS2.L Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
OP_DEF(cas_l)
{
uint n = ir & 0x3f;
if (n == 0x3c) {
// CAS2.L Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
ir2 = fetch_2();
uint32 ir3 = fetch_2();
uint c1 = ir2 & 7;
uint u1 = (ir2 >> 6) & 7;
uint r1 = ir2 >> 12;
uint c2 = ir3 & 7;
uint u2 = (ir3 >> 6) & 7;
uint r2 = ir3 >> 12;
uint32 dc1 = reg.D[c1];
uint32 du1 = reg.D[u1];
uint32 ea1 = reg.R[r1];
uint32 dc2 = reg.D[c2];
uint32 du2 = reg.D[u2];
uint32 ea2 = reg.R[r2];
uint32 dst1 = read_4(ea1);
uint32 dst2 = read_4(ea2);
ACC.cmp_32(dc1, dst1);
if (CCR.IsZ()) {
ACC.cmp_32(dc2, dst2);
if (CCR.IsZ()) {
// 更新オペランド -> デスティネーション
CYCLE2(0, 2); // これは成功時の追加分
write_4(ea1, du1);
write_4(ea2, du2);
}
}
// デスティネーション -> 比較オペランド
CYCLE(24); // 本当はこれは最大値
reg.D[c1] = dst1;
reg.D[c2] = dst2;
} else {
// CAS.L Dc,Du,<ea>
ir2 = fetch_2();
uint c = ir2 & 7;
uint u = (ir2 >> 6) & 7;
uint32 dc = reg.D[c];
uint32 du = reg.D[u];
uint ea = cea_data_4();
uint32 dst = read_4(ea);
ACC.cmp_32(dc, dst);
if (CCR.IsZ()) {
// 等しければ、Du -> dst
CYCLE(13);
write_4(ea, du);
} else {
// そうでなければ、dst -> Dc
CYCLE(11);
reg.D[c] = dst;
}
}
}
// %0001_xxx000_mmmrrr MOVE.B <ea>,Dx
OP_DEF(move_b_ea_dn)
{
CYCLE(2);
uint32 data = fea_all_1();
ACC.move_8(data);
RegDX = (RegDX & 0xffffff00) | data;
}
// %0001_xxx010_mmmrrr MOVE.B <ea>,(Ax)
OP_DEF(move_b_ea_anin)
{
// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_1();
uint32 ea = cea_anin(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx011_mmmrrr MOVE.B <ea>,(Ax)+
OP_DEF(move_b_ea_anpi)
{
// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_1();
// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
save_reg_pi_if(RegIRX);
uint32 ea = cea_anpi_1(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx100_mmmrrr MOVE.B <ea>,-(Ax)
OP_DEF(move_b_ea_anpd)
{
// 実際にはソースがレジスタなら (4, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_1();
// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
save_reg_pd_if(RegIRX);
uint32 ea = cea_anpd_1(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx101_mmmrrr MOVE.B <ea>,d16(Ax)
OP_DEF(move_b_ea_andi)
{
CYCLE2(4, 5);
uint32 data = fea_all_1();
uint32 ea = cea_andi(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx110_mmmrrr MOVE.B <ea>,(Ax,IX)
OP_DEF(move_b_ea_anix)
{
// XXX 実際にはdstのフォーマットによって(8,9)-(20,23)
CYCLE2(16, 18);
uint32 data = fea_all_1();
uint32 ea = cea_anix(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_000111_mmmrrr MOVE.B <ea>,Abs.W
OP_DEF(move_b_ea_absw)
{
CYCLE2(4, 5);
uint32 data = fea_all_1();
uint32 ea = cea_absw();
ACC.move_8(data);
write_1(ea, data);
}
// %0001_001111_mmmrrr MOVE.B <ea>,Abs.L
OP_DEF(move_b_ea_absl)
{
CYCLE2(6, 7);
uint32 data = fea_all_1();
uint32 ea = cea_absl();
ACC.move_8(data);
write_1(ea, data);
}
// %0010_xxx000_mmmrrr MOVE.L <ea>,Dx
OP_DEF(move_l_ea_dn)
{
CYCLE(2);
uint32 data = fea_all_4();
ACC.move_32(data);
RegDX = data;
}
// %0010_xxx001_mmmrrr MOVEA.L <ea>,Ax
OP_DEF(movea_l)
{
CYCLE(2);
uint32 data = fea_all_4();
RegAX = data;
}
// %0010_xxx010_mmmrrr MOVE.L <ea>,(Ax)
OP_DEF(move_l_ea_anin)
{
// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_4();
uint32 ea = cea_anin(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx011_mmmrrr MOVE.L <ea>,(Ax)+
OP_DEF(move_l_ea_anpi)
{
// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_4();
// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
save_reg_pi_if(RegIRX);
uint32 ea = cea_anpi_4(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx100_mmmrrr MOVE.L <ea>,-(Ax)
OP_DEF(move_l_ea_anpd)
{
// 実際にはソースがレジスタなら (4, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_4();
// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
save_reg_pd_if(RegIRX);
uint32 ea = cea_anpd_4(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx101_mmmrrr MOVE.L <ea>,d16(Ax)
OP_DEF(move_l_ea_andi)
{
CYCLE2(4, 5);
uint32 data = fea_all_4();
uint32 ea = cea_andi(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx110_mmmrrr MOVE.L <ea>,(Ax,IX)
OP_DEF(move_l_ea_anix)
{
// XXX 実際にはdstのフォーマットによって(8,9)-(20,23)
CYCLE2(16, 18);
uint32 data = fea_all_4();
uint32 ea = cea_anix(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_000111_mmmrrr MOVE.L <ea>,Abs.W
OP_DEF(move_l_ea_absw)
{
CYCLE2(4, 5);
uint32 data = fea_all_4();
uint32 ea = cea_absw();
ACC.move_32(data);
write_4(ea, data);
}
// %0010_001111_mmmrrr MOVE.L <ea>,Abs.L
OP_DEF(move_l_ea_absl)
{
CYCLE2(6, 7);
uint32 data = fea_all_4();
uint32 ea = cea_absl();
ACC.move_32(data);
write_4(ea, data);
}
// %0011_xxx000_mmmrrr MOVE.W <ea>,Dx
OP_DEF(move_w_ea_dn)
{
CYCLE(2);
uint32 data = fea_all_2();
ACC.move_16(data);
RegDX = (RegDX & 0xffff0000) | data;
}
// %0011_xxx001_mmmrrr MOVEA.W <ea>,Ax
OP_DEF(movea_w)
{
CYCLE(2);
uint32 data = (int32)(int16)fea_all_2();
RegAX = data;
}
// %0011_xxx010_mmmrrr MOVE.W <ea>,(Ax)
OP_DEF(move_w_ea_anin)
{
// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_2();
uint32 ea = cea_anin(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx011_mmmrrr MOVE.W <ea>,(Ax)+
OP_DEF(move_w_ea_anpi)
{
// 実際にはソースがレジスタなら (3, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_2();
// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
save_reg_pi_if(RegIRX);
uint32 ea = cea_anpi_2(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx100_mmmrrr MOVE.W <ea>,-(Ax)
OP_DEF(move_w_ea_anpd)
{
// 実際にはソースがレジスタなら (4, 4)、メモリなら (4, 5)
CYCLE2(4, 5);
uint32 data = fea_all_2();
// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
save_reg_pd_if(RegIRX);
uint32 ea = cea_anpd_2(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx101_mmmrrr MOVE.W <ea>,d16(Ax)
OP_DEF(move_w_ea_andi)
{
CYCLE2(4, 5);
uint32 data = fea_all_2();
uint32 ea = cea_andi(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx110_mmmrrr MOVE.W <ea>,(Ax,IX)
OP_DEF(move_w_ea_anix)
{
// XXX 実際にはdstのフォーマットによって(8,9)-(20,23)
CYCLE2(16, 18);
uint32 data = fea_all_2();
uint32 ea = cea_anix(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_000111_mmmrrr MOVE.W <ea>,Abs.W
OP_DEF(move_w_ea_absw)
{
CYCLE2(4, 5);
uint32 data = fea_all_2();
uint32 ea = cea_absw();
ACC.move_16(data);
write_2(ea, data);
}
// %0011_001111_mmmrrr MOVE.W <ea>,Abs.L
OP_DEF(move_w_ea_absl)
{
CYCLE2(6, 7);
uint32 data = fea_all_2();
uint32 ea = cea_absl();
ACC.move_16(data);
write_2(ea, data);
}
// %0100_000000_mmmrrr NEGX.B <ea>
OP_DEF(negx_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEGX.B Dn
CYCLE(2);
uint32 data = reg.D[n] & 0xff;
data = ACC.subx_8(data, 0);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else if (n < 16) {
op_illegal();
} else {
// NEGX.B <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.subx_8(data, 0);
write_1(ea, data);
}
}
// %0100_000001_mmmrrr NEGX.W <ea>
OP_DEF(negx_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEGX.W Dn
CYCLE(2);
uint32 data = reg.D[n] & 0xffff;
data = ACC.subx_16(data, 0);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else if (n < 16) {
op_illegal();
} else {
// NEGX.W <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.subx_16(data, 0);
write_2(ea, data);
}
}
// %0100_000010_mmmrrr NEGX.L <ea>
OP_DEF(negx_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEGX.L Dn
CYCLE(2);
reg.D[n] = ACC.subx_32(reg.D[n], 0);
} else if (n < 16) {
op_illegal();
} else {
// NEGX.L <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.subx_32(data, 0);
write_4(ea, data);
}
}
// %0100_000011_mmmrrr MOVE.W SR,<ea>
OP_DEF(move_sr_ea)
{
SUPERVISOR_OP;
uint n = ir & 0x3f;
if (n < 8) {
// MOVE.W SR,Dn
CYCLE(4);
reg.D[n] = (reg.D[n] & 0xffff0000) | GetSR();
} else {
// MOVE.W SR,<ea>
CYCLE2(4, 5);
uint32 ea = cea_data_2();
write_2(ea, GetSR());
}
}
// %0100_xxx100_mmmrrr CHK.L <ea>,Dx
OP_DEF(chk_l)
{
uint32 dst = RegDX;
ACC.move_32(dst);
if (CCR.IsN()) {
// これは最大値で次の条件式が成立した時の値なので、
// 実際にはこれより小さい確定した値のはずだけど。
CYCLE2(28, 30);
Exception(M68K::EXCEP_CHK);
return;
}
// 本当はこうじゃないけど、とりあえず
uint32 src = fea_data_4();
if ((int32)dst > (int32)src) {
CYCLE2(28, 30);
CCR.SetN(false);
Exception(M68K::EXCEP_CHK);
return;
}
CYCLE(8);
}
// %0100_xxx110_mmmrrr CHK.W <ea>,Dx
OP_DEF(chk_w)
{
uint32 dst = RegDX & 0xffff;
ACC.move_16(dst);
if (CCR.IsN()) {
// これは最大値で次の条件式が成立した時の値なので、
// 実際にはこれより小さい確定した値のはずだけど。
CYCLE2(28, 30);
Exception(M68K::EXCEP_CHK);
return;
}
// 本当はこうじゃないけど、とりあえず
uint32 src = fea_data_2();
if ((int16)dst > (int16)src) {
CYCLE2(28, 30);
CCR.SetN(false);
Exception(M68K::EXCEP_CHK);
return;
}
CYCLE(8);
}
// %0100_xxx111_mmmrrr LEA.L <ea>,Ax
// %0100_100111_000yyy EXTB.L Dy
OP_DEF(lea)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXTB.L Dy
CYCLE(4);
RegDY = (int32)(int8)(RegDY & 0xff);
ACC.move_32(RegDY);
} else {
// LEA.L <ea>,Ax
CYCLE(2);
RegAX = cea_ctrl();
}
}
// %0100_001000_mmmrrr CLR.B <ea>
OP_DEF(clr_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// CLR.B Dn
CYCLE(2);
RegDY &= 0xffffff00;
ACC.move_8(0);
} else {
// CLR.B <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
ACC.move_8(0);
write_1(ea, 0);
}
}
// %0100_001001_mmmrrr CLR.W <ea>
OP_DEF(clr_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// CLR.W Dn
CYCLE(2);
RegDY &= 0xffff0000;
ACC.move_16(0);
} else {
// CLR.W <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
ACC.move_16(0);
write_2(ea, 0);
}
}
// %0100_001010_mmmrrr CLR.L <ea>
OP_DEF(clr_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// CLR.L Dn
CYCLE(2);
RegDY = 0;
ACC.move_32(0);
} else {
// CLR.L <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
ACC.move_32(0);
write_4(ea, 0);
}
}
// %0100_001011_mmmrrr MOVE.W CCR,<ea>
OP_DEF(move_ccr_ea)
{
uint n = ir & 0x3f;
// 転送は16ビットで行われ、上位バイトと未実装ビットは %0 になる。
if (n < 8) {
// MOVE.W CCR,Dn
CYCLE(4);
reg.D[n] = (reg.D[n] & 0xffff0000) | CCR.Get();
} else if (n < 16) {
// MOVE.W CCR,An はない
op_illegal();
} else {
// MOVE.W CCR,<ea>
CYCLE2(4, 5);
uint32 ea = cea_data_2();
write_2(ea, CCR.Get());
}
}
// %0100_010000_mmmrrr NEG.B <ea>
OP_DEF(neg_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEG.B Dn
CYCLE(2);
uint32 data = ACC.sub_8(reg.D[n] & 0xff, 0);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// NEG.B <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.sub_8(data, 0);
write_1(ea, data);
}
}
// %0100_010001_mmmrrr NEG.W <ea>
OP_DEF(neg_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEG.W Dn
CYCLE(2);
uint32 data = ACC.sub_16(reg.D[n] & 0xffff, 0);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else {
// NEG.W <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.sub_16(data, 0);
write_2(ea, data);
}
}
// %0100_010010_mmmrrr NEG.L <ea>
OP_DEF(neg_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEG.L Dn
CYCLE(2);
reg.D[n] = ACC.sub_32(reg.D[n], 0);
} else {
// NEG.L <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.sub_32(data, 0);
write_4(ea, data);
}
}
// %0100_010011_mmmrrr MOVE.W <ea>,CCR
OP_DEF(move_ea_ccr)
{
uint n = ir & 0x3f;
if (n < 8) {
// MOVE.W Dn,CCR
CYCLE(4);
uint32 data = reg.D[n] & 0xff;
CCR.Set(data);
} else if (n < 16) {
// MOVE.W An,CCR はない
op_illegal();
} else {
// MOVE.W <ea>,CCR
CYCLE(4);
uint32 data = fea_data_2();
CCR.Set(data);
}
}
// %0100_011000_mmmrrr NOT.B <ea>
OP_DEF(not_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// NOT.B Dn
CYCLE(2);
uint32 data = (~reg.D[n]) & 0xff;
ACC.move_8(data);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// NOT.B <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = (~data) & 0xff;
ACC.move_8(data);
write_1(ea, data);
}
}
// %0100_011001_mmmrrr NOT.W <ea>
OP_DEF(not_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// NOT.W Dn
CYCLE(2);
uint32 data = (~reg.D[n]) & 0xffff;
ACC.move_16(data);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else {
// NOT.W <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = (~data) & 0xffff;
ACC.move_16(data);
write_2(ea, data);
}
}
// %0100_011010_mmmrrr NOT.L <ea>
OP_DEF(not_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// NOT.L Dn
CYCLE(2);
reg.D[n] = ~reg.D[n];
ACC.move_32(reg.D[n]);
} else {
// NOT.L <ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ~data;
ACC.move_32(data);
write_4(ea, data);
}
}
// %0100_011011_mmmrrr MOVE.W <ea>,SR
OP_DEF(move_ea_sr)
{
SUPERVISOR_OP;
CYCLE2(8, 10);
uint16 data = fea_data_2();
SetSR(data);
}
// %0100_100000_mmmrrr NBCD.B <ea>
// %0100_100000_001yyy LINK.L Ay,#<imm>
OP_DEF(nbcd)
{
uint n = ir & 0x3f;
int32 imm;
if (n < 8) {
// NBCD.B Dn
CYCLE(6);
uint32 dst = RegDY & 0xff;
dst = ACC.sbcd_8(dst, 0);
RegDY = (RegDY & 0xffffff00) | dst;
} else if (n == 0x0e) {
// LINK.L A6,#<imm>
CYCLE2(6, 7);
// レジスタやスタックを変更する前にフェッチしないと、
// ページフォルトで再実行できなくなる
imm = fetch_4();
// ページフォルトに備えて保存する
save_reg_pd(7);
push_4(reg.A[6]);
reg.A[6] = reg.A[7];
reg.A[7] += imm;
} else if (n < 16) {
// LINK.L An,#<imm>
CYCLE2(6, 7);
// レジスタやスタックを変更する前にフェッチしないと、
// ページフォルトで再実行できなくなる
imm = fetch_4();
// ページフォルトに備えて保存する
save_reg_pd(7);
push_4(RegAY);
RegAY = reg.A[7];
reg.A[7] += imm;
} else {
// NBCD.B <ea>
CYCLE(6);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst = ACC.sbcd_8(dst, 0);
write_1(ea, dst);
}
}
// %0100_100001_000yyy SWAP.W Dy
// %0100_100001_001nnn BKPT #<imm>
// %0100_100001_mmmrrr PEA.L <ea>
OP_DEF(pea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SWAP.W Dy
CYCLE(4);
reg.D[n] = (reg.D[n] << 16) | (reg.D[n] >> 16);
ACC.move_32(reg.D[n]);
} else if (n < 16) {
// BKPT #<imm>
// ブレークポイント・アクノリッジサイクルに応答するデバイスはないので
// 常に不当命令にする。
CYCLE(9); // ?
op_illegal();
} else {
// PEA.L <ea>
CYCLE(4);
uint32 ea = cea_ctrl();
// ページフォルトに備えて保存する
save_reg_pd(7);
push_4(ea);
}
}
// MOVEM.[WL] <list>,<ea> の共通部分。
// bytesize は1レジスタ分のサイズ、.Wなら2、.Lなら4。
// 本当はテンプレートにしたい。
void
MPU680x0Device::ops_movem_list_ea(int bytesize)
{
uint32 ea;
int regcount;
// 不当な第1ワードを弾く
#define INVALID(x) (0xffULL << (56 - ((x) * 8)))
const uint64 valid =
INVALID(0) // Dn
| INVALID(1) // An
| INVALID(3) // (An)+
| 0x3fL; // (PC)...
if ((int64)(valid << (ir & 0x3f)) < 0) {
op_illegal();
return;
}
// 第2ワードは EA が正当な場合のみ EA より先にフェッチ
ir2 = fetch_2();
// EA 取得。MOVEM だけ別対応
// | M -WXZ | MOVEM list,<ea>
// だが、不当 EA はすでに弾いてあるので cea_data でいい
if (bytesize == 2) {
ea = cea_data_2();
} else {
ea = cea_data_4();
}
regcount = 0;
uint list = ir2;
if (eamode(ir) == 4/*-(An)*/) {
// -(An) の場合 reglist の格納順が逆(転送順は LSB から)
// bit15 bit0
// D0 D1 D2 D3 D4 D5 D6 D7 A0 A1 A2 A3 A4 A5 A6 A7
while (list) {
int ctz = __builtin_ctz(list);
if (bytesize == 2) {
write_2(ea, reg.R[15 - ctz] & 0xffff);
} else {
write_4(ea, reg.R[15 - ctz]);
}
ea -= bytesize;
regcount++;
// 処理した最下位ビットを落とす
list &= list - 1;
}
// ea は一つ行き過ぎるので補正
RegAY = ea + bytesize;
} else {
// LSB 側から転送
// bit15 bit0
// A7 A6 A5 A4 A4 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
while (list) {
int ctz = __builtin_ctz(list);
if (bytesize == 2) {
write_2(ea, reg.R[ctz] & 0xffff);
} else {
write_4(ea, reg.R[ctz]);
}
ea += bytesize;
regcount++;
// 処理した最下位ビットを落とす
list &= list - 1;
}
}
CYCLE(4 + 2 * regcount);
}
// %0100_100010_000yyy EXT.W Dy
// %0100_100010_mmmrrr MOVEM.W <list>,<ea>
OP_DEF(movem_w_mem)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXT.W Dy
CYCLE(4);
uint16 data = (int16)(int8)(RegDY & 0xff);
ACC.move_16(data);
RegDY = (RegDY & 0xffff0000) | data;
} else {
// MOVEM.W <list>,<ea>
ops_movem_list_ea(2);
}
}
// %0100_100011_000yyy EXT.L Dy
// %0100_100011_mmmrrr MOVEM.L <list>,<ea>
OP_DEF(movem_l_mem)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXT.L Dy
CYCLE(4);
RegDY = (int32)(int16)(RegDY & 0x0000ffff);
ACC.move_32(RegDY);
} else {
// MOVEM.L <list>,<ea>
ops_movem_list_ea(4);
}
}
// %0100_101000_mmmrrr TST.B <ea>
OP_DEF(tst_b)
{
CYCLE(2);
uint32 data = fea_all_1();
ACC.move_8(data);
}
// %0100_101001_mmmrrr TST.W <ea>
OP_DEF(tst_w)
{
CYCLE(2);
uint32 data = fea_all_2();
ACC.move_16(data);
}
// %0100_101010_mmmrrr TST.L <ea>
OP_DEF(tst_l)
{
CYCLE(2);
uint32 data = fea_all_4();
ACC.move_32(data);
}
// %0100_101011_mmmrrr TAS.B <ea>
// %0100_101011_111100 ILLEGAL
OP_DEF(tas)
{
uint n = ir & 0x3f;
if (n < 8) {
// TAS.B Dn
// リード・モディファイ・ライトという概念はない
CYCLE(4);
uint32 data = reg.D[n];
ACC.move_8(data);
reg.D[n] |= 0x80;
} else if (n == 0x3c) {
// ILLEGAL
op_illegal();
} else {
// TAS.B <ea>
// リード・モディファイ・ライトという概念はない
CYCLE(12);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
ACC.move_8(data);
write_1(ea, (data | 0x80));
}
}
// %0100_110000_mmmrrr MUL{U,S}.L <ea>,Dl
OP_DEF(mul)
{
// 2ワード目
// %0LLL_Ss0000_000HHH
// +++ || +++- Dh
// | |+------------ %1:64bit, %0:32bit
// | +------------- %1:MULS, %0:MULU
// +---------------- Dl
ir2 = fetch_2();
uint h = ir2 & 7;
uint l = (ir2 >> 12) & 7;
CYCLE(44); // XXX これは本当は最大値だけど
switch ((ir2 >> 10) & 3) {
case 0:
{
// MULU.L <ea>,Dl
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
reg.D[l] = ACC.mulu_32(src, dst);
break;
}
case 1:
{
// MULU.L <ea>,Dh:Dl
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
uint64 res = ACC.mulu_64(src, dst);
// h == l の時は未定義なので考えない。
reg.D[h] = res >> 32;
reg.D[l] = res;
break;
}
case 2:
{
// MULS.L <ea>,Dl
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
reg.D[l] = ACC.muls_32(src, dst);
break;
}
case 3:
{
// MULS.L <ea>,Dh:Dl
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
uint64 res = ACC.muls_64(src, dst);
// h == l の時は未定義なので考えない。
reg.D[h] = res >> 32;
reg.D[l] = res;
break;
}
default:
__unreachable();
}
}
// DIVU.L <ea>,Dq
// DIVUL.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divu_32_32(uint r, uint q)
{
CYCLE(78); // XXX これは本当は最大値だけど
uint32 src = fea_data_4();
uint32 dst = reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
uint32 quo = dst / src;
uint32 rem = dst % src;
// このケースでオーバーフローは起きないはず
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// DIVU.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divu_64_32(uint r, uint q)
{
CYCLE(78); // XXX これは本当は最大値だけど
uint32 src = fea_data_4();
uint64 dst = (((uint64)reg.D[r]) << 32) | reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
uint64 q64 = dst / src;
if (q64 > 0xffffffffUL) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
uint32 quo = q64;
uint32 rem = dst % src;
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// DIVS.L <ea>,Dq
// DIVSL.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divs_32_32(uint r, uint q)
{
CYCLE(90); // XXX これは本当は最大値だけど
uint32 src = fea_data_4();
uint32 dst = reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
// ホストでオーバーフローが起きるのはこのケースのみ
if (dst == INT32_MIN && src == -1) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
uint32 quo = (int32)dst / (int32)src;
uint32 rem = (int32)dst % (int32)src;
// ここでオーバーフローは起きない
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// DIVSL.L
void
MPU680x0Device::ops_divs_64_32(uint r, uint q)
{
CYCLE(90); // XXX これは本当は最大値だけど
uint32 src = fea_data_4();
uint64 dst = (((uint64)reg.D[r]) << 32) | reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
// ホストでオーバーフローが起きるのはこのケースのみ
if (dst == INT64_MIN && src == -1) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
int64 sq64 = (int64)dst / (int32)src;
if ((int32)sq64 != sq64) {
// オーバーフロー
CCR.SetV(true);
CCR.SetC(false);
return;
}
uint32 quo = (uint32)sq64;
uint32 rem = (int64)dst % (int32)src;
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// %0100_110001_mmmrrr DIVU.L <ea>,Dq
// %0100_110001_mmmrrr DIVU.L <ea>,Dr:Dq
// %0100_110001_mmmrrr DIVUL.L <ea>,Dr:Dq
// %0100_110001_mmmrrr DIVS.L <ea>,Dq
// %0100_110001_mmmrrr DIVS.L <ea>,Dr:Dq
// %0100_110001_mmmrrr DIVSL.L <ea>,Dr:Dq
OP_DEF(div)
{
// 2ワード目
// %0QQQ_Ss0000_000RRR
// +++ || +++- Dr
// | |+------------ %1:64bit, %0:32bit
// | +------------- %1:DIVS, %0:DIVU
// +---------------- Dq
ir2 = fetch_2();
uint r = ir2 & 7;
uint q = (ir2 >> 12) & 7;
switch ((ir2 >> 10) & 3) {
case 0:
ops_divu_32_32(r, q);
break;
case 1:
ops_divu_64_32(r, q);
break;
case 2:
ops_divs_32_32(r, q);
break;
case 3:
ops_divs_64_32(r, q);
break;
default:
__unreachable();
}
}
void
MPU680x0Device::ops_movem_ea_list(int bytesize)
{
uint32 ea;
int regcount;
bool anpi = false;
ir2 = fetch_2();
// EA 取得。MOVEM だけ別対応
// | M+ WXZP | MOVEM <ea>,list
switch (eamode(ir)) {
case 2: // (An)
ea = cea_anin(eanum(ir));
break;
case 3: // (An)+
save_reg_pi(eanum(ir));
if (bytesize == 2) {
ea = cea_anpi_2(eanum(ir));
} else {
ea = cea_anpi_4(eanum(ir));
}
anpi = true;
break;
case 5: // d16(An)
ea = cea_andi(eanum(ir));
break;
case 6: // (An,IX)
ea = cea_anix(eanum(ir));
break;
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = cea_absw();
break;
case 1: // Abs.L
ea = cea_absl();
break;
case 2: // d16(PC)
ea = cea_pcdi();
break;
case 3: // (PC,IX)
ea = cea_pcix();
break;
default:
op_illegal();
return;
}
break;
default:
op_illegal();
return;
}
// XXX レジスタリストに表れて、ea オペランドに出てくる
// レジスタは Dn、IX も含めて全部保存しておく必要がある。
regcount = 0;
uint list = ir2;
while (list) {
uint32 data;
if (bytesize == 2) {
data = (int32)(int16)read_2(ea);
} else {
data = read_4(ea);
}
ea += bytesize;
regcount++;
int ctz = __builtin_ctz(list);
reg.R[ctz] = data;
// clear LSB bits
list &= ((~1U) << ctz);
}
// (An)+ なら An を更新
if (anpi) {
RegAY = ea;
}
CYCLE(8 + 4 * regcount);
}
// %0100_110010_mmmrrr MOVEM.W <ea>,<list>
OP_DEF(movem_w)
{
ops_movem_ea_list(2);
}
// %0100_110011_mmmrrr MOVEM.L <ea>,<list>
OP_DEF(movem_l)
{
ops_movem_ea_list(4);
}
// MOVEC.L Rc,Rn
void
MPU680x0Device::ops_movec_rc_rn()
{
SUPERVISOR_OP;
CYCLE(6);
ir2 = fetch_2();
uint n = ir2 >> 12;
uint c = ir2 & 0xfff;
switch (c) {
case 0x000:
reg.R[n] = reg.GetSFC();
return;
case 0x001:
reg.R[n] = reg.GetDFC();
return;
case 0x002:
reg.R[n] = reg.cacr;
return;
case 0x800:
reg.R[n] = reg.usp;
return;
case 0x801:
reg.R[n] = reg.vbr;
return;
case 0x802:
reg.R[n] = reg.caar;
return;
case 0x803:
if (reg.m) {
reg.R[n] = reg.A[7];
} else {
reg.R[n] = reg.msp;
}
return;
case 0x804:
if (reg.m) {
reg.R[n] = reg.isp;
} else {
reg.R[n] = reg.A[7];
}
return;
default:
break;
}
op_illegal();
}
// MOVEC.L Rn,Rc
void
MPU680x0Device::ops_movec_rn_rc()
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint c = ir2 & 0xfff;
switch (c) {
case 0x000:
CYCLE(12);
reg.sfc = busaddr::FC(reg.R[n] & 7) | BusAddr::R;
return;
case 0x001:
CYCLE(12);
reg.dfc = busaddr::FC(reg.R[n] & 7) | BusAddr::W;
return;
case 0x002:
CYCLE(12);
SetCACR(reg.R[n]);
return;
case 0x800:
CYCLE(6);
reg.usp = reg.R[n];
return;
case 0x801:
CYCLE(6);
reg.vbr = reg.R[n];
return;
case 0x802:
CYCLE(6);
reg.caar = reg.R[n];
return;
case 0x803:
CYCLE(6);
if (reg.m) {
reg.A[7] = reg.R[n];
} else {
reg.msp = reg.R[n];
}
return;
case 0x804:
CYCLE(6);
if (reg.m) {
reg.isp = reg.R[n];
} else {
reg.A[7] = reg.R[n];
}
return;
default:
break;
}
op_illegal();
}
// %0100_111001_00nnnn TRAP #<vector>
// %0100_111001_010yyy LINK.W Ay,#<imm>
// %0100_111001_011yyy UNLK Ay
// %0100_111001_100yyy MOVE.L Ay,USP
// %0100_111001_101yyy MOVE.L USP,Ay
// %0100_111001_110000 RESET
// %0100_111001_110001 NOP
// %0100_111001_110010 STOP #<imm>
// %0100_111001_110011 RTE
// %0100_111001_110100 RTD #<imm>
// %0100_111001_110101 RTS
// %0100_111001_110110 TRAPV
// %0100_111001_110111 RTR
// %0100_111001_111010 MOVEC.L Rc,Rn
// %0100_111001_111011 MOVEC.L Rn,Rc
OP_DEF(trap)
{
uint n = ir & 0x3f;
int32 imm;
switch (n) {
case 0x00 ... 0x0e:// TRAP #<vector>
CYCLE2(18, 20);
// TRAP#N 例外
Exception(M68K::EXCEP_TRAP0 + n);
return;
case 0x0f: // TRAP #15
CYCLE2(18, 20);
// TRAP#15 例外 (IOCS コール表示のためこれだけ別処理)
ExceptionTrap15();
return;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x17: // LINK.W Ay,#<imm>
CYCLE2(4, 5);
// レジスタやスタックを変更する前にフェッチとセーブをしないと、
// ページフォルトで再実行できなくなる
imm = (int32)(int16)fetch_2();
save_reg_pd(7);
push_4(RegAY);
RegAY = reg.A[7];
reg.A[7] += imm;
return;
case 0x16: // LINK.W A6,#<imm>
// LINK はほぼ A6 なのでこいつだけ展開してみる
CYCLE2(4, 5);
// レジスタやスタックを変更する前にフェッチとセーブをしないと、
// ページフォルトで再実行できなくなる
imm = (int32)(int16)fetch_2();
save_reg_pd(7);
push_4(reg.A[6]);
reg.A[6] = reg.A[7];
reg.A[7] += imm;
return;
case 0x18:
case 0x19:
case 0x1a:
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1f: // UNLK Ay
CYCLE(5);
// ページフォルトに備えて保存する
save_reg_pi(7);
reg.A[7] = RegAY;
RegAY = pop_4();
return;
case 0x1e: // UNLK A6
// UNLK はほぼ A6 なのでこいつだけ展開してみる
CYCLE(5);
// ページフォルトに備えて保存する
save_reg_pi(7);
reg.A[7] = reg.A[6];
reg.A[6] = pop_4();
return;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27: // MOVE.L Ay,USP
SUPERVISOR_OP;
CYCLE(4);
reg.usp = RegAY;
return;
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f: // MOVE.L USP,Ay
SUPERVISOR_OP;
CYCLE(4);
RegAY = reg.usp;
return;
case 0x30: // RESET
CYCLE(518);
ops_reset();
return;
case 0x31: // NOP
CYCLE(2);
// XXX ほんとは何かするらしいけど
return;
case 0x32: // STOP #<imm>
SUPERVISOR_OP;
CYCLE(8);
ops_stop();
return;
case 0x33: // RTE
SUPERVISOR_OP;
ops_rte();
return;
case 0x34: // RTD #<imm>
{
CYCLE2(10, 12);
// ページフォルトに備えて保存する
save_reg_pi(7);
uint32 disp = fetch_2();
Jump(pop_4());
reg.A[7] += (int32)(int16)disp;
return;
}
case 0x35: // RTS
CYCLE2(9, 11);
// ページフォルトに備えて保存する
save_reg_pi(7);
Jump(pop_4());
return;
case 0x36: // TRAPV
if (CCR.IsV()) {
CYCLE2(22, 24);
Exception(M68K::EXCEP_TRAPV);
} else {
CYCLE(4);
}
return;
case 0x37: // RTR
CYCLE2(12, 14);
// ページフォルトに備えて保存する
save_reg_pi(7);
CCR.Set(pop_2());
Jump(pop_4());
return;
case 0x3a: // MOVEC.L Rc,Rn
ops_movec_rc_rn();
return;
case 0x3b: // MOVEC.L Rn,Rc
ops_movec_rn_rc();
return;
default:
op_illegal();
return;
}
}
// %0100_111010_mmmrrr JSR <ea>
OP_DEF(jsr)
{
CYCLE2(4, 7);
uint32 ea = cea_ctrl();
// ページフォルトに備えて保存する
save_reg_pd(7);
push_4(reg.pc);
Jump(ea);
}
// %0100_111011_mmmrrr JMP <ea>
OP_DEF(jmp)
{
CYCLE2(4, 6);
// 実際には CEA ではなく JEA の実行時間を足すんだがまあいいか
uint32 ea = cea_ctrl();
Jump(ea);
}
// %0101_qqq000_mmmrrr ADDQ.B #qqq,<ea>
OP_DEF(addq_b)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// ADDQ.B #qqq,Dn
CYCLE(2);
uint32 data = ACC.add_8(src, reg.D[n] & 0xff);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// ADDQ.B #qqq,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.add_8(src, data);
write_1(ea, data);
}
}
// %0101_qqq001_mmmrrr ADDQ.W #qqq,<ea>
// %0101_qqq001_001yyy ADDQ.W #qqq,Ay (.Lと等価)
OP_DEF(addq_w)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// ADDQ.W #qqq,Dn
CYCLE(2);
uint32 data = ACC.add_16(src, reg.D[n] & 0xffff);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else if (n < 16) {
// ADDQ.W #qqq,An は ADDQ.L と等価
// フラグは変化しない
CYCLE(2);
reg.R[n] += src;
} else {
// ADDQ.W #qqq,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.add_16(src, data);
write_2(ea, data);
}
}
// %0101_qqq010_mmmrrr ADDQ.L #qqq,<ea>
// %0101_qqq010_001yyy ADDQ.L #qqq,Ay
OP_DEF(addq_l)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// ADDQ.L #qqq,Dn
CYCLE(2);
reg.D[n] = ACC.add_32(src, reg.D[n]);
} else if (n < 16) {
// ADDQ.L #qqq,An
// フラグは変化しない
CYCLE(2);
reg.R[n] += src;
} else {
// ADDQ.L #qqq,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.add_32(src, data);
write_4(ea, data);
}
}
// TRAPcc の共通部分。
void
MPU680x0Device::ops_trapcc(uint cond)
{
// 条件成立すれば例外。成立しなければ何もしない。
// いずれの場合もオペランドありの形態なら事前に読み飛ばしておくこと。
if (CCR.Cond(cond)) {
CYCLE2(22, 24);
Exception(M68K::EXCEP_TRAPV);
} else {
// サイクルを消費するだけ
CYCLE(4);
}
}
// %0101_cccc11_mmmrrr Scc.B <ea>
// %0101_cccc11_001yyy DBcc.W Dy,<label>
// %0101_cccc11_111010 TRAPcc.W #<imm>
// %0101_cccc11_111011 TRAPcc.L #<imm>
// %0101_cccc11_111100 TRAPcc
// %0101_000111_001yyy DBRA.W Dy,<label>
OP_DEF(scc)
{
uint n = ir & 0x3f;
uint cond = (ir >> 8) & 0x0f;
switch (n) {
case 0b000000 ... 0b000111: // Scc.B Dn
CYCLE(4);
if (CCR.Cond(cond)) {
RegDY |= 0xff;
} else {
RegDY &= ~0xff;
}
return;
case 0b001000 ... 0b001111: // DBcc.W Dy,<label>
if (CCR.Cond(cond)) {
// 真なら何もしない。disp を読み飛ばして次へ。
CYCLE2(6, 8);
fetch_2();
} else {
// 偽の場合
// Dy.W を減算して(下位ワードに)書き戻し、Dy.W が -1 だったら
// ループ終了。だが最適化のため、減算前の Dy.W が 0 の時は
// 下位ワードを 0xffff にしてループ終了、そうでなければ Dy.L を
// 減算するだけでいいはず。
uint16 data = RegDY;
if (data == 0) {
// ループ終了。disp を読み飛ばす
CYCLE2(10, 13);
RegDY |= 0x0000ffff;
fetch_2();
} else {
CYCLE2(6, 8);
RegDY--;
uint32 origin = reg.pc;
int32 disp = (int32)(int16)fetch_2();
Jump(origin + disp);
}
}
return;
case 0b010000 ... 0b010111: // Scc.B <ea>
case 0b011000 ... 0b011111: // Scc.B <ea>
case 0b100000 ... 0b100111: // Scc.B <ea>
case 0b101000 ... 0b101111: // Scc.B <ea>
case 0b110000 ... 0b110111: // Scc.B <ea>
case 0b111000: // Scc.B <ea>
case 0b111001: // Scc.B <ea>
{
CYCLE(5);
// 条件成立可否に関わらず EA は取得しないといけない
uint32 ea = cea_data_1();
uint32 data;
if (CCR.Cond(cond)) {
data = 0xff;
} else {
data = 0;
}
write_1(ea, data);
return;
}
case 0b111010: // TRAPcc.W #<imm>
// オペランドなしTRAPccに比べてすべてのケースで2サイクル多い
CYCLE(2);
fetch_2();
ops_trapcc(cond);
return;
case 0b111011: // TRAPcc.L #<imm>
// オペランドなしTRAPccに比べてすべてのケースで4サイクル多い
CYCLE(4);
fetch_4();
ops_trapcc(cond);
return;
case 0b111100: // TRAPcc
ops_trapcc(cond);
return;
default:
OP_FUNC(illegal);
return;
}
}
// %0101_qqq100_mmmrrr SUBQ.B #qqq,<ea>
OP_DEF(subq_b)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// SUBQ.B #qqq,Dn
CYCLE(2);
uint32 data = ACC.sub_8(src, reg.D[n] & 0xff);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// SUBQ.B #qqq,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.sub_8(src, data);
write_1(ea, data);
}
}
// %0101_qqq101_mmmrrr SUBQ.W #qqq,<ea>
// %0101_qqq101_001yyy SUBQ.W #qqq,Ay (.Lと等価)
OP_DEF(subq_w)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// SUBQ.W #qqq,Dn
CYCLE(2);
uint32 data = ACC.sub_16(src, reg.D[n] & 0xffff);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else if (n < 16) {
// SUBQ.W #qqq,An は SUBQ.L と等価
// フラグは変化しない
CYCLE(2);
reg.R[n] -= src;
} else {
// SUBQ.W #qqq,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.sub_16(src, data);
write_2(ea, data);
}
}
// %0101_qqq110_mmmrrr SUBQ.L #qqq,<ea>
// %0101_qqq110_001yyy SUBQ.L #qqq,Ay
OP_DEF(subq_l)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// SUBQ.L #qqq,Dn
CYCLE(2);
reg.D[n] = ACC.sub_32(src, reg.D[n]);
} else if (n < 16) {
// SUBQ.L #qqq,An
// フラグは変化しない
CYCLE(2);
reg.R[n] -= src;
} else {
// SUBQ.L #qqq,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.sub_32(src, data);
write_4(ea, data);
}
}
inline void
MPU680x0Device::ops_bra()
{
CYCLE2(6, 8);
uint32 origin = reg.pc;
int32 disp = (int32)(int8)(ir & 0xff);
if (disp == -1) {
// Bcc.L
disp = (int32)fetch_4();
} else if (disp == 0) {
// Bcc.W
disp = (int32)(int16)fetch_2();
}
Jump(origin + disp);
}
// %0110_000000_000000 BRA.W <label>
// %0110_0000nn_nnnnnn BRA.B <label>
// %0110_000011_111111 BRA.L <label>
OP_DEF(bra)
{
ops_bra();
}
// %0110_000100_000000 BSR.W <label>
// %0110_0001nn_nnnnnn BSR.B <label>
// %0110_000111_111111 BSR.L <label>
OP_DEF(bsr)
{
CYCLE2(6, 9);
uint32 origin = reg.pc;
int32 disp = (int32)(int8)(ir & 0xff);
if (disp == -1) {
// BSR.L <label>
disp = (int32)fetch_4();
} else if (disp == 0) {
// BSR.W <label>
disp = (int32)(int16)fetch_2();
}
// ページフォルトに備えて保存する
save_reg_pd(7);
push_4(reg.pc);
Jump(origin + disp);
}
// %0110_cccc00_000000 Bcc.W <label>
// %0110_ccccnn_nnnnnn Bcc.B <label>
// %0110_cccc11_111111 Bcc.L <label>
OP_DEF(bcc)
{
// ブランチするかどうかでサイクルが変わるので先に条件を調べる
uint cond = (ir >> 8) & 0x0f;
if (CCR.Cond(cond)) {
// Bcc (taken)
ops_bra();
} else {
int32 disp = (int32)(int8)(ir & 0xff);
if (disp == -1) {
// Bcc.L (not taken)
CYCLE(8);
fetch_4();
} else if (disp == 0) {
// Bcc.W (not taken)
CYCLE(6);
fetch_2();
} else {
// Bcc.B (not taken)
CYCLE(4);
}
}
}
// %0111_xxx0nn_nnnnnn MOVEQ.L #<imm>,Dx
OP_DEF(moveq)
{
CYCLE(2);
RegDX = (int32)(int8)(ir & 0xff);
ACC.move_32(RegDX);
}
// %1000_xxx000_mmmrrr OR.B <ea>,Dx
OP_DEF(or_b_ea_dn)
{
uint n = ir & 0x3f;
CYCLE(2);
uint x = RegIRX;
if (n < 8) {
// OR.B Dn,Dx
uint32 data = (reg.D[x] | reg.D[n]) & 0xff;
ACC.move_8(data);
reg.D[x] = (reg.D[x] & 0xffffff00) | data;
} else {
// OR.B <ea>,Dx
uint32 src = fea_data_1();
uint32 data = (reg.D[x] | src) & 0xff;
ACC.move_8(data);
reg.D[x] = (reg.D[x] & 0xffffff00) | data;
}
}
// %1000_xxx001_mmmrrr OR.W <ea>,Dx
OP_DEF(or_w_ea_dn)
{
uint n = ir & 0x3f;
CYCLE(2);
uint x = RegIRX;
if (n < 8) {
// OR.W Dn,Dx
uint32 data = (reg.D[x] | reg.D[n]) & 0xffff;
ACC.move_16(data);
reg.D[x] = (reg.D[x] & 0xffff0000) | data;
} else {
// OR.W <ea>,Dx
uint32 src = fea_data_2();
uint32 data = (reg.D[x] | src) & 0xffff;
ACC.move_16(data);
reg.D[x] = (reg.D[x] & 0xffff0000) | data;
}
}
// %1000_xxx010_mmmrrr OR.L <ea>,Dx
OP_DEF(or_l_ea_dn)
{
uint n = ir & 0x3f;
CYCLE(2);
uint x = RegIRX;
if (n < 8) {
// OR.L Dn,Dx
reg.D[x] |= reg.D[n];
ACC.move_32(reg.D[x]);
} else {
// OR.L <ea>,Dx
uint32 src = fea_data_4();
uint32 data = reg.D[x] | src;
ACC.move_32(data);
reg.D[x] = data;
}
}
// %1000_xxx011_mmmrrr DIVU.W <ea>,Dx
OP_DEF(divu_w)
{
CYCLE(44); // XXX これは本当は最大値だけど
uint16 src = fea_data_2();
uint32 dst = RegDX;
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
uint32 quo = dst / src;
uint32 rem = dst % src;
if (quo > 0xffff) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
RegDX = (rem << 16) | quo;
ACC.move_16(quo);
}
// %1000_xxx100_000yyy SBCD.B Dy,Dx
// %1000_xxx100_001yyy SBCD.B -(Ay),-(Ax)
// %1000_xxx100_mmmrrr OR.B Dx,<ea>
OP_DEF(or_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SBCD.B Dy,Dx
CYCLE(4);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.sbcd_8(src, dst);
RegDX &= 0xffffff00;
RegDX |= dst;
} else if (n < 16) {
// SBCD.B -(Ay),-(Ax)
CYCLE2(13, 14);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.sbcd_8(src, dst);
write_1(dstea, dst);
} else {
// OR.B Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint8 data = read_1(ea);
data |= RegDX;
ACC.move_8(data);
write_1(ea, data);
}
}
// %1000_xxx101_000yyy PACK Dy,Dx,#<imm>
// %1000_xxx101_001yyy PACK -(Ay),-(Ax),#<imm>
// %1000_xxx101_mmmrrr OR.W Dx,<ea>
OP_DEF(or_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// PACK Dy,Dx,#<imm>
CYCLE(6);
uint32 imm = fetch_2();
uint32 src = RegDY + imm;
RegDX = (RegDX & 0xffffff00) | ((src >> 4) & 0x00f0) | (src & 0x000f);
} else if (n < 16) {
// PACK -(Ay),-(Ax),#<imm>
CYCLE(11);
uint32 imm = fetch_2();
uint32 srcea;
uint32 src;
// -(Ay) を2回行う
save_reg_pd(RegIRY);
srcea = internal_ea_anpd_1(RegIRY);
src = read_1(srcea);
srcea = internal_ea_anpd_1(RegIRY);
src |= (read_1(srcea) << 8);
src += imm;
uint32 dst = ((src >> 4) & 0x00f0) | (src & 0x000f);
save_reg_pd_if(RegIRX);
uint32 dstea = internal_ea_anpd_1(RegIRX);
write_1(dstea, dst);
} else {
// OR.W Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint16 data = read_2(ea);
data |= RegDX;
ACC.move_16(data);
write_2(ea, data);
}
}
// %1000_xxx110_000yyy UNPK Dy,Dx,#<imm>
// %1000_xxx110_001yyy UNPK -(Ay),-(Ax),#<imm>
// %1000_xxx110_mmmrrr OR.L Dx,<ea>
OP_DEF(or_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// UNPK Dy,Dx,#<imm>
CYCLE(8);
uint32 imm = fetch_2();
uint16 src = RegDY;
src = ((src & 0x00f0) << 4) | (src & 0x000f);
src += imm;
RegDX = (RegDX & 0xffff0000) | src;
} else if (n < 16) {
// UNPK -(Ay),-(Ax),#<imm>
CYCLE(11);
uint32 imm = fetch_2();
save_reg_pd(RegIRY);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint16 src = read_1(srcea);
src = ((src & 0x00f0) << 4) | (src & 0x000f);
src += imm;
// -(Ax) を2回行う
save_reg_pd_if(RegIRX);
uint32 dstea;
dstea = internal_ea_anpd_1(RegIRX);
write_1(dstea, (src & 0xff));
dstea = internal_ea_anpd_1(RegIRX);
write_1(dstea, src >> 8);
} else {
// OR.L Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data |= RegDX;
ACC.move_32(data);
write_4(ea, data);
}
}
// %1000_xxx111_mmmrrr DIVS.W <ea>,Dx
OP_DEF(divs_w)
{
CYCLE(56); // XXX これは本当は最大値だけど
uint16 src = fea_data_2();
uint32 dst = RegDX;
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
// ホストでオーバーフローが起きるのはこのケースのみ
if (dst == 0x80000000 && src == 0xffff) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
int32 squo = (int32)dst / (int32)(int16)src;
int32 srem = (int32)dst % (int32)(int16)src;
if ((int16)squo != squo) {
// オーバーフローの場合
CCR.SetV(true);
CCR.SetC(false);
return;
}
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
uint32 quo = (uint32)squo & 0xffff;
uint32 rem = (uint32)srem & 0xffff;
RegDX = (rem << 16) | quo;
ACC.move_16(quo);
}
// %1001_xxx000_mmmrrr SUB.B <ea>,Dx
OP_DEF(sub_b_ea_dn)
{
CYCLE(2);
uint32 src = fea_all_1();
uint32 data = ACC.sub_8(src, RegDX & 0xff);
RegDX = (RegDX & 0xffffff00) | data;
}
// %1001_xxx001_mmmrrr SUB.W <ea>,Dx
OP_DEF(sub_w_ea_dn)
{
CYCLE(2);
uint32 src = fea_all_2();
uint32 data = ACC.sub_16(src, RegDX & 0xffff);
RegDX = (RegDX & 0xffff0000) | data;
}
// %1001_xxx010_mmmrrr SUB.L <ea>,Dx
OP_DEF(sub_l_ea_dn)
{
CYCLE(2);
uint32 src = fea_all_4();
RegDX = ACC.sub_32(src, RegDX);
}
// %1001_xxx011_mmmrrr SUBA.W <ea>,Ax
OP_DEF(suba_w)
{
CYCLE(4);
uint32 src = (int32)(int16)fea_all_2();
RegAX -= src;
}
// %1001_xxx100_000yyy SUBX.B Dy,Dx
// %1001_xxx100_001yyy SUBX.B -(Ay),-(Ax)
// %1001_xxx100_mmmrrr SUB.B Dx,<ea>
OP_DEF(sub_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SUBX.B Dy,Dx
CYCLE(2);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.subx_8(src, dst);
RegDX = (RegDX & 0xffffff00) | dst;
} else if (n < 16) {
// SUBX.B -(Ay),-(Ax)
CYCLE2(9, 10);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.subx_8(src, dst);
write_1(dstea, dst);
} else {
// SUB.B Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.sub_8(RegDX & 0xff, data);
write_1(ea, data);
}
}
// %1001_xxx101_000yyy SUBX.W Dy,Dx
// %1001_xxx101_001yyy SUBX.W -(Ay),-(Ax)
// %1001_xxx101_mmmrrr SUB.W Dx,<ea>
OP_DEF(sub_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SUBX.W Dy,Dx
CYCLE(2);
uint32 src = RegDY & 0xffff;
uint32 dst = RegDX & 0xffff;
dst = ACC.subx_16(src, dst);
RegDX = (RegDX & 0xffff0000) | dst;
} else if (n < 16) {
// SUBX.W -(Ay),-(Ax)
CYCLE2(9, 10);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_2(RegIRY);
uint32 dstea = internal_ea_anpd_2(RegIRX);
uint32 src = read_2(srcea);
uint32 dst = read_2(dstea);
dst = ACC.subx_16(src, dst);
write_2(dstea, dst);
} else {
// SUB.W Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.sub_16(RegDX & 0xffff, data);
write_2(ea, data);
}
}
// %1001_xxx110_000yyy SUBX.L Dy,Dx
// %1001_xxx110_001yyy SUBX.L -(Ay),-(Ax)
// %1001_xxx110_mmmrrr SUB.L Dx,<ea>
OP_DEF(sub_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SUBX.L Dy,Dx
CYCLE(2);
uint32 src = RegDY;
uint32 dst = RegDX;
RegDX = ACC.subx_32(src, dst);
} else if (n < 16) {
// SUBX.L -(Ay),-(Ax)
CYCLE2(9, 10);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_4(RegIRY);
uint32 dstea = internal_ea_anpd_4(RegIRX);
uint32 src = read_4(srcea);
uint32 dst = read_4(dstea);
dst = ACC.subx_32(src, dst);
write_4(dstea, dst);
} else {
// SUB.L Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.sub_32(RegDX, data);
write_4(ea, data);
}
}
// %1001_xxx111_mmmrrr SUBA.L <ea>,Ax
OP_DEF(suba_l)
{
CYCLE(2);
uint32 src = fea_all_4();
RegAX -= src;
}
// %1010_nnnnnn_nnnnnn A-Line
OP_DEF(aline)
{
if (aline_callback) {
if (aline_callback(this, aline_arg)) {
return;
}
}
// A系列命令例外
Exception(M68K::EXCEP_ALINE);
}
// %1011_xxx000_mmmrrr CMP.B <ea>,Dx
OP_DEF(cmp_b)
{
CYCLE(2);
uint32 src = fea_all_1();
uint32 dst = RegDX & 0xff;
ACC.cmp_8(src, dst);
}
// %1011_xxx001_mmmrrr CMP.W <ea>,Dx
OP_DEF(cmp_w)
{
CYCLE(2);
uint32 src = fea_all_2();
uint32 dst = RegDX & 0xffff;
ACC.cmp_16(src, dst);
}
// %1011_xxx010_mmmrrr CMP.L <ea>,Dx
OP_DEF(cmp_l)
{
CYCLE(2);
uint32 src = fea_all_4();
ACC.cmp_32(src, RegDX);
}
// %1011_xxx011_mmmrrr CMPA.W <ea>,Ax
OP_DEF(cmpa_w)
{
CYCLE(4);
uint32 src = (uint32)(int32)(int16)fea_all_2();
ACC.cmp_32(src, RegAX);
}
// %1011_xxx100_mmmrrr EOR.B Dx,<ea>
// %1011_xxx100_001yyy CMPM.B (Ay)+,(Ax)+
OP_DEF(eor_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// EOR.B Dx,Dy
CYCLE(2);
uint32 data = (reg.D[n] ^ RegDX) & 0xff;
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
ACC.move_8(data);
} else if (n < 16) {
// CMPM.B (Ay)+,(Ax)+
CYCLE(8);
save_reg_pi_if(RegIRY);
save_reg_pi_if(RegIRX);
uint32 srcea = internal_ea_anpi_1(RegIRY);
uint32 dstea = internal_ea_anpi_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
ACC.cmp_8(src, dst);
} else {
// EOR.B Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data ^= (RegDX & 0xff);
write_1(ea, data);
ACC.move_8(data);
}
}
// %1011_xxx101_mmmrrr EOR.W Dx,<ea>
// %1011_xxx101_001yyy CMPM.W (Ay)+,(Ax)+
OP_DEF(eor_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// EOR.W Dx,Dy
CYCLE(2);
uint32 data = (reg.D[n] ^ RegDX) & 0xffff;
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
ACC.move_16(data);
} else if (n < 16) {
// CMPM.W (Ay)+,(Ax)+
CYCLE(8);
save_reg_pi_if(RegIRY);
save_reg_pi_if(RegIRX);
uint32 srcea = internal_ea_anpi_2(RegIRY);
uint32 dstea = internal_ea_anpi_2(RegIRX);
uint32 src = read_2(srcea);
uint32 dst = read_2(dstea);
ACC.cmp_16(src, dst);
} else {
// EOR.W Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data ^= (RegDX & 0xffff);
write_2(ea, data);
ACC.move_16(data);
}
}
// %1011_xxx110_mmmrrr EOR.L Dx,<ea>
// %1011_xxx110_001yyy CMPM.L (Ay)+,(Ax)+
OP_DEF(eor_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// EOR.L Dx,Dy
CYCLE(2);
reg.D[n] ^= RegDX;
ACC.move_32(reg.D[n]);
} else if (n < 16) {
// CMPM.L (Ay)+,(Ax)+
CYCLE(8);
save_reg_pi_if(RegIRY);
save_reg_pi_if(RegIRX);
uint32 srcea = internal_ea_anpi_4(RegIRY);
uint32 dstea = internal_ea_anpi_4(RegIRX);
uint32 src = read_4(srcea);
uint32 dst = read_4(dstea);
ACC.cmp_32(src, dst);
} else {
// EOR.L Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data ^= RegDX;
write_4(ea, data);
ACC.move_32(data);
}
}
// %1011_xxx111_mmmrrr CMPA.L <ea>,Ax
OP_DEF(cmpa_l)
{
CYCLE(4);
uint32 src = fea_all_4();
ACC.cmp_32(src, RegAX);
}
// %1100_xxx000_mmmrrr AND.B <ea>,Dx
OP_DEF(and_b_ea_dn)
{
CYCLE(2);
uint32 src = fea_data_1();
uint32 dst = (RegDX & 0x000000ff) & src;
ACC.move_8(dst);
RegDX = (RegDX & 0xffffff00) | dst;
}
// %1100_xxx001_mmmrrr AND.W <ea>,Dx
OP_DEF(and_w_ea_dn)
{
CYCLE(2);
uint32 src = fea_data_2();
uint32 dst = (RegDX & 0x0000ffff) & src;
ACC.move_16(dst);
RegDX = (RegDX & 0xffff0000) | dst;
}
// %1100_xxx010_mmmrrr AND.L <ea>,Dx
OP_DEF(and_l_ea_dn)
{
CYCLE(2);
uint32 src = fea_data_4();
RegDX = RegDX & src;
ACC.move_32(RegDX);
}
// %1100_xxx011_mmmrrr MULU.W <ea>,Dx
OP_DEF(mulu_w)
{
CYCLE(28); // 実際にはこれは最大値
uint32 src = fea_data_2();
uint32 dst = RegDX & 0xffff;
RegDX = ACC.mulu_16(src, dst);
}
// %1100_xxx100_000yyy ABCD.B Dy,Dx
// %1100_xxx100_001yyy ABCD.B -(Ay),-(Ax)
// %1100_xxx100_mmmrrr AND.B Dx,<ea>
OP_DEF(and_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ABCD.B Dy,Dx
CYCLE(4);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.abcd_8(src, dst);
RegDX &= 0xffffff00;
RegDX |= dst;
return;
} else if (n < 16) {
// ABCD.B -(Ay),-(Ax)
CYCLE2(13, 14);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.abcd_8(src, dst);
write_1(dstea, dst);
return;
} else {
// AND.B Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst &= RegDX & 0xff;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %1100_xxx101_000yyy EXG.L Dx,Dy
// %1100_xxx101_001yyy EXG.L Ax,Ay
// %1100_xxx101_mmmrrr AND.W Dx,<ea>
OP_DEF(and_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXG.L Dx,Dy
CYCLE(4);
uint x = RegIRX;
uint y = n;
uint32 tmp = reg.D[x];
reg.D[x] = reg.D[y];
reg.D[y] = tmp;
return;
} else if (n < 16) {
// EXG.L Ax,Ay
// ここでは x は 0..7 で A(x)、y は 8..15 で R(y)
CYCLE(4);
uint x = RegIRX;
uint y = n;
uint32 tmp = reg.A[x];
reg.A[x] = reg.R[y];
reg.R[y] = tmp;
return;
} else {
// AND.W Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst &= RegDX & 0xffff;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %1100_xxx110_001yyy EXG.L Dx,Ay
// %1100_xxx110_mmmrrr AND.L Dx,<ea>
OP_DEF(and_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
op_illegal();
return;
} else if (n < 16) {
// EXG.L Dx,Ay
// ここでは x は 0..7 で D(x)、y は 8..15 で R(y)
CYCLE(4);
uint x = RegIRX;
uint y = n;
uint32 tmp = reg.D[x];
reg.D[x] = reg.R[y];
reg.R[y] = tmp;
return;
} else {
// AND.L Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst &= RegDX;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %1100_xxx111_mmmrrr MULS.W <ea>,Dx
OP_DEF(muls_w)
{
CYCLE(28); // 実際にはこれは最大値
uint32 src = fea_data_2();
uint32 dst = RegDX & 0xffff;
RegDX = ACC.muls_16(src, dst);
}
// %1101_xxx000_mmmrrr ADD.B <ea>,Dx
OP_DEF(add_b_ea_dn)
{
CYCLE(2);
uint32 src = fea_all_1();
uint32 data = ACC.add_8(src, RegDX & 0xff);
RegDX = (RegDX & 0xffffff00) | data;
}
// %1101_xxx001_mmmrrr ADD.W <ea>,Dx
OP_DEF(add_w_ea_dn)
{
CYCLE(2);
uint32 src = fea_all_2();
uint32 data = ACC.add_16(src, RegDX & 0xffff);
RegDX = (RegDX & 0xffff0000) | data;
}
// %1101_xxx010_mmmrrr ADD.L <ea>,Dx
OP_DEF(add_l_ea_dn)
{
CYCLE(2);
uint32 src = fea_all_4();
RegDX = ACC.add_32(src, RegDX);
}
// %1101_xxx011_mmmrrr ADDA.W <ea>,Ax
OP_DEF(adda_w)
{
CYCLE(4);
uint32 src = (int32)(int16)fea_all_2();
RegAX += src;
}
// %1101_xxx100_000yyy ADDX.B Dy,Dx
// %1101_xxx100_001yyy ADDX.B -(Ay),-(Ax)
// %1101_xxx100_mmmrrr ADD.B Dx,<ea>
OP_DEF(add_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ADDX.B Dy,Dx
CYCLE(2);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.addx_8(src, dst);
RegDX = (RegDX & 0xffffff00) | dst;
} else if (n < 16) {
// ADDX.B -(Ay),-(Ax)
CYCLE2(9, 10);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.addx_8(src, dst);
write_1(dstea, dst);
} else {
// ADD.B Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.add_8(RegDX & 0xff, data);
write_1(ea, data);
}
}
// %1101_xxx101_000yyy ADDX.W Dy,Dx
// %1101_xxx101_001yyy ADDX.W -(Ay),-(Ax)
// %1101_xxx101_mmmrrr ADD.W Dx,<ea>
OP_DEF(add_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ADDX.W Dy,Dx
CYCLE(2);
uint32 src = RegDY & 0xffff;
uint32 dst = RegDX & 0xffff;
dst = ACC.addx_16(src, dst);
RegDX = (RegDX & 0xffff0000) | dst;
} else if (n < 16) {
// ADDX.W -(Ay),-(Ax)
CYCLE2(9, 10);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_2(RegIRY);
uint32 dstea = internal_ea_anpd_2(RegIRX);
uint32 src = read_2(srcea);
uint32 dst = read_2(dstea);
dst = ACC.addx_16(src, dst);
write_2(dstea, dst);
} else {
// ADD.W Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.add_16(RegDX & 0xffff, data);
write_2(ea, data);
}
}
// %1101_xxx110_000yyy ADDX.L Dy,Dx
// %1101_xxx110_001yyy ADDX.L -(Ay),-(Ax)
// %1101_xxx110_mmmrrr ADD.L Dx,<ea>
OP_DEF(add_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ADDX.L Dy,Dx
CYCLE(2);
uint32 src = RegDY;
uint32 dst = RegDX;
RegDX = ACC.addx_32(src, dst);
} else if (n < 16) {
// ADDX.L -(Ay),-(Ax)
CYCLE2(9, 10);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_4(RegIRY);
uint32 dstea = internal_ea_anpd_4(RegIRX);
uint32 src = read_4(srcea);
uint32 dst = read_4(dstea);
dst = ACC.addx_32(src, dst);
write_4(dstea, dst);
} else {
// ADD.L Dx,<ea>
CYCLE2(3, 4);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.add_32(RegDX, data);
write_4(ea, data);
}
}
// %1101_xxx111_mmmrrr ADDA.L <ea>,Ax
OP_DEF(adda_l)
{
CYCLE(2);
uint32 src = fea_all_4();
RegAX += src;
}
// %1110_qqq000_000yyy ASR.B #qqq,Dy
// %1110_qqq000_001yyy LSR.B #qqq,Dy
// %1110_qqq000_010yyy ROXR.B #qqq,Dy
// %1110_qqq000_011yyy ROR.B #qqq,Dy
// %1110_xxx000_100yyy ASR.B Dx,Dy
// %1110_xxx000_101yyy LSR.B Dx,Dy
// %1110_xxx000_110yyy ROXR.B Dx,Dy
// %1110_xxx000_111yyy ROR.B Dx,Dy
OP_DEF(asr_b_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASR.B #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 1: // LSR.B #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 2: // ROXR.B #qqq,Dy
CYCLE(12);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 3: // ROR.B #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.ror_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 4: // ASR.B Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 8 ? 6 : 10);
__assume(0 <= count && count < 64);
data = ACC.asr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 5: // LSR.B Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 8 ? 6 : 8);
__assume(0 <= count && count < 64);
data = ACC.lsr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 6: // ROXR.B Dx,Dy
CYCLE(12);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 7: // ROR.B Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.ror_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
}
}
// %1110_qqq001_000yyy ASR.W #qqq,Dy
// %1110_qqq001_001yyy LSR.W #qqq,Dy
// %1110_qqq001_010yyy ROXR.W #qqq,Dy
// %1110_qqq001_011yyy ROR.W #qqq,Dy
// %1110_xxx001_100yyy ASR.W Dx,Dy
// %1110_xxx001_101yyy LSR.W Dx,Dy
// %1110_xxx001_110yyy ROXR.W Dx,Dy
// %1110_xxx001_111yyy ROR.W Dx,Dy
OP_DEF(asr_w_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASR.W #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 1: // LSR.W #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 2: // ROXR.W #qqq,Dy
CYCLE(12);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 3: // ROR.W #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.ror_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 4: // ASR.W Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 16 ? 6 : 10);
__assume(0 <= count && count < 64);
data = ACC.asr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 5: // LSR.W Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 16 ? 6 : 8);
__assume(0 <= count && count < 64);
data = ACC.lsr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 6: // ROXR.W Dx,Dy
CYCLE(12);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 7: // ROR.W Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.ror_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
}
}
// %1110_qqq010_000yyy ASR.L #qqq,Dy
// %1110_qqq010_001yyy LSR.L #qqq,Dy
// %1110_qqq010_010yyy ROXR.L #qqq,Dy
// %1110_qqq010_011yyy ROR.L #qqq,Dy
// %1110_xxx010_100yyy ASR.L Dx,Dy
// %1110_xxx010_101yyy LSR.L Dx,Dy
// %1110_xxx010_110yyy ROXR.L Dx,Dy
// %1110_xxx010_111yyy ROR.L Dx,Dy
OP_DEF(asr_l_imm)
{
int count;
switch (eamode(ir)) {
case 0: // ASR.L #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.asr_32(RegDY, count);
return;
case 1: // LSR.L #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.lsr_32(RegDY, count);
return;
case 2: // ROXR.L #qqq,Dy
CYCLE(12);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.roxr_32(RegDY, count);
return;
case 3: // ROR.L #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.ror_32(RegDY, count);
return;
case 4: // ASR.L Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 32 ? 6 : 10);
__assume(0 <= count && count < 64);
RegDY = ACC.asr_32(RegDY, count);
return;
case 5: // LSR.L Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 32 ? 6 : 8);
__assume(0 <= count && count < 64);
RegDY = ACC.lsr_32(RegDY, count);
return;
case 6: // ROXR.L Dx,Dy
CYCLE(12);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.roxr_32(RegDY, count);
return;
case 7: // ROR.L Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.ror_32(RegDY, count);
return;
}
}
// %1110_000011_mmmrrr ASR.W <ea>
OP_DEF(asr_w)
{
CYCLE(4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.asr_16(data, 1);
write_2(ea, data);
}
// %1110_qqq100_000yyy ASL.B #qqq,Dy
// %1110_qqq100_001yyy LSL.B #qqq,Dy
// %1110_qqq100_010yyy ROXL.B #qqq,Dy
// %1110_qqq100_011yyy ROL.B #qqq,Dy
// %1110_xxx100_100yyy ASL.B Dx,Dy
// %1110_xxx100_101yyy LSL.B Dx,Dy
// %1110_xxx100_110yyy ROXL.B Dx,Dy
// %1110_xxx100_111yyy ROL.B Dx,Dy
OP_DEF(asl_b_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASL.B #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 1: // LSL.B #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 2: // ROXL.B #qqq,Dy
CYCLE(12);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 3: // ROL.B #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.rol_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 4: // ASL.B Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.asl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 5: // LSL.B Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 8 ? 6 : 8);
__assume(0 <= count && count < 64);
data = ACC.lsl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 6: // ROXL.B Dx,Dy
CYCLE(12);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 7: // ROL.B Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.rol_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
}
}
// %1110_qqq101_000yyy ASL.W #qqq,Dy
// %1110_qqq101_001yyy LSL.W #qqq,Dy
// %1110_qqq101_010yyy ROXL.W #qqq,Dy
// %1110_qqq101_011yyy ROL.W #qqq,Dy
// %1110_xxx101_100yyy ASL.W Dx,Dy
// %1110_xxx101_101yyy LSL.W Dx,Dy
// %1110_xxx101_110yyy ROXL.W Dx,Dy
// %1110_xxx101_111yyy ROL.W Dx,Dy
OP_DEF(asl_w_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASL.W #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 1: // LSL.W #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 2: // ROXL.W #qqq,Dy
CYCLE(12);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 3: // ROL.W #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.rol_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 4: // ASL.W Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.asl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 5: // LSL.W Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 16 ? 6 : 8);
__assume(0 <= count && count < 64);
data = ACC.lsl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 6: // ROXL.W Dx,Dy
CYCLE(12);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 7: // ROL.W Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.rol_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
}
}
// %1110_qqq110_000yyy ASL.L #qqq,Dy
// %1110_qqq110_001yyy LSL.L #qqq,Dy
// %1110_qqq110_010yyy ROXL.L #qqq,Dy
// %1110_qqq110_011yyy ROL.L #qqq,Dy
// %1110_xxx110_100yyy ASL.L Dx,Dy
// %1110_xxx110_101yyy LSL.L Dx,Dy
// %1110_xxx110_110yyy ROXL.L Dx,Dy
// %1110_xxx110_111yyy ROL.L Dx,Dy
OP_DEF(asl_l_imm)
{
int count;
switch (eamode(ir)) {
case 0: // ASL.L #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.asl_32(RegDY, count);
return;
case 1: // LSL.L #qqq,Dy
CYCLE(4);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.lsl_32(RegDY, count);
return;
case 2: // ROXL.L #qqq,Dy
CYCLE(12);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.roxl_32(RegDY, count);
return;
case 3: // ROL.L #qqq,Dy
CYCLE(6);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.rol_32(RegDY, count);
return;
case 4: // ASL.L Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.asl_32(RegDY, count);
return;
case 5: // LSL.L Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
CYCLE(count <= 32 ? 6 : 8);
__assume(0 <= count && count < 64);
RegDY = ACC.lsl_32(RegDY, count);
return;
case 6: // ROXL.L Dx,Dy
CYCLE(12);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.roxl_32(RegDY, count);
return;
case 7: // ROL.L Dx,Dy
CYCLE(8);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.rol_32(RegDY, count);
return;
}
}
// %1110_000111_mmmrrr ASL.W <ea>
OP_DEF(asl_w)
{
CYCLE(6);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.asl_16(data, 1);
write_2(ea, data);
}
// %1110_001011_mmmrrr LSR.W <ea>
OP_DEF(lsr_w)
{
CYCLE(4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.lsr_16(data, 1);
write_2(ea, data);
}
// %1110_001111_mmmrrr LSL.W <ea>
OP_DEF(lsl_w)
{
CYCLE(4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.lsl_16(data, 1);
write_2(ea, data);
}
// %1110_010011_mmmrrr ROXR.W <ea>
OP_DEF(roxr_w)
{
CYCLE(4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.roxr_16(data, 1);
write_2(ea, data);
}
// %1110_010111_mmmrrr ROXL.W <ea>
OP_DEF(roxl_w)
{
CYCLE(4);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.roxl_16(data, 1);
write_2(ea, data);
}
// %1110_011011_mmmrrr ROR.W <ea>
OP_DEF(ror_w)
{
CYCLE(6);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.ror_16(data, 1);
write_2(ea, data);
}
// %1110_011111_mmmrrr ROL.W <ea>
OP_DEF(rol_w)
{
CYCLE(6);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.rol_16(data, 1);
write_2(ea, data);
}
// %1110_100011_mmmrrr BFTST <ea>{#o:#w}
OP_DEF(bftst)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFTST Dn{#o:#w}
bf.LoadReg(n);
} else {
// BFTST <ea>{#o:#w}
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
ACC.move_32(bf.data);
}
// %1110_100111_mmmrrr BFEXTU <ea>{#o:#w},Dn
OP_DEF(bfextu)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFEXTU Dn{#o:#w},Dn
bf.LoadReg(n);
} else {
// BFEXTU <ea>{#o:#w},Dn
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
// 符号なしシフト
reg.D[dn] = bf.data >> (32 - bf.width);
}
// %1110_101011_mmmrrr BFCHG <ea>{#o:#w}
OP_DEF(bfchg)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFCHG Dn{#o:#w}
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFCHG <ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFCHG <ea>{#o:#w}
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
bf.data = ~bf.data;
bf.Store(n);
}
// %1110_101111_mmmrrr BFEXTS <ea>{#o:#w},Dn
OP_DEF(bfexts)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFEXTS Dn{#o:#w},Dn
bf.LoadReg(n);
} else {
// BFEXTS <ea>{#o:#w},Dn
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
// 符号付きシフト
// XXX 負数の右シフト
reg.D[dn] = ((int32)bf.data) >> (32 - bf.width);
}
// %1110_110011_mmmrrr BFCLR <ea>{#o:#w}
OP_DEF(bfclr)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFCLR Dn{#o:#w}
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFCLR <ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFCLR <ea>{#o:#w}
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
bf.data = 0;
bf.Store(n);
}
// %1110_110111_mmmrrr BFFFO <ea>{#o:#w},Dn
OP_DEF(bfffo)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFFFO Dn{#o:#w},Dn
bf.LoadReg(n);
} else {
// BFFFO <ea>{#o:#w},Dn
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
// 1 になっているビットを探す
for (; (int)bf.width-- > 0 && (int32)bf.data >= 0; bf.data <<= 1) {
bf.offset++;
}
reg.D[dn] = bf.offset;
}
// %1110_111011_mmmrrr BFSET <ea>{#o:#w}
OP_DEF(bfset)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFSET Dn{#o:#w}
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFSET <ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFSET <ea>{#o:#w}
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
bf.data = 0xffffffff;
bf.Store(n);
}
// %1110_111111_mmmrrr BFINS Dn,<ea>{#o:#w}
OP_DEF(bfins)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFINS Dm,Dn{#o:#w}
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFINS Dn,<ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFINS Dn,<ea>{#o:#w}
uint32 ea = cea_ctrl();
bf.LoadMem(ea);
}
bf.data = reg.D[dn] << (32 - bf.width);
// BFINS のみ CCR は操作後のビットフィールドに対して
ACC.move_32(bf.data);
bf.Store(n);
}
// %1111_000nnn_nnnnnn MMU_OP
OP_DEF(mmuop)
{
ir2 = fetch_2();
switch ((ir2 >> 8) & 0xff) {
case (0x0800 >> 8):
case (0x0900 >> 8):
case (0x0c00 >> 8):
case (0x0d00 >> 8):
// %000_01n00_000_00000 PMOVE.L <ea>,TTn
// %000_01n01_000_00000 PMOVEFD.L <ea>,TTn
{
CYCLE2(12, 14);
uint32 ea = cea_copro();
uint32 data = read_4(ea);
uint n = (ir2 >> 10) & 1;
SetTT(n, data);
if ((ir2 & 0x0100) == 0)
atc.flush();
break;
}
case (0x0a00 >> 8):
case (0x0e00 >> 8):
// %000_01n10_000_00000 PMOVE.L TTn,<ea>
{
CYCLE(8);
uint32 ea = cea_copro();
uint n = (ir2 >> 10) & 1;
write_4(ea, GetTT(n));
break;
}
case (0x2000 >> 8):
// %001_00000_000_00000 PLOADW SFC,<ea>
// %001_00000_000_00001 PLOADW DFC,<ea>
// %001_00000_000_01yyy PLOADW Dy,<ea>
// %001_00000_000_10nnn PLOADW #<imm>,<ea>
{
putlog(0, "ploadw");
mmu_op_pload();
break;
}
case (0x2200 >> 8):
// %001_00010_000_00000 PLOADR SFC,<ea>
// %001_00010_000_00001 PLOADR DFC,<ea>
// %001_00010_000_01yyy PLOADR Dy,<ea>
// %001_00010_000_10nnn PLOADR #<imm>,<ea>
{
putlog(0, "ploadr");
mmu_op_pload();
break;
}
case (0x2400 >> 8):
// %001_00100_000_00000 PFLUSHA
{
CYCLE2(12, 14);
atc.flush();
break;
}
case (0x3000 >> 8):
// %001_10000_nnn_00000 PFLUSH SFC,#<mask>
// %001_10000_nnn_00001 PFLUSH DFC,#<mask>
// %001_10000_nnn_01yyy PFLUSH Dy,#<mask>
// %001_10000_nnn_10nnn PFLUSH #<imm>,#<mask>
{
mmu_op_pflush();
break;
}
case (0x3800 >> 8):
// %001_11000_nnn_00000 PFLUSH SFC,#<mask>,<ea>
// %001_11000_nnn_00001 PFLUSH DFC,#<mask>,<ea>
// %001_11000_nnn_01yyy PFLUSH Dy,#<mask>,<ea>
// %001_11000_nnn_10nnn PFLUSH #<imm>,#<mask>,<ea>
{
mmu_op_pflush_ea();
break;
}
case (0x4000 >> 8):
case (0x4100 >> 8):
// %010_00000_000_00000 PMOVE.L <ea>,TC
// %010_00001_000_00000 PMOVEFD.L <ea>,TC
{
// たぶん
// 無効→有効が (38, 40)
// 有効→無効が (56, 58)
// 無効→無効が (14, 16) ってことだと思うんだけど。
CYCLE2(14, 16);
uint32 ea = cea_copro();
uint32 data = read_4(ea);
if (SetTC(data) == false) {
Exception(M68K::EXCEP_MMU_CONFIG);
break;
}
if ((ir2 & 0x0100) == 0)
atc.flush();
break;
}
case (0x4200 >> 8):
// %010_00010_000_00000 PMOVE.L TC,<ea>
{
CYCLE2(4, 5);
uint32 ea = cea_copro();
write_4(ea, GetTC());
break;
}
case (0x4800 >> 8):
case (0x4900 >> 8):
// %010_01000_000_00000 PMOVE.Q <ea>,SRP
// %010_01001_000_00000 PMOVEFD.Q <ea>,SRP
{
// たぶん有効になる時が (12, 14)
// それ以外が (28, 30) ってことかな。
CYCLE2(28, 30);
uint32 ea = cea_copro();
uint32 h = read_4(ea);
uint32 l = read_4(ea + 4);
if (SetSRP(h, l) == false) {
Exception(M68K::EXCEP_MMU_CONFIG);
break;
}
if ((ir2 & 0x0100) == 0)
atc.flush();
break;
}
case (0x4a00 >> 8):
// %010_01010_000_00000 PMOVE.Q SRP,<ea>
{
CYCLE2(4, 5);
uint32 ea = cea_copro();
write_4(ea, GetSRPh());
write_4(ea + 4, GetSRPl());
break;
}
case (0x4c00 >> 8):
case (0x4d00 >> 8):
// %010_01100_000_00000 PMOVE.Q <ea>,CRP
// %010_01101_000_00000 PMOVEFD.Q <ea>,CRP
{
// たぶん有効になる時が (12, 14)
// それ以外が (28, 30) ってことかな。
CYCLE2(28, 30);
uint32 ea = cea_copro();
uint32 h = read_4(ea);
uint32 l = read_4(ea + 4);
if (SetCRP(h, l) == false) {
Exception(M68K::EXCEP_MMU_CONFIG);
break;
}
if ((ir2 & 0x0100) == 0)
atc.flush();
break;
}
case (0x4e00 >> 8):
// %010_01110_000_00000 PMOVE.Q CRP,<ea>
{
CYCLE2(4, 5);
uint32 ea = cea_copro();
write_4(ea, GetCRPh());
write_4(ea + 4, GetCRPl());
break;
}
case (0x6000 >> 8):
// %011_00000_000_00000 PMOVE.W <ea>,MMUSR
{
CYCLE(6);
uint32 ea = cea_copro();
uint16 data = read_2(ea);
SetMMUSR(data);
break;
}
case (0x6200 >> 8):
// %011_00010_000_00000 PMOVE.W MMUSR,<ea>
{
CYCLE2(4, 5);
uint32 ea = cea_copro();
write_2(ea, GetMMUSR());
break;
}
case (0x8000 >> 8):
case (0x8400 >> 8):
case (0x8800 >> 8):
case (0x8c00 >> 8):
case (0x9000 >> 8):
case (0x9400 >> 8):
case (0x9800 >> 8):
case (0x9c00 >> 8):
// %100_nnn00_000_00000 PTESTW SFC,<ea>,#<level>
// %100_nnn00_000_00001 PTESTW DFC,<ea>,#<level>
// %100_nnn00_000_01yyy PTESTW Dy,<ea>,#<level>
// %100_nnn00_000_10nnn PTESTW #<imm>,<ea>,#<level>
{
mmu_op_ptest();
break;
}
case (0x8100 >> 8):
case (0x8500 >> 8):
case (0x8900 >> 8):
case (0x8d00 >> 8):
case (0x9100 >> 8):
case (0x9500 >> 8):
case (0x9900 >> 8):
case (0x9d00 >> 8):
// %100_nnn01_nnn_00000 PTESTW SFC,<ea>,#<level>,An
// %100_nnn01_nnn_00001 PTESTW DFC,<ea>,#<level>,An
// %100_nnn01_nnn_01yyy PTESTW Dy,<ea>,#<level>,An
// %100_nnn01_nnn_10nnn PTESTW #<imm>,<ea>,#<level>,An
{
mmu_op_ptest();
break;
}
case (0x8200 >> 8):
case (0x8600 >> 8):
case (0x8a00 >> 8):
case (0x8e00 >> 8):
case (0x9200 >> 8):
case (0x9600 >> 8):
case (0x9a00 >> 8):
case (0x9e00 >> 8):
// %100_nnn10_000_00000 PTESTR SFC,<ea>,#<level>
// %100_nnn10_000_00001 PTESTR DFC,<ea>,#<level>
// %100_nnn10_000_01yyy PTESTR Dy,<ea>,#<level>
// %100_nnn10_000_10nnn PTESTR #<imm>,<ea>,#<level>
{
mmu_op_ptest();
break;
}
case (0x8300 >> 8):
case (0x8700 >> 8):
case (0x8b00 >> 8):
case (0x8f00 >> 8):
case (0x9300 >> 8):
case (0x9700 >> 8):
case (0x9b00 >> 8):
case (0x9f00 >> 8):
// %100_nnn11_nnn_00000 PTESTR SFC,<ea>,#<level>,An
// %100_nnn11_nnn_00001 PTESTR DFC,<ea>,#<level>,An
// %100_nnn11_nnn_01yyy PTESTR Dy,<ea>,#<level>,An
// %100_nnn11_nnn_10nnn PTESTR #<imm>,<ea>,#<level>,An
{
mmu_op_ptest();
break;
}
default:
OP_FUNC(illegal);
break;
}
}
// %1111_001000_nnnnnn FPGEN
OP_DEF(fpgen)
{
if (has_fpu == 0) {
op_fline();
return;
}
fpu_op_start();
ir2 = fetch_2();
switch (ir2 >> 13) {
case 0:
fpu_op_fgen_reg();
break;
case 1:
fpu_op_illg();
break;
case 2:
fpu_op_fgen_mem();
break;
case 3:
{
// FMOVE reg,<ea> はサイズごとに分岐
uint size = (ir2 >> 10) & 7;
switch (size) {
case SIZE_B:
fpu_op_fmove_b_mem();
break;
case SIZE_W:
fpu_op_fmove_w_mem();
break;
case SIZE_L:
fpu_op_fmove_l_mem();
break;
case SIZE_S:
fpu_op_fmove_s_mem();
break;
case SIZE_D:
fpu_op_fmove_d_mem();
break;
case SIZE_X:
fpu_op_fmove_x_mem();
break;
case SIZE_P:
case 7:
fpu_op_fmove_p_mem();
break;
}
break;
}
case 4:
fpu_op_fmovem_ea2ctl();
break;
case 5:
fpu_op_fmovem_ctl2ea();
break;
case 6:
fpu_op_fmovem_ea2reg();
break;
case 7:
fpu_op_fmovem_reg2ea();
break;
}
}
// %1111_001001_nnnnnn FScc.B <ea>
// %1111_001001_001yyy FDBcc Dy,<label>
// %1111_001001_111010 FTRAPcc.W #<imm>
// %1111_001001_111011 FTRAPcc.L #<imm>
// %1111_001001_111100 FTRAPcc
OP_DEF(fxcc)
{
if (has_fpu == 0) {
op_fline();
return;
}
fpu_op_start();
ir2 = fetch_2();
switch (eamode(ir)) {
case 1:
fpu_op_fdbcc();
return;
case 7:
switch (ir & 7) {
case 0:
case 1:
fpu_op_fscc();
return;
case 2:
fpu_op_ftrapcc_w();
return;
case 3:
fpu_op_ftrapcc_l();
return;
case 4:
fpu_op_ftrapcc();
return;
default:
break;
}
break;
default:
fpu_op_fscc();
return;
}
}
// %1111_001010_nnnnnn FBcc.W <label>
OP_DEF(fbcc_w)
{
if (has_fpu == 0) {
op_fline();
return;
}
fpu_op_start();
fpu_op_fbcc_w();
}
// %1111_001011_nnnnnn FBcc.L <label>
OP_DEF(fbcc_l)
{
if (has_fpu == 0) {
op_fline();
return;
}
fpu_op_start();
fpu_op_fbcc_l();
}
// %1111_001100_mmmrrr FSAVE <ea>
OP_DEF(fsave)
{
if (has_fpu == 0) {
op_fline();
return;
}
SUPERVISOR_OP;
fpu_op_fsave();
}
// %1111_001101_mmmrrr FRESTORE <ea>
OP_DEF(frestore)
{
if (has_fpu == 0) {
op_fline();
return;
}
SUPERVISOR_OP;
fpu_op_frestore();
}
// %1111_nnnnnn_nnnnnn F-Line
OP_DEF(fline)
{
CYCLE2(18, 20);
if (fline_callback) {
if (fline_callback(this, fline_arg)) {
return;
}
}
// F系列命令例外
Exception(M68K::EXCEP_FLINE);
}
// illegal instructions
OP_DEF(illegal)
{
CYCLE2(18, 20);
// 不当命令例外
Exception(M68K::EXCEP_ILLEGAL);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.