|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
#include "mpu680x0.h"
#include "m680x0acc.h"
#include "m680x0bitfield.h"
#include "m680x0cycle.h"
#include "m68040mmu.h"
#define OP_DEF(name) void __CONCAT(MPU680x0Device::op_,name)()
#define OP_FUNC(name) __CONCAT(op_,name)()
#define CCR reg.ccr
#define ACC (*(m680x0ACC*)®.ccr)
#define RegIRX ((ir >> 9) & 7)
#define RegIRY (ir & 7)
#define RegDX reg.D[RegIRX]
#define RegAX reg.A[RegIRX]
#define RegDY reg.D[RegIRY]
#define RegAY reg.A[RegIRY]
// (エミュレータ的)未実装命令
#define op_unimpl(cpu) \
PANIC("unimplemented instruction! %s()", __FUNCTION__)
// 副作用のあるマクロ
// 特権違反例外のスタックに積む PC は違反を起こした命令先頭。
#define SUPERVISOR_OP do { \
if (!IsSuper()) { \
CYCLE3(excep_priv); \
Exception(M68K::EXCEP_PRIV); \
return; \
} \
} while (0)
// %0000_000000_mmmrrr d.m+-rxw.. 034 ORI.B #<imm>,<ea>
// %0000_000000_111100 .......... 034 ORI.B #<imm>,CCR
OP_DEF(ori_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// ORI.B #<imm>,Dn
CYCLE3(ori_dn);
uint32 dst = (reg.D[n] & 0xff) | src;
ACC.move_8(dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else if (n == 0b111100) {
// ORI.B #<imm>,CCR
CYCLE3(ori_ccr);
CCR.Set(CCR.Get() | src);
} else {
// ORI.B #<imm>,<ea>
CYCLE3(ori_ea);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst |= src;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %0000_000001_mmmrrr d.m+-rxw.. 034 ORI.W #<imm>,<ea>
// %0000_000001_111100 .......... 034 ORI.W #<imm>,SR
OP_DEF(ori_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// ORI.W #<imm>,Dn
CYCLE3(ori_dn);
uint32 src = fetch_2();
uint32 dst = (reg.D[n] & 0xffff) | src;
ACC.move_16(dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else if (n == 0b111100) {
// ORI.W #<imm>,SR
SUPERVISOR_OP;
CYCLE3(ori_sr);
uint32 src = fetch_2();
SetSR(GetSR() | src);
} else {
// ORI.W #<imm>,<ea>
CYCLE3(ori_ea);
uint32 src = fetch_2();
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst |= src;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %0000_000010_mmmrrr d.m+-rxw.. 034 ORI.L #<imm>,<ea>
OP_DEF(ori_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// ORI.L #<imm>,Dn
CYCLE3(ori_dn);
reg.D[n] |= src;
ACC.move_32(reg.D[n]);
} else {
// ORI.L #<imm>,<ea>
CYCLE3(ori_ea);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst |= src;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %0000_000011_mmmrrr ..m..rxwp. -34 CMP2/CHK2.B <ea>,Rn
OP_DEF(cmp2chk2_b)
{
ir2 = fetch_2();
uint32 compare;
uint32 ea = cea_ctrl();
uint32 lower;
uint32 upper;
if ((ir2 & 0x8000) == 0) {
// compare が Dn
compare = (int32)(int8)(reg.R[ir2 >> 12] & 0xff);
} else {
// compare が An
compare = reg.R[ir2 >> 12];
}
// 本当は PC 相対ならプログラム空間アクセス、
// それ以外はデータ空間アクセスだが、ここでは区別しない。
lower = (int32)(int8)read_1(ea);
upper = (int32)(int8)read_1(ea + 1);
ACC.chk2cmp2_32(compare, lower, upper);
// サイクル数はこれは実際には全部最大値
if ((ir2 & 0x0800)) {
// CHK2 で条件を満たしていれば例外
if (reg.ccr.CondCS()) {
CYCLE3(chk2_excep_max);
Exception(M68K::EXCEP_CHK);
} else {
CYCLE3(chk2);
}
} else {
// CMP2
CYCLE3(cmp2_max);
}
}
// MOVEP.[WL] (d,Ay),Dx と
// MOVEP.[WL] Dx,(d,Ay) の共通部分。
void
MPU680x0Device::ops_movep()
{
uint32 disp = (int32)(int16)fetch_2();
uint32 ea = RegAY + disp;
bool size_long = ((ir & 0x40) != 0);
bool reg2mem = ((ir & 0x80) != 0);
CYCLE3(movep);
if (reg2mem) {
// Dx -> memory
uint32 dx = RegDX;
if (size_long) {
write_1(ea, (dx >> 24));
ea += 2;
write_1(ea, (dx >> 16) & 0xff);
ea += 2;
}
write_1(ea, (dx >> 8) & 0xff);
ea += 2;
write_1(ea, (dx & 0xff));
} else {
// memory -> Dx
uint32 dx = 0;
if (size_long) {
dx = read_1(ea);
dx <<= 8;
ea += 2;
dx |= read_1(ea);
dx <<= 8;
ea += 2;
}
// word
dx |= read_1(ea);
dx <<= 8;
ea += 2;
dx |= read_1(ea);
if (size_long) {
RegDX = dx;
} else {
RegDX = (RegDX & 0xffff0000) | (dx & 0xffff);
}
}
}
// %0000_xxx100_mmmrrr ..m+-rxwpi 034 BTST.B Dx,<ea>
// %0000_xxx100_000yyy .......... 034 BTST.L Dx,Dy
// %0000_xxx100_001yyy .......... 034 MOVEP.W (d,Ay),Dx
OP_DEF(btst_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BTST.L Dx,Dy
CYCLE3(btst_dn);
uint bit = (RegDX & 31);
ACC.btst(RegDY, bit);
} else if (n < 16) {
// MOVEP.W (d,Ay),Dx
ops_movep();
} else {
// BTST.B Dx,<ea>
CYCLE3(btst_dn);
uint bit = (RegDX & 7);
uint32 data = fea_data_1();
ACC.btst(data, bit);
}
}
// %0000_xxx101_mmmrrr ..m+-rxw.. 034 BCHG.B Dx,<ea>
// %0000_xxx101_000yyy .......... 034 BCHG.L Dx,Dy
// %0000_xxx101_001yyy .......... 034 MOVEP.L (d,Ay),Dx
OP_DEF(bchg_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCHG.L Dx,Dy
CYCLE3(bchg_dn);
uint bit = (RegDX & 31);
RegDY = ACC.bchg(RegDY, bit);
} else if (n < 16) {
// MOVEP.L (d,Ay),Dx
ops_movep();
} else {
// BCHG.B Dx,<ea>
CYCLE3(bchg_dn);
uint bit = (RegDX & 7);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bchg(data, bit);
write_1(ea, data);
}
}
// %0000_xxx110_mmmrrr ..m+-rxw.. 034 BCLR.B Dx,<ea>
// %0000_xxx110_000yyy .......... 034 BCLR.L Dx,Dy
// %0000_xxx110_001yyy .......... 034 MOVEP.W Dx,(d,Ay)
OP_DEF(bclr_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCLR.L Dx,Dy
CYCLE3(bclr_dn);
uint bit = (RegDX & 31);
RegDY = ACC.bclr(RegDY, bit);
} else if (n < 16) {
// MOVEP.W Dx,(d,Ay)
ops_movep();
} else {
// BCLR.B Dx,<ea>
CYCLE3(bclr_dn);
uint bit = (RegDX & 7);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bclr(data, bit);
write_1(ea, data);
}
}
// %0000_xxx111_mmmrrr ..m+-rxw.. 034 BSET.B Dx,<ea>
// %0000_xxx111_000yyy .......... 034 BSET.L Dx,Dy
// %0000_xxx111_001yyy .......... 034 MOVEP.L Dx,(d,Ay)
OP_DEF(bset_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BSET.L Dx,Dy
CYCLE3(bset_dn);
uint bit = (RegDX & 31);
RegDY = ACC.bset(RegDY, bit);
} else if (n < 16) {
// MOVEP.L Dx,(d,Ay)
ops_movep();
} else {
// BSET.B Dx,<ea>
CYCLE3(bset_dn);
uint bit = (RegDX & 7);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bset(data, bit);
write_1(ea, data);
}
}
// %0000_001000_mmmrrr d.m+-rxw.. 034 ANDI.B #<imm>,<ea>
// %0000_001000_111100 .......... 034 ANDI.B #<imm>,CCR
OP_DEF(andi_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// ANDI.B #<imm>,Dn
CYCLE3(andi_dn);
uint32 dst = reg.D[n] & 0xff;
dst &= src;
ACC.move_8(dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else if (n == 0b111100) {
// ANDI.B #<imm>,CCR
CYCLE3(andi_ccr);
CCR.Set(CCR.Get() & src);
} else {
// ANDI.B #<imm>,<ea>
CYCLE3(andi_ea);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst &= src;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %0000_001001_mmmrrr d.m+-rxw.. 034 ANDI.W #<imm>,<ea>
// %0000_001001_111100 .......... 034 ANDI.W #<imm>,SR
OP_DEF(andi_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// ANDI.W #<imm>,Dn
CYCLE3(andi_dn);
uint32 src = fetch_2();
uint32 dst = reg.D[n] & 0xffff;
dst &= src;
ACC.move_16(dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else if (n == 0b111100) {
// ANDI.W #<imm>,SR
SUPERVISOR_OP;
CYCLE3(andi_sr);
uint32 src = fetch_2();
SetSR(GetSR() & src);
} else {
// ANDI.W #<imm>,<ea>
CYCLE3(andi_ea);
uint32 src = fetch_2();
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst &= src;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %0000_001010_mmmrrr d.m+-rxw.. 034 ANDI.L #<imm>,<ea>
OP_DEF(andi_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// ANDI.L #<imm>,Dn
CYCLE3(andi_dn);
reg.D[n] &= src;
ACC.move_32(reg.D[n]);
} else {
// ANDI.L #<imm>,<ea>
CYCLE3(andi_ea);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst &= src;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %0000_001011_mmmrrr ..m..rxwp. -34 CMP2/CHK2.W <ea>,Rn
OP_DEF(cmp2chk2_w)
{
ir2 = fetch_2();
uint32 compare;
uint32 ea = cea_ctrl();
uint32 lower;
uint32 upper;
if ((ir2 & 0x8000) == 0) {
// compare が Dn
compare = (int32)(int16)(reg.R[ir2 >> 12] & 0xffff);
} else {
// compare が An
compare = reg.R[ir2 >> 12];
}
// 本当は PC 相対ならプログラム空間アクセス、
// それ以外はデータ空間アクセスだが、ここでは区別しない。
lower = (int32)(int16)read_2(ea);
upper = (int32)(int16)read_2(ea + 2);
ACC.chk2cmp2_32(compare, lower, upper);
// サイクル数はこれは実際には全部最大値
if ((ir2 & 0x0800)) {
// CHK2 で条件を満たしていれば例外
if (reg.ccr.CondCS()) {
CYCLE3(chk2_excep_max);
Exception(M68K::EXCEP_CHK);
} else {
CYCLE3(chk2);
}
} else {
// CMP2
CYCLE3(cmp2_max);
}
}
// %0000_010000_mmmrrr d.m+-rxw.. 034 SUBI.B #<imm>,<ea>
OP_DEF(subi_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// SUBI.B #<imm>,Dn
CYCLE3(subi_dn);
uint32 dst = reg.D[n] & 0xff;
dst = ACC.sub_8(src, dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else {
// SUBI.B #<imm>,<ea>
CYCLE3(subi_ea);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst = ACC.sub_8(src, dst);
write_1(ea, dst);
}
}
// %0000_010001_mmmrrr d.m+-rxw.. 034 SUBI.W #<imm>,<ea>
OP_DEF(subi_w)
{
uint n = ir & 0x3f;
uint32 src = fetch_2();
if (n < 8) {
// SUBI.W #<imm>,Dn
CYCLE3(subi_dn);
uint32 dst = reg.D[n] & 0xffff;
dst = ACC.sub_16(src, dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else {
// SUBI.W #<imm>,<ea>
CYCLE3(subi_ea);
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst = ACC.sub_16(src, dst);
write_2(ea, dst);
}
}
// %0000_010010_mmmrrr d.m+-rxw.. 034 SUBI.L #<imm>,<ea>
OP_DEF(subi_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// SUBI.L #<imm>,Dn
CYCLE3(subi_dn);
reg.D[n] = ACC.sub_32(src, reg.D[n]);
} else {
// SUBI.L #<imm>,<ea>
CYCLE3(subi_ea);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst = ACC.sub_32(src, dst);
write_4(ea, dst);
}
}
// %0000_010011_mmmrrr ..m..rxwp. -34 CMP2/CHK2.L <ea>,Rn
OP_DEF(cmp2chk2_l)
{
ir2 = fetch_2();
uint32 compare = reg.R[ir2 >> 12];
uint32 ea = cea_ctrl();
uint32 lower;
uint32 upper;
// 本当は PC 相対ならプログラム空間アクセス、
// それ以外はデータ空間アクセスだが、ここでは区別しない。
lower = read_4(ea);
upper = read_4(ea + 4);
ACC.chk2cmp2_32(compare, lower, upper);
// サイクル数はこれは実際には全部最大値
if ((ir2 & 0x0800)) {
// CHK2 で条件を満たしていれば例外
if (reg.ccr.CondCS()) {
CYCLE3(chk2_excep_max);
Exception(M68K::EXCEP_CHK);
} else {
CYCLE3(chk2);
}
} else {
// CMP2
CYCLE3(cmp2_max);
}
}
// %0000_011000_mmmrrr d.m+-rxw.. 034 ADDI.B #<imm>,<ea>
OP_DEF(addi_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// ADDI.B #<imm>,Dn
CYCLE3(addi_dn);
uint32 dst = reg.D[n] & 0xff;
dst = ACC.add_8(src, dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else {
// ADDI.B #<imm>,<ea>
CYCLE3(addi_ea);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst = ACC.add_8(src, dst);
write_1(ea, dst);
}
}
// %0000_011001_mmmrrr d.m+-rxw.. 034 ADDI.W #<imm>,<ea>
OP_DEF(addi_w)
{
uint n = ir & 0x3f;
uint32 src = fetch_2();
if (n < 8) {
// ADDI.W #<imm>,Dn
CYCLE3(addi_dn);
uint32 dst = reg.D[n] & 0xffff;
dst = ACC.add_16(src, dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else {
// ADDI.W #<imm>,<ea>
CYCLE3(addi_ea);
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst = ACC.add_16(src, dst);
write_2(ea, dst);
}
}
// %0000_011010_mmmrrr d.m+-rxw.. 034 ADDI.L #<imm>,<ea>
OP_DEF(addi_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// ADDI.L #<imm>,Dn
CYCLE3(addi_dn);
reg.D[n] = ACC.add_32(src, reg.D[n]);
} else {
// ADDI.L #<imm>,<ea>
CYCLE3(addi_ea);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst = ACC.add_32(src, dst);
write_4(ea, dst);
}
}
// %0000_011011_mmmrrr ..m..rxwp. 2-- CALLM #<imm>,<ea>
// %0000_011011_00nnnn .......... 2-- RTM Rn
OP_DEF(callm)
{
op_illegal();
}
// %0000_100000_mmmrrr ..m+-rxwp. 034 BTST.B #<imm>,<ea>
// %0000_100000_000yyy .......... 034 BTST.L #<imm>,Dy
OP_DEF(btst_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BTST.L #<imm>,Dy
CYCLE3(btst_imm);
uint bit = fetch_2() & 31;
ACC.btst(RegDY, bit);
} else if (n == 0x3c) {
// BTST.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BTST.B #<imm>,<ea>
CYCLE3(btst_imm);
uint bit = fetch_2() & 7;
uint32 data = fea_data_1();
ACC.btst(data, bit);
}
}
// %0000_100001_mmmrrr ..m+-rxw.. 034 BCHG.B #<imm>,<ea>
// %0000_100001_000yyy .......... 034 BCHG.L #<imm>,Dy
OP_DEF(bchg_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCHG.L #<imm>,Dy
CYCLE3(bchg_imm);
uint bit = fetch_2() & 31;
RegDY = ACC.bchg(RegDY, bit);
} else if (n == 0x3c) {
// BCHG.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BCHG.B #<imm>,<ea>
CYCLE3(bchg_imm);
uint bit = fetch_2() & 7;
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bchg(data, bit);
write_1(ea, data);
}
}
// %0000_100010_mmmrrr ..m+-rxw.. 034 BCLR.B #<imm>,<ea>
// %0000_100010_000yyy .......... 034 BCLR.L #<imm>,Dy
OP_DEF(bclr_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BCLR.L #<imm>,Dy
CYCLE3(bclr_imm);
uint bit = fetch_2() & 31;
RegDY = ACC.bclr(RegDY, bit);
} else if (n == 0x3c) {
// BCLR.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BCLR.B #<imm>,<ea>
CYCLE3(bclr_imm);
uint bit = fetch_2() & 7;
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bclr(data, bit);
write_1(ea, data);
}
}
// %0000_100011_mmmrrr ..m+-rxw.. 034 BSET.B #<imm>,<ea>
// %0000_100011_000yyy .......... 034 BSET.L #<imm>,Dy
OP_DEF(bset_imm_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// BSET.L #<imm>,Dy
CYCLE3(bset_imm);
uint bit = fetch_2() & 31;
RegDY = ACC.bset(RegDY, bit);
} else if (n == 0x3c) {
// BSET.B #<imm>,<ea> の <ea> には #imm はない
op_illegal();
} else {
// BSET.B #<imm>,<ea>
CYCLE3(bset_imm);
uint bit = fetch_2() & 7;
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.bset(data, bit);
write_1(ea, data);
}
}
// %0000_101000_mmmrrr d.m+-rxw.. 034 EORI.B #<imm>,<ea>
// %0000_101000_111100 .......... 034 EORI.B #<imm>,CCR
OP_DEF(eori_b)
{
uint n = ir & 0x3f;
uint32 src = fetch_2() & 0xff;
if (n < 8) {
// EORI.B #<imm>,Dn
CYCLE3(eori_dn);
uint32 dst = (reg.D[n] & 0xff) ^ src;
ACC.move_8(dst);
reg.D[n] = (reg.D[n] & 0xffffff00) | dst;
} else if (n == 0b111100) {
// EORI.B #<imm>,CCR
CYCLE3(eori_ccr);
CCR.Set(CCR.Get() ^ src);
} else {
// EORI.B #<imm>,<ea>
CYCLE3(eori_ea);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst ^= src;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %0000_101001_mmmrrr d.m+-rxw.. 034 EORI.W #<imm>,<ea>
// %0000_101001_111100 .......... 034 EORI.W #<imm>,SR
OP_DEF(eori_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// EORI.W #<imm>,Dn
CYCLE3(eori_dn);
uint32 src = fetch_2();
uint32 dst = (reg.D[n] & 0xffff) ^ src;
ACC.move_16(dst);
reg.D[n] = (reg.D[n] & 0xffff0000) | dst;
} else if (n == 0b111100) {
// EORI.W #<imm>,SR
SUPERVISOR_OP;
CYCLE3(eori_sr);
uint32 src = fetch_2();
SetSR(GetSR() ^ src);
} else {
// EORI.W #<imm>,<ea>
CYCLE3(eori_ea);
uint32 src = fetch_2();
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst ^= src;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %0000_101010_mmmrrr d.m+-rxw.. 034 EORI.L #<imm>,<ea>
OP_DEF(eori_l)
{
uint n = ir & 0x3f;
uint32 src = fetch_4();
if (n < 8) {
// EORI.L #<imm>,Dn
CYCLE3(eori_dn);
reg.D[n] ^= src;
ACC.move_32(reg.D[n]);
} else {
// EORI.L #<imm>,<ea>
CYCLE3(eori_ea);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst ^= src;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %0000_101011_mmmrrr ..m+-rxw.. -34 CAS.B Dc,Du,<ea>
OP_DEF(cas_b)
{
ir2 = fetch_2();
uint c = ir2 & 7;
uint u = (ir2 >> 6) & 7;
uint32 dc = reg.D[c] & 0xff;
uint32 du = reg.D[u] & 0xff;
uint ea = cea_data_1();
uint32 dst = read_1(ea);
ACC.cmp_8(dc, dst);
if (CCR.IsZ()) {
// 等しければ、Du -> dst
CYCLE3(cas_eq);
write_1(ea, du);
} else {
// そうでなければ、dst -> Dc
CYCLE3(cas_ne);
reg.D[c] = (reg.D[c] & 0xffffff00) | dst;
}
}
// %0000_110000_mmmrrr d.m+-rxwp. -34 CMPI.B #<imm>,<ea>
OP_DEF(cmpi_b)
{
uint n = ir & 0x3f;
// CMPI はデータアドレッシングだが #imm がないことに注意
if (n == 0x3c) {
op_illegal();
return;
}
CYCLE3(cmpi);
uint32 src = fetch_2() & 0xff;
uint32 dst = fea_data_1();
ACC.cmp_8(src, dst);
}
// %0000_110001_mmmrrr d.m+-rxwp. -34 CMPI.W #<imm>,<ea>
OP_DEF(cmpi_w)
{
uint n = ir & 0x3f;
// CMPI はデータアドレッシングだが #imm がないことに注意
if (n == 0x3c) {
op_illegal();
return;
}
CYCLE3(cmpi);
uint32 src = fetch_2();
uint32 dst = fea_data_2();
ACC.cmp_16(src, dst);
}
// %0000_110010_mmmrrr d.m+-rxwp. -34 CMPI.L #<imm>,<ea>
OP_DEF(cmpi_l)
{
uint n = ir & 0x3f;
// CMPI はデータアドレッシングだが #imm がないことに注意
if (n == 0x3c) {
op_illegal();
return;
}
CYCLE3(cmpi);
uint32 src = fetch_4();
uint32 dst = fea_data_4();
ACC.cmp_32(src, dst);
}
// %0000_110011_mmmrrr ..m+-rxw.. -34 CAS.W Dc,Du,<ea>
// %0000_110011_111100 .......... -34 CAS2.W Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
OP_DEF(cas_w)
{
uint n = ir & 0x3f;
if (n == 0x3c) {
// CAS2.W Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
ir2 = fetch_2();
uint32 ir3 = fetch_2();
uint c1 = ir2 & 7;
uint u1 = (ir2 >> 6) & 7;
uint r1 = ir2 >> 12;
uint c2 = ir3 & 7;
uint u2 = (ir3 >> 6) & 7;
uint r2 = ir3 >> 12;
uint32 dc1 = reg.D[c1] & 0xffff;
uint32 du1 = reg.D[u1] & 0xffff;
uint32 ea1 = reg.R[r1];
uint32 dc2 = reg.D[c2] & 0xffff;
uint32 du2 = reg.D[u2] & 0xffff;
uint32 ea2 = reg.R[r2];
uint32 dst1 = read_2(ea1);
uint32 dst2 = read_2(ea2);
ACC.cmp_16(dc1, dst1);
if (CCR.IsZ()) {
ACC.cmp_16(dc2, dst2);
if (CCR.IsZ()) {
// 更新オペランド -> デスティネーション
CYCLE3(cas2_true_inc); // これは成功時の追加分
write_2(ea1, du1);
write_2(ea2, du2);
}
}
// デスティネーション -> 比較オペランド
CYCLE3(cas2_max);
reg.D[c1] = (reg.D[c1] & 0xffff0000) | dst1;
reg.D[c2] = (reg.D[c2] & 0xffff0000) | dst2;
} else {
// CAS.W Dc,Du,<ea>
ir2 = fetch_2();
uint c = ir2 & 7;
uint u = (ir2 >> 6) & 7;
uint32 dc = reg.D[c] & 0xffff;
uint32 du = reg.D[u] & 0xffff;
uint ea = cea_data_2();
uint32 dst = read_2(ea);
ACC.cmp_16(dc, dst);
if (CCR.IsZ()) {
// 等しければ、Du -> dst
CYCLE3(cas_eq);
write_2(ea, du);
} else {
// そうでなければ、dst -> Dc
CYCLE3(cas_ne);
reg.D[c] = (reg.D[c] & 0xffff0000) | dst;
}
}
}
// 68040 は MOVES でのプログラム空間アクセスをデータ空間アクセスに読み替える。
// バスエラーで報告されるのも読み替え後の FC なので、ここで差し替える。
// MC68040UM.pdf, p3-22。
// 68000PRM.pdf, p.6-26 の記述は逆に読めるが、誤りだと思われる。
busaddr
MPU680x0Device::translate_fc40(busaddr xfc)
{
if (mpu_type == m680x0MPUType::M68040) {
uint32 fc = xfc.GetFC();
if (fc == 2) {
xfc.ChangeFC(1);
} else if (fc == 6) {
xfc.ChangeFC(5);
}
}
return xfc;
}
// %0000_111000_mmmrrr ..m+-rxw.. -34 MOVES.B <ea>,Rn
// %0000_111000_mmmrrr ..m+-rxw.. -34 MOVES.B Rn,<ea>
OP_DEF(moves_b)
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint ea;
uint32 data;
if ((ir & 0x3f) < 16) {
op_illegal();
return;
}
ea = cea_data_1();
if ((ir2 & 0x0800) == 0) {
// <ea>,Rn
busaddr sfc = translate_fc40(reg.sfc);
busaddr addr = busaddr(ea) | sfc | BusAddr::Size1;
data = read_data(addr);
if (n < 8) { // Dn
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
CYCLE3(moves_ea_dn);
} else { // An
reg.R[n] = (int32)(int8)data;
CYCLE3(moves_ea_an);
}
} else {
// Rn,<ea>
CYCLE3(moves_rn_ea);
busaddr dfc = translate_fc40(reg.dfc);
busaddr addr = busaddr(ea) | dfc | BusAddr::Size1;
data = reg.R[n] & 0xff;
write_data(addr, data);
}
}
// %0000_111001_mmmrrr ..m+-rxw.. -34 MOVES.W <ea>,Rn
// %0000_111001_mmmrrr ..m+-rxw.. -34 MOVES.W Rn,<ea>
OP_DEF(moves_w)
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint ea;
uint32 data;
if ((ir & 0x3f) < 16) {
op_illegal();
return;
}
ea = cea_data_2();
if ((ir2 & 0x0800) == 0) {
// <ea>,Rn
busaddr sfc = translate_fc40(reg.sfc);
busaddr addr = busaddr(ea) | sfc | BusAddr::Size2;
data = read_data(addr);
if (n < 8) { // Dn
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
CYCLE3(moves_ea_dn);
} else { // An
reg.R[n] = (int32)(int16)data;
CYCLE3(moves_ea_an);
}
} else {
// Rn,<ea>
CYCLE3(moves_rn_ea);
busaddr dfc = translate_fc40(reg.dfc);
busaddr addr = busaddr(ea) | dfc | BusAddr::Size2;
data = reg.R[n] & 0xffff;
write_data(addr, data);
}
}
// %0000_111010_mmmrrr ..m+-rxw.. -34 MOVES.L <ea>,Rn
// %0000_111010_mmmrrr ..m+-rxw.. -34 MOVES.L Rn,<ea>
OP_DEF(moves_l)
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint ea;
uint32 data;
if ((ir & 0x3f) < 16) {
op_illegal();
return;
}
ea = cea_data_4();
if ((ir2 & 0x0800) == 0) {
// <ea>,Rn
busaddr sfc = translate_fc40(reg.sfc);
busaddr addr = busaddr(ea) | sfc | BusAddr::Size4;
data = read_data(addr);
reg.R[n] = data;
if (n < 8) {
CYCLE3(moves_ea_dn);
} else {
CYCLE3(moves_ea_an);
}
} else {
// Rn,<ea>
CYCLE3(moves_rn_ea);
busaddr dfc = translate_fc40(reg.dfc);
busaddr addr = busaddr(ea) | dfc | BusAddr::Size4;
data = reg.R[n];
write_data(addr, data);
}
}
// %0000_111011_mmmrrr ..m+-rxw.. -34 CAS.L Dc,Du,<ea>
// %0000_111011_111100 .......... -34 CAS2.L Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
OP_DEF(cas_l)
{
uint n = ir & 0x3f;
if (n == 0x3c) {
// CAS2.L Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
ir2 = fetch_2();
uint32 ir3 = fetch_2();
uint c1 = ir2 & 7;
uint u1 = (ir2 >> 6) & 7;
uint r1 = ir2 >> 12;
uint c2 = ir3 & 7;
uint u2 = (ir3 >> 6) & 7;
uint r2 = ir3 >> 12;
uint32 dc1 = reg.D[c1];
uint32 du1 = reg.D[u1];
uint32 ea1 = reg.R[r1];
uint32 dc2 = reg.D[c2];
uint32 du2 = reg.D[u2];
uint32 ea2 = reg.R[r2];
uint32 dst1 = read_4(ea1);
uint32 dst2 = read_4(ea2);
ACC.cmp_32(dc1, dst1);
if (CCR.IsZ()) {
ACC.cmp_32(dc2, dst2);
if (CCR.IsZ()) {
// 更新オペランド -> デスティネーション
CYCLE3(cas2_true_inc); // これは成功時の追加分
write_4(ea1, du1);
write_4(ea2, du2);
}
}
// デスティネーション -> 比較オペランド
CYCLE3(cas2_max);
reg.D[c1] = dst1;
reg.D[c2] = dst2;
} else {
// CAS.L Dc,Du,<ea>
ir2 = fetch_2();
uint c = ir2 & 7;
uint u = (ir2 >> 6) & 7;
uint32 dc = reg.D[c];
uint32 du = reg.D[u];
uint ea = cea_data_4();
uint32 dst = read_4(ea);
ACC.cmp_32(dc, dst);
if (CCR.IsZ()) {
// 等しければ、Du -> dst
CYCLE3(cas_eq);
write_4(ea, du);
} else {
// そうでなければ、dst -> Dc
CYCLE3(cas_ne);
reg.D[c] = dst;
}
}
}
// %0001_xxx000_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,Dx
OP_DEF(move_b_ea_dn)
{
CYCLE3(move_ea_dn);
uint32 data = fea_all_1();
ACC.move_8(data);
RegDX = (RegDX & 0xffffff00) | data;
}
// %0001_xxx010_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,(Ax)
OP_DEF(move_b_ea_anin)
{
// dst 分込み。
CYCLE3(move_ea_anin);
uint32 data = fea_all_1();
uint32 ea = internal_ea_anin(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx011_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,(Ax)+
OP_DEF(move_b_ea_anpi)
{
// dst 分込み。
CYCLE3(move_ea_anpi);
uint32 data = fea_all_1();
// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
save_reg_pi_if(RegIRX);
uint32 ea = internal_ea_anpi_1(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx100_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,-(Ax)
OP_DEF(move_b_ea_anpd)
{
// dst 分込み。
CYCLE3(move_ea_anpd);
uint32 data = fea_all_1();
// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
save_reg_pd_if(RegIRX);
uint32 ea = internal_ea_anpd_1(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx101_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,d16(Ax)
OP_DEF(move_b_ea_andi)
{
// dst 分込み。
CYCLE3(move_ea_andi);
uint32 data = fea_all_1();
uint32 ea = internal_ea_andi(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_xxx110_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,(Ax,IX)
OP_DEF(move_b_ea_anix)
{
// dst 分込み。
CYCLE3(move_ea_anix);
uint32 data = fea_all_1();
uint32 ea = internal_ea_anix(RegIRX);
ACC.move_8(data);
write_1(ea, data);
}
// %0001_000111_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,Abs.W
OP_DEF(move_b_ea_absw)
{
// dst 分込み。
CYCLE3(move_ea_absw);
uint32 data = fea_all_1();
uint32 ea = internal_ea_absw();
ACC.move_8(data);
write_1(ea, data);
}
// %0001_001111_mmmrrr d.m+-rxwpi 034 MOVE.B <ea>,Abs.L
OP_DEF(move_b_ea_absl)
{
// dst 分込み。
CYCLE3(move_ea_absl);
uint32 data = fea_all_1();
uint32 ea = internal_ea_absl();
ACC.move_8(data);
write_1(ea, data);
}
// %0010_xxx000_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,Dx
OP_DEF(move_l_ea_dn)
{
CYCLE3(move_ea_dn);
uint32 data = fea_all_4();
ACC.move_32(data);
RegDX = data;
}
// %0010_xxx001_mmmrrr dam+-rxwpi 034 MOVEA.L <ea>,Ax
OP_DEF(movea_l)
{
CYCLE3(movea_l);
uint32 data = fea_all_4();
RegAX = data;
}
// %0010_xxx010_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,(Ax)
OP_DEF(move_l_ea_anin)
{
// dst 分込み。
CYCLE3(move_ea_anin);
uint32 data = fea_all_4();
uint32 ea = internal_ea_anin(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx011_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,(Ax)+
OP_DEF(move_l_ea_anpi)
{
// dst 分込み。
CYCLE3(move_ea_anpi);
uint32 data = fea_all_4();
// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
save_reg_pi_if(RegIRX);
uint32 ea = internal_ea_anpi_4(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx100_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,-(Ax)
OP_DEF(move_l_ea_anpd)
{
// dst 分込み。
CYCLE3(move_ea_anpd);
uint32 data = fea_all_4();
// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
save_reg_pd_if(RegIRX);
uint32 ea = internal_ea_anpd_4(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx101_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,d16(Ax)
OP_DEF(move_l_ea_andi)
{
// dst 分込み。
CYCLE3(move_ea_andi);
uint32 data = fea_all_4();
uint32 ea = internal_ea_andi(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_xxx110_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,(Ax,IX)
OP_DEF(move_l_ea_anix)
{
// dst 分込み。
CYCLE3(move_ea_anix);
uint32 data = fea_all_4();
uint32 ea = internal_ea_anix(RegIRX);
ACC.move_32(data);
write_4(ea, data);
}
// %0010_000111_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,Abs.W
OP_DEF(move_l_ea_absw)
{
// dst 分込み。
CYCLE3(move_ea_absw);
uint32 data = fea_all_4();
uint32 ea = internal_ea_absw();
ACC.move_32(data);
write_4(ea, data);
}
// %0010_001111_mmmrrr dam+-rxwpi 034 MOVE.L <ea>,Abs.L
OP_DEF(move_l_ea_absl)
{
// dst 分込み。
CYCLE3(move_ea_absl);
uint32 data = fea_all_4();
uint32 ea = internal_ea_absl();
ACC.move_32(data);
write_4(ea, data);
}
// %0011_xxx000_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,Dx
OP_DEF(move_w_ea_dn)
{
CYCLE3(move_ea_dn);
uint32 data = fea_all_2();
ACC.move_16(data);
RegDX = (RegDX & 0xffff0000) | data;
}
// %0011_xxx001_mmmrrr dam+-rxwpi 034 MOVEA.W <ea>,Ax
OP_DEF(movea_w)
{
CYCLE3(movea_w);
uint32 data = (int32)(int16)fea_all_2();
RegAX = data;
}
// %0011_xxx010_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,(Ax)
OP_DEF(move_w_ea_anin)
{
// dst 分込み。
CYCLE3(move_ea_anin);
uint32 data = fea_all_2();
uint32 ea = internal_ea_anin(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx011_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,(Ax)+
OP_DEF(move_w_ea_anpi)
{
// dst 分込み。
CYCLE3(move_ea_anpi);
uint32 data = fea_all_2();
// (An)+,(Ax)+ が n==x なら2回目はセーブしてはいけない。
save_reg_pi_if(RegIRX);
uint32 ea = internal_ea_anpi_2(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx100_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,-(Ax)
OP_DEF(move_w_ea_anpd)
{
// dst 分込み。
CYCLE3(move_ea_anpd);
uint32 data = fea_all_2();
// -(An),-(Ax) が n==x なら2回目はセーブしてはいけない。
save_reg_pd_if(RegIRX);
uint32 ea = internal_ea_anpd_2(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx101_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,d16(Ax)
OP_DEF(move_w_ea_andi)
{
// dst 分込み。
CYCLE3(move_ea_andi);
uint32 data = fea_all_2();
uint32 ea = internal_ea_andi(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_xxx110_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,(Ax,IX)
OP_DEF(move_w_ea_anix)
{
// dst 分込み。
CYCLE3(move_ea_anix);
uint32 data = fea_all_2();
uint32 ea = internal_ea_anix(RegIRX);
ACC.move_16(data);
write_2(ea, data);
}
// %0011_000111_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,Abs.W
OP_DEF(move_w_ea_absw)
{
// dst 分込み。
CYCLE3(move_ea_absw);
uint32 data = fea_all_2();
uint32 ea = internal_ea_absw();
ACC.move_16(data);
write_2(ea, data);
}
// %0011_001111_mmmrrr dam+-rxwpi 034 MOVE.W <ea>,Abs.L
OP_DEF(move_w_ea_absl)
{
// dst 分込み。
CYCLE3(move_ea_absl);
uint32 data = fea_all_2();
uint32 ea = internal_ea_absl();
ACC.move_16(data);
write_2(ea, data);
}
// %0100_000000_mmmrrr d.m+-rxw.. 034 NEGX.B <ea>
OP_DEF(negx_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEGX.B Dn
CYCLE3(negx_dn);
uint32 data = reg.D[n] & 0xff;
data = ACC.subx_8(data, 0);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else if (n < 16) {
op_illegal();
} else {
// NEGX.B <ea>
CYCLE3(negx_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.subx_8(data, 0);
write_1(ea, data);
}
}
// %0100_000001_mmmrrr d.m+-rxw.. 034 NEGX.W <ea>
OP_DEF(negx_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEGX.W Dn
CYCLE3(negx_dn);
uint32 data = reg.D[n] & 0xffff;
data = ACC.subx_16(data, 0);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else if (n < 16) {
op_illegal();
} else {
// NEGX.W <ea>
CYCLE3(negx_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.subx_16(data, 0);
write_2(ea, data);
}
}
// %0100_000010_mmmrrr d.m+-rxw.. 034 NEGX.L <ea>
OP_DEF(negx_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEGX.L Dn
CYCLE3(negx_dn);
reg.D[n] = ACC.subx_32(reg.D[n], 0);
} else if (n < 16) {
op_illegal();
} else {
// NEGX.L <ea>
CYCLE3(negx_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.subx_32(data, 0);
write_4(ea, data);
}
}
// %0100_000011_mmmrrr d.m+-rxw.. -34 MOVE.W SR,<ea>
OP_DEF(move_sr_ea)
{
SUPERVISOR_OP;
uint n = ir & 0x3f;
if (n < 8) {
// MOVE.W SR,Dn
CYCLE3(move_sr_dn);
reg.D[n] = (reg.D[n] & 0xffff0000) | GetSR();
} else {
// MOVE.W SR,<ea>
CYCLE3(move_sr_ea);
uint32 ea = cea_data_2();
write_2(ea, GetSR());
}
}
// %0100_xxx100_mmmrrr d.m+-rxwpi -34 CHK.L <ea>,Dx
OP_DEF(chk_l)
{
uint32 dst = RegDX;
ACC.move_32(dst);
if (CCR.IsN()) {
// これは最大値で次の条件式が成立した時の値なので、
// 実際にはこれより小さい確定した値のはずだけど。
CYCLE3(chk_excep_max);
Exception(M68K::EXCEP_CHK);
return;
}
// 本当はこうじゃないけど、とりあえず
uint32 src = fea_data_4();
if ((int32)dst > (int32)src) {
CYCLE3(chk_excep_max);
CCR.SetN(false);
Exception(M68K::EXCEP_CHK);
return;
}
CYCLE3(chk);
}
// %0100_xxx110_mmmrrr d.m+-rxwpi 034 CHK.W <ea>,Dx
OP_DEF(chk_w)
{
uint32 dst = RegDX & 0xffff;
ACC.move_16(dst);
if (CCR.IsN()) {
// これは最大値で次の条件式が成立した時の値なので、
// 実際にはこれより小さい確定した値のはずだけど。
CYCLE3(chk_excep_max);
Exception(M68K::EXCEP_CHK);
return;
}
// 本当はこうじゃないけど、とりあえず
uint32 src = fea_data_2();
if ((int16)dst > (int16)src) {
CYCLE3(chk_excep_max);
CCR.SetN(false);
Exception(M68K::EXCEP_CHK);
return;
}
CYCLE3(chk);
}
// %0100_xxx111_mmmrrr ..m..rxwp. 034 LEA.L <ea>,Ax
// %0100_100111_000yyy .......... -34 EXTB.L Dy
OP_DEF(lea)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXTB.L Dy
CYCLE3(extb);
RegDY = (int32)(int8)(RegDY & 0xff);
ACC.move_32(RegDY);
} else {
// LEA.L <ea>,Ax
CYCLE3(lea);
RegAX = cea_ctrl();
}
}
// %0100_001000_mmmrrr d.m+-rxw.. 034 CLR.B <ea>
OP_DEF(clr_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// CLR.B Dn
CYCLE3(clr_dn);
RegDY &= 0xffffff00;
ACC.move_8(0);
} else {
// CLR.B <ea>
CYCLE3(clr_ea);
uint32 ea = cea_data_1();
ACC.move_8(0);
write_1(ea, 0);
}
}
// %0100_001001_mmmrrr d.m+-rxw.. 034 CLR.W <ea>
OP_DEF(clr_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// CLR.W Dn
CYCLE3(clr_dn);
RegDY &= 0xffff0000;
ACC.move_16(0);
} else {
// CLR.W <ea>
CYCLE3(clr_ea);
uint32 ea = cea_data_2();
ACC.move_16(0);
write_2(ea, 0);
}
}
// %0100_001010_mmmrrr d.m+-rxw.. 034 CLR.L <ea>
OP_DEF(clr_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// CLR.L Dn
CYCLE3(clr_dn);
RegDY = 0;
ACC.move_32(0);
} else {
// CLR.L <ea>
CYCLE3(clr_ea);
uint32 ea = cea_data_4();
ACC.move_32(0);
write_4(ea, 0);
}
}
// %0100_001011_mmmrrr d.m+-rxw.. -34 MOVE.W CCR,<ea>
OP_DEF(move_ccr_ea)
{
uint n = ir & 0x3f;
// 転送は16ビットで行われ、上位バイトと未実装ビットは %0 になる。
if (n < 8) {
// MOVE.W CCR,Dn
CYCLE3(move_ccr_dn);
reg.D[n] = (reg.D[n] & 0xffff0000) | CCR.Get();
} else if (n < 16) {
// MOVE.W CCR,An はない
op_illegal();
} else {
// MOVE.W CCR,<ea>
CYCLE3(move_ccr_ea);
uint32 ea = cea_data_2();
write_2(ea, CCR.Get());
}
}
// %0100_010000_mmmrrr d.m+-rxw.. 034 NEG.B <ea>
OP_DEF(neg_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEG.B Dn
CYCLE3(neg_dn);
uint32 data = ACC.sub_8(reg.D[n] & 0xff, 0);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// NEG.B <ea>
CYCLE3(neg_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.sub_8(data, 0);
write_1(ea, data);
}
}
// %0100_010001_mmmrrr d.m+-rxw.. 034 NEG.W <ea>
OP_DEF(neg_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEG.W Dn
CYCLE3(neg_dn);
uint32 data = ACC.sub_16(reg.D[n] & 0xffff, 0);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else {
// NEG.W <ea>
CYCLE3(neg_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.sub_16(data, 0);
write_2(ea, data);
}
}
// %0100_010010_mmmrrr d.m+-rxw.. 034 NEG.L <ea>
OP_DEF(neg_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// NEG.L Dn
CYCLE3(neg_dn);
reg.D[n] = ACC.sub_32(reg.D[n], 0);
} else {
// NEG.L <ea>
CYCLE3(neg_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.sub_32(data, 0);
write_4(ea, data);
}
}
// %0100_010011_mmmrrr d.m+-rxwpi 034 MOVE.W <ea>,CCR
OP_DEF(move_ea_ccr)
{
uint n = ir & 0x3f;
if (n < 8) {
// MOVE.W Dn,CCR
CYCLE3(move_dn_ccr);
uint32 data = reg.D[n] & 0xff;
CCR.Set(data);
} else if (n < 16) {
// MOVE.W An,CCR はない
op_illegal();
} else {
// MOVE.W <ea>,CCR
CYCLE3(move_ea_ccr);
uint32 data = fea_data_2();
CCR.Set(data);
}
}
// %0100_011000_mmmrrr d.m+-rxw.. 034 NOT.B <ea>
OP_DEF(not_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// NOT.B Dn
CYCLE3(not_dn);
uint32 data = (~reg.D[n]) & 0xff;
ACC.move_8(data);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// NOT.B <ea>
CYCLE3(not_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = (~data) & 0xff;
ACC.move_8(data);
write_1(ea, data);
}
}
// %0100_011001_mmmrrr d.m+-rxw.. 034 NOT.W <ea>
OP_DEF(not_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// NOT.W Dn
CYCLE3(not_dn);
uint32 data = (~reg.D[n]) & 0xffff;
ACC.move_16(data);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else {
// NOT.W <ea>
CYCLE3(not_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = (~data) & 0xffff;
ACC.move_16(data);
write_2(ea, data);
}
}
// %0100_011010_mmmrrr d.m+-rxw.. 034 NOT.L <ea>
OP_DEF(not_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// NOT.L Dn
CYCLE3(not_dn);
reg.D[n] = ~reg.D[n];
ACC.move_32(reg.D[n]);
} else {
// NOT.L <ea>
CYCLE3(not_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ~data;
ACC.move_32(data);
write_4(ea, data);
}
}
// %0100_011011_mmmrrr d.m+-rxwpi 034 MOVE.W <ea>,SR
OP_DEF(move_ea_sr)
{
SUPERVISOR_OP;
CYCLE3(move_ea_sr);
uint16 data = fea_data_2();
SetSR(data);
}
// LINK.W, LINK.L は即値の取り出しが違うだけ。
void
MPU680x0Device::ops_link(int32 imm)
{
// ページフォルトに備えて保存する。
save_reg_pd(7);
push_4(RegAY);
RegAY = reg.A[7];
reg.A[7] += imm;
}
// %0100_100000_mmmrrr d.m+-rxw.. 034 NBCD.B <ea>
// %0100_100000_001yyy .......... -34 LINK.L Ay,#<imm>
OP_DEF(nbcd)
{
uint n = ir & 0x3f;
if (n < 8) {
// NBCD.B Dn
CYCLE3(nbcd);
uint32 dst = RegDY & 0xff;
dst = ACC.sbcd_8(dst, 0);
RegDY = (RegDY & 0xffffff00) | dst;
} else if (n < 16) {
// LINK.L An,#<imm>
CYCLE3(link_l);
// レジスタやスタックを変更する前にフェッチしないと、
// ページフォルトで再実行できなくなる
int32 imm = fetch_4();
ops_link(imm);
} else {
// NBCD.B <ea>
CYCLE3(nbcd);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst = ACC.sbcd_8(dst, 0);
write_1(ea, dst);
}
}
// %0100_100001_mmmrrr ..m..rxwp. 034 PEA.L <ea>
// %0100_100001_000yyy .......... 034 SWAP.W Dy
// %0100_100001_001nnn .......... -34 BKPT #<imm>
OP_DEF(pea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SWAP.W Dy
CYCLE3(swap);
reg.D[n] = (reg.D[n] << 16) | (reg.D[n] >> 16);
ACC.move_32(reg.D[n]);
} else if (n < 16) {
// BKPT #<imm>
// ブレークポイント・アクノリッジサイクルに応答するデバイスはないので
// 常に不当命令にする。
CYCLE3(bkpt); // ?
op_illegal();
} else {
// PEA.L <ea>
CYCLE3(pea);
uint32 ea = cea_ctrl();
// ページフォルトに備えて保存する
save_reg_pd(7);
push_4(ea);
}
}
// MOVEM.[WL] <list>,<ea> の共通部分。
// bytesize は1レジスタ分のサイズ、.Wなら2、.Lなら4。
// 本当はテンプレートにしたい。
void
MPU680x0Device::ops_movem_list_ea(int bytesize)
{
uint32 ea;
int regcount;
// 不当な第1ワードを弾く
#define INVALID(x) (0xffULL << (56 - ((x) * 8)))
const uint64 valid =
INVALID(0) // Dn
| INVALID(1) // An
| INVALID(3) // (An)+
| 0x3fL; // (PC)...
if ((int64)(valid << (ir & 0x3f)) < 0) {
op_illegal();
return;
}
// 第2ワードは EA が正当な場合のみ EA より先にフェッチ
ir2 = fetch_2();
// EA 取得。MOVEM だけ別対応
// | M -WXZ | MOVEM list,<ea>
// だが、不当 EA はすでに弾いてあるので cea_data でいい
if (bytesize == 2) {
ea = cea_data_2();
} else {
ea = cea_data_4();
}
regcount = 0;
uint list = ir2;
if (eamode(ir) == 4/*-(An)*/) {
// -(An) の場合 reglist の格納順が逆(転送順は LSB から)
// bit15 bit0
// D0 D1 D2 D3 D4 D5 D6 D7 A0 A1 A2 A3 A4 A5 A6 A7
while (list) {
int ctz = __builtin_ctz(list);
if (bytesize == 2) {
write_2(ea, reg.R[15 - ctz] & 0xffff);
} else {
write_4(ea, reg.R[15 - ctz]);
}
ea -= bytesize;
regcount++;
// 処理した最下位ビットを落とす
list &= list - 1;
}
// ea は一つ行き過ぎるので補正
RegAY = ea + bytesize;
} else {
// LSB 側から転送
// bit15 bit0
// A7 A6 A5 A4 A4 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
while (list) {
int ctz = __builtin_ctz(list);
if (bytesize == 2) {
write_2(ea, reg.R[ctz] & 0xffff);
} else {
write_4(ea, reg.R[ctz]);
}
ea += bytesize;
regcount++;
// 処理した最下位ビットを落とす
list &= list - 1;
}
}
// 040 では実際は、転送するデータレジスタの数が0なら1個として
// (Dn + An) * 1 を加算なのだが、そこはもう省略。(68040UM.pdf p.10-23)
CYCLE3(movem_list_ea);
CYCLE3(movem_list_ea_n) * regcount; // 副作用上等!
}
// %0100_100010_mmmrrr ..m.-rxw.. 034 MOVEM.W <list>,<ea>
// %0100_100010_000yyy .......... 034 EXT.W Dy
OP_DEF(movem_w_mem)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXT.W Dy
CYCLE3(ext);
uint16 data = (int16)(int8)(RegDY & 0xff);
ACC.move_16(data);
RegDY = (RegDY & 0xffff0000) | data;
} else {
// MOVEM.W <list>,<ea>
ops_movem_list_ea(2);
}
}
// %0100_100011_mmmrrr ..m.-rxw.. 034 MOVEM.L <list>,<ea>
// %0100_100011_000yyy .......... 034 EXT.L Dy
OP_DEF(movem_l_mem)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXT.L Dy
CYCLE3(ext);
RegDY = (int32)(int16)(RegDY & 0x0000ffff);
ACC.move_32(RegDY);
} else {
// MOVEM.L <list>,<ea>
ops_movem_list_ea(4);
}
}
// %0100_101000_mmmrrr dam+-rxwpi -34 TST.B <ea>
OP_DEF(tst_b)
{
CYCLE3(tst);
uint32 data = fea_all_1();
ACC.move_8(data);
}
// %0100_101001_mmmrrr dam+-rxwpi -34 TST.W <ea>
OP_DEF(tst_w)
{
CYCLE3(tst);
uint32 data = fea_all_2();
ACC.move_16(data);
}
// %0100_101010_mmmrrr dam+-rxwpi -34 TST.L <ea>
OP_DEF(tst_l)
{
CYCLE3(tst);
uint32 data = fea_all_4();
ACC.move_32(data);
}
// %0100_101011_mmmrrr d.m+-rxw.. 034 TAS.B <ea>
// %0100_101011_111100 .......... 034 ILLEGAL
OP_DEF(tas)
{
uint n = ir & 0x3f;
if (n < 8) {
// TAS.B Dn
// リード・モディファイ・ライトという概念はない
CYCLE3(tas_dn);
uint32 data = reg.D[n];
ACC.move_8(data);
reg.D[n] |= 0x80;
} else if (n == 0x3c) {
// ILLEGAL
op_illegal();
} else {
// TAS.B <ea>
// リード・モディファイ・ライトという概念はない
CYCLE3(tas_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
ACC.move_8(data);
write_1(ea, (data | 0x80));
}
}
// %0100_110000_mmmrrr d.m+-rxwpi -34 MULS.L <ea>,Dl
// %0100_110000_mmmrrr d.m+-rxwpi -34 MULS.L <ea>,Dh:Dl
// %0100_110000_mmmrrr d.m+-rxwpi -34 MULU.L <ea>,Dl
// %0100_110000_mmmrrr d.m+-rxwpi -34 MULU.L <ea>,Dh:Dl
OP_DEF(mul)
{
// 2ワード目
// %0LLL_Ss0000_000HHH
// +++ || +++- Dh
// | |+------------ %1:64bit, %0:32bit
// | +------------- %1:MULS, %0:MULU
// +---------------- Dl
ir2 = fetch_2();
uint h = ir2 & 7;
uint l = (ir2 >> 12) & 7;
switch ((ir2 >> 10) & 3) {
case 0:
{
// MULU.L <ea>,Dl
CYCLE3(mulu_l_max);
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
reg.D[l] = ACC.mulu_32(src, dst);
break;
}
case 1:
{
// MULU.L <ea>,Dh:Dl
CYCLE3(mulu_l_max);
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
uint64 res = ACC.mulu_64(src, dst);
// h == l の時は未定義なので考えない。
reg.D[h] = res >> 32;
reg.D[l] = res;
break;
}
case 2:
{
// MULS.L <ea>,Dl
CYCLE3(muls_l_max);
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
reg.D[l] = ACC.muls_32(src, dst);
break;
}
case 3:
{
// MULS.L <ea>,Dh:Dl
CYCLE3(muls_l_max);
uint32 src = fea_data_4();
uint32 dst = reg.D[l];
uint64 res = ACC.muls_64(src, dst);
// h == l の時は未定義なので考えない。
reg.D[h] = res >> 32;
reg.D[l] = res;
break;
}
default:
__unreachable();
}
}
// DIVU.L <ea>,Dq
// DIVUL.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divu_32_32(uint r, uint q)
{
CYCLE3(divu_l_max);
uint32 src = fea_data_4();
uint32 dst = reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
uint32 quo = dst / src;
uint32 rem = dst % src;
// このケースでオーバーフローは起きないはず
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// DIVU.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divu_64_32(uint r, uint q)
{
CYCLE3(divu_l_max);
uint32 src = fea_data_4();
uint64 dst = (((uint64)reg.D[r]) << 32) | reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
uint64 q64 = dst / src;
if (q64 > 0xffffffffUL) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
uint32 quo = q64;
uint32 rem = dst % src;
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// DIVS.L <ea>,Dq
// DIVSL.L <ea>,Dr:Dq
void
MPU680x0Device::ops_divs_32_32(uint r, uint q)
{
CYCLE3(divs_l_max);
uint32 src = fea_data_4();
uint32 dst = reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
// ホストでオーバーフローが起きるのはこのケースのみ
if (dst == INT32_MIN && src == -1) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
uint32 quo = (int32)dst / (int32)src;
uint32 rem = (int32)dst % (int32)src;
// ここでオーバーフローは起きない
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// DIVSL.L
void
MPU680x0Device::ops_divs_64_32(uint r, uint q)
{
CYCLE3(divs_l_max);
uint32 src = fea_data_4();
uint64 dst = (((uint64)reg.D[r]) << 32) | reg.D[q];
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
// ホストでオーバーフローが起きるのはこのケースのみ
if (dst == INT64_MIN && src == -1) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
int64 sq64 = (int64)dst / (int32)src;
if ((int32)sq64 != sq64) {
// オーバーフロー
CCR.SetV(true);
CCR.SetC(false);
return;
}
uint32 quo = (uint32)sq64;
uint32 rem = (int64)dst % (int32)src;
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
// r == q の場合 quo が残るので、rem を先に書く
reg.D[r] = rem;
reg.D[q] = quo;
ACC.move_32(quo);
}
// %0100_110001_mmmrrr d.m+-rxwpi -34 DIVS.L <ea>,Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34 DIVS.L <ea>,Dr:Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34 DIVSL.L <ea>,Dr:Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34 DIVU.L <ea>,Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34 DIVU.L <ea>,Dr:Dq
// %0100_110001_mmmrrr d.m+-rxwpi -34 DIVUL.L <ea>,Dr:Dq
OP_DEF(div)
{
// 2ワード目
// %0QQQ_Ss0000_000RRR
// +++ || +++- Dr
// | |+------------ %1:64bit, %0:32bit
// | +------------- %1:DIVS, %0:DIVU
// +---------------- Dq
ir2 = fetch_2();
uint r = ir2 & 7;
uint q = (ir2 >> 12) & 7;
switch ((ir2 >> 10) & 3) {
case 0:
ops_divu_32_32(r, q);
break;
case 1:
ops_divu_64_32(r, q);
break;
case 2:
ops_divs_32_32(r, q);
break;
case 3:
ops_divs_64_32(r, q);
break;
default:
__unreachable();
}
}
void
MPU680x0Device::ops_movem_ea_list(int bytesize)
{
uint32 ea;
int regcount;
bool anpi = false;
ir2 = fetch_2();
// EA 取得。MOVEM だけ別対応
// | M+ WXZP | MOVEM <ea>,list
switch (eamode(ir)) {
case 2: // (An)
ea = cea_anin(eanum(ir));
break;
case 3: // (An)+
save_reg_pi(eanum(ir));
if (bytesize == 2) {
ea = cea_anpi_2(eanum(ir));
} else {
ea = cea_anpi_4(eanum(ir));
}
anpi = true;
break;
case 5: // d16(An)
ea = cea_andi(eanum(ir));
break;
case 6: // (An,IX)
ea = cea_anix(eanum(ir));
break;
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = cea_absw();
break;
case 1: // Abs.L
ea = cea_absl();
break;
case 2: // d16(PC)
ea = cea_pcdi();
break;
case 3: // (PC,IX)
ea = cea_pcix();
break;
default:
op_illegal();
return;
}
break;
default:
op_illegal();
return;
}
// XXX レジスタリストに表れて、ea オペランドに出てくる
// レジスタは Dn、IX も含めて全部保存しておく必要がある。
regcount = 0;
uint list = ir2;
while (list) {
uint32 data;
if (bytesize == 2) {
data = (int32)(int16)read_2(ea);
} else {
data = read_4(ea);
}
ea += bytesize;
regcount++;
int ctz = __builtin_ctz(list);
reg.R[ctz] = data;
// clear LSB bits
list &= ((~1U) << ctz);
}
// (An)+ なら An を更新
if (anpi) {
RegAY = ea;
}
// 040 では実際は、転送するデータレジスタの数が0なら1個として
// (Dn + An) * 1 を加算なのだが、そこはもう省略。(68040UM.pdf p.10-23)
CYCLE3(movem_ea_list);
CYCLE3(movem_ea_list_n) * regcount; // 副作用上等!
}
// %0100_110010_mmmrrr ..m+.rxwp. 034 MOVEM.W <ea>,<list>
OP_DEF(movem_w)
{
ops_movem_ea_list(2);
}
// %0100_110011_mmmrrr ..m+.rxwp. 034 MOVEM.L <ea>,<list>
OP_DEF(movem_l)
{
ops_movem_ea_list(4);
}
// 制御レジスタ:
// MPU
// $000 SFC 234
// $001 DFC 234
// $002 CACR 234
// $003 TC --4
// $004 ITT0 --4
// $005 ITT1 --4
// $006 DTT0 --4
// $007 DTT1 --4
// $800 USP 234
// $801 VBR 234
// $802 CAAR 23-
// $803 MSP 234
// $804 ISP 234
// $805 MMUSR --4
// $806 URP --4
// $807 SRP --4
// MOVEC.L Rc,Rn
void
MPU680x0Device::ops_movec_rc_rn()
{
SUPERVISOR_OP;
CYCLE3(movec_rc_rn);
ir2 = fetch_2();
uint n = ir2 >> 12;
uint c = ir2 & 0xfff;
// まず CPU 固有レジスタを試す。
if (ops_movec_rc_rn_cpu(c, n)) {
return;
}
// なければ共通レジスタを試す。
switch (c) {
case 0x000:
reg.R[n] = reg.GetSFC();
return;
case 0x001:
reg.R[n] = reg.GetDFC();
return;
case 0x002:
reg.R[n] = reg.cacr;
return;
case 0x800:
reg.R[n] = reg.usp;
return;
case 0x801:
reg.R[n] = reg.vbr;
return;
case 0x803:
if (reg.m) {
reg.R[n] = reg.A[7];
} else {
reg.R[n] = reg.msp;
}
return;
case 0x804:
if (reg.m) {
reg.R[n] = reg.isp;
} else {
reg.R[n] = reg.A[7];
}
return;
default:
break;
}
op_illegal();
}
// MOVEC.L Rc,Rn (68030 固有)
bool
MPU68030Device::ops_movec_rc_rn_cpu(uint c, uint n)
{
switch (c) {
case 0x802:
reg.R[n] = reg.caar;
return true;
default:
break;
}
return false;
}
// MOVEC.L Rc,Rn (68040 固有)
bool
MPU68040Device::ops_movec_rc_rn_cpu(uint c, uint n)
{
switch (c) {
case 0x003:
reg.R[n] = reg.tc40;
return true;
case 0x004:
reg.R[n] = reg.itt[0];
return true;
case 0x005:
reg.R[n] = reg.itt[1];
return true;
case 0x006:
reg.R[n] = reg.dtt[0];
return true;
case 0x007:
reg.R[n] = reg.dtt[1];
return true;
case 0x805:
reg.R[n] = reg.mmusr40;
return true;
case 0x806:
reg.R[n] = reg.urp40;
return true;
case 0x807:
reg.R[n] = reg.srp40;
return true;
default:
break;
}
return false;
}
// MOVEC.L Rn,Rc
void
MPU680x0Device::ops_movec_rn_rc()
{
SUPERVISOR_OP;
ir2 = fetch_2();
uint n = ir2 >> 12;
uint c = ir2 & 0xfff;
// まず CPU 固有レジスタを試す。
if (ops_movec_rn_rc_cpu(c, n)) {
return;
}
// なければ共通レジスタを試す。
switch (c) {
case 0x000:
CYCLE3(movec_rn_rcb);
reg.sfc = busaddr::FC(reg.R[n] & 7) | BusAddr::R;
return;
case 0x001:
CYCLE3(movec_rn_rcb);
reg.dfc = busaddr::FC(reg.R[n] & 7) | BusAddr::W;
return;
case 0x002:
CYCLE3(movec_rn_rcb);
SetCACR(reg.R[n]);
return;
case 0x800:
CYCLE3(movec_rn_rca);
reg.usp = reg.R[n];
return;
case 0x801:
CYCLE3(movec_rn_rca);
reg.vbr = reg.R[n];
return;
case 0x803:
CYCLE3(movec_rn_rca);
if (reg.m) {
reg.A[7] = reg.R[n];
} else {
reg.msp = reg.R[n];
}
return;
case 0x804:
CYCLE3(movec_rn_rca);
if (reg.m) {
reg.isp = reg.R[n];
} else {
reg.A[7] = reg.R[n];
}
return;
default:
break;
}
op_illegal();
}
// MOVEC.L Rn,Rc (68030 固有)
bool
MPU68030Device::ops_movec_rn_rc_cpu(uint c, uint n)
{
switch (c) {
case 0x802:
CYCLE3(movec_rn_rca);
reg.caar = reg.R[n];
return true;
default:
break;
}
return false;
}
// MOVEC.L Rn,Rc (68040 固有)
bool
MPU68040Device::ops_movec_rn_rc_cpu(uint c, uint n)
{
switch (c) {
case 0x003:
SetTC(reg.R[n]);
return true;
case 0x004:
SetTT(mmu_itt[0].get(), reg.R[n]);
return true;
case 0x005:
SetTT(mmu_itt[1].get(), reg.R[n]);
return true;
case 0x006:
SetTT(mmu_dtt[0].get(), reg.R[n]);
return true;
case 0x007:
SetTT(mmu_dtt[1].get(), reg.R[n]);
return true;
case 0x805:
// 書き込める?
//SetMMUSR(reg.R[n]);
OP_FUNC(unimpl);
return true;
case 0x806:
SetURP(reg.R[n]);
return true;
case 0x807:
SetSRP(reg.R[n]);
return true;
default:
break;
}
return false;
}
// %0100_111001_00nnnn .......... 034 TRAP #<vector>
// %0100_111001_010yyy .......... 034 LINK.W Ay,#<imm>
// %0100_111001_011yyy .......... 034 UNLK Ay
// %0100_111001_100yyy .......... 034 MOVE.L Ay,USP
// %0100_111001_101yyy .......... 034 MOVE.L USP,Ay
// %0100_111001_110000 .......... 034 RESET
// %0100_111001_110001 .......... 034 NOP
// %0100_111001_110010 .......... 034 STOP #<imm>
// %0100_111001_110011 .......... 034 RTE
// %0100_111001_110100 .......... -34 RTD #<imm>
// %0100_111001_110101 .......... 034 RTS
// %0100_111001_110110 .......... 034 TRAPV
// %0100_111001_110111 .......... 034 RTR
// %0100_111001_111010 .......... -34 MOVEC.L Rc,Rn
// %0100_111001_111011 .......... -34 MOVEC.L Rn,Rc
OP_DEF(trap)
{
uint n = ir & 0x3f;
switch (n) {
case 0x00: // TRAP #0
CYCLE3(trap);
// TRAP#0 例外 (NetBSD システムコール表示のため別処理)
ExceptionTrap0();
return;
case 0x01 ... 0x0e:// TRAP #<vector>
CYCLE3(trap);
// TRAP#N 例外
Exception(M68K::EXCEP_TRAP0 + n);
return;
case 0x0f: // TRAP #15
CYCLE3(trap);
// TRAP#15 例外 (IOCS コール表示のためこれだけ別処理)
ExceptionTrap15();
return;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17: // LINK.W Ay,#<imm>
{
CYCLE3(link_w);
// レジスタやスタックを変更する前にフェッチとセーブをしないと、
// ページフォルトで再実行できなくなる
int32 imm = (int32)(int16)fetch_2();
ops_link(imm);
return;
}
case 0x18:
case 0x19:
case 0x1a:
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f: // UNLK Ay
CYCLE3(unlk);
// ページフォルトに備えて保存する
save_reg_pi(7);
reg.A[7] = RegAY;
RegAY = pop_4();
return;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27: // MOVE.L Ay,USP
SUPERVISOR_OP;
CYCLE3(move_an_usp);
reg.usp = RegAY;
return;
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f: // MOVE.L USP,Ay
SUPERVISOR_OP;
CYCLE3(move_usp_an);
RegAY = reg.usp;
return;
case 0x30: // RESET
// CYCLE3() は int8 なので。
CYCLE(518);
ops_reset();
return;
case 0x31: // NOP
CYCLE3(nop);
// XXX ほんとは何かするらしいけど
return;
case 0x32: // STOP #<imm>
SUPERVISOR_OP;
CYCLE3(stop);
ops_stop();
return;
case 0x33: // RTE
SUPERVISOR_OP;
ops_rte();
return;
case 0x34: // RTD #<imm>
{
CYCLE3(rtd);
// ページフォルトに備えて保存する
save_reg_pi(7);
uint32 disp = fetch_2();
Jump(pop_4());
reg.A[7] += (int32)(int16)disp;
return;
}
case 0x35: // RTS
CYCLE3(rts);
// ページフォルトに備えて保存する
save_reg_pi(7);
Jump(pop_4());
return;
case 0x36: // TRAPV
if (CCR.IsV()) {
CYCLE3(trapv_excep);
Exception(M68K::EXCEP_TRAPV);
} else {
CYCLE3(trapv);
}
return;
case 0x37: // RTR
CYCLE3(rtr);
// ページフォルトに備えて保存する
save_reg_pi(7);
CCR.Set(pop_2());
Jump(pop_4());
return;
case 0x3a: // MOVEC.L Rc,Rn
ops_movec_rc_rn();
return;
case 0x3b: // MOVEC.L Rn,Rc
ops_movec_rn_rc();
return;
default:
op_illegal();
return;
}
}
// %0100_111010_mmmrrr ..m..rxwp. 034 JSR <ea>
OP_DEF(jsr)
{
CYCLE3(jsr);
uint32 ea = cea_ctrl();
uint32 return_addr = reg.pc;
// ページフォルトに備えて保存する。
save_reg_pd(7);
push_4(return_addr);
Jump(ea);
}
// %0100_111011_mmmrrr ..m..rxwp. 034 JMP <ea>
OP_DEF(jmp)
{
CYCLE3(jmp);
// 実際には CEA ではなく JEA の実行時間を足すんだがまあいいか
uint32 ea = cea_ctrl();
Jump(ea);
}
// %0101_qqq000_mmmrrr d.m+-rxw.. 034 ADDQ.B #qqq,<ea>
OP_DEF(addq_b)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// ADDQ.B #qqq,Dn
CYCLE3(addq_rn);
uint32 data = ACC.add_8(src, reg.D[n] & 0xff);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// ADDQ.B #qqq,<ea>
CYCLE3(addq_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.add_8(src, data);
write_1(ea, data);
}
}
// %0101_qqq001_mmmrrr d.m+-rxw.. 034 ADDQ.W #qqq,<ea>
// %0101_qqq001_001yyy .a........ 034 ADDQ.W #qqq,Ay (.Lと等価)
OP_DEF(addq_w)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// ADDQ.W #qqq,Dn
CYCLE3(addq_rn);
uint32 data = ACC.add_16(src, reg.D[n] & 0xffff);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else if (n < 16) {
// ADDQ.W #qqq,An は ADDQ.L と等価
// フラグは変化しない
CYCLE3(addq_rn);
reg.R[n] += src;
} else {
// ADDQ.W #qqq,<ea>
CYCLE3(addq_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.add_16(src, data);
write_2(ea, data);
}
}
// %0101_qqq010_mmmrrr d.m+-rxw.. 034 ADDQ.L #qqq,<ea>
// %0101_qqq010_001yyy .a........ 034 ADDQ.L #qqq,Ay
OP_DEF(addq_l)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// ADDQ.L #qqq,Dn
CYCLE3(addq_rn);
reg.D[n] = ACC.add_32(src, reg.D[n]);
} else if (n < 16) {
// ADDQ.L #qqq,An
// フラグは変化しない
CYCLE3(addq_rn);
reg.R[n] += src;
} else {
// ADDQ.L #qqq,<ea>
CYCLE3(addq_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.add_32(src, data);
write_4(ea, data);
}
}
// TRAPcc の共通部分。
void
MPU680x0Device::ops_trapcc(uint cond)
{
// 条件成立すれば例外。成立しなければ何もしない。
// いずれの場合もオペランドありの形態なら事前に読み飛ばしておくこと。
if (CCR.Cond(cond)) {
CYCLE3(trapcc_excep);
Exception(M68K::EXCEP_TRAPV);
} else {
// サイクルを消費するだけ
CYCLE3(trapcc);
}
}
// %0101_cccc11_mmmrrr d.m+-rxw.. 034 Scc.B <ea>
// %0101_cccc11_001yyy .......... 034 DBcc.W Dy,<label>
// %0101_cccc11_111010 .......... -34 TRAPcc.W #<imm>
// %0101_cccc11_111011 .......... -34 TRAPcc.L #<imm>
// %0101_cccc11_111100 .......... -34 TRAPcc
// %0101_000111_001yyy .......... 034 DBRA.W Dy,<label>
OP_DEF(scc)
{
uint n = ir & 0x3f;
uint cond = (ir >> 8) & 0x0f;
switch (n) {
case 0b000000 ... 0b000111: // Scc.B Dn
CYCLE3(scc_dn);
if (CCR.Cond(cond)) {
RegDY |= 0xff;
} else {
RegDY &= ~0xff;
}
return;
case 0b001000 ... 0b001111: // DBcc.W Dy,<label>
if (CCR.Cond(cond)) {
// 真なら何もしない。disp を読み飛ばして次へ。
CYCLE3(dbcc_nop);
fetch_2();
} else {
// 偽の場合
// Dy.W を減算して(下位ワードに)書き戻し、Dy.W が -1 だったら
// ループ終了。だが最適化のため、減算前の Dy.W が 0 の時は
// 下位ワードを 0xffff にしてループ終了、そうでなければ Dy.L を
// 減算するだけでいいはず。
uint16 data = RegDY;
if (data == 0) {
// ループ終了。disp を読み飛ばす
CYCLE3(dbcc_done);
RegDY |= 0x0000ffff;
fetch_2();
} else {
CYCLE3(dbcc_jmp);
RegDY--;
uint32 origin = reg.pc;
int32 disp = (int32)(int16)fetch_2();
Jump(origin + disp);
}
}
return;
case 0b010000 ... 0b010111: // Scc.B <ea>
case 0b011000 ... 0b011111: // Scc.B <ea>
case 0b100000 ... 0b100111: // Scc.B <ea>
case 0b101000 ... 0b101111: // Scc.B <ea>
case 0b110000 ... 0b110111: // Scc.B <ea>
case 0b111000: // Scc.B <ea>
case 0b111001: // Scc.B <ea>
{
CYCLE3(scc_ea);
// 条件成立可否に関わらず EA は取得しないといけない
uint32 ea = cea_data_1();
uint32 data;
if (CCR.Cond(cond)) {
data = 0xff;
} else {
data = 0;
}
write_1(ea, data);
return;
}
case 0b111010: // TRAPcc.W #<imm>
// オペランドなしTRAPccに比べてすべてのケースで2サイクル多い
CYCLE3(trapcc_w_inc);
fetch_2();
ops_trapcc(cond);
return;
case 0b111011: // TRAPcc.L #<imm>
// オペランドなしTRAPccに比べてすべてのケースで4サイクル多い
CYCLE3(trapcc_l_inc);
fetch_4();
ops_trapcc(cond);
return;
case 0b111100: // TRAPcc
ops_trapcc(cond);
return;
default:
break;
}
OP_FUNC(illegal);
}
// %0101_qqq100_mmmrrr d.m+-rxw.. 034 SUBQ.B #qqq,<ea>
OP_DEF(subq_b)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// SUBQ.B #qqq,Dn
CYCLE3(subq_rn);
uint32 data = ACC.sub_8(src, reg.D[n] & 0xff);
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
} else {
// SUBQ.B #qqq,<ea>
CYCLE3(subq_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.sub_8(src, data);
write_1(ea, data);
}
}
// %0101_qqq101_mmmrrr d.m+-rxw.. 034 SUBQ.W #qqq,<ea>
// %0101_qqq101_001yyy .a........ 034 SUBQ.W #qqq,Ay (.Lと等価)
OP_DEF(subq_w)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// SUBQ.W #qqq,Dn
CYCLE3(subq_rn);
uint32 data = ACC.sub_16(src, reg.D[n] & 0xffff);
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
} else if (n < 16) {
// SUBQ.W #qqq,An は SUBQ.L と等価
// フラグは変化しない
CYCLE3(subq_rn);
reg.R[n] -= src;
} else {
// SUBQ.W #qqq,<ea>
CYCLE3(subq_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.sub_16(src, data);
write_2(ea, data);
}
}
// %0101_qqq110_mmmrrr d.m+-rxw.. 034 SUBQ.L #qqq,<ea>
// %0101_qqq110_001yyy .a........ 034 SUBQ.L #qqq,Ay
OP_DEF(subq_l)
{
uint n = ir & 0x3f;
uint32 src = RegIRX;
src = (src == 0) ? 8 : src;
if (n < 8) {
// SUBQ.L #qqq,Dn
CYCLE3(subq_rn);
reg.D[n] = ACC.sub_32(src, reg.D[n]);
} else if (n < 16) {
// SUBQ.L #qqq,An
// フラグは変化しない
CYCLE3(subq_rn);
reg.R[n] -= src;
} else {
// SUBQ.L #qqq,<ea>
CYCLE3(subq_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.sub_32(src, data);
write_4(ea, data);
}
}
inline void
MPU680x0Device::ops_bra()
{
CYCLE3(bra);
uint32 origin = reg.pc;
int32 disp = (int32)(int8)(ir & 0xff);
if (disp == -1) {
// Bcc.L
disp = (int32)fetch_4();
} else if (disp == 0) {
// Bcc.W
disp = (int32)(int16)fetch_2();
}
Jump(origin + disp);
}
// %0110_0000nn_nnnnnn .......... 034 BRA.B <label>
// %0110_000000_000000 .......... 034 BRA.W <label>
// %0110_000011_111111 .......... -34 BRA.L <label>
OP_DEF(bra)
{
ops_bra();
}
// %0110_0001nn_nnnnnn .......... 034 BSR.B <label>
// %0110_000100_000000 .......... 034 BSR.W <label>
// %0110_000111_111111 .......... -34 BSR.L <label>
OP_DEF(bsr)
{
CYCLE3(bsr);
uint32 origin = reg.pc;
int32 disp = (int32)(int8)(ir & 0xff);
if (disp == -1) {
// BSR.L <label>
disp = (int32)fetch_4();
} else if (disp == 0) {
// BSR.W <label>
disp = (int32)(int16)fetch_2();
}
// ページフォルトに備えて保存する。
save_reg_pd(7);
push_4(reg.pc);
Jump(origin + disp);
}
// %0110_ccccnn_nnnnnn .......... 034 Bcc.B <label>
// %0110_cccc00_000000 .......... 034 Bcc.W <label>
// %0110_cccc11_111111 .......... -34 Bcc.L <label>
OP_DEF(bcc)
{
// ブランチするかどうかでサイクルが変わるので先に条件を調べる
uint cond = (ir >> 8) & 0x0f;
if (CCR.Cond(cond)) {
// Bcc (taken)
ops_bra();
} else {
int32 disp = (int32)(int8)(ir & 0xff);
if (disp == -1) {
// Bcc.L (not taken)
CYCLE3(bcc_l_not);
fetch_4();
} else if (disp == 0) {
// Bcc.W (not taken)
CYCLE3(bcc_w_not);
fetch_2();
} else {
// Bcc.B (not taken)
CYCLE3(bcc_b_not);
}
}
}
// %0111_xxx0nn_nnnnnn .......... 034 MOVEQ.L #<imm>,Dx
OP_DEF(moveq)
{
CYCLE3(moveq);
RegDX = (int32)(int8)(ir & 0xff);
ACC.move_32(RegDX);
}
// %1000_xxx000_mmmrrr d.m+-rxwpi 034 OR.B <ea>,Dx
OP_DEF(or_b_ea_dn)
{
uint n = ir & 0x3f;
CYCLE3(or_ea_dn);
uint x = RegIRX;
if (n < 8) {
// OR.B Dn,Dx
uint32 data = (reg.D[x] | reg.D[n]) & 0xff;
ACC.move_8(data);
reg.D[x] = (reg.D[x] & 0xffffff00) | data;
} else {
// OR.B <ea>,Dx
uint32 src = fea_data_1();
uint32 data = (reg.D[x] | src) & 0xff;
ACC.move_8(data);
reg.D[x] = (reg.D[x] & 0xffffff00) | data;
}
}
// %1000_xxx001_mmmrrr d.m+-rxwpi 034 OR.W <ea>,Dx
OP_DEF(or_w_ea_dn)
{
uint n = ir & 0x3f;
CYCLE3(or_ea_dn);
uint x = RegIRX;
if (n < 8) {
// OR.W Dn,Dx
uint32 data = (reg.D[x] | reg.D[n]) & 0xffff;
ACC.move_16(data);
reg.D[x] = (reg.D[x] & 0xffff0000) | data;
} else {
// OR.W <ea>,Dx
uint32 src = fea_data_2();
uint32 data = (reg.D[x] | src) & 0xffff;
ACC.move_16(data);
reg.D[x] = (reg.D[x] & 0xffff0000) | data;
}
}
// %1000_xxx010_mmmrrr d.m+-rxwpi 034 OR.L <ea>,Dx
OP_DEF(or_l_ea_dn)
{
uint n = ir & 0x3f;
CYCLE3(or_ea_dn);
uint x = RegIRX;
if (n < 8) {
// OR.L Dn,Dx
reg.D[x] |= reg.D[n];
ACC.move_32(reg.D[x]);
} else {
// OR.L <ea>,Dx
uint32 src = fea_data_4();
uint32 data = reg.D[x] | src;
ACC.move_32(data);
reg.D[x] = data;
}
}
// %1000_xxx011_mmmrrr d.m+-rxwpi 034 DIVU.W <ea>,Dx
OP_DEF(divu_w)
{
CYCLE3(divu_w_max);
uint16 src = fea_data_2();
uint32 dst = RegDX;
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
uint32 quo = dst / src;
uint32 rem = dst % src;
if (quo > 0xffff) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
RegDX = (rem << 16) | quo;
ACC.move_16(quo);
}
// %1000_xxx100_mmmrrr ..m+-rxw.. 034 OR.B Dx,<ea>
// %1000_xxx100_000yyy .......... 034 SBCD.B Dy,Dx
// %1000_xxx100_001yyy .......... 034 SBCD.B -(Ay),-(Ax)
OP_DEF(or_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SBCD.B Dy,Dx
CYCLE3(sbcd_dn);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.sbcd_8(src, dst);
RegDX &= 0xffffff00;
RegDX |= dst;
} else if (n < 16) {
// SBCD.B -(Ay),-(Ax)
CYCLE3(sbcd_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.sbcd_8(src, dst);
write_1(dstea, dst);
} else {
// OR.B Dx,<ea>
CYCLE3(or_dn_ea);
uint32 ea = cea_data_1();
uint8 data = read_1(ea);
data |= RegDX;
ACC.move_8(data);
write_1(ea, data);
}
}
// %1000_xxx101_mmmrrr ..m+-rxw.. 034 OR.W Dx,<ea>
// %1000_xxx101_000yyy .......... -34 PACK Dy,Dx,#<imm>
// %1000_xxx101_001yyy .......... -34 PACK -(Ay),-(Ax),#<imm>
OP_DEF(or_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// PACK Dy,Dx,#<imm>
CYCLE3(pack_dn);
uint32 imm = fetch_2();
uint32 src = RegDY + imm;
RegDX = (RegDX & 0xffffff00) | ((src >> 4) & 0x00f0) | (src & 0x000f);
} else if (n < 16) {
// PACK -(Ay),-(Ax),#<imm>
CYCLE3(pack_an);
uint32 imm = fetch_2();
save_reg_pd(RegIRY);
uint32 srcea = internal_ea_anpd_2(RegIRY);
uint32 src = read_2(srcea);
src += imm;
uint32 dst = ((src >> 4) & 0x00f0) | (src & 0x000f);
save_reg_pd_if(RegIRX);
uint32 dstea = internal_ea_anpd_1(RegIRX);
write_1(dstea, dst);
} else {
// OR.W Dx,<ea>
CYCLE3(or_dn_ea);
uint32 ea = cea_data_2();
uint16 data = read_2(ea);
data |= RegDX;
ACC.move_16(data);
write_2(ea, data);
}
}
// %1000_xxx110_mmmrrr ..m+-rxw.. 034 OR.L Dx,<ea>
// %1000_xxx110_000yyy .......... -34 UNPK Dy,Dx,#<imm>
// %1000_xxx110_001yyy .......... -34 UNPK -(Ay),-(Ax),#<imm>
OP_DEF(or_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// UNPK Dy,Dx,#<imm>
CYCLE3(unpk_dn);
uint32 imm = fetch_2();
uint16 src = RegDY;
src = ((src & 0x00f0) << 4) | (src & 0x000f);
src += imm;
RegDX = (RegDX & 0xffff0000) | src;
} else if (n < 16) {
// UNPK -(Ay),-(Ax),#<imm>
CYCLE3(unpk_an);
uint32 imm = fetch_2();
save_reg_pd(RegIRY);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint16 src = read_1(srcea);
src = ((src & 0x00f0) << 4) | (src & 0x000f);
src += imm;
save_reg_pd_if(RegIRX);
uint32 dstea = internal_ea_anpd_2(RegIRX);
write_2(dstea, src);
} else {
// OR.L Dx,<ea>
CYCLE3(or_dn_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data |= RegDX;
ACC.move_32(data);
write_4(ea, data);
}
}
// %1000_xxx111_mmmrrr d.m+-rxwpi 034 DIVS.W <ea>,Dx
OP_DEF(divs_w)
{
CYCLE3(divs_w_max);
uint16 src = fea_data_2();
uint32 dst = RegDX;
if (src == 0) {
// ゼロ除算の場合、
// X は変化しない
// C は常にクリア
// N,Z,V は未定義
CCR.SetC(false);
Exception(M68K::EXCEP_ZERODIV);
return;
}
// ホストでオーバーフローが起きるのはこのケースのみ
if (dst == 0x80000000 && src == 0xffff) {
// オーバーフローの場合、
// X は変化しない
// N,Z は未定義
// V はセット
// C は常にクリア
CCR.SetV(true);
CCR.SetC(false);
return;
}
int32 squo = (int32)dst / (int32)(int16)src;
int32 srem = (int32)dst % (int32)(int16)src;
if ((int16)squo != squo) {
// オーバーフローの場合
CCR.SetV(true);
CCR.SetC(false);
return;
}
// 正常の場合、
// X は変化しない
// V, C はクリア
// N, Z は quo の結果。
uint32 quo = (uint32)squo & 0xffff;
uint32 rem = (uint32)srem & 0xffff;
RegDX = (rem << 16) | quo;
ACC.move_16(quo);
}
// %1001_xxx000_mmmrrr dam+-rxwpi 034 SUB.B <ea>,Dx
OP_DEF(sub_b_ea_dn)
{
CYCLE3(sub_ea_dn);
uint32 src = fea_all_1();
uint32 data = ACC.sub_8(src, RegDX & 0xff);
RegDX = (RegDX & 0xffffff00) | data;
}
// %1001_xxx001_mmmrrr dam+-rxwpi 034 SUB.W <ea>,Dx
OP_DEF(sub_w_ea_dn)
{
CYCLE3(sub_ea_dn);
uint32 src = fea_all_2();
uint32 data = ACC.sub_16(src, RegDX & 0xffff);
RegDX = (RegDX & 0xffff0000) | data;
}
// %1001_xxx010_mmmrrr dam+-rxwpi 034 SUB.L <ea>,Dx
OP_DEF(sub_l_ea_dn)
{
CYCLE3(sub_ea_dn);
uint32 src = fea_all_4();
RegDX = ACC.sub_32(src, RegDX);
}
// %1001_xxx011_mmmrrr dam+-rxwpi 034 SUBA.W <ea>,Ax
OP_DEF(suba_w)
{
CYCLE3(suba_w);
uint32 src = (int32)(int16)fea_all_2();
RegAX -= src;
}
// %1001_xxx100_mmmrrr ..m+-rxw.. 034 SUB.B Dx,<ea>
// %1001_xxx100_000yyy .......... 034 SUBX.B Dy,Dx
// %1001_xxx100_001yyy .......... 034 SUBX.B -(Ay),-(Ax)
OP_DEF(sub_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SUBX.B Dy,Dx
CYCLE3(subx_dn);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.subx_8(src, dst);
RegDX = (RegDX & 0xffffff00) | dst;
} else if (n < 16) {
// SUBX.B -(Ay),-(Ax)
CYCLE3(subx_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.subx_8(src, dst);
write_1(dstea, dst);
} else {
// SUB.B Dx,<ea>
CYCLE3(sub_dn_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.sub_8(RegDX & 0xff, data);
write_1(ea, data);
}
}
// %1001_xxx101_mmmrrr ..m+-rxw.. 034 SUB.W Dx,<ea>
// %1001_xxx101_000yyy .......... 034 SUBX.W Dy,Dx
// %1001_xxx101_001yyy .......... 034 SUBX.W -(Ay),-(Ax)
OP_DEF(sub_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SUBX.W Dy,Dx
CYCLE3(subx_dn);
uint32 src = RegDY & 0xffff;
uint32 dst = RegDX & 0xffff;
dst = ACC.subx_16(src, dst);
RegDX = (RegDX & 0xffff0000) | dst;
} else if (n < 16) {
// SUBX.W -(Ay),-(Ax)
CYCLE3(subx_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_2(RegIRY);
uint32 dstea = internal_ea_anpd_2(RegIRX);
uint32 src = read_2(srcea);
uint32 dst = read_2(dstea);
dst = ACC.subx_16(src, dst);
write_2(dstea, dst);
} else {
// SUB.W Dx,<ea>
CYCLE3(sub_dn_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.sub_16(RegDX & 0xffff, data);
write_2(ea, data);
}
}
// %1001_xxx110_mmmrrr ..m+-rxw.. 034 SUB.L Dx,<ea>
// %1001_xxx110_000yyy .......... 034 SUBX.L Dy,Dx
// %1001_xxx110_001yyy .......... 034 SUBX.L -(Ay),-(Ax)
OP_DEF(sub_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// SUBX.L Dy,Dx
CYCLE3(subx_dn);
uint32 src = RegDY;
uint32 dst = RegDX;
RegDX = ACC.subx_32(src, dst);
} else if (n < 16) {
// SUBX.L -(Ay),-(Ax)
CYCLE3(subx_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_4(RegIRY);
uint32 dstea = internal_ea_anpd_4(RegIRX);
uint32 src = read_4(srcea);
uint32 dst = read_4(dstea);
dst = ACC.subx_32(src, dst);
write_4(dstea, dst);
} else {
// SUB.L Dx,<ea>
CYCLE3(sub_dn_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.sub_32(RegDX, data);
write_4(ea, data);
}
}
// %1001_xxx111_mmmrrr dam+-rxwpi 034 SUBA.L <ea>,Ax
OP_DEF(suba_l)
{
CYCLE3(suba_l);
uint32 src = fea_all_4();
RegAX -= src;
}
// %1010_nnnnnn_nnnnnn .......... 034 A-Line
OP_DEF(aline)
{
CYCLE3(aline);
if (aline_callback) {
if (aline_callback(this, aline_arg)) {
return;
}
}
// A系列命令例外
Exception(M68K::EXCEP_ALINE);
}
// %1011_xxx000_mmmrrr d.m+-rxwpi 034 CMP.B <ea>,Dx
OP_DEF(cmp_b)
{
CYCLE3(cmp);
uint32 src = fea_all_1();
uint32 dst = RegDX & 0xff;
ACC.cmp_8(src, dst);
}
// %1011_xxx001_mmmrrr d.m+-rxwpi 034 CMP.W <ea>,Dx
OP_DEF(cmp_w)
{
CYCLE3(cmp);
uint32 src = fea_all_2();
uint32 dst = RegDX & 0xffff;
ACC.cmp_16(src, dst);
}
// %1011_xxx010_mmmrrr d.m+-rxwpi 034 CMP.L <ea>,Dx
OP_DEF(cmp_l)
{
CYCLE3(cmp);
uint32 src = fea_all_4();
ACC.cmp_32(src, RegDX);
}
// %1011_xxx011_mmmrrr dam+-rxwpi 034 CMPA.W <ea>,Ax
OP_DEF(cmpa_w)
{
CYCLE3(cmpa);
uint32 src = (uint32)(int32)(int16)fea_all_2();
ACC.cmp_32(src, RegAX);
}
// %1011_xxx100_mmmrrr d.m+-rxw.. 034 EOR.B Dx,<ea>
// %1011_xxx100_001yyy .......... 034 CMPM.B (Ay)+,(Ax)+
OP_DEF(eor_b)
{
uint n = ir & 0x3f;
if (n < 8) {
// EOR.B Dx,Dy
CYCLE3(eor_dn_dn);
uint32 data = (reg.D[n] ^ RegDX) & 0xff;
reg.D[n] = (reg.D[n] & 0xffffff00) | data;
ACC.move_8(data);
} else if (n < 16) {
// CMPM.B (Ay)+,(Ax)+
CYCLE3(cmpm);
save_reg_pi_if(RegIRY);
save_reg_pi_if(RegIRX);
uint32 srcea = internal_ea_anpi_1(RegIRY);
uint32 dstea = internal_ea_anpi_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
ACC.cmp_8(src, dst);
} else {
// EOR.B Dx,<ea>
CYCLE3(eor_dn_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data ^= (RegDX & 0xff);
ACC.move_8(data);
write_1(ea, data);
}
}
// %1011_xxx101_mmmrrr d.m+-rxw.. 034 EOR.W Dx,<ea>
// %1011_xxx101_001yyy .......... 034 CMPM.W (Ay)+,(Ax)+
OP_DEF(eor_w)
{
uint n = ir & 0x3f;
if (n < 8) {
// EOR.W Dx,Dy
CYCLE3(eor_dn_dn);
uint32 data = (reg.D[n] ^ RegDX) & 0xffff;
reg.D[n] = (reg.D[n] & 0xffff0000) | data;
ACC.move_16(data);
} else if (n < 16) {
// CMPM.W (Ay)+,(Ax)+
CYCLE3(cmpm);
save_reg_pi_if(RegIRY);
save_reg_pi_if(RegIRX);
uint32 srcea = internal_ea_anpi_2(RegIRY);
uint32 dstea = internal_ea_anpi_2(RegIRX);
uint32 src = read_2(srcea);
uint32 dst = read_2(dstea);
ACC.cmp_16(src, dst);
} else {
// EOR.W Dx,<ea>
CYCLE3(eor_dn_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data ^= (RegDX & 0xffff);
ACC.move_16(data);
write_2(ea, data);
}
}
// %1011_xxx110_mmmrrr d.m+-rxw.. 034 EOR.L Dx,<ea>
// %1011_xxx110_001yyy .......... 034 CMPM.L (Ay)+,(Ax)+
OP_DEF(eor_l)
{
uint n = ir & 0x3f;
if (n < 8) {
// EOR.L Dx,Dy
CYCLE3(eor_dn_dn);
reg.D[n] ^= RegDX;
ACC.move_32(reg.D[n]);
} else if (n < 16) {
// CMPM.L (Ay)+,(Ax)+
CYCLE3(cmpm);
save_reg_pi_if(RegIRY);
save_reg_pi_if(RegIRX);
uint32 srcea = internal_ea_anpi_4(RegIRY);
uint32 dstea = internal_ea_anpi_4(RegIRX);
uint32 src = read_4(srcea);
uint32 dst = read_4(dstea);
ACC.cmp_32(src, dst);
} else {
// EOR.L Dx,<ea>
CYCLE3(eor_dn_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data ^= RegDX;
ACC.move_32(data);
write_4(ea, data);
}
}
// %1011_xxx111_mmmrrr dam+-rxwpi 034 CMPA.L <ea>,Ax
OP_DEF(cmpa_l)
{
CYCLE3(cmpa);
uint32 src = fea_all_4();
ACC.cmp_32(src, RegAX);
}
// %1100_xxx000_mmmrrr d.m+-rxwpi 034 AND.B <ea>,Dx
OP_DEF(and_b_ea_dn)
{
CYCLE3(and_ea_dn);
uint32 src = fea_data_1();
uint32 dst = (RegDX & 0x000000ff) & src;
ACC.move_8(dst);
RegDX = (RegDX & 0xffffff00) | dst;
}
// %1100_xxx001_mmmrrr d.m+-rxwpi 034 AND.W <ea>,Dx
OP_DEF(and_w_ea_dn)
{
CYCLE3(and_ea_dn);
uint32 src = fea_data_2();
uint32 dst = (RegDX & 0x0000ffff) & src;
ACC.move_16(dst);
RegDX = (RegDX & 0xffff0000) | dst;
}
// %1100_xxx010_mmmrrr d.m+-rxwpi 034 AND.L <ea>,Dx
OP_DEF(and_l_ea_dn)
{
CYCLE3(and_ea_dn);
uint32 src = fea_data_4();
RegDX = RegDX & src;
ACC.move_32(RegDX);
}
// %1100_xxx011_mmmrrr d.m+-rxwpi 034 MULU.W <ea>,Dx
OP_DEF(mulu_w)
{
CYCLE3(mulu_w_max);
uint32 src = fea_data_2();
uint32 dst = RegDX & 0xffff;
RegDX = ACC.mulu_16(src, dst);
}
// %1100_xxx100_mmmrrr ..m+-rxw.. 034 AND.B Dx,<ea>
// %1100_xxx100_000yyy .......... 034 ABCD.B Dy,Dx
// %1100_xxx100_001yyy .......... 034 ABCD.B -(Ay),-(Ax)
OP_DEF(and_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ABCD.B Dy,Dx
CYCLE3(abcd_dn);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.abcd_8(src, dst);
RegDX &= 0xffffff00;
RegDX |= dst;
return;
} else if (n < 16) {
// ABCD.B -(Ay),-(Ax)
CYCLE3(abcd_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.abcd_8(src, dst);
write_1(dstea, dst);
return;
} else {
// AND.B Dx,<ea>
CYCLE3(and_ea_dn);
uint32 ea = cea_data_1();
uint32 dst = read_1(ea);
dst &= RegDX & 0xff;
ACC.move_8(dst);
write_1(ea, dst);
}
}
// %1100_xxx101_mmmrrr ..m+-rxw.. 034 AND.W Dx,<ea>
// %1100_xxx101_000yyy .......... 034 EXG.L Dx,Dy
// %1100_xxx101_001yyy .......... 034 EXG.L Ax,Ay
OP_DEF(and_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// EXG.L Dx,Dy
CYCLE3(exg);
uint x = RegIRX;
uint y = n;
uint32 tmp = reg.D[x];
reg.D[x] = reg.D[y];
reg.D[y] = tmp;
return;
} else if (n < 16) {
// EXG.L Ax,Ay
// ここでは x は 0..7 で A(x)、y は 8..15 で R(y)
CYCLE3(exg);
uint x = RegIRX;
uint y = n;
uint32 tmp = reg.A[x];
reg.A[x] = reg.R[y];
reg.R[y] = tmp;
return;
} else {
// AND.W Dx,<ea>
CYCLE3(and_dn_ea);
uint32 ea = cea_data_2();
uint32 dst = read_2(ea);
dst &= RegDX & 0xffff;
ACC.move_16(dst);
write_2(ea, dst);
}
}
// %1100_xxx110_mmmrrr ..m+-rxw.. 034 AND.L Dx,<ea>
// %1100_xxx110_001yyy .......... 034 EXG.L Dx,Ay
OP_DEF(and_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
op_illegal();
return;
} else if (n < 16) {
// EXG.L Dx,Ay
// ここでは x は 0..7 で D(x)、y は 8..15 で R(y)
CYCLE3(exg);
uint x = RegIRX;
uint y = n;
uint32 tmp = reg.D[x];
reg.D[x] = reg.R[y];
reg.R[y] = tmp;
return;
} else {
// AND.L Dx,<ea>
CYCLE3(and_dn_ea);
uint32 ea = cea_data_4();
uint32 dst = read_4(ea);
dst &= RegDX;
ACC.move_32(dst);
write_4(ea, dst);
}
}
// %1100_xxx111_mmmrrr d.m+-rxwpi 034 MULS.W <ea>,Dx
OP_DEF(muls_w)
{
CYCLE3(muls_w_max);
uint32 src = fea_data_2();
uint32 dst = RegDX & 0xffff;
RegDX = ACC.muls_16(src, dst);
}
// %1101_xxx000_mmmrrr dam+-rxwpi 034 ADD.B <ea>,Dx
OP_DEF(add_b_ea_dn)
{
CYCLE3(add_ea_dn);
uint32 src = fea_all_1();
uint32 data = ACC.add_8(src, RegDX & 0xff);
RegDX = (RegDX & 0xffffff00) | data;
}
// %1101_xxx001_mmmrrr dam+-rxwpi 034 ADD.W <ea>,Dx
OP_DEF(add_w_ea_dn)
{
CYCLE3(add_ea_dn);
uint32 src = fea_all_2();
uint32 data = ACC.add_16(src, RegDX & 0xffff);
RegDX = (RegDX & 0xffff0000) | data;
}
// %1101_xxx010_mmmrrr dam+-rxwpi 034 ADD.L <ea>,Dx
OP_DEF(add_l_ea_dn)
{
CYCLE3(add_ea_dn);
uint32 src = fea_all_4();
RegDX = ACC.add_32(src, RegDX);
}
// %1101_xxx011_mmmrrr dam+-rxwpi 034 ADDA.W <ea>,Ax
OP_DEF(adda_w)
{
CYCLE3(adda_w);
uint32 src = (int32)(int16)fea_all_2();
RegAX += src;
}
// %1101_xxx100_mmmrrr ..m+-rxw.. 034 ADD.B Dx,<ea>
// %1101_xxx100_000yyy .......... 034 ADDX.B Dy,Dx
// %1101_xxx100_001yyy .......... 034 ADDX.B -(Ay),-(Ax)
OP_DEF(add_b_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ADDX.B Dy,Dx
CYCLE3(addx_dn);
uint32 src = RegDY & 0xff;
uint32 dst = RegDX & 0xff;
dst = ACC.addx_8(src, dst);
RegDX = (RegDX & 0xffffff00) | dst;
} else if (n < 16) {
// ADDX.B -(Ay),-(Ax)
CYCLE3(addx_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_1(RegIRY);
uint32 dstea = internal_ea_anpd_1(RegIRX);
uint32 src = read_1(srcea);
uint32 dst = read_1(dstea);
dst = ACC.addx_8(src, dst);
write_1(dstea, dst);
} else {
// ADD.B Dx,<ea>
CYCLE3(add_dn_ea);
uint32 ea = cea_data_1();
uint32 data = read_1(ea);
data = ACC.add_8(RegDX & 0xff, data);
write_1(ea, data);
}
}
// %1101_xxx101_mmmrrr ..m+-rxw.. 034 ADD.W Dx,<ea>
// %1101_xxx101_000yyy .......... 034 ADDX.W Dy,Dx
// %1101_xxx101_001yyy .......... 034 ADDX.W -(Ay),-(Ax)
OP_DEF(add_w_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ADDX.W Dy,Dx
CYCLE3(addx_dn);
uint32 src = RegDY & 0xffff;
uint32 dst = RegDX & 0xffff;
dst = ACC.addx_16(src, dst);
RegDX = (RegDX & 0xffff0000) | dst;
} else if (n < 16) {
// ADDX.W -(Ay),-(Ax)
CYCLE3(addx_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_2(RegIRY);
uint32 dstea = internal_ea_anpd_2(RegIRX);
uint32 src = read_2(srcea);
uint32 dst = read_2(dstea);
dst = ACC.addx_16(src, dst);
write_2(dstea, dst);
} else {
// ADD.W Dx,<ea>
CYCLE3(add_dn_ea);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.add_16(RegDX & 0xffff, data);
write_2(ea, data);
}
}
// %1101_xxx110_mmmrrr ..m+-rxw.. 034 ADD.L Dx,<ea>
// %1101_xxx110_000yyy .......... 034 ADDX.L Dy,Dx
// %1101_xxx110_001yyy .......... 034 ADDX.L -(Ay),-(Ax)
OP_DEF(add_l_dn_ea)
{
uint n = ir & 0x3f;
if (n < 8) {
// ADDX.L Dy,Dx
CYCLE3(addx_dn);
uint32 src = RegDY;
uint32 dst = RegDX;
RegDX = ACC.addx_32(src, dst);
} else if (n < 16) {
// ADDX.L -(Ay),-(Ax)
CYCLE3(addx_an);
save_reg_pd_if(RegIRY);
save_reg_pd_if(RegIRX);
uint32 srcea = internal_ea_anpd_4(RegIRY);
uint32 dstea = internal_ea_anpd_4(RegIRX);
uint32 src = read_4(srcea);
uint32 dst = read_4(dstea);
dst = ACC.addx_32(src, dst);
write_4(dstea, dst);
} else {
// ADD.L Dx,<ea>
CYCLE3(add_dn_ea);
uint32 ea = cea_data_4();
uint32 data = read_4(ea);
data = ACC.add_32(RegDX, data);
write_4(ea, data);
}
}
// %1101_xxx111_mmmrrr dam+-rxwpi 034 ADDA.L <ea>,Ax
OP_DEF(adda_l)
{
CYCLE3(adda_l);
uint32 src = fea_all_4();
RegAX += src;
}
// %1110_qqq000_000yyy .......... 034 ASR.B #qqq,Dy
// %1110_qqq000_001yyy .......... 034 LSR.B #qqq,Dy
// %1110_qqq000_010yyy .......... 034 ROXR.B #qqq,Dy
// %1110_qqq000_011yyy .......... 034 ROR.B #qqq,Dy
// %1110_xxx000_100yyy .......... 034 ASR.B Dx,Dy
// %1110_xxx000_101yyy .......... 034 LSR.B Dx,Dy
// %1110_xxx000_110yyy .......... 034 ROXR.B Dx,Dy
// %1110_xxx000_111yyy .......... 034 ROR.B Dx,Dy
OP_DEF(asr_b_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASR.B #qqq,Dy
CYCLE3(asr_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 1: // LSR.B #qqq,Dy
CYCLE3(lsd_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 2: // ROXR.B #qqq,Dy
CYCLE3(roxd_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 3: // ROR.B #qqq,Dy
CYCLE3(rod_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.ror_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 4: // ASR.B Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 8) {
CYCLE3(asr_dn_dn_less);
} else {
CYCLE3(asr_dn_dn_over);
}
__assume(0 <= count && count < 64);
data = ACC.asr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 5: // LSR.B Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 8) {
CYCLE3(lsd_dn_dn_less);
} else {
CYCLE3(lsd_dn_dn_over);
}
__assume(0 <= count && count < 64);
data = ACC.lsr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 6: // ROXR.B Dx,Dy
CYCLE3(roxd_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxr_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 7: // ROR.B Dx,Dy
CYCLE3(rod_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.ror_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
}
}
// %1110_qqq001_000yyy .......... 034 ASR.W #qqq,Dy
// %1110_qqq001_001yyy .......... 034 LSR.W #qqq,Dy
// %1110_qqq001_010yyy .......... 034 ROXR.W #qqq,Dy
// %1110_qqq001_011yyy .......... 034 ROR.W #qqq,Dy
// %1110_xxx001_100yyy .......... 034 ASR.W Dx,Dy
// %1110_xxx001_101yyy .......... 034 LSR.W Dx,Dy
// %1110_xxx001_110yyy .......... 034 ROXR.W Dx,Dy
// %1110_xxx001_111yyy .......... 034 ROR.W Dx,Dy
OP_DEF(asr_w_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASR.W #qqq,Dy
CYCLE3(asr_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 1: // LSR.W #qqq,Dy
CYCLE3(lsd_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 2: // ROXR.W #qqq,Dy
CYCLE3(roxd_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 3: // ROR.W #qqq,Dy
CYCLE3(rod_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.ror_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 4: // ASR.W Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 16) {
CYCLE3(asr_dn_dn_less);
} else {
CYCLE3(asr_dn_dn_over);
}
__assume(0 <= count && count < 64);
data = ACC.asr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 5: // LSR.W Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 16) {
CYCLE3(lsd_dn_dn_less);
} else {
CYCLE3(lsd_dn_dn_over);
}
__assume(0 <= count && count < 64);
data = ACC.lsr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 6: // ROXR.W Dx,Dy
CYCLE3(roxd_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxr_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 7: // ROR.W Dx,Dy
CYCLE3(rod_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.ror_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
}
}
// %1110_qqq010_000yyy .......... 034 ASR.L #qqq,Dy
// %1110_qqq010_001yyy .......... 034 LSR.L #qqq,Dy
// %1110_qqq010_010yyy .......... 034 ROXR.L #qqq,Dy
// %1110_qqq010_011yyy .......... 034 ROR.L #qqq,Dy
// %1110_xxx010_100yyy .......... 034 ASR.L Dx,Dy
// %1110_xxx010_101yyy .......... 034 LSR.L Dx,Dy
// %1110_xxx010_110yyy .......... 034 ROXR.L Dx,Dy
// %1110_xxx010_111yyy .......... 034 ROR.L Dx,Dy
OP_DEF(asr_l_imm)
{
int count;
switch (eamode(ir)) {
case 0: // ASR.L #qqq,Dy
CYCLE3(asr_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.asr_32(RegDY, count);
return;
case 1: // LSR.L #qqq,Dy
CYCLE3(lsd_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.lsr_32(RegDY, count);
return;
case 2: // ROXR.L #qqq,Dy
CYCLE3(roxd_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.roxr_32(RegDY, count);
return;
case 3: // ROR.L #qqq,Dy
CYCLE3(rod_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.ror_32(RegDY, count);
return;
case 4: // ASR.L Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 32) {
CYCLE3(asr_dn_dn_less);
} else {
CYCLE3(asr_dn_dn_over);
}
__assume(0 <= count && count < 64);
RegDY = ACC.asr_32(RegDY, count);
return;
case 5: // LSR.L Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 32) {
CYCLE3(lsd_dn_dn_less);
} else {
CYCLE3(lsd_dn_dn_over);
}
__assume(0 <= count && count < 64);
RegDY = ACC.lsr_32(RegDY, count);
return;
case 6: // ROXR.L Dx,Dy
CYCLE3(roxd_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.roxr_32(RegDY, count);
return;
case 7: // ROR.L Dx,Dy
CYCLE3(rod_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.ror_32(RegDY, count);
return;
}
}
// %1110_000011_mmmrrr ..m+-rxw.. 034 ASR.W <ea>
OP_DEF(asr_w)
{
CYCLE3(asr_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.asr_16(data, 1);
write_2(ea, data);
}
// %1110_qqq100_000yyy .......... 034 ASL.B #qqq,Dy
// %1110_qqq100_001yyy .......... 034 LSL.B #qqq,Dy
// %1110_qqq100_010yyy .......... 034 ROXL.B #qqq,Dy
// %1110_qqq100_011yyy .......... 034 ROL.B #qqq,Dy
// %1110_xxx100_100yyy .......... 034 ASL.B Dx,Dy
// %1110_xxx100_101yyy .......... 034 LSL.B Dx,Dy
// %1110_xxx100_110yyy .......... 034 ROXL.B Dx,Dy
// %1110_xxx100_111yyy .......... 034 ROL.B Dx,Dy
OP_DEF(asl_b_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASL.B #qqq,Dy
CYCLE3(asl_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 1: // LSL.B #qqq,Dy
CYCLE3(lsd_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 2: // ROXL.B #qqq,Dy
CYCLE3(roxd_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 3: // ROL.B #qqq,Dy
CYCLE3(rod_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.rol_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 4: // ASL.B Dx,Dy
CYCLE3(asl_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.asl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 5: // LSL.B Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 8) {
CYCLE3(lsd_dn_dn_less);
} else {
CYCLE3(lsd_dn_dn_over);
}
__assume(0 <= count && count < 64);
data = ACC.lsl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 6: // ROXL.B Dx,Dy
CYCLE3(roxd_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxl_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
case 7: // ROL.B Dx,Dy
CYCLE3(rod_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.rol_8(RegDY & 0xff, count);
RegDY = (RegDY & 0xffffff00) | data;
return;
}
}
// %1110_qqq101_000yyy .......... 034 ASL.W #qqq,Dy
// %1110_qqq101_001yyy .......... 034 LSL.W #qqq,Dy
// %1110_qqq101_010yyy .......... 034 ROXL.W #qqq,Dy
// %1110_qqq101_011yyy .......... 034 ROL.W #qqq,Dy
// %1110_xxx101_100yyy .......... 034 ASL.W Dx,Dy
// %1110_xxx101_101yyy .......... 034 LSL.W Dx,Dy
// %1110_xxx101_110yyy .......... 034 ROXL.W Dx,Dy
// %1110_xxx101_111yyy .......... 034 ROL.W Dx,Dy
OP_DEF(asl_w_imm)
{
int count;
uint32 data;
switch (eamode(ir)) {
case 0: // ASL.W #qqq,Dy
CYCLE3(asl_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.asl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 1: // LSL.W #qqq,Dy
CYCLE3(lsd_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.lsl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 2: // ROXL.W #qqq,Dy
CYCLE3(roxd_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.roxl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 3: // ROL.W #qqq,Dy
CYCLE3(rod_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
data = ACC.rol_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 4: // ASL.W Dx,Dy
CYCLE3(asl_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.asl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 5: // LSL.W Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 16) {
CYCLE3(lsd_dn_dn_less);
} else {
CYCLE3(lsd_dn_dn_over);
}
__assume(0 <= count && count < 64);
data = ACC.lsl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 6: // ROXL.W Dx,Dy
CYCLE3(roxd_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.roxl_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
case 7: // ROL.W Dx,Dy
CYCLE3(rod_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
data = ACC.rol_16(RegDY & 0xffff, count);
RegDY = (RegDY & 0xffff0000) | data;
return;
}
}
// %1110_qqq110_000yyy .......... 034 ASL.L #qqq,Dy
// %1110_qqq110_001yyy .......... 034 LSL.L #qqq,Dy
// %1110_qqq110_010yyy .......... 034 ROXL.L #qqq,Dy
// %1110_qqq110_011yyy .......... 034 ROL.L #qqq,Dy
// %1110_xxx110_100yyy .......... 034 ASL.L Dx,Dy
// %1110_xxx110_101yyy .......... 034 LSL.L Dx,Dy
// %1110_xxx110_110yyy .......... 034 ROXL.L Dx,Dy
// %1110_xxx110_111yyy .......... 034 ROL.L Dx,Dy
OP_DEF(asl_l_imm)
{
int count;
switch (eamode(ir)) {
case 0: // ASL.L #qqq,Dy
CYCLE3(asl_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.asl_32(RegDY, count);
return;
case 1: // LSL.L #qqq,Dy
CYCLE3(lsd_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.lsl_32(RegDY, count);
return;
case 2: // ROXL.L #qqq,Dy
CYCLE3(roxd_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.roxl_32(RegDY, count);
return;
case 3: // ROL.L #qqq,Dy
CYCLE3(rod_imm_dn);
count = RegIRX;
count = (count == 0) ? 8 : count;
__assume(1 <= count && count <= 8);
RegDY = ACC.rol_32(RegDY, count);
return;
case 4: // ASL.L Dx,Dy
CYCLE3(asl_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.asl_32(RegDY, count);
return;
case 5: // LSL.L Dx,Dy
count = RegDX & 63;
// シフト数がデータサイズを越えるかどうかでサイクルが違う
if (count <= 32) {
CYCLE3(lsd_dn_dn_less);
} else {
CYCLE3(lsd_dn_dn_over);
}
__assume(0 <= count && count < 64);
RegDY = ACC.lsl_32(RegDY, count);
return;
case 6: // ROXL.L Dx,Dy
CYCLE3(roxd_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.roxl_32(RegDY, count);
return;
case 7: // ROL.L Dx,Dy
CYCLE3(rod_dn_dn);
count = RegDX & 63;
__assume(0 <= count && count < 64);
RegDY = ACC.rol_32(RegDY, count);
return;
}
}
// %1110_000111_mmmrrr ..m+-rxw.. 034 ASL.W <ea>
OP_DEF(asl_w)
{
CYCLE3(asl_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.asl_16(data, 1);
write_2(ea, data);
}
// %1110_001011_mmmrrr ..m+-rxw.. 034 LSR.W <ea>
OP_DEF(lsr_w)
{
CYCLE3(lsd_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.lsr_16(data, 1);
write_2(ea, data);
}
// %1110_001111_mmmrrr ..m+-rxw.. 034 LSL.W <ea>
OP_DEF(lsl_w)
{
CYCLE3(lsd_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.lsl_16(data, 1);
write_2(ea, data);
}
// %1110_010011_mmmrrr ..m+-rxw.. 034 ROXR.W <ea>
OP_DEF(roxr_w)
{
CYCLE3(roxd_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.roxr_16(data, 1);
write_2(ea, data);
}
// %1110_010111_mmmrrr ..m+-rxw.. 034 ROXL.W <ea>
OP_DEF(roxl_w)
{
CYCLE3(roxd_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.roxl_16(data, 1);
write_2(ea, data);
}
// %1110_011011_mmmrrr ..m+-rxw.. 034 ROR.W <ea>
OP_DEF(ror_w)
{
CYCLE3(rod_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.ror_16(data, 1);
write_2(ea, data);
}
// %1110_011111_mmmrrr ..m+-rxw.. 034 ROL.W <ea>
OP_DEF(rol_w)
{
CYCLE3(rod_w);
uint32 ea = cea_data_2();
uint32 data = read_2(ea);
data = ACC.rol_16(data, 1);
write_2(ea, data);
}
// %1110_100011_mmmrrr d.m..rxwp. -34 BFTST <ea>{#o:#w}
OP_DEF(bftst)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFTST Dn{#o:#w}
CYCLE3(bftst_dn);
bf.LoadReg(n);
} else {
// BFTST <ea>{#o:#w}
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bftst_ea_less);
} else {
CYCLE3(bftst_ea_over);
}
}
ACC.move_32(bf.data);
}
// %1110_100111_mmmrrr d.m..rxwp. -34 BFEXTU <ea>{#o:#w},Dn
OP_DEF(bfextu)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFEXTU Dn{#o:#w},Dn
CYCLE3(bfext_dn);
bf.LoadReg(n);
} else {
// BFEXTU <ea>{#o:#w},Dn
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bfext_ea_less);
} else {
CYCLE3(bfext_ea_over);
}
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
// 符号なしシフト
reg.D[dn] = bf.data >> (32 - bf.width);
}
// %1110_101011_mmmrrr d.m..rxw.. -34 BFCHG <ea>{#o:#w}
OP_DEF(bfchg)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFCHG Dn{#o:#w}
CYCLE3(bfchg_dn);
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFCHG <ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFCHG <ea>{#o:#w}
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bfchg_ea_less);
} else {
CYCLE3(bfchg_ea_over);
}
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
bf.data = ~bf.data;
bf.Store(n);
}
// %1110_101111_mmmrrr d.m..rxwp. -34 BFEXTS <ea>{#o:#w},Dn
OP_DEF(bfexts)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFEXTS Dn{#o:#w},Dn
CYCLE3(bfext_dn);
bf.LoadReg(n);
} else {
// BFEXTS <ea>{#o:#w},Dn
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bfext_ea_less);
} else {
CYCLE3(bfext_ea_over);
}
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
// 符号付きシフト
// XXX 負数の右シフト
reg.D[dn] = ((int32)bf.data) >> (32 - bf.width);
}
// %1110_110011_mmmrrr d.m..rxw.. -34 BFCLR <ea>{#o:#w}
OP_DEF(bfclr)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFCLR Dn{#o:#w}
CYCLE3(bfclr_dn);
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFCLR <ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFCLR <ea>{#o:#w}
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bfclr_ea_less);
} else {
CYCLE3(bfclr_ea_over);
}
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
bf.data = 0;
bf.Store(n);
}
// %1110_110111_mmmrrr d.m..rxwp. -34 BFFFO <ea>{#o:#w},Dn
OP_DEF(bfffo)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFFFO Dn{#o:#w},Dn
CYCLE3(bfffo_dn);
bf.LoadReg(n);
} else {
// BFFFO <ea>{#o:#w},Dn
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bfffo_ea_less);
} else {
CYCLE3(bfffo_ea_over);
}
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
// 1 になっているビットを探す
for (; (int)bf.width-- > 0 && (int32)bf.data >= 0; bf.data <<= 1) {
bf.offset++;
}
reg.D[dn] = bf.offset;
}
// %1110_111011_mmmrrr d.m..rxw.. -34 BFSET <ea>{#o:#w}
OP_DEF(bfset)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
acc_bf bf(this);
if (n < 8) {
// BFSET Dn{#o:#w}
CYCLE3(bfset_dn);
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFSET <ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFSET <ea>{#o:#w}
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bfset_ea_less);
} else {
CYCLE3(bfset_ea_over);
}
}
// CCR は操作前のビットフィールドに対して
ACC.move_32(bf.data);
bf.data = 0xffffffff;
bf.Store(n);
}
// %1110_111111_mmmrrr d.m..rxw.. -34 BFINS Dn,<ea>{#o:#w}
OP_DEF(bfins)
{
uint n = ir & 0x3f;
ir2 = fetch_2();
uint dn = ir2 >> 12;
acc_bf bf(this);
if (n < 8) {
// BFINS Dm,Dn{#o:#w}
CYCLE3(bfins_dn);
bf.LoadReg(n);
} else if (n >= 0x3a) {
// BFINS Dn,<ea> に PC 相対(と #imm) はない
op_illegal();
} else {
// BFINS Dn,<ea>{#o:#w}
uint32 ea = cea_ctrl();
if (__predict_true(bf.LoadMem(ea))) {
CYCLE3(bfins_ea_less);
} else {
CYCLE3(bfins_ea_over);
}
}
bf.data = reg.D[dn] << (32 - bf.width);
// BFINS のみ CCR は操作後のビットフィールドに対して
ACC.move_32(bf.data);
bf.Store(n);
}
// %1111_000nnn_nnnnnn .......... -3- MMU30_OP
OP_DEF(mmu30)
{
// CPU ごとの virtual 関数になっている。
ops_mmu30();
}
// 68030 MMU 命令跡地は 68040 では全部 F ライン例外。
void
MPU68040Device::ops_mmu30()
{
op_illegal();
}
// 68030 MMU 命令。
void
MPU68030Device::ops_mmu30()
{
ir2 = fetch_2();
switch ((ir2 >> 8) & 0xff) {
case (0x0800 >> 8):
case (0x0900 >> 8):
case (0x0c00 >> 8):
case (0x0d00 >> 8):
// %000_01n00_000_00000 PMOVE.L <ea>,TTn
// %000_01n01_000_00000 PMOVEFD.L <ea>,TTn
{
CYCLE3(pmove_ea_tt);
uint32 ea = cea_copro();
uint32 data = read_4(ea);
uint n = (ir2 >> 10) & 1;
SetTT(n, data);
if ((ir2 & 0x0100) == 0) {
atc.FlushAll();
}
return;
}
case (0x0a00 >> 8):
case (0x0e00 >> 8):
// %000_01n10_000_00000 PMOVE.L TTn,<ea>
{
CYCLE3(pmove_tt_ea);
uint32 ea = cea_copro();
uint n = (ir2 >> 10) & 1;
write_4(ea, GetTT(n));
return;
}
case (0x2000 >> 8):
// %001_00000_000_00000 PLOADW SFC,<ea>
// %001_00000_000_00001 PLOADW DFC,<ea>
// %001_00000_000_01yyy PLOADW Dy,<ea>
// %001_00000_000_10nnn PLOADW #<imm>,<ea>
{
CYCLE3(pload);
putlog(0, "ploadw");
ops_mmu30_pload();
return;
}
case (0x2200 >> 8):
// %001_00010_000_00000 PLOADR SFC,<ea>
// %001_00010_000_00001 PLOADR DFC,<ea>
// %001_00010_000_01yyy PLOADR Dy,<ea>
// %001_00010_000_10nnn PLOADR #<imm>,<ea>
{
CYCLE3(pload);
putlog(0, "ploadr");
ops_mmu30_pload();
return;
}
case (0x2400 >> 8):
// %001_00100_000_00000 PFLUSHA
{
CYCLE3(pflusha);
ops_mmu30_pflusha();
return;
}
case (0x3000 >> 8):
// %001_10000_nnn_00000 PFLUSH SFC,#<mask>
// %001_10000_nnn_00001 PFLUSH DFC,#<mask>
// %001_10000_nnn_01yyy PFLUSH Dy,#<mask>
// %001_10000_nnn_10nnn PFLUSH #<imm>,#<mask>
{
CYCLE3(pflush);
ops_mmu30_pflush();
return;
}
case (0x3800 >> 8):
// %001_11000_nnn_00000 PFLUSH SFC,#<mask>,<ea>
// %001_11000_nnn_00001 PFLUSH DFC,#<mask>,<ea>
// %001_11000_nnn_01yyy PFLUSH Dy,#<mask>,<ea>
// %001_11000_nnn_10nnn PFLUSH #<imm>,#<mask>,<ea>
{
CYCLE3(pflush);
ops_mmu30_pflush_ea();
return;
}
case (0x4000 >> 8):
case (0x4100 >> 8):
// %010_00000_000_00000 PMOVE.L <ea>,TC
// %010_00001_000_00000 PMOVEFD.L <ea>,TC
{
CYCLE3(pmove_ea_tc);
uint32 ea = cea_copro();
uint32 data = read_4(ea);
if (SetTC(data)) {
if ((ir2 & 0x0100) == 0) {
atc.FlushAll();
}
} else {
Exception(M68K::EXCEP_MMU_CONFIG);
}
return;
}
case (0x4200 >> 8):
// %010_00010_000_00000 PMOVE.L TC,<ea>
{
CYCLE3(pmove_tc_ea);
uint32 ea = cea_copro();
write_4(ea, GetTC());
return;
}
case (0x4800 >> 8):
case (0x4900 >> 8):
// %010_01000_000_00000 PMOVE.Q <ea>,SRP
// %010_01001_000_00000 PMOVEFD.Q <ea>,SRP
{
CYCLE3(pmove_ea_xrp);
uint32 ea = cea_copro();
uint32 h = read_4(ea);
uint32 l = read_4(ea + 4);
if (SetSRP(h, l)) {
if ((ir2 & 0x0100) == 0) {
atc.FlushAll();
}
} else {
Exception(M68K::EXCEP_MMU_CONFIG);
}
return;
}
case (0x4a00 >> 8):
// %010_01010_000_00000 PMOVE.Q SRP,<ea>
{
CYCLE3(pmove_xrp_ea);
uint32 ea = cea_copro();
write_4(ea, GetSRPh());
write_4(ea + 4, GetSRPl());
return;
}
case (0x4c00 >> 8):
case (0x4d00 >> 8):
// %010_01100_000_00000 PMOVE.Q <ea>,CRP
// %010_01101_000_00000 PMOVEFD.Q <ea>,CRP
{
CYCLE3(pmove_ea_xrp);
uint32 ea = cea_copro();
uint32 h = read_4(ea);
uint32 l = read_4(ea + 4);
if (SetCRP(h, l)) {
if ((ir2 & 0x0100) == 0) {
atc.FlushAll();
}
} else {
Exception(M68K::EXCEP_MMU_CONFIG);
}
return;
}
case (0x4e00 >> 8):
// %010_01110_000_00000 PMOVE.Q CRP,<ea>
{
CYCLE3(pmove_xrp_ea);
uint32 ea = cea_copro();
write_4(ea, GetCRPh());
write_4(ea + 4, GetCRPl());
return;
}
case (0x6000 >> 8):
// %011_00000_000_00000 PMOVE.W <ea>,MMUSR
{
CYCLE3(pmove_ea_mmusr);
uint32 ea = cea_copro();
uint16 data = read_2(ea);
SetMMUSR(data);
return;
}
case (0x6200 >> 8):
// %011_00010_000_00000 PMOVE.W MMUSR,<ea>
{
CYCLE3(pmove_mmusr_ea);
uint32 ea = cea_copro();
write_2(ea, GetMMUSR());
return;
}
case (0x8000 >> 8):
case (0x8400 >> 8):
case (0x8800 >> 8):
case (0x8c00 >> 8):
case (0x9000 >> 8):
case (0x9400 >> 8):
case (0x9800 >> 8):
case (0x9c00 >> 8):
// %100_nnn00_000_00000 PTESTW SFC,<ea>,#<level>
// %100_nnn00_000_00001 PTESTW DFC,<ea>,#<level>
// %100_nnn00_000_01yyy PTESTW Dy,<ea>,#<level>
// %100_nnn00_000_10nnn PTESTW #<imm>,<ea>,#<level>
{
ops_mmu30_ptest();
return;
}
case (0x8100 >> 8):
case (0x8500 >> 8):
case (0x8900 >> 8):
case (0x8d00 >> 8):
case (0x9100 >> 8):
case (0x9500 >> 8):
case (0x9900 >> 8):
case (0x9d00 >> 8):
// %100_nnn01_nnn_00000 PTESTW SFC,<ea>,#<level>,An
// %100_nnn01_nnn_00001 PTESTW DFC,<ea>,#<level>,An
// %100_nnn01_nnn_01yyy PTESTW Dy,<ea>,#<level>,An
// %100_nnn01_nnn_10nnn PTESTW #<imm>,<ea>,#<level>,An
{
ops_mmu30_ptest();
return;
}
case (0x8200 >> 8):
case (0x8600 >> 8):
case (0x8a00 >> 8):
case (0x8e00 >> 8):
case (0x9200 >> 8):
case (0x9600 >> 8):
case (0x9a00 >> 8):
case (0x9e00 >> 8):
// %100_nnn10_000_00000 PTESTR SFC,<ea>,#<level>
// %100_nnn10_000_00001 PTESTR DFC,<ea>,#<level>
// %100_nnn10_000_01yyy PTESTR Dy,<ea>,#<level>
// %100_nnn10_000_10nnn PTESTR #<imm>,<ea>,#<level>
{
ops_mmu30_ptest();
return;
}
case (0x8300 >> 8):
case (0x8700 >> 8):
case (0x8b00 >> 8):
case (0x8f00 >> 8):
case (0x9300 >> 8):
case (0x9700 >> 8):
case (0x9b00 >> 8):
case (0x9f00 >> 8):
// %100_nnn11_nnn_00000 PTESTR SFC,<ea>,#<level>,An
// %100_nnn11_nnn_00001 PTESTR DFC,<ea>,#<level>,An
// %100_nnn11_nnn_01yyy PTESTR Dy,<ea>,#<level>,An
// %100_nnn11_nnn_10nnn PTESTR #<imm>,<ea>,#<level>,An
{
ops_mmu30_ptest();
return;
}
default:
break;
}
OP_FUNC(illegal);
}
// 現在の FPCR/FPSR を fe 構造体にコピー。
//
// fe.fe_{fpcr,fpsr} のほうはこの fpe 用の内部ワークなので破壊してよい。
// 命令実行の結果、FPSR レジスタの値を更新する際は fpu_upd_fpsr() を
// 呼ぶこと。これを使わず独自に更新する場合は fe.fe_fpframe->fpf_fpsr
// (こっちがレジスタ値) と fe.fe_fpsr (FPE 用) を同時に更新すること。
// FPCR のほうは FMOVE-to-FPCR 命令以外で変更されることはないはず。
#define INIT_FE() do { \
fe.fe_fpcr = RegFPCR; \
fe.fe_fpsr = RegFPSR; \
} while (0)
// ステートを (NULL なら) IDLE に変える。
// 6888x では非条件命令、条件命令どちらでも IDLE になる。
// 68040 では非条件命令でだけ IDLE になる。
// 非条件命令はここでは1ワード目の opclass が 1,2,3 の命令。
#define SET_IDLE() do { \
if (fpu_state == FPU_STATE_NULL) \
fpu_state = FPU_STATE_IDLE; \
} while (0)
// %1111_001000_nnnnnn .......... -34 FPGEN
OP_DEF(fpgen)
{
if (GetFPUType().IsNoFPU()) {
op_illegal();
return;
}
INIT_FE();
SET_IDLE();
ir2 = fetch_2();
switch (ir2 >> 13) {
case 0:
fpu_op_fgen_reg();
break;
case 1:
fpu_op_illg();
break;
case 2:
fpu_op_fgen_mem();
break;
case 3:
fpu_op_fmove_to_mem();
break;
case 4:
fpu_op_fmovem_ea2ctl();
break;
case 5:
fpu_op_fmovem_ctl2ea();
break;
case 6:
fpu_op_fmovem_ea2reg();
break;
case 7:
fpu_op_fmovem_reg2ea();
break;
}
}
// %1111_001001_mmmrrr d.m+-rxw.. -34 FScc.B <ea>
// %1111_001001_001yyy .......... -34 FDBcc Dy,<label>
// %1111_001001_111010 .......... -34 FTRAPcc.W #<imm>
// %1111_001001_111011 .......... -34 FTRAPcc.L #<imm>
// %1111_001001_111100 .......... -34 FTRAPcc
OP_DEF(fxcc)
{
if (GetFPUType().IsNoFPU()) {
op_illegal();
return;
}
if ((ir & 077) >= 075) {
op_illegal();
return;
}
INIT_FE();
if (GetFPUType().Is6888x()) {
SET_IDLE();
}
// ここまで来ると共通で ir2 に cc が来る。
ir2 = fetch_2();
switch (ir & 077) {
case 010 ... 017: // FDBcc
fpu_op_fdbcc();
break;
case 000 ... 007: // FScc
case 020 ... 027:
case 030 ... 037:
case 040 ... 047:
case 050 ... 057:
case 060 ... 067:
case 070 ... 071:
fpu_op_fscc();
break;
case 072: // FTRAPcc.W
fpu_op_ftrapcc_w();
break;
case 073: // FTRAPcc.L
fpu_op_ftrapcc_l();
break;
case 074: // FTRAPcc
fpu_op_ftrapcc();
break;
default:
__unreachable();
}
}
// %1111_001010_nnnnnn .......... -34 FBcc.W <label>
OP_DEF(fbcc_w)
{
if (GetFPUType().IsNoFPU()) {
op_illegal();
return;
}
INIT_FE();
if (GetFPUType().Is6888x()) {
SET_IDLE();
}
fpu_op_fbcc_w();
}
// %1111_001011_nnnnnn .......... -34 FBcc.L <label>
OP_DEF(fbcc_l)
{
if (GetFPUType().IsNoFPU()) {
op_illegal();
return;
}
INIT_FE();
if (GetFPUType().Is6888x()) {
SET_IDLE();
}
fpu_op_fbcc_l();
}
// %1111_001100_mmmrrr ..m.-rxw.. -34 FSAVE <ea>
OP_DEF(fsave)
{
if (GetFPUType().IsNoFPU()) {
op_illegal();
return;
}
SUPERVISOR_OP;
fpu_op_fsave();
}
// %1111_001101_mmmrrr ..m+.rxw.. -34 FRESTORE <ea>
OP_DEF(frestore)
{
if (GetFPUType().IsNoFPU()) {
op_illegal();
return;
}
SUPERVISOR_OP;
fpu_op_frestore();
}
// %1111_0100nn_001yyy .......... --4 CINVL <caches>,(Ay)
// %1111_0100nn_010yyy .......... --4 CINVP <caches>,(Ay)
// %1111_0100nn_011000 .......... --4 CINVA <caches>
// %1111_0100nn_101yyy .......... --4 CPUSHL <caches>,(Ay)
// %1111_0100nn_110yyy .......... --4 CPUSHP <caches>,(Ay)
// %1111_0100nn_111000 .......... --4 CPUSHA <caches>
OP_DEF(cinv)
{
if (mpu_type != m680x0MPUType::M68040) {
op_illegal();
return;
}
// putlog(1, "cinv*/cpush* (NOT IMPLEMENTED)");
}
// %1111_010100_mmmrrr ..m.-rxw.. 23- cpSAVE
// %1111_010100_000yyy .......... --4 PFLUSHN (Ay)
// %1111_010100_001yyy .......... --4 PFLUSH (Ay)
// %1111_010100_010000 .......... --4 PFLUSHAN
// %1111_010100_011000 .......... --4 PFLUSHA
OP_DEF(pflush)
{
// CPU ごとの virtual 関数になっている。
ops_mmu40_pflush();
}
// 68030 では 68040 MMU 命令の位置は全部 cpSAVE。
void
MPU68030Device::ops_mmu40_pflush()
{
op_cpsave();
}
// 68040 MMU 命令。
void
MPU68040Device::ops_mmu40_pflush()
{
SUPERVISOR_OP;
// DFC は 1,2,5,6 の場合のみ有効で、0,3,4,7 なら動作不定。
// 68000PRM.pdf, p6-35。
// ここでは FC2 だけで判定する。
switch (ir & 077) {
case 000 ... 007: // PFLUSHN (Ay)
{
CYCLE(11);
busaddr addr = busaddr(RegAY) | reg.dfc;
atc_inst->Flush(addr, true);
atc_data->Flush(addr, true);
return;
}
case 010 ... 017: // PFLUSH (Ay)
{
CYCLE(11);
busaddr addr = busaddr(RegAY) | reg.dfc;
atc_inst->Flush(addr, false);
atc_data->Flush(addr, false);
return;
}
case 020: // PFLUSHAN
{
CYCLE(27);
bool s = reg.dfc.IsSuper();
atc_inst->Flush(s, true);
atc_data->Flush(s, true);
return;
}
case 030: // PFLUSHA
{
CYCLE3(pflusha);
bool s = reg.dfc.IsSuper();
atc_inst->Flush(s, false);
atc_data->Flush(s, false);
return;
}
default:
break;
}
op_illegal();
}
// %1111_010101_mmmrrr ..m+.rxwp. 23- cpRESTORE
// %1111_010101_001yyy .......... --4 PTESTW (Ay)
// %1111_010101_101yyy .......... --4 PTESTR (Ay)
OP_DEF(ptest)
{
if (mpu_type != m680x0MPUType::M68040) {
op_cprestore();
return;
}
//CYCLE(25);
OP_FUNC(unimpl);
}
// %1111_011000_000yyy .......... --4 MOVE16 (Ay)+,xxx.L
// %1111_011000_001yyy .......... --4 MOVE16 xxx.L,(Ay)+
// %1111_011000_010yyy .......... --4 MOVE16 (Ay),xxx.L
// %1111_011000_011yyy .......... --4 MOVE16 xxx.L,(Ay)
// %1111_011000_100yyy .......... --4 MOVE16 (Ay)+,(An)+
OP_DEF(move16)
{
if (mpu_type != m680x0MPUType::M68040) {
op_illegal();
return;
}
OP_FUNC(unimpl);
}
// %1111_011100_mmmrrr ..m.-rxw.. 23- cpSAVE
// %1111_100100_mmmrrr ..m.-rxw.. 23- cpSAVE
// %1111_101100_mmmrrr ..m.-rxw.. 23- cpSAVE
// %1111_110100_mmmrrr ..m.-rxw.. 23- cpSAVE
// %1111_111100_mmmrrr ..m.-rxw.. 23- cpSAVE
OP_DEF(cpsave)
{
// 020/030 では、(第1ワードが?) 有効な命令パターンの場合
// まず特権チェックを行う。
// cpSAVE の場合先に CIR で問い合わせて、その後 EA を評価すると書いて
// あるように読める (68020 本 p.104) ので、コプロセッサがいない場合は
// EA は評価しなさそう。
// -(An) はコプロセッサがいなければ変化しないような気がする。
// EA のパターンが無効なら F ライン例外になる。
// cpID=6,7 はユーザ用とあるが cpSAVE は影響を受けるかどうか。
// 040 ではコプロセッサプロトコル自体ないので全部 F ライン例外になる?
//
// ただし、Human68k モードではその特権判定よりも先んじて不当命令に
// ならなければいけない。
// Human68k モードでは F ライン命令は例外を起こすのではなく、命令内部で
// 直接ホストのコールバックを実行しているため、ゲスト側の特権違反ハンドラ
// に来たものを F ライン例外へ回すというような処理は出来ないため。
if (fline_callback == NULL && mpu_type == m680x0MPUType::M68030) {
switch (ir & 077) {
case 020 ... 027: // m:(An)
case 040 ... 047: // -:-(An)
case 050 ... 057: // r:d16(An)
case 060 ... 067: // x:d8(An,IX)
case 070 ... 071: // w:Abs
SUPERVISOR_OP;
// コプロセッサがいないので EA をフェッチせず終了のはず。
break;
default:
break;
}
}
op_illegal();
}
// %1111_011101_mmmrrr ..m+.rxwp. 23- cpRESTORE
// %1111_100101_mmmrrr ..m+.rxwp. 23- cpRESTORE
// %1111_101101_mmmrrr ..m+.rxwp. 23- cpRESTORE
// %1111_110101_mmmrrr ..m+.rxwp. 23- cpRESTORE
// %1111_111101_mmmrrr ..m+.rxwp. 23- cpRESTORE
OP_DEF(cprestore)
{
// すぐ上の cpsave 内のコメント参照。
// cpRESTORE の場合先に1ロングワード読んでみて、その後コプロセッサに
// 通信するので、コプロセッサがいなくても読み込みは発生する。
// See XEiJ/misc/flinebuserror.x
if (fline_callback == NULL && mpu_type == m680x0MPUType::M68030) {
switch (ir & 077) {
case 020 ... 027: // m:(An)
case 030 ... 037: // +:(An)+
case 050 ... 057: // r:d16(An)
case 060 ... 067: // x:d8(An,IX)
case 070 ... 071: // w:Abs
case 072 ... 073: // p:d8(PC,IX)
{
SUPERVISOR_OP;
uint32 ea = cea_fpu(4);
read_4(ea);
break;
}
default:
break;
}
}
op_illegal();
}
// %1111_010110_001nnn .......... --6 PLPAW (An)
// %1111_010111_001nnn .......... --6 PLPAR (An)
OP_DEF(plpa)
{
op_illegal();
}
// %1111_100000_000000 .......... --6 LPSTOP
OP_DEF(lpstop)
{
op_illegal();
}
// illegal (or not-assigned) instructions
OP_DEF(illegal)
{
// ILLEGAL 命令と F ライン命令と不当命令パターンがすべてここに来る。
// catch 内からも呼ばれるので、ここで C++ の例外をスローしてはいけない。
if ((ir & 0xf000) == 0xf000) {
// F系列命令
CYCLE3(fline);
if (fline_callback) {
if (fline_callback(this, fline_arg)) {
return;
}
}
ExceptionFLine();
} else {
// 不当命令
CYCLE3(illegal);
Exception(M68K::EXCEP_ILLEGAL);
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.