mpw/cpu/CpuModule_Instructions.c

3759 lines
80 KiB
C
Raw Normal View History

/* @(#) $Id: CpuModule_Instructions.c,v 1.12 2013-01-08 18:55:48 peschau Exp $ */
2013-02-06 04:11:41 +00:00
/*=========================================================================*/
/* Fellow */
/* CPU 68k functions */
/* */
/* Author: Petter Schau */
/* */
/* */
/* Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc. */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2, or (at your option) */
/* any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software Foundation, */
/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*=========================================================================*/
#include "defs.h"
#include "CpuModule_Memory.h"
2013-02-06 04:11:41 +00:00
#include "CpuModule.h"
#include "CpuModule_Internal.h"
static cpuLineExceptionFunc cpu_a_line_exception_func = NULL;
static cpuLineExceptionFunc cpu_f_line_exception_func = NULL;
void cpuSetALineExceptionFunc(cpuLineExceptionFunc func)
{
cpu_a_line_exception_func = func;
}
void cpuSetFLineExceptionFunc(cpuLineExceptionFunc func)
{
cpu_f_line_exception_func = func;
}
2013-02-06 04:11:41 +00:00
/*============================================================================*/
/* profiling help functions */
/*============================================================================*/
2013-02-06 23:47:55 +00:00
#if 0
2013-02-06 04:11:41 +00:00
#ifndef X64
static __inline void cpuTscBefore(LLO* a)
{
LLO local_a = *a;
__asm
{
push eax
push edx
push ecx
mov ecx,10h
rdtsc
pop ecx
mov dword ptr [local_a], eax
mov dword ptr [local_a + 4], edx
pop edx
pop eax
}
*a = local_a;
}
static __inline void cpuTscAfter(LLO* a, LLO* b, ULO* c)
{
LLO local_a = *a;
LLO local_b = *b;
ULO local_c = *c;
__asm
{
push eax
push edx
push ecx
mov ecx, 10h
rdtsc
pop ecx
sub eax, dword ptr [local_a]
sbb edx, dword ptr [local_a + 4]
add dword ptr [local_b], eax
adc dword ptr [local_b + 4], edx
inc dword ptr [local_c]
pop edx
pop eax
}
*a = local_a;
*b = local_b;
*c = local_c;
}
#endif
2013-02-06 23:47:55 +00:00
#endif
2013-02-06 04:11:41 +00:00
/* Maintains the integrity of the super/user state */
void cpuUpdateSr(ULO new_sr)
{
BOOLE supermode_was_set = cpuGetFlagSupervisor();
BOOLE master_was_set = (cpuGetModelMajor() >= 2) && cpuGetFlagMaster();
2013-02-06 04:11:41 +00:00
BOOLE supermode_is_set = !!(new_sr & 0x2000);
BOOLE master_is_set = (cpuGetModelMajor() >= 2) && !!(new_sr & 0x1000);
2013-02-06 04:11:41 +00:00
ULO runlevel_old = (cpuGetSR() >> 8) & 7;
ULO runlevel_new = (new_sr >> 8) & 7;
2013-02-06 04:11:41 +00:00
if (!supermode_was_set)
{
cpuSetUspDirect(cpuGetAReg(7));
}
else if (master_was_set)
{
cpuSetMspDirect(cpuGetAReg(7));
}
else
{
cpuSetSspDirect(cpuGetAReg(7));
}
2013-02-06 04:11:41 +00:00
if (!supermode_is_set)
{
cpuSetAReg(7, cpuGetUspDirect());
}
else if (master_is_set)
{
cpuSetAReg(7, cpuGetMspDirect());
}
else
{
cpuSetAReg(7, cpuGetSspDirect());
}
2013-02-06 04:11:41 +00:00
cpuSetSR(new_sr);
2013-02-06 04:11:41 +00:00
if (runlevel_old != runlevel_new)
{
cpuCheckPendingInterrupts();
}
2013-02-06 04:11:41 +00:00
}
static void cpuIllegal(void)
{
UWO opcode = memoryReadWord(cpuGetPC() - 2);
if ((opcode & 0xf000) == 0xf000)
{
if (cpu_f_line_exception_func)
{
cpu_f_line_exception_func(opcode);
cpuInitializeFromNewPC(cpuGetPC());
cpuSetInstructionTime(512);
}
else
{
cpuThrowFLineException();
}
}
else if ((opcode & 0xa000) == 0xa000)
{
#if 0
2013-02-06 04:11:41 +00:00
if ((cpuGetPC() & 0xff0000) == 0xf00000)
{
call_calltrap(opcode & 0xfff);
cpuInitializeFromNewPC(cpuGetPC());
cpuSetInstructionTime(512);
}
#else
if (cpu_a_line_exception_func)
{
cpu_a_line_exception_func(opcode);
cpuInitializeFromNewPC(cpuGetPC());
cpuSetInstructionTime(512);
}
#endif
else
2013-02-06 04:11:41 +00:00
{
cpuThrowALineException();
}
}
else
{
cpuThrowIllegalInstructionException(FALSE);
}
}
/// <summary>
/// Illegal instruction handler.
/// </summary>
static void cpuIllegalInstruction(ULO *opcode_data)
{
cpuIllegal();
}
/// <summary>
/// BKPT
/// </summary>
static void cpuBkpt(ULO vector)
{
cpuIllegal();
}
/// <summary>
/// Adds bytes src1 to src2. Sets all flags.
/// </summary>
/// <returns>The result</returns>
static UBY cpuAddB(UBY src2, UBY src1)
{
UBY res = src2 + src1;
cpuSetFlagsAdd(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(src2), cpuMsbB(src1));
return res;
}
/// <summary>
/// Adds words src1 to src2. Sets all flags.
/// </summary>
/// <returns>The result</returns>
static UWO cpuAddW(UWO src2, UWO src1)
{
UWO res = src2 + src1;
cpuSetFlagsAdd(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(src2), cpuMsbW(src1));
return res;
}
/// <summary>
/// Adds dwords src1 to src2. Sets all flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuAddL(ULO src2, ULO src1)
{
ULO res = src2 + src1;
cpuSetFlagsAdd(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(src2), cpuMsbL(src1));
return res;
}
/// <summary>
/// Adds src1 to src2 (For address registers). No flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuAddaW(ULO src2, ULO src1)
{
return src2 + src1;
}
/// <summary>
/// Adds src1 to src2 (For address registers). No flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuAddaL(ULO src2, ULO src1)
{
return src2 + src1;
}
/// <summary>
/// Subtracts src1 from src2. Sets all flags.
/// </summary>
/// <returns>The result</returns>
static UBY cpuSubB(UBY src2, UBY src1)
{
UBY res = src2 - src1;
cpuSetFlagsSub(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(src2), cpuMsbB(src1));
return res;
}
/// <summary>
/// Subtracts src1 from src2. Sets all flags.
/// </summary>
/// <returns>The result</returns>
static UWO cpuSubW(UWO src2, UWO src1)
{
UWO res = src2 - src1;
cpuSetFlagsSub(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(src2), cpuMsbW(src1));
return res;
}
/// <summary>
/// Subtracts src1 from src2. Sets all flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuSubL(ULO src2, ULO src1)
{
ULO res = src2 - src1;
cpuSetFlagsSub(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(src2), cpuMsbL(src1));
return res;
}
/// <summary>
/// Subtracts src1 from src2 (For address registers). No flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuSubaW(ULO src2, ULO src1)
{
return src2 - src1;
}
/// <summary>
/// Subtracts src1 from src2 (For address registers). No flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuSubaL(ULO src2, ULO src1)
{
return src2 - src1;
}
/// <summary>
/// Subtracts src1 from src2. Sets all flags.
/// </summary>
static void cpuCmpB(UBY src2, UBY src1)
{
UBY res = src2 - src1;
cpuSetFlagsCmp(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(src2), cpuMsbB(src1));
}
/// <summary>
/// Subtracts src1 from src2. Sets all flags.
/// </summary>
static void cpuCmpW(UWO src2, UWO src1)
{
UWO res = src2 - src1;
cpuSetFlagsCmp(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(src2), cpuMsbW(src1));
}
/// <summary>
/// Subtracts src1 from src2. Sets all flags.
/// </summary>
static void cpuCmpL(ULO src2, ULO src1)
{
ULO res = src2 - src1;
cpuSetFlagsCmp(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(src2), cpuMsbL(src1));
}
/// <summary>
/// Ands src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static UBY cpuAndB(UBY src2, UBY src1)
{
UBY res = src2 & src1;
cpuSetFlagsNZ00NewB(res);
return res;
}
/// <summary>
/// Ands src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static UWO cpuAndW(UWO src2, UWO src1)
{
UWO res = src2 & src1;
cpuSetFlagsNZ00NewW(res);
return res;
}
/// <summary>
/// Ands src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuAndL(ULO src2, ULO src1)
{
ULO res = src2 & src1;
cpuSetFlagsNZ00NewL(res);
return res;
}
/// <summary>
/// Eors src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static UBY cpuEorB(UBY src2, UBY src1)
{
UBY res = src2 ^ src1;
cpuSetFlagsNZ00NewB(res);
return res;
}
/// <summary>
/// Eors src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static UWO cpuEorW(UWO src2, UWO src1)
{
UWO res = src2 ^ src1;
cpuSetFlagsNZ00NewW(res);
return res;
}
/// <summary>
/// Eors src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuEorL(ULO src2, ULO src1)
{
ULO res = src2 ^ src1;
cpuSetFlagsNZ00NewL(res);
return res;
}
/// <summary>
/// Ors src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static UBY cpuOrB(UBY src2, UBY src1)
{
UBY res = src2 | src1;
cpuSetFlagsNZ00NewB(res);
return res;
}
/// <summary>
/// Ors src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static UWO cpuOrW(UWO src2, UWO src1)
{
UWO res = src2 | src1;
cpuSetFlagsNZ00NewW(res);
return res;
}
/// <summary>
/// Ors src1 to src2. Sets NZ00 flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuOrL(ULO src2, ULO src1)
{
ULO res = src2 | src1;
cpuSetFlagsNZ00NewL(res);
return res;
}
/// <summary>
/// Changes bit in src. Sets Z flag.
/// </summary>
/// <returns>The result</returns>
static UBY cpuBchgB(UBY src, UBY bit)
{
UBY bit_mask = 1 << (bit & 7);
cpuSetZFlagBitOpsB(src & bit_mask);
return src ^ bit_mask;
}
/// <summary>
/// Changes bit in src. Sets Z flag.
/// </summary>
/// <returns>The result</returns>
static ULO cpuBchgL(ULO src, ULO bit)
{
ULO bit_mask = 1 << (bit & 31);
cpuSetZFlagBitOpsL(src & bit_mask);
return src ^ bit_mask;
}
/// <summary>
/// Clears bit in src. Sets Z flag.
/// </summary>
/// <returns>The result</returns>
static UBY cpuBclrB(UBY src, UBY bit)
{
UBY bit_mask = 1 << (bit & 7);
cpuSetZFlagBitOpsB(src & bit_mask);
return src & ~bit_mask;
}
/// <summary>
/// Clears bit in src. Sets Z flag.
/// </summary>
/// <returns>The result</returns>
static ULO cpuBclrL(ULO src, ULO bit)
{
ULO bit_mask = 1 << (bit & 31);
cpuSetZFlagBitOpsL(src & bit_mask);
return src & ~bit_mask;
}
/// <summary>
/// Sets bit in src. Sets Z flag.
/// </summary>
/// <returns>The result</returns>
static UBY cpuBsetB(UBY src, UBY bit)
{
UBY bit_mask = 1 << (bit & 7);
cpuSetZFlagBitOpsB(src & bit_mask);
return src | bit_mask;
}
/// <summary>
/// Sets bit in src. Sets Z flag.
/// </summary>
/// <returns>The result</returns>
static ULO cpuBsetL(ULO src, ULO bit)
{
ULO bit_mask = 1 << (bit & 31);
cpuSetZFlagBitOpsL(src & bit_mask);
return src | bit_mask;
}
/// <summary>
/// Tests bit in src. Sets Z flag.
/// </summary>
static void cpuBtstB(UBY src, UBY bit)
{
UBY bit_mask = 1 << (bit & 7);
cpuSetZFlagBitOpsB(src & bit_mask);
}
/// <summary>
/// Tests bit in src. Sets Z flag.
/// </summary>
static void cpuBtstL(ULO src, ULO bit)
{
ULO bit_mask = 1 << (bit & 31);
cpuSetZFlagBitOpsL(src & bit_mask);
}
/// <summary>
/// Set flags for clr operation. X0100.
/// </summary>
static void cpuClr()
{
cpuSetFlags0100();
}
/// <summary>
/// Neg src1. Sets sub flags.
/// </summary>
/// <returns>The result</returns>
static UBY cpuNegB(UBY src1)
{
UBY res = (UBY)-(BYT)src1;
cpuSetFlagsNeg(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(src1));
return res;
}
/// <summary>
/// Neg src1. Sets sub flags.
/// </summary>
/// <returns>The result</returns>
static UWO cpuNegW(UWO src1)
{
UWO res = (UWO)-(WOR)src1;
cpuSetFlagsNeg(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(src1));
return res;
}
/// <summary>
/// Neg src1. Sets sub flags.
/// </summary>
/// <returns>The result</returns>
static ULO cpuNegL(ULO src1)
{
ULO res = (ULO)-(LON)src1;
cpuSetFlagsNeg(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(src1));
return res;
}
/// <summary>
/// Negx src1.
/// </summary>
/// <returns>The result</returns>
static UBY cpuNegxB(UBY src1)
{
BYT x = (cpuGetFlagX()) ? 1 : 0;
UBY res = (UBY)-(BYT)src1 - x;
cpuSetFlagsNegx(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(src1));
return res;
}
/// <summary>
/// Negx src1.
/// </summary>
/// <returns>The result</returns>
static UWO cpuNegxW(UWO src1)
{
WOR x = (cpuGetFlagX()) ? 1 : 0;
UWO res = (UWO)-(WOR)src1 - x;
cpuSetFlagsNegx(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(src1));
return res;
}
/// <summary>
/// Negx src1.
/// </summary>
/// <returns>The result</returns>
static ULO cpuNegxL(ULO src1)
{
LON x = (cpuGetFlagX()) ? 1 : 0;
ULO res = (ULO)-(LON)src1 - x;
cpuSetFlagsNegx(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(src1));
return res;
}
/// <summary>
/// Not src1.
/// </summary>
/// <returns>The result</returns>
static UBY cpuNotB(UBY src1)
{
UBY res = ~src1;
cpuSetFlagsNZ00NewB(res);
return res;
}
/// <summary>
/// Not src1.
/// </summary>
/// <returns>The result</returns>
static UWO cpuNotW(UWO src1)
{
UWO res = ~src1;
cpuSetFlagsNZ00NewW(res);
return res;
}
/// <summary>
/// Not src.
/// </summary>
/// <returns>The result</returns>
static ULO cpuNotL(ULO src)
{
ULO res = ~src;
cpuSetFlagsNZ00NewL(res);
return res;
}
/// <summary>
/// Tas src.
/// </summary>
/// <returns>The result</returns>
static UBY cpuTas(UBY src)
{
cpuSetFlagsNZ00NewB(src);
return src | 0x80;
}
/// <summary>
/// Tst res.
/// </summary>
static void cpuTestB(UBY res)
{
cpuSetFlagsNZ00NewB(res);
}
/// <summary>
/// Tst res.
/// </summary>
static void cpuTestW(UWO res)
{
cpuSetFlagsNZ00NewW(res);
}
/// <summary>
/// Tst res.
/// </summary>
static void cpuTestL(ULO res)
{
cpuSetFlagsNZ00NewL(res);
}
/// <summary>
/// PEA ea.
/// </summary>
static void cpuPeaL(ULO ea)
{
cpuSetAReg(7, cpuGetAReg(7) - 4);
memoryWriteLong(ea, cpuGetAReg(7));
}
/// <summary>
/// JMP ea.
/// </summary>
static void cpuJmp(ULO ea)
{
cpuInitializeFromNewPC(ea);
}
/// <summary>
/// JSR ea.
/// </summary>
static void cpuJsr(ULO ea)
{
cpuSetAReg(7, cpuGetAReg(7) - 4);
memoryWriteLong(cpuGetPC(), cpuGetAReg(7));
cpuInitializeFromNewPC(ea);
}
/// <summary>
/// Move res
/// </summary>
/// <returns>The result</returns>
static void cpuMoveB(UBY res)
{
cpuSetFlagsNZ00NewB(res);
}
/// <summary>
/// Move res
/// </summary>
/// <returns>The result</returns>
static void cpuMoveW(UWO res)
{
cpuSetFlagsNZ00NewW(res);
}
/// <summary>
/// Move res
/// </summary>
/// <returns>The result</returns>
static void cpuMoveL(ULO res)
{
cpuSetFlagsNZ00NewL(res);
}
/// <summary>
/// Bra byte offset.
/// </summary>
static void cpuBraB(ULO offset)
{
cpuInitializeFromNewPC(cpuGetPC() + offset);
cpuSetInstructionTime(10);
}
/// <summary>
/// Bra word offset.
/// </summary>
static void cpuBraW()
{
ULO tmp_pc = cpuGetPC();
cpuInitializeFromNewPC(tmp_pc + cpuGetNextWordSignExt());
cpuSetInstructionTime(10);
}
/// <summary>
/// Bra long offset.
/// </summary>
static void cpuBraL()
{
if (cpuGetModelMajor() < 2) cpuBraB(0xffffffff);
else
{
ULO tmp_pc = cpuGetPC();
cpuInitializeFromNewPC(tmp_pc + cpuGetNextLong());
cpuSetInstructionTime(4);
}
}
/// <summary>
/// Bsr byte offset.
/// </summary>
static void cpuBsrB(ULO offset)
{
cpuSetAReg(7, cpuGetAReg(7) - 4);
memoryWriteLong(cpuGetPC(), cpuGetAReg(7));
cpuInitializeFromNewPC(cpuGetPC() + offset);
cpuSetInstructionTime(18);
}
/// <summary>
/// Bsr word offset.
/// </summary>
static void cpuBsrW()
{
ULO tmp_pc = cpuGetPC();
ULO offset = cpuGetNextWordSignExt();
cpuSetAReg(7, cpuGetAReg(7) - 4);
memoryWriteLong(cpuGetPC(), cpuGetAReg(7));
cpuInitializeFromNewPC(tmp_pc + offset);
cpuSetInstructionTime(18);
}
/// <summary>
/// Bsr long offset. (020+)
/// </summary>
static void cpuBsrL()
{
if (cpuGetModelMajor() < 2) cpuBsrB(0xffffffff);
else
{
ULO tmp_pc = cpuGetPC();
ULO offset = cpuGetNextLong();
cpuSetAReg(7, cpuGetAReg(7) - 4);
memoryWriteLong(cpuGetPC(), cpuGetAReg(7));
cpuInitializeFromNewPC(tmp_pc + offset);
cpuSetInstructionTime(4);
}
}
/// <summary>
/// Bcc byte offset.
/// </summary>
static void cpuBccB(BOOLE cc, ULO offset)
{
if (cc)
{
cpuInitializeFromNewPC(cpuGetPC() + offset);
cpuSetInstructionTime(10);
}
else
{
cpuSetInstructionTime(8);
}
}
/// <summary>
/// Bcc word offset.
/// </summary>
static void cpuBccW(BOOLE cc)
{
if (cc)
{
ULO tmp_pc = cpuGetPC();
cpuInitializeFromNewPC(tmp_pc + cpuGetNextWordSignExt());
cpuSetInstructionTime(10);
}
else
{
cpuSkipNextWord();
cpuSetInstructionTime(12);
}
}
/// <summary>
/// Bcc long offset. (020+)
/// </summary>
static void cpuBccL(BOOLE cc)
{
if (cpuGetModelMajor() < 2) cpuBccB(cc, 0xffffffff);
else
{
if (cc)
{
ULO tmp_pc = cpuGetPC();
cpuInitializeFromNewPC(tmp_pc + cpuGetNextLong());
}
else
{
cpuSkipNextLong();
}
cpuSetInstructionTime(4);
}
}
/// <summary>
/// DBcc word offset.
/// </summary>
static void cpuDbcc(BOOLE cc, ULO reg)
{
if (!cc)
{
WOR val = (WOR)cpuGetDRegWord(reg);
val--;
cpuSetDRegWord(reg, val);
if (val != -1)
{
ULO tmp_pc = cpuGetPC();
cpuInitializeFromNewPC(tmp_pc + cpuGetNextWordSignExt());
cpuSetInstructionTime(10);
}
else
{
cpuSkipNextWord();
cpuSetInstructionTime(14);
}
}
else
{
cpuSkipNextWord();
cpuSetInstructionTime(12);
}
}
/// <summary>
/// And #imm, ccr
/// </summary>
static void cpuAndCcrB()
{
UWO imm = cpuGetNextWord();
cpuSetSR(cpuGetSR() & (0xffe0 | (imm & 0x1f)));
}
/// <summary>
/// And #imm, sr
/// </summary>
static void cpuAndSrW()
{
if (cpuGetFlagSupervisor())
{
UWO imm = cpuGetNextWord();
cpuUpdateSr(cpuGetSR() & imm);
}
else
{
cpuThrowPrivilegeViolationException();
}
}
/// <summary>
/// Or #imm, ccr
/// </summary>
static void cpuOrCcrB()
{
UWO imm = cpuGetNextWord();
cpuSetSR(cpuGetSR() | (imm & 0x1f));
}
/// <summary>
/// Or #imm, sr
/// </summary>
static void cpuOrSrW()
{
if (cpuGetFlagSupervisor())
{
UWO imm = cpuGetNextWord();
cpuUpdateSr(cpuGetSR() | imm);
}
else
{
cpuThrowPrivilegeViolationException();
}
}
/// <summary>
/// Eor #imm, ccr
/// </summary>
static void cpuEorCcrB()
{
UWO imm = cpuGetNextWord();
cpuSetSR(cpuGetSR() ^ (imm & 0x1f));
}
/// <summary>
/// Eor #imm, sr
/// </summary>
static void cpuEorSrW()
{
if (cpuGetFlagSupervisor())
{
UWO imm = cpuGetNextWord();
cpuUpdateSr(cpuGetSR() ^ imm);
}
else
{
cpuThrowPrivilegeViolationException();
}
}
/// <summary>
/// Move ea, ccr
/// </summary>
static void cpuMoveToCcr(UWO src)
{
cpuSetSR((cpuGetSR() & 0xff00) | (src & 0x1f));
}
/// <summary>
/// Move <ea>, sr
/// </summary>
static void cpuMoveToSr(UWO src)
{
if (cpuGetFlagSupervisor())
{
cpuUpdateSr(src);
}
else
{
cpuThrowPrivilegeViolationException();
}
}
/// <summary>
/// Move ccr, ea
/// </summary>
static UWO cpuMoveFromCcr()
{
return cpuGetSR() & 0x1f;
}
/// <summary>
/// Move <ea>, sr
/// </summary>
static UWO cpuMoveFromSr()
{
if (cpuGetModelMajor() == 0 || (cpuGetModelMajor() > 0 && cpuGetFlagSupervisor()))
{
return (UWO) cpuGetSR();
}
else
{
cpuThrowPrivilegeViolationException();
}
return 0;
}
/// <summary>
/// Scc byte.
/// </summary>
static UBY cpuScc(ULO cc)
{
return (cpuCalculateConditionCode(cc)) ? 0xff : 0;
}
/// <summary>
/// Rts
/// </summary>
static void cpuRts()
{
cpuInitializeFromNewPC(memoryReadLong(cpuGetAReg(7)));
cpuSetAReg(7, cpuGetAReg(7) + 4);
cpuSetInstructionTime(16);
}
/// <summary>
/// Rtr
/// </summary>
static void cpuRtr()
{
cpuSetSR((cpuGetSR() & 0xffe0) | (memoryReadWord(cpuGetAReg(7)) & 0x1f));
cpuSetAReg(7, cpuGetAReg(7) + 2);
cpuInitializeFromNewPC(memoryReadLong(cpuGetAReg(7)));
cpuSetAReg(7, cpuGetAReg(7) + 4);
cpuSetInstructionTime(20);
}
/// <summary>
/// Nop
/// </summary>
static void cpuNop()
{
cpuSetInstructionTime(4);
}
/// <summary>
/// Trapv
/// </summary>
static void cpuTrapv()
{
if (cpuGetFlagV())
{
cpuThrowTrapVException();
return;
}
cpuSetInstructionTime(4);
}
/// <summary>
/// Muls/u.l
/// </summary>
static void cpuMulL(ULO src1, UWO extension)
{
ULO dl = (extension >> 12) & 7;
if (extension & 0x0800) // muls.l
{
LLO result = ((LLO)(LON) src1) * ((LLO)(LON)cpuGetDReg(dl));
if (extension & 0x0400) // 32bx32b=64b
{
ULO dh = extension & 7;
cpuSetDReg(dh, (ULO)(result >> 32));
cpuSetDReg(dl, (ULO)result);
cpuSetFlagsNZ00New64(result);
}
else // 32bx32b=32b
{
BOOLE o;
if (result >= 0)
o = (result & 0xffffffff00000000) != 0;
2013-02-06 04:11:41 +00:00
else
o = (result & 0xffffffff00000000) != 0xffffffff00000000;
2013-02-06 04:11:41 +00:00
cpuSetDReg(dl, (ULO)result);
cpuSetFlagsNZVC(result == 0, result < 0, o, FALSE);
}
}
else // mulu.l
{
ULL result = ((ULL) src1) * ((ULL) cpuGetDReg(dl));
if (extension & 0x0400) // 32bx32b=64b
{
ULO dh = extension & 7;
cpuSetDReg(dh, (ULO)(result >> 32));
cpuSetDReg(dl, (ULO)result);
cpuSetFlagsNZ00New64(result);
}
else // 32bx32b=32b
{
cpuSetDReg(dl, (ULO)result);
cpuSetFlagsNZVC(result == 0, !!(result & 0x80000000), (result >> 32) != 0, FALSE);
2013-02-06 04:11:41 +00:00
}
}
cpuSetInstructionTime(4);
}
UBY cpuMuluTime[256];
UBY cpuMulsTime[512];
void cpuCreateMuluTimeTable(void)
{
ULO i, j, k;
for (i = 0; i < 256; i++)
{
j = 0;
for (k = 0; k < 8; k++)
if (((i>>k) & 1) == 1)
j++;
2013-02-06 04:11:41 +00:00
cpuMuluTime[i] = (UBY) j*2;
}
}
void cpuCreateMulsTimeTable(void)
{
ULO i, j, k;
for (i = 0; i < 512; i++)
{
j = 0;
for (k = 0; k < 9; k++)
if ((((i>>k) & 3) == 1) || (((i>>k) & 3) == 2))
j++;
2013-02-06 04:11:41 +00:00
cpuMulsTime[i] = (UBY) j*2;
}
}
void cpuCreateMulTimeTables(void)
{
cpuCreateMuluTimeTable();
cpuCreateMulsTimeTable();
}
/// <summary>
/// Muls.w
/// </summary>
static ULO cpuMulsW(UWO src2, UWO src1, ULO eatime)
{
ULO res = (ULO)(((LON)(WOR)src2)*((LON)(WOR)src1));
cpuSetFlagsNZ00NewL(res);
cpuSetInstructionTime(38 + eatime + cpuMulsTime[(src1 << 1) & 0x1ff] + cpuMulsTime[src1 >> 7]);
return res;
}
/// <summary>
/// Mulu.w
/// </summary>
static ULO cpuMuluW(UWO src2, UWO src1, ULO eatime)
{
ULO res = ((ULO)src2)*((ULO)src1);
cpuSetFlagsNZ00NewL(res);
cpuSetInstructionTime(38 + eatime + cpuMuluTime[src1 & 0xff] + cpuMuluTime[src1 >> 8]);
return res;
}
/// <summary>
/// Divsw, src1 / src2
/// </summary>
static void cpuDivsW(ULO dst, UWO src1, ULO destination_reg, ULO instruction_time)
2013-02-06 04:11:41 +00:00
{
if (src1 == 0)
{
// Alcatraz odyssey assumes that PC in this exception points after the instruction.
cpuThrowDivisionByZeroException();
2013-02-06 04:11:41 +00:00
}
else
{
ULO result;
2013-02-06 04:11:41 +00:00
LON x = (LON) dst;
LON y = (LON)(WOR) src1;
LON res = x / y;
LON rem = x % y;
if (res > 32767 || res < -32768)
{
result = dst;
cpuSetFlagsVC(TRUE, FALSE);
}
else
{
result = (rem << 16) | (res & 0xffff);
cpuSetFlagsNZVC(cpuIsZeroW((UWO) res), cpuMsbW((UWO) res), FALSE, FALSE);
}
cpuSetDReg(destination_reg, result);
cpuSetInstructionTime(instruction_time);
2013-02-06 04:11:41 +00:00
}
}
/// <summary>
/// Divuw, src1 / src2
/// </summary>
static void cpuDivuW(ULO dst, UWO src1, ULO destination_reg, ULO instruction_time)
2013-02-06 04:11:41 +00:00
{
if (src1 == 0)
{
// Alcatraz odyssey assumes that PC in this exception points after the instruction.
cpuThrowDivisionByZeroException();
2013-02-06 04:11:41 +00:00
}
else
{
ULO result;
2013-02-06 04:11:41 +00:00
ULO x = dst;
ULO y = (ULO) src1;
ULO res = x / y;
ULO rem = x % y;
if (res > 65535)
{
result = dst;
cpuSetFlagsVC(TRUE, FALSE);
}
else
{
result = (rem << 16) | (res & 0xffff);
cpuSetFlagsNZVC(cpuIsZeroW((UWO) res), cpuMsbW((UWO) res), FALSE, FALSE);
}
cpuSetDReg(destination_reg, result);
cpuSetInstructionTime(instruction_time);
2013-02-06 04:11:41 +00:00
}
}
static void cpuDivL(ULO divisor, ULO ext, ULO instruction_time)
2013-02-06 04:11:41 +00:00
{
if (divisor != 0)
{
ULO dq_reg = (ext>>12) & 7; /* Get operand registers, size and sign */
ULO dr_reg = ext & 7;
BOOLE size64 = (ext>>10) & 1;
BOOLE sign = (ext>>11) & 1;
BOOLE resultsigned = FALSE, restsigned = FALSE;
ULL result, rest;
ULL x, y;
LLO x_signed, y_signed;
if (sign)
{
if (size64) x_signed = ((LLO) (LON) cpuGetDReg(dq_reg)) | (((LLO) cpuGetDReg(dr_reg))<<32);
else x_signed = (LLO) (LON) cpuGetDReg(dq_reg);
y_signed = (LLO) (LON) divisor;
if (y_signed < 0)
{
y = (ULL) -y_signed;
resultsigned = !resultsigned;
2013-02-06 04:11:41 +00:00
}
else y = y_signed;
if (x_signed < 0)
{
x = (ULL) -x_signed;
resultsigned = !resultsigned;
restsigned = TRUE;
2013-02-06 04:11:41 +00:00
}
else x = (ULL) x_signed;
}
else
{
if (size64) x = ((ULL) cpuGetDReg(dq_reg)) | (((ULL) cpuGetDReg(dr_reg))<<32);
else x = (ULL) cpuGetDReg(dq_reg);
y = (ULL) divisor;
}
result = x / y;
rest = x % y;
if (sign)
{
if ((resultsigned && result > 0x80000000) || (!resultsigned && result > 0x7fffffff))
{
/* Overflow */
cpuSetFlagsVC(TRUE, FALSE);
2013-02-06 04:11:41 +00:00
}
else
{
LLO result_signed = (resultsigned) ? (-(LLO)result) : ((LLO)result);
LLO rest_signed = (restsigned) ? (-(LLO)rest) : ((LLO)rest);
cpuSetDReg(dr_reg, (ULO) rest_signed);
cpuSetDReg(dq_reg, (ULO) result_signed);
cpuSetFlagsNZ00NewL((ULO) result_signed);
2013-02-06 04:11:41 +00:00
}
}
else
{
if (result > 0xffffffff)
{
/* Overflow */
cpuSetFlagsVC(TRUE, FALSE);
2013-02-06 04:11:41 +00:00
}
else
{
cpuSetDReg(dr_reg, (ULO) rest);
cpuSetDReg(dq_reg, (ULO) result);
cpuSetFlagsNZ00NewL((ULO) result);
2013-02-06 04:11:41 +00:00
}
}
cpuSetInstructionTime(instruction_time);
2013-02-06 04:11:41 +00:00
}
else
{
cpuThrowDivisionByZeroException();
2013-02-06 04:11:41 +00:00
}
}
/// <summary>
/// Lslb
/// </summary>
static UBY cpuLslB(UBY dst, ULO sh, ULO cycles)
{
UBY res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroB(dst), cpuMsbB(dst));
res = dst;
}
else if (sh >= 8)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 8) ? (dst & 1) : FALSE, FALSE);
}
else
{
res = dst << sh;
cpuSetFlagsShift(cpuIsZeroB(res), cpuMsbB(res), dst & (0x80>>(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Lslw
/// </summary>
static UWO cpuLslW(UWO dst, ULO sh, ULO cycles)
{
UWO res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroW(dst), cpuMsbW(dst));
res = dst;
}
else if (sh >= 16)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 16) ? (dst & 1) : FALSE, FALSE);
}
else
{
res = dst << sh;
cpuSetFlagsShift(cpuIsZeroW(res), cpuMsbW(res), dst & (0x8000>>(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Lsll
/// </summary>
static ULO cpuLslL(ULO dst, ULO sh, ULO cycles)
{
ULO res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroL(dst), cpuMsbL(dst));
res = dst;
}
else if (sh >= 32)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 32) ? (dst & 1) : FALSE, FALSE);
}
else
{
res = dst << sh;
cpuSetFlagsShift(cpuIsZeroL(res), cpuMsbL(res), dst & (0x80000000>>(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Lsrb
/// </summary>
static UBY cpuLsrB(UBY dst, ULO sh, ULO cycles)
{
UBY res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroB(dst), cpuMsbB(dst));
res = dst;
}
else if (sh >= 8)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 8) ? cpuMsbB(dst) : FALSE, FALSE);
}
else
{
res = dst >> sh;
cpuSetFlagsShift(cpuIsZeroB(res), FALSE, dst & (1<<(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Lsrw
/// </summary>
static UWO cpuLsrW(UWO dst, ULO sh, ULO cycles)
{
UWO res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroW(dst), cpuMsbW(dst));
res = dst;
}
else if (sh >= 16)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 16) ? cpuMsbW(dst) : FALSE, FALSE);
}
else
{
res = dst >> sh;
cpuSetFlagsShift(cpuIsZeroW(res), FALSE, dst & (1<<(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Lsrl
/// </summary>
static ULO cpuLsrL(ULO dst, ULO sh, ULO cycles)
{
ULO res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroL(dst), cpuMsbL(dst));
res = dst;
}
else if (sh >= 32)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 32) ? cpuMsbL(dst) : FALSE, FALSE);
}
else
{
res = dst >> sh;
cpuSetFlagsShift(cpuIsZeroL(res), FALSE, dst & (1<<(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Aslb
/// </summary>
static UBY cpuAslB(UBY dst, ULO sh, ULO cycles)
{
BYT res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroB(dst), cpuMsbB(dst));
res = (BYT) dst;
}
else if (sh >= 8)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 8) ? (dst & 1) : FALSE, dst != 0);
}
else
{
UBY mask = 0xff << (7-sh);
UBY out = dst & mask;
res = ((BYT)dst) << sh;
// Overflow calculation:
// 1. The msb of the result and original are different
// 2. Or the bits shifted out were not all the same as the msb of the original
BOOLE n_result = cpuMsbB(res);
BOOLE n_original = cpuMsbB(dst);
BOOLE msb_changed = (n_result != n_original) || ((n_original) ? (out != mask) : (out != 0));
cpuSetFlagsShift(cpuIsZeroB(res), n_result, dst & (0x80>>(sh-1)), msb_changed);
2013-02-06 04:11:41 +00:00
}
cpuSetInstructionTime(cycles + sh*2);
return (UBY) res;
}
/// <summary>
/// Aslw
/// </summary>
static UWO cpuAslW(UWO dst, ULO sh, ULO cycles)
{
WOR res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroW(dst), cpuMsbW(dst));
res = (WOR) dst;
}
else if (sh >= 16)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 16) ? (dst & 1) : FALSE, dst != 0);
}
else
{
UWO mask = 0xffff << (15-sh);
UWO out = dst & mask;
res = ((WOR)dst) << sh;
// Overflow calculation:
// 1. The msb of the result and original are different
// 2. Or the bits shifted out were not all the same as the msb of the original
BOOLE n_result = cpuMsbW(res);
BOOLE n_original = cpuMsbW(dst);
BOOLE msb_changed = (n_result != n_original) || ((n_original) ? (out != mask) : (out != 0));
cpuSetFlagsShift(cpuIsZeroW(res), n_result, dst & (0x8000>>(sh-1)), msb_changed);
2013-02-06 04:11:41 +00:00
}
cpuSetInstructionTime(cycles + sh*2);
return (UWO) res;
}
/// <summary>
/// Asll
/// </summary>
static ULO cpuAslL(ULO dst, ULO sh, ULO cycles)
{
LON res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroL(dst), cpuMsbL(dst));
res = (LON) dst;
}
else if (sh >= 32)
{
res = 0;
cpuSetFlagsShift(TRUE, FALSE, (sh == 32) ? (dst & 1) : FALSE, dst != 0);
}
else
{
ULO mask = 0xffffffff << (31-sh);
ULO out = dst & mask;
res = ((LON)dst) << sh;
// Overflow calculation:
// 1. The msb of the result and original are different
// 2. Or the bits shifted out were not all the same as the msb of the original
BOOLE n_result = cpuMsbL(res);
BOOLE n_original = cpuMsbL(dst);
BOOLE msb_changed = (n_result != n_original) || ((n_original) ? (out != mask) : (out != 0));
cpuSetFlagsShift(cpuIsZeroL(res), n_result, dst & (0x80000000>>(sh-1)), msb_changed);
2013-02-06 04:11:41 +00:00
}
cpuSetInstructionTime(cycles + sh*2);
return (ULO) res;
}
/// <summary>
/// Asrb
/// </summary>
static UBY cpuAsrB(UBY dst, ULO sh, ULO cycles)
{
BYT res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroB(dst), cpuMsbB(dst));
res = (BYT) dst;
}
else if (sh >= 8)
{
res = (cpuMsbB(dst)) ? 0xff : 0;
cpuSetFlagsShift(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(res), FALSE);
}
else
{
res = ((BYT)dst) >> sh;
cpuSetFlagsShift(cpuIsZeroB(res), cpuMsbB(res), dst & (1<<(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return (UBY) res;
}
/// <summary>
/// Asrw
/// </summary>
static UWO cpuAsrW(UWO dst, ULO sh, ULO cycles)
{
WOR res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroW(dst), cpuMsbW(dst));
res = (WOR) dst;
}
else if (sh >= 16)
{
res = (cpuMsbW(dst)) ? 0xffff : 0;
cpuSetFlagsShift(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(res), FALSE);
}
else
{
res = ((WOR)dst) >> sh;
cpuSetFlagsShift(cpuIsZeroW(res), cpuMsbW(res), dst & (1<<(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return (UWO) res;
}
/// <summary>
/// Asrl
/// </summary>
static ULO cpuAsrL(ULO dst, ULO sh, ULO cycles)
{
LON res;
sh &= 0x3f;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroL(dst), cpuMsbL(dst));
res = (LON) dst;
}
else if (sh >= 32)
{
res = (cpuMsbL(dst)) ? 0xffffffff : 0;
cpuSetFlagsShift(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(res), FALSE);
}
else
{
res = ((LON)dst) >> sh;
cpuSetFlagsShift(cpuIsZeroL(res), cpuMsbL(res), dst & (1<<(sh-1)), FALSE);
}
cpuSetInstructionTime(cycles + sh*2);
return (ULO) res;
}
/// <summary>
/// Rolb
/// </summary>
static UBY cpuRolB(UBY dst, ULO sh, ULO cycles)
{
UBY res;
sh &= 0x3f;
cycles += sh*2;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroB(dst), cpuMsbB(dst));
res = dst;
}
else
{
sh &= 7;
res = (dst << sh) | (dst >> (8-sh));
cpuSetFlagsRotate(cpuIsZeroB(res), cpuMsbB(res), res & 1);
}
cpuSetInstructionTime(cycles);
return res;
}
/// <summary>
/// Rolw
/// </summary>
static UWO cpuRolW(UWO dst, ULO sh, ULO cycles)
{
UWO res;
sh &= 0x3f;
cycles += sh*2;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroW(dst), cpuMsbW(dst));
res = dst;
}
else
{
sh &= 15;
res = (dst << sh) | (dst >> (16-sh));
cpuSetFlagsRotate(cpuIsZeroW(res), cpuMsbW(res), res & 1);
}
cpuSetInstructionTime(cycles);
return res;
}
/// <summary>
/// Roll
/// </summary>
static ULO cpuRolL(ULO dst, ULO sh, ULO cycles)
{
ULO res;
sh &= 0x3f;
cycles += sh*2;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroL(dst), cpuMsbL(dst));
res = dst;
}
else
{
sh &= 31;
res = (dst << sh) | (dst >> (32-sh));
cpuSetFlagsRotate(cpuIsZeroL(res), cpuMsbL(res), res & 1);
}
cpuSetInstructionTime(cycles);
return res;
}
/// <summary>
/// Rorb
/// </summary>
static UBY cpuRorB(UBY dst, ULO sh, ULO cycles)
{
UBY res;
sh &= 0x3f;
cycles += sh*2;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroB(dst), cpuMsbB(dst));
res = dst;
}
else
{
sh &= 7;
res = (dst >> sh) | (dst << (8-sh));
cpuSetFlagsRotate(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(res));
}
cpuSetInstructionTime(cycles);
return res;
}
/// <summary>
/// Rorw
/// </summary>
static UWO cpuRorW(UWO dst, ULO sh, ULO cycles)
{
UWO res;
sh &= 0x3f;
cycles += sh*2;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroW(dst), cpuMsbW(dst));
res = dst;
}
else
{
sh &= 15;
res = (dst >> sh) | (dst << (16-sh));
cpuSetFlagsRotate(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(res));
}
cpuSetInstructionTime(cycles);
return res;
}
/// <summary>
/// Rorl
/// </summary>
static ULO cpuRorL(ULO dst, ULO sh, ULO cycles)
{
ULO res;
sh &= 0x3f;
cycles += sh*2;
if (sh == 0)
{
cpuSetFlagsShiftZero(cpuIsZeroL(dst), cpuMsbL(dst));
res = dst;
}
else
{
sh &= 31;
res = (dst >> sh) | (dst << (32-sh));
cpuSetFlagsRotate(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(res));
}
cpuSetInstructionTime(cycles);
return res;
}
/// <summary>
/// Roxlb
/// </summary>
static UBY cpuRoxlB(UBY dst, ULO sh, ULO cycles)
{
BOOLE x = cpuGetFlagX();
BOOLE x_temp;
UBY res = dst;
ULO i;
sh &= 0x3f;
for (i = 0; i < sh; ++i)
{
x_temp = cpuMsbB(res);
res = (res << 1) | ((x) ? 1:0);
x = x_temp;
}
cpuSetFlagsRotateX(cpuGetZFlagB(res), cpuGetNFlagB(res), (x) ? 0x11 : 0);
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Roxlw
/// </summary>
static UWO cpuRoxlW(UWO dst, ULO sh, ULO cycles)
{
BOOLE x = cpuGetFlagX();
BOOLE x_temp;
UWO res = dst;
ULO i;
sh &= 0x3f;
for (i = 0; i < sh; ++i)
{
x_temp = cpuMsbW(res);
res = (res << 1) | ((x) ? 1:0);
x = x_temp;
}
cpuSetFlagsRotateX(cpuGetZFlagW(res), cpuGetNFlagW(res), (x) ? 0x11 : 0);
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Roxll
/// </summary>
static ULO cpuRoxlL(ULO dst, ULO sh, ULO cycles)
{
BOOLE x = cpuGetFlagX();
BOOLE x_temp;
ULO res = dst;
ULO i;
sh &= 0x3f;
for (i = 0; i < sh; ++i)
{
x_temp = cpuMsbL(res);
res = (res << 1) | ((x) ? 1:0);
x = x_temp;
}
cpuSetFlagsRotateX(cpuGetZFlagL(res), cpuGetNFlagL(res), (x) ? 0x11 : 0);
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Roxrb
/// </summary>
static UBY cpuRoxrB(UBY dst, ULO sh, ULO cycles)
{
BOOLE x = cpuGetFlagX();
BOOLE x_temp;
UBY res = dst;
ULO i;
sh &= 0x3f;
for (i = 0; i < sh; ++i)
{
x_temp = res & 1;
res = (res >> 1) | ((x) ? 0x80:0);
x = x_temp;
}
cpuSetFlagsRotateX(cpuGetZFlagB(res), cpuGetNFlagB(res), (x) ? 0x11 : 0);
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Roxrw
/// </summary>
static UWO cpuRoxrW(UWO dst, ULO sh, ULO cycles)
{
BOOLE x = cpuGetFlagX();
BOOLE x_temp;
UWO res = dst;
ULO i;
sh &= 0x3f;
for (i = 0; i < sh; ++i)
{
x_temp = res & 1;
res = (res >> 1) | ((x) ? 0x8000:0);
x = x_temp;
}
cpuSetFlagsRotateX(cpuGetZFlagW(res), cpuGetNFlagW(res), (x) ? 0x11 : 0);
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Roxrl
/// </summary>
static ULO cpuRoxrL(ULO dst, ULO sh, ULO cycles)
{
BOOLE x = cpuGetFlagX();
BOOLE x_temp;
ULO res = dst;
ULO i;
sh &= 0x3f;
for (i = 0; i < sh; ++i)
{
x_temp = res & 1;
res = (res >> 1) | ((x) ? 0x80000000:0);
x = x_temp;
}
cpuSetFlagsRotateX(cpuGetZFlagL(res), cpuGetNFlagL(res), (x) ? 0x11 : 0);
cpuSetInstructionTime(cycles + sh*2);
return res;
}
/// <summary>
/// Stop
/// </summary>
static void cpuStop(UWO flags)
{
if (cpuGetFlagSupervisor())
{
cpuSetStop(TRUE);
cpuUpdateSr(flags);
cpuSetInstructionTime(4);
}
else
{
cpuThrowPrivilegeViolationException();
}
}
/// <summary>
/// Reset
/// </summary>
static void cpuReset()
{
cpuCallResetExceptionFunc();
cpuSetInstructionTime(132);
}
/// <summary>
/// Rtd
/// </summary>
static void cpuRtd()
{
ULO displacement = cpuGetNextWordSignExt();
cpuInitializeFromNewPC(memoryReadLong(cpuGetAReg(7)));
2013-02-06 04:11:41 +00:00
cpuSetAReg(7, cpuGetAReg(7) + 4 + displacement);
cpuSetInstructionTime(4);
}
static ULO cpuRteStackInc[16] = {0, 0, 4, 4, 8, 0, 0, 52, 50, 10, 24, 84, 16, 18, 0, 0};
/// <summary>
/// Rte
/// </summary>
static void cpuRte()
{
if (cpuGetFlagSupervisor())
{
BOOLE redo = TRUE;
UWO newsr;
do
{
newsr = memoryReadWord(cpuGetAReg(7));
cpuSetAReg(7, cpuGetAReg(7) + 2);
cpuInitializeFromNewPC(memoryReadLong(cpuGetAReg(7)));
cpuSetAReg(7, cpuGetAReg(7) + 4);
if (cpuGetModelMajor() > 0)
{
ULO frame_type = (memoryReadWord(cpuGetAReg(7)) >> 12) & 0xf;
cpuSetAReg(7, cpuGetAReg(7) + 2);
cpuSetAReg(7, cpuGetAReg(7) + cpuRteStackInc[frame_type]);
redo = (frame_type == 1 && cpuGetModelMajor() >= 2 && cpuGetModelMajor() < 6);
2013-02-06 04:11:41 +00:00
}
else redo = FALSE;
cpuUpdateSr(newsr); // Because we can go from isp to msp here.
} while (redo);
}
else
{
cpuThrowPrivilegeViolationException();
}
cpuSetInstructionTime(20);
}
/// <summary>
/// Swap
/// </summary>
static void cpuSwap(ULO reg)
{
ULO res = cpuJoinWordToLong((UWO)cpuGetDReg(reg), (UWO) (cpuGetDReg(reg) >> 16));
cpuSetDReg(reg, res);
cpuSetFlagsNZ00NewL(res);
cpuSetInstructionTime(4);
}
/// <summary>
/// Unlk
/// </summary>
static void cpuUnlk(ULO reg)
{
cpuSetAReg(7, cpuGetAReg(reg));
cpuSetAReg(reg, memoryReadLong(cpuGetAReg(7)));
cpuSetAReg(7, cpuGetAReg(7) + 4);
cpuSetInstructionTime(12);
}
/// <summary>
/// Link
/// </summary>
static void cpuLinkW(ULO reg)
{
ULO disp = cpuGetNextWordSignExt();
cpuSetAReg(7, cpuGetAReg(7) - 4);
memoryWriteLong(cpuGetAReg(reg), cpuGetAReg(7));
cpuSetAReg(reg, cpuGetAReg(7));
cpuSetAReg(7, cpuGetAReg(7) + disp);
cpuSetInstructionTime(16);
}
/// <summary>
/// Link.
/// 68020, 68030 and 68040 only.
/// </summary>
static void cpuLinkL(ULO reg)
{
ULO disp = cpuGetNextLong();
cpuSetAReg(7, cpuGetAReg(7) - 4);
memoryWriteLong(cpuGetAReg(reg), cpuGetAReg(7));
cpuSetAReg(reg, cpuGetAReg(7));
cpuSetAReg(7, cpuGetAReg(7) + disp);
cpuSetInstructionTime(4);
}
/// <summary>
/// Ext.w (byte to word)
/// </summary>
static void cpuExtW(ULO reg)
{
UWO res = cpuGetDRegByteSignExtWord(reg);
cpuSetDRegWord(reg, res);
cpuSetFlagsNZ00NewW(res);
cpuSetInstructionTime(4);
}
/// <summary>
/// Ext.l (word to long)
/// </summary>
static void cpuExtL(ULO reg)
{
ULO res = cpuGetDRegWordSignExtLong(reg);
cpuSetDReg(reg, res);
cpuSetFlagsNZ00NewL(res);
cpuSetInstructionTime(4);
}
/// <summary>
/// ExtB.l (byte to long) (020+)
/// </summary>
static void cpuExtBL(ULO reg)
{
ULO res = cpuGetDRegByteSignExtLong(reg);
cpuSetDReg(reg, res);
cpuSetFlagsNZ00NewL(res);
cpuSetInstructionTime(4);
}
/// <summary>
/// Exg Rx,Ry
/// </summary>
static void cpuExgAll(ULO reg1_type, ULO reg1, ULO reg2_type, ULO reg2)
{
ULO tmp = cpuGetReg(reg1_type, reg1);
cpuSetReg(reg1_type, reg1, cpuGetReg(reg2_type, reg2));
cpuSetReg(reg2_type, reg2, tmp);
cpuSetInstructionTime(6);
}
/// <summary>
/// Exg Dx,Dy
/// </summary>
static void cpuExgDD(ULO reg1, ULO reg2)
{
cpuExgAll(0, reg1, 0, reg2);
}
/// <summary>
/// Exg Ax,Ay
/// </summary>
static void cpuExgAA(ULO reg1, ULO reg2)
{
cpuExgAll(1, reg1, 1, reg2);
}
/// <summary>
/// Exg Dx,Ay
/// </summary>
static void cpuExgDA(ULO reg1, ULO reg2)
{
cpuExgAll(0, reg1, 1, reg2);
}
/// <summary>
/// Movem.w regs, -(Ax)
/// Order: d0-d7,a0-a7 a7 first
/// </summary>
static void cpuMovemwPre(UWO regs, ULO reg)
{
ULO cycles = 8;
ULO dstea = cpuGetAReg(reg);
ULO index = 1;
LON i, j;
BOOLE ea_reg_seen = FALSE;
ULO ea_reg_ea = 0;
i = 1;
for (j = 7; j >= 0; j--)
{
if (regs & index)
{
dstea -= 2;
if (cpuGetModelMajor() >= 2 && j == reg)
{
ea_reg_seen = TRUE;
ea_reg_ea = dstea;
2013-02-06 04:11:41 +00:00
}
else
{
memoryWriteWord(cpuGetRegWord(i, j), dstea);
2013-02-06 04:11:41 +00:00
}
cycles += 4;
}
index = index << 1;
}
i = 0;
for (j = 7; j >= 0; j--)
{
if (regs & index)
{
dstea -= 2;
memoryWriteWord(cpuGetRegWord(i, j), dstea);
cycles += 4;
}
index = index << 1;
}
if (ea_reg_seen)
{
memoryWriteWord((UWO)dstea, ea_reg_ea);
}
cpuSetAReg(reg, dstea);
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Movem.l regs, -(Ax)
/// Order: d0-d7,a0-a7 a7 first
/// </summary>
static void cpuMovemlPre(UWO regs, ULO reg)
{
ULO cycles = 8;
ULO dstea = cpuGetAReg(reg);
ULO index = 1;
LON i, j;
BOOLE ea_reg_seen = FALSE;
ULO ea_reg_ea = 0;
i = 1;
for (j = 7; j >= 0; j--)
{
if (regs & index)
{
dstea -= 4;
if (cpuGetModelMajor() >= 2 && j == reg)
{
ea_reg_seen = TRUE;
ea_reg_ea = dstea;
2013-02-06 04:11:41 +00:00
}
else
{
memoryWriteLong(cpuGetReg(i, j), dstea);
2013-02-06 04:11:41 +00:00
}
cycles += 8;
}
index = index << 1;
}
i = 0;
for (j = 7; j >= 0; j--)
{
if (regs & index)
{
dstea -= 4;
memoryWriteLong(cpuGetReg(i, j), dstea);
cycles += 8;
}
index = index << 1;
}
if (ea_reg_seen)
{
memoryWriteLong(dstea, ea_reg_ea);
}
cpuSetAReg(reg, dstea);
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Movem.w (Ax)+, regs
/// Order: a7-a0,d7-d0 d0 first
/// </summary>
static void cpuMovemwPost(UWO regs, ULO reg)
{
ULO cycles = 12;
ULO dstea = cpuGetAReg(reg);
ULO index = 1;
ULO i, j;
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 8; ++j)
{
if (regs & index)
{
// Each word, for both data and address registers, is sign-extended before stored.
cpuSetReg(i, j, (ULO)(LON)(WOR) memoryReadWord(dstea));
dstea += 2;
cycles += 4;
2013-02-06 04:11:41 +00:00
}
index = index << 1;
}
}
cpuSetAReg(reg, dstea);
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Movem.l (Ax)+, regs
/// Order: a7-a0,d7-d0 d0 first
/// </summary>
static void cpuMovemlPost(UWO regs, ULO reg)
{
ULO cycles = 12;
ULO dstea = cpuGetAReg(reg);
ULO index = 1;
ULO i, j;
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 8; ++j)
{
if (regs & index)
{
cpuSetReg(i, j, memoryReadLong(dstea));
dstea += 4;
cycles += 8;
2013-02-06 04:11:41 +00:00
}
index = index << 1;
}
}
cpuSetAReg(reg, dstea);
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Movem.w <Control>, regs
/// Order: a7-a0,d7-d0 d0 first
/// </summary>
static void cpuMovemwEa2R(UWO regs, ULO ea, ULO eacycles)
{
ULO cycles = eacycles;
ULO dstea = ea;
ULO index = 1;
ULO i, j;
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 8; ++j)
{
if (regs & index)
{
// Each word, for both data and address registers, is sign-extended before stored.
cpuSetReg(i, j, (ULO)(LON)(WOR) memoryReadWord(dstea));
dstea += 2;
cycles += 4;
2013-02-06 04:11:41 +00:00
}
index = index << 1;
}
}
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Movem.l <Control>, regs
/// Order: a7-a0,d7-d0 d0 first
/// </summary>
static void cpuMovemlEa2R(UWO regs, ULO ea, ULO eacycles)
{
ULO cycles = eacycles;
ULO dstea = ea;
ULO index = 1;
ULO i, j;
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 8; ++j)
{
if (regs & index)
{
cpuSetReg(i, j, memoryReadLong(dstea));
dstea += 4;
cycles += 8;
2013-02-06 04:11:41 +00:00
}
index = index << 1;
}
}
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Movem.w regs, <Control>
/// Order: a7-a0,d7-d0 d0 first
/// </summary>
static void cpuMovemwR2Ea(UWO regs, ULO ea, ULO eacycles)
{
ULO cycles = eacycles;
ULO dstea = ea;
ULO index = 1;
ULO i, j;
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 8; ++j)
{
if (regs & index)
{
memoryWriteWord(cpuGetRegWord(i, j), dstea);
dstea += 2;
cycles += 4;
2013-02-06 04:11:41 +00:00
}
index = index << 1;
}
}
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Movem.l regs, <Control>
/// Order: a7-a0,d7-d0 d0 first
/// </summary>
static void cpuMovemlR2Ea(UWO regs, ULO ea, ULO eacycles)
{
ULO cycles = eacycles;
ULO dstea = ea;
ULO index = 1;
ULO i, j;
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 8; ++j)
{
if (regs & index)
{
memoryWriteLong(cpuGetReg(i, j), dstea);
dstea += 4;
cycles += 8;
2013-02-06 04:11:41 +00:00
}
index = index << 1;
}
}
cpuSetInstructionTime(cycles);
}
/// <summary>
/// Trap #vectorno
/// </summary>
static void cpuTrap(ULO vectorno)
{
// PC written to the exception frame must be pc + 2, the address of the next instruction.
cpuThrowTrapException(vectorno);
}
/// <summary>
/// move.l Ax,Usp
/// </summary>
static void cpuMoveToUsp(ULO reg)
{
if (cpuGetFlagSupervisor())
{
// In supervisor mode, usp does not affect a7
cpuSetUspDirect(cpuGetAReg(reg));
cpuSetInstructionTime(4);
}
else
{
cpuThrowPrivilegeViolationException();
}
}
/// <summary>
/// move.l Usp,Ax
/// </summary>
static void cpuMoveFromUsp(ULO reg)
{
if (cpuGetFlagSupervisor())
{
// In supervisor mode, usp is up to date
cpuSetAReg(reg, cpuGetUspDirect());
cpuSetInstructionTime(4);
}
else
{
cpuThrowPrivilegeViolationException();
}
}
/// <summary>
/// cmp.b (Ay)+,(Ax)+
/// </summary>
static void cpuCmpMB(ULO regx, ULO regy)
{
UBY src = memoryReadByte(cpuEA03(regy, 1));
UBY dst = memoryReadByte(cpuEA03(regx, 1));
UBY res = dst - src;
cpuSetFlagsCmp(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(dst), cpuMsbB(src));
cpuSetInstructionTime(12);
}
/// <summary>
/// cmp.w (Ay)+,(Ax)+
/// </summary>
static void cpuCmpMW(ULO regx, ULO regy)
{
UWO src = memoryReadWord(cpuEA03(regy, 2));
UWO dst = memoryReadWord(cpuEA03(regx, 2));
UWO res = dst - src;
cpuSetFlagsCmp(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(dst), cpuMsbW(src));
cpuSetInstructionTime(12);
}
/// <summary>
/// cmp.l (Ay)+,(Ax)+
/// </summary>
static void cpuCmpML(ULO regx, ULO regy)
{
ULO src = memoryReadLong(cpuEA03(regy, 4));
ULO dst = memoryReadLong(cpuEA03(regx, 4));
ULO res = dst - src;
cpuSetFlagsCmp(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(dst), cpuMsbL(src));
cpuSetInstructionTime(20);
}
/// <summary>
/// chk.w Dx, ea
/// Undocumented features:
/// Z is set from the register operand,
/// V and C is always cleared.
/// </summary>
static void cpuChkW(UWO value, UWO ub)
{
cpuSetFlagZ(value == 0);
cpuClearFlagsVC();
2013-02-06 04:11:41 +00:00
if (((WOR)value) < 0)
{
cpuSetFlagN(TRUE);
cpuThrowChkException();
}
else if (((WOR)value) > ((WOR)ub))
{
cpuSetFlagN(FALSE);
cpuThrowChkException();
}
}
/// <summary>
/// chk.l Dx, ea
/// 68020+
/// Undocumented features:
/// Z is set from the register operand,
/// V and C is always cleared.
/// </summary>
static void cpuChkL(ULO value, ULO ub)
{
cpuSetFlagZ(value == 0);
cpuClearFlagsVC();
2013-02-06 04:11:41 +00:00
if (((LON)value) < 0)
{
cpuSetFlagN(TRUE);
cpuThrowChkException();
}
else if (((LON)value) > ((LON)ub))
{
cpuSetFlagN(FALSE);
cpuThrowChkException();
}
}
/// <summary>
/// addx.b dx,dy
/// </summary>
static UBY cpuAddXB(UBY dst, UBY src)
{
UBY res = dst + src + ((cpuGetFlagX()) ? 1:0);
cpuSetFlagsAddX(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(dst), cpuMsbB(src));
return res;
}
/// <summary>
/// addx.w dx,dy
/// </summary>
static UWO cpuAddXW(UWO dst, UWO src)
{
UWO res = dst + src + ((cpuGetFlagX()) ? 1:0);
cpuSetFlagsAddX(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(dst), cpuMsbW(src));
return res;
}
/// <summary>
/// addx.l dx,dy
/// </summary>
static ULO cpuAddXL(ULO dst, ULO src)
{
ULO res = dst + src + ((cpuGetFlagX()) ? 1:0);
cpuSetFlagsAddX(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(dst), cpuMsbL(src));
return res;
}
/// <summary>
/// subx.b dx,dy
/// </summary>
static UBY cpuSubXB(UBY dst, UBY src)
{
UBY res = dst - src - ((cpuGetFlagX()) ? 1:0);
cpuSetFlagsSubX(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(dst), cpuMsbB(src));
return res;
}
/// <summary>
/// subx.w dx,dy
/// </summary>
static UWO cpuSubXW(UWO dst, UWO src)
{
UWO res = dst - src - ((cpuGetFlagX()) ? 1:0);
cpuSetFlagsSubX(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(dst), cpuMsbW(src));
return res;
}
/// <summary>
/// subx.l dx,dy
/// </summary>
static ULO cpuSubXL(ULO dst, ULO src)
{
ULO res = dst - src - ((cpuGetFlagX()) ? 1:0);
cpuSetFlagsSubX(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(dst), cpuMsbL(src));
return res;
}
/// <summary>
/// abcd.b src,dst
/// Implemented using the information from:
/// 68000 Undocumented Behavior Notes
/// Fourth Edition
/// by Bart Trzynadlowski, May 12, 2003
/// </summary>
static UBY cpuAbcdB(UBY dst, UBY src)
{
UBY xflag = (cpuGetFlagX()) ? 1 : 0;
UWO low_nibble = (dst & 0xf) + (src & 0xf) + xflag;
UWO high_nibble = ((UWO)(dst & 0xf0)) + ((UWO)(src & 0xf0));
UWO result_unadjusted = low_nibble + high_nibble;
UWO result_bcd = result_unadjusted;
2013-02-06 04:11:41 +00:00
if (low_nibble > 9)
{
result_bcd += 6;
2013-02-06 04:11:41 +00:00
}
BOOLE xc_flags = (result_bcd & 0xfff0) > 0x90;
cpuSetFlagXC(xc_flags);
if (xc_flags)
2013-02-06 04:11:41 +00:00
{
result_bcd += 0x60;
2013-02-06 04:11:41 +00:00
}
if (result_bcd & 0xff)
2013-02-06 04:11:41 +00:00
{
cpuSetFlagZ(FALSE);
}
if (cpuGetModelMajor() < 4) // 040 apparently does not set these flags
2013-02-06 04:11:41 +00:00
{
cpuSetFlagN(result_bcd & 0x80);
cpuSetFlagV(((result_unadjusted & 0x80) == 0) && (result_bcd & 0x80));
2013-02-06 04:11:41 +00:00
}
return (UBY)result_bcd;
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// sbcd.b src,dst
/// nbcd.b src (set dst=0)
/// Implemented using the information from:
/// 68000 Undocumented Behavior Notes
/// Fourth Edition
/// by Bart Trzynadlowski, May 12, 2003
/// </summary>
static UBY cpuSbcdB(UBY dst, UBY src)
{
UWO xflag = (cpuGetFlagX()) ? 1:0;
UWO result_plain_binary = (UWO)dst - (UWO)src - xflag;
UWO low_nibble = (UWO)(dst & 0xf) - (UWO)(src & 0xf) - xflag;
UWO high_nibble = ((UWO)(dst & 0xf0)) - ((UWO)(src & 0xf0));
UWO result_unadjusted = low_nibble + high_nibble;
UWO result_bcd = result_unadjusted;
2013-02-06 04:11:41 +00:00
if ((WOR)result_plain_binary < 0)
2013-02-06 04:11:41 +00:00
{
result_bcd -= 0x60;
2013-02-06 04:11:41 +00:00
}
if (((WOR)low_nibble) < 0)
2013-02-06 04:11:41 +00:00
{
result_bcd -= 6;
result_plain_binary -= 6;
2013-02-06 04:11:41 +00:00
}
BOOLE borrow = ((WOR)result_plain_binary < 0);
cpuSetFlagXC(borrow);
if (result_bcd & 0xff)
2013-02-06 04:11:41 +00:00
{
cpuSetFlagZ(FALSE);
}
if (cpuGetModelMajor() < 4)
2013-02-06 04:11:41 +00:00
{
cpuSetFlagN(result_bcd & 0x80);
cpuSetFlagV(((result_unadjusted & 0x80) == 0x80) && !(result_bcd & 0x80));
2013-02-06 04:11:41 +00:00
}
return (UBY) result_bcd;
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// nbcd.b dst
/// </summary>
static UBY cpuNbcdB(UBY dst)
{
return cpuSbcdB(0, dst);
}
// Bit field functions
struct cpuBfData
2013-02-06 04:11:41 +00:00
{
LON offset;
ULO width;
ULO normalized_offset;
2013-02-06 04:11:41 +00:00
ULO base_address;
LON base_address_byte_offset;
ULO base_address_byte_count;
2013-02-06 04:11:41 +00:00
ULO field;
ULL field_mask;
ULO dn;
ULL field_memory;
};
2013-02-06 04:11:41 +00:00
static LON cpuGetBfOffset(UWO ext, bool offsetIsDataRegister)
2013-02-06 04:11:41 +00:00
{
LON offset = (ext >> 6) & 0x1f;
if (offsetIsDataRegister)
2013-02-06 04:11:41 +00:00
{
offset = (LON) cpuGetDReg(offset & 7);
}
return offset;
}
static ULO cpuGetBfWidth(UWO ext, bool widthIsDataRegister)
2013-02-06 04:11:41 +00:00
{
ULO width = (ext & 0x1f);
if (widthIsDataRegister)
2013-02-06 04:11:41 +00:00
{
width = cpuGetDReg(width & 7) & 0x1f;
2013-02-06 04:11:41 +00:00
}
if (width == 0)
{
width = 32;
}
return width;
}
static void cpuSetBfField(struct cpuBfData *bf_data, ULO ea_or_reg, bool has_ea)
2013-02-06 04:11:41 +00:00
{
if (has_ea)
2013-02-06 04:11:41 +00:00
{
ULO shift = bf_data->base_address_byte_count*8 - bf_data->normalized_offset - bf_data->width;
ULL field_value = (bf_data->field_memory & ~(bf_data->field_mask << shift)) | (bf_data->field << shift);
ULO address = bf_data->base_address + bf_data->base_address_byte_offset;
2013-02-06 04:11:41 +00:00
for (int i = bf_data->base_address_byte_count - 1; i >= 0; --i)
{
UBY field_byte = (field_value >> (i*8)) & 0xff;
memoryWriteByte(field_byte, address);
++address;
}
2013-02-06 04:11:41 +00:00
}
else
2013-02-06 04:11:41 +00:00
{
ULO reg_shift = (32 - bf_data->offset - bf_data->width);
ULO reg_value = (cpuGetDReg(ea_or_reg) & ~(bf_data->field_mask << reg_shift)) | (bf_data->field << reg_shift);
cpuSetDReg(ea_or_reg, reg_value);
2013-02-06 04:11:41 +00:00
}
}
void cpuBfDecodeExtWordAndGetField(struct cpuBfData *bf_data, ULO ea_or_reg, bool has_dn, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
bool offsetIsDataRegister = ((ext & 0x0800) == 0x0800);
bool widthIsDataRegister = ((ext & 0x0020) == 0x0020);
2013-02-06 04:11:41 +00:00
bf_data->offset = cpuGetBfOffset(ext, offsetIsDataRegister);
bf_data->width = cpuGetBfWidth(ext, widthIsDataRegister);
2013-02-06 04:11:41 +00:00
bf_data->field_mask = 0xffffffff >> (32 - bf_data->width);
2013-02-06 04:11:41 +00:00
if (has_dn)
{
bf_data->dn = (ext & 0x7000) >> 12;
2013-02-06 04:11:41 +00:00
}
2013-02-06 04:11:41 +00:00
if (has_ea)
{
bf_data->base_address = ea_or_reg; // Base address of the field, before offset is applied
bf_data->base_address_byte_offset = (bf_data->offset >> 3); // The first byte in the field
bf_data->normalized_offset = bf_data->offset - (bf_data->base_address_byte_offset)*8; // Offset relative to the first byte in the field
bf_data->base_address_byte_count = (bf_data->normalized_offset + bf_data->width + 7) / 8;
ULO field = 0;
ULL field_memory = 0;
ULO address = bf_data->base_address + bf_data->base_address_byte_offset;
ULO shift = (8 - bf_data->normalized_offset - bf_data->width) & 7;
for (int i = bf_data->base_address_byte_count - 1; i >= 0; --i)
{
ULL value = ((ULL)memoryReadByte(address)) << (8 * i);
field_memory |= value;
field |= (value >> shift);
++address;
}
bf_data->field_memory = field_memory;
bf_data->field = field;
2013-02-06 04:11:41 +00:00
}
else
{
bf_data->field = cpuGetDReg(ea_or_reg) >> (32 - bf_data->offset - bf_data->width);
2013-02-06 04:11:41 +00:00
}
bf_data->field &= bf_data->field_mask;
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfchg common logic
/// </summary>
static void cpuBfChgCommon(ULO ea_or_reg, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
cpuBfDecodeExtWordAndGetField(&bf_data, ea_or_reg, false, has_ea, ext);
2013-02-06 04:11:41 +00:00
cpuSetFlagsNZVC(bf_data.field == 0, bf_data.field & (1 << (bf_data.width - 1)), FALSE, FALSE);
bf_data.field = (~bf_data.field) & bf_data.field_mask;
cpuSetBfField(&bf_data, ea_or_reg, has_ea);
2013-02-06 04:11:41 +00:00
}
// bfchg dx {offset:width}
2013-02-06 04:11:41 +00:00
static void cpuBfChgReg(ULO regno, UWO ext)
{
cpuBfChgCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfchg ea {offset:width}
/// </summary>
static void cpuBfChgEa(ULO ea, UWO ext)
{
cpuBfChgCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfclr common logic
/// </summary>
static void cpuBfClrCommon(ULO ea_or_reg, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
cpuBfDecodeExtWordAndGetField(&bf_data, ea_or_reg, false, has_ea, ext);
2013-02-06 04:11:41 +00:00
cpuSetFlagsNZVC(bf_data.field == 0, bf_data.field & (1 << (bf_data.width - 1)), FALSE, FALSE);
bf_data.field = 0;
cpuSetBfField(&bf_data, ea_or_reg, has_ea);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfclr dx {offset:width}
/// </summary>
static void cpuBfClrReg(ULO regno, UWO ext)
{
cpuBfClrCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfclr ea {offset:width}
/// </summary>
static void cpuBfClrEa(ULO ea, UWO ext)
{
cpuBfClrCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfexts common logic
/// </summary>
static void cpuBfExtsCommon(ULO ea_or_reg, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
BOOLE n_flag;
cpuBfDecodeExtWordAndGetField(&bf_data, ea_or_reg, true, has_ea, ext);
2013-02-06 04:11:41 +00:00
n_flag = bf_data.field & (1 << (bf_data.width - 1));
2013-02-06 04:11:41 +00:00
cpuSetFlagsNZVC(bf_data.field == 0, n_flag, FALSE, FALSE);
2013-02-06 04:11:41 +00:00
if (n_flag)
{
bf_data.field = (ULO)((~bf_data.field_mask) | bf_data.field);
2013-02-06 04:11:41 +00:00
}
// Destination is always Dn
2013-02-06 04:11:41 +00:00
cpuSetDReg(bf_data.dn, bf_data.field);
}
/// <summary>
/// bfexts dx {offset:width}, Dn
/// </summary>
static void cpuBfExtsReg(ULO regno, UWO ext)
{
cpuBfExtsCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfexts ea {offset:width}, Dn
/// </summary>
static void cpuBfExtsEa(ULO ea, UWO ext)
{
cpuBfExtsCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfextu ea {offset:width}, Dn
/// </summary>
static void cpuBfExtuCommon(ULO ea_or_reg, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
cpuBfDecodeExtWordAndGetField(&bf_data, ea_or_reg, true, has_ea, ext);
2013-02-06 04:11:41 +00:00
cpuSetFlagsNZVC(bf_data.field == 0, bf_data.field & (1 << (bf_data.width - 1)), FALSE, FALSE);
// Destination is always Dn
2013-02-06 04:11:41 +00:00
cpuSetDReg(bf_data.dn, bf_data.field);
}
/// <summary>
/// bfextu dx {offset:width}, Dn
/// </summary>
static void cpuBfExtuReg(ULO regno, UWO ext)
{
cpuBfExtuCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfextu ea {offset:width}, Dn
/// </summary>
static void cpuBfExtuEa(ULO ea, UWO ext)
{
cpuBfExtuCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfffo common logic
/// </summary>
static void cpuBfFfoCommon(ULO val, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
ULO i;
cpuBfDecodeExtWordAndGetField(&bf_data, val, true, has_ea, ext);
2013-02-06 04:11:41 +00:00
cpuSetFlagsNZVC(bf_data.field == 0, bf_data.field & (1 << (bf_data.width - 1)), FALSE, FALSE);
2013-02-06 04:11:41 +00:00
for (i = 0; i < bf_data.width; ++i)
{
if (bf_data.field & (1 << (bf_data.width - i - 1)))
2013-02-06 04:11:41 +00:00
break;
}
cpuSetDReg(bf_data.dn, bf_data.offset + i);
}
/// <summary>
/// bfffo dx {offset:width}, Dn
/// </summary>
static void cpuBfFfoReg(ULO regno, UWO ext)
{
cpuBfFfoCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfffo ea {offset:width}, Dn
/// </summary>
static void cpuBfFfoEa(ULO ea, UWO ext)
{
cpuBfFfoCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfins common logic
/// </summary>
static void cpuBfInsCommon(ULO ea_or_reg, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
cpuBfDecodeExtWordAndGetField(&bf_data, ea_or_reg, true, has_ea, ext);
2013-02-06 04:11:41 +00:00
bf_data.field = cpuGetDReg(bf_data.dn) & bf_data.field_mask;
// Flags are set according to the inserted value
cpuSetFlagsNZVC(bf_data.field == 0, bf_data.field & (1 << (bf_data.width - 1)), FALSE, FALSE);
cpuSetBfField(&bf_data, ea_or_reg, has_ea);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfins Dn, ea {offset:width}
/// </summary>
static void cpuBfInsReg(ULO regno, UWO ext)
{
cpuBfInsCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfins Dn, ea {offset:width}
/// </summary>
static void cpuBfInsEa(ULO ea, UWO ext)
{
cpuBfInsCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfset common logic
/// </summary>
static void cpuBfSetCommon(ULO ea_or_reg, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
cpuBfDecodeExtWordAndGetField(&bf_data, ea_or_reg, false, has_ea, ext);
2013-02-06 04:11:41 +00:00
cpuSetFlagsNZVC(bf_data.field == 0, bf_data.field & (1 << (bf_data.width - 1)), FALSE, FALSE);
bf_data.field = (ULO)bf_data.field_mask;
cpuSetBfField(&bf_data, ea_or_reg, has_ea);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfset dx {offset:width}
/// </summary>
static void cpuBfSetReg(ULO regno, UWO ext)
{
cpuBfSetCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bfset ea {offset:width}
/// </summary>
static void cpuBfSetEa(ULO ea, UWO ext)
{
cpuBfSetCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bftst common logic
/// </summary>
static void cpuBfTstCommon(ULO ea_or_reg, bool has_ea, UWO ext)
2013-02-06 04:11:41 +00:00
{
struct cpuBfData bf_data;
cpuBfDecodeExtWordAndGetField(&bf_data, ea_or_reg, false, has_ea, ext);
2013-02-06 04:11:41 +00:00
cpuSetFlagsNZVC(bf_data.field == 0, bf_data.field & (1 << (bf_data.width - 1)), FALSE, FALSE);
}
/// <summary>
/// bftst dx {offset:width}
/// </summary>
static void cpuBfTstReg(ULO regno, UWO ext)
{
cpuBfTstCommon(regno, false, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// bftst ea {offset:width}
/// </summary>
static void cpuBfTstEa(ULO ea, UWO ext)
{
cpuBfTstCommon(ea, true, ext);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// movep.w (d16, Ay), Dx
/// </summary>
static void cpuMovepWReg(ULO areg, ULO dreg)
{
ULO ea = cpuGetAReg(areg) + cpuGetNextWordSignExt();
cpuSetDRegWord(dreg, cpuJoinByteToWord(memoryReadByte(ea), memoryReadByte(ea + 2)));
2013-02-06 04:11:41 +00:00
cpuSetInstructionTime(16);
}
/// <summary>
/// movep.l (d16, Ay), Dx
/// </summary>
static void cpuMovepLReg(ULO areg, ULO dreg)
{
ULO ea = cpuGetAReg(areg) + cpuGetNextWordSignExt();
cpuSetDReg(dreg, cpuJoinByteToLong(memoryReadByte(ea), memoryReadByte(ea + 2), memoryReadByte(ea + 4), memoryReadByte(ea + 6)));
2013-02-06 04:11:41 +00:00
cpuSetInstructionTime(24);
}
/// <summary>
/// movep.w Dx, (d16, Ay)
/// </summary>
static void cpuMovepWEa(ULO areg, ULO dreg)
{
ULO ea = cpuGetAReg(areg) + cpuGetNextWordSignExt();
memoryWriteByte((UBY) (cpuGetDReg(dreg) >> 8), ea);
memoryWriteByte(cpuGetDRegByte(dreg), ea + 2);
2013-02-06 04:11:41 +00:00
cpuSetInstructionTime(16);
}
/// <summary>
/// movep.l Dx, (d16, Ay)
/// </summary>
static void cpuMovepLEa(ULO areg, ULO dreg)
{
ULO ea = cpuGetAReg(areg) + cpuGetNextWordSignExt();
memoryWriteByte((UBY)(cpuGetDReg(dreg) >> 24), ea);
memoryWriteByte((UBY)(cpuGetDReg(dreg) >> 16), ea + 2);
memoryWriteByte((UBY)(cpuGetDReg(dreg) >> 8), ea + 4);
memoryWriteByte(cpuGetDRegByte(dreg), ea + 6);
2013-02-06 04:11:41 +00:00
cpuSetInstructionTime(24);
}
/// <summary>
/// pack Dx, Dy, #adjustment
/// </summary>
static void cpuPackReg(ULO yreg, ULO xreg)
{
UWO adjustment = cpuGetNextWord();
UWO src = cpuGetDRegWord(xreg) + adjustment;
cpuSetDRegByte(yreg, (UBY) (((src >> 4) & 0xf0) | (src & 0xf)));
cpuSetInstructionTime(4);
}
/// <summary>
/// pack -(Ax), -(Ay), #adjustment
/// </summary>
static void cpuPackEa(ULO yreg, ULO xreg)
{
UWO adjustment = cpuGetNextWord();
UBY b1 = memoryReadByte(cpuEA04(xreg, 1));
UBY b2 = memoryReadByte(cpuEA04(xreg, 1));
UWO result = ((((UWO)b1) << 8) | (UWO) b2) + adjustment;
memoryWriteByte((UBY) (((result >> 4) & 0xf0) | (result & 0xf)), cpuEA04(yreg, 1));
cpuSetInstructionTime(4);
}
/// <summary>
/// unpk Dx, Dy, #adjustment
/// </summary>
static void cpuUnpkReg(ULO yreg, ULO xreg)
{
UWO adjustment = cpuGetNextWord();
UBY b1 = cpuGetDRegByte(xreg);
UWO result = ((((UWO)(b1 & 0xf0)) << 4) | ((UWO)(b1 & 0xf))) + adjustment;
cpuSetDRegWord(yreg, result);
cpuSetInstructionTime(4);
}
/// <summary>
/// unpk -(Ax), -(Ay), #adjustment
/// </summary>
static void cpuUnpkEa(ULO yreg, ULO xreg)
{
UWO adjustment = cpuGetNextWord();
UBY b1 = memoryReadByte(cpuEA04(xreg, 1));
UWO result = ((((UWO)(b1 & 0xf0)) << 4) | ((UWO)(b1 & 0xf))) + adjustment;
memoryWriteByte((UBY) (result >> 8), cpuEA04(yreg, 1));
memoryWriteByte((UBY) result, cpuEA04(yreg, 1));
cpuSetInstructionTime(4);
}
/// <summary>
/// movec
/// </summary>
static void cpuMoveCFrom()
{
if (cpuGetFlagSupervisor())
{
UWO extension = (UWO) cpuGetNextWord();
ULO da = (extension >> 15) & 1;
ULO regno = (extension >> 12) & 7;
ULO ctrl_regno = extension & 0xfff;
if (cpuGetModelMajor() == 1)
{
switch (ctrl_regno)
{
case 0x000: cpuSetReg(da, regno, cpuGetSfc()); break;
case 0x001: cpuSetReg(da, regno, cpuGetDfc()); break;
case 0x800: cpuSetReg(da, regno, cpuGetUspDirect()); break; // In supervisor mode, usp is up to date.
case 0x801: cpuSetReg(da, regno, cpuGetVbr()); break;
default: cpuThrowIllegalInstructionException(FALSE); return; // Illegal instruction
2013-02-06 04:11:41 +00:00
}
}
else if (cpuGetModelMajor() == 2)
{
switch (ctrl_regno)
{
case 0x000: cpuSetReg(da, regno, cpuGetSfc()); break;
case 0x001: cpuSetReg(da, regno, cpuGetDfc()); break;
case 0x002: cpuSetReg(da, regno, cpuGetCacr() & 3); break;
case 0x800: cpuSetReg(da, regno, cpuGetUspDirect()); break; // In supervisor mode, usp is up to date.
case 0x801: cpuSetReg(da, regno, cpuGetVbr()); break;
case 0x802: cpuSetReg(da, regno, cpuGetCaar() & 0xfc); break;
case 0x803: cpuSetReg(da, regno, cpuGetMspAutoMap()); break;
case 0x804: cpuSetReg(da, regno, cpuGetIspAutoMap()); break;
default: cpuThrowIllegalInstructionException(FALSE); return; // Illegal instruction
2013-02-06 04:11:41 +00:00
}
}
else if (cpuGetModelMajor() == 3)
{
switch (ctrl_regno)
{
case 0x000: cpuSetReg(da, regno, cpuGetSfc()); break;
case 0x001: cpuSetReg(da, regno, cpuGetDfc()); break;
case 0x002: cpuSetReg(da, regno, cpuGetCacr()); break;
case 0x800: cpuSetReg(da, regno, cpuGetUspDirect()); break; // In supervisor mode, usp is up to date.
case 0x801: cpuSetReg(da, regno, cpuGetVbr()); break;
case 0x802: cpuSetReg(da, regno, cpuGetCaar() & 0xfc); break;
case 0x803: cpuSetReg(da, regno, cpuGetMspAutoMap()); break;
case 0x804: cpuSetReg(da, regno, cpuGetIspAutoMap()); break;
default: cpuThrowIllegalInstructionException(FALSE); return; // Illegal instruction
2013-02-06 04:11:41 +00:00
}
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
}
/// <summary>
/// movec
/// </summary>
static void cpuMoveCTo()
{
if (cpuGetFlagSupervisor())
{
UWO extension = (UWO) cpuGetNextWord();
ULO da = (extension >> 15) & 1;
ULO regno = (extension >> 12) & 7;
ULO ctrl_regno = extension & 0xfff;
if (cpuGetModelMajor() == 1)
{
switch (ctrl_regno)
{
case 0x000: cpuSetSfc(cpuGetReg(da, regno) & 7); break;
case 0x001: cpuSetDfc(cpuGetReg(da, regno) & 7); break;
case 0x800: cpuSetUspDirect(cpuGetReg(da, regno)); break;
case 0x801: cpuSetVbr(cpuGetReg(da, regno)); break;
default: cpuThrowIllegalInstructionException(FALSE); return; // Illegal instruction
2013-02-06 04:11:41 +00:00
}
}
else if (cpuGetModelMajor() == 2)
{
switch (ctrl_regno)
{
case 0x000: cpuSetSfc(cpuGetReg(da, regno) & 7); break;
case 0x001: cpuSetDfc(cpuGetReg(da, regno) & 7); break;
case 0x002: cpuSetCacr(cpuGetReg(da, regno) & 0x3); break;
case 0x800: cpuSetUspDirect(cpuGetReg(da, regno)); break;
case 0x801: cpuSetVbr(cpuGetReg(da, regno)); break;
case 0x802: cpuSetCaar(cpuGetReg(da, regno) & 0x00fc); break;
case 0x803: cpuSetMspAutoMap(cpuGetReg(da, regno)); break;
case 0x804: cpuSetIspAutoMap(cpuGetReg(da, regno)); break;
default: cpuThrowIllegalInstructionException(FALSE); return; // Illegal instruction
2013-02-06 04:11:41 +00:00
}
}
else if (cpuGetModelMajor() == 3)
{
switch (ctrl_regno)
{
case 0x000: cpuSetSfc(cpuGetReg(da, regno) & 7); break;
case 0x001: cpuSetDfc(cpuGetReg(da, regno) & 7); break;
case 0x002: cpuSetCacr(cpuGetReg(da, regno) & 0x3313); break;
case 0x800: cpuSetUspDirect(cpuGetReg(da, regno)); break;
case 0x801: cpuSetVbr(cpuGetReg(da, regno)); break;
case 0x802: cpuSetCaar(cpuGetReg(da, regno) & 0x00fc); break;
case 0x803: cpuSetMspAutoMap(cpuGetReg(da, regno)); break;
case 0x804: cpuSetIspAutoMap(cpuGetReg(da, regno)); break;
default: cpuThrowIllegalInstructionException(FALSE); return; // Illegal instruction
2013-02-06 04:11:41 +00:00
}
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
}
/// <summary>
/// moves.b Rn, ea / moves.b ea, Rn
/// </summary>
static void cpuMoveSB(ULO ea, UWO extension)
{
if (cpuGetFlagSupervisor())
{
ULO da = (extension >> 15) & 1;
ULO regno = (extension >> 12) & 7;
if (extension & 0x0800) // From Rn to ea (in dfc)
{
memoryWriteByte((UBY)cpuGetReg(da, regno), ea);
}
else // From ea to Rn (in sfc)
{
UBY data = memoryReadByte(ea);
if (da == 0)
{
cpuSetDRegByte(regno, data);
2013-02-06 04:11:41 +00:00
}
else
{
cpuSetAReg(regno, (ULO)(LON)(BYT) data);
2013-02-06 04:11:41 +00:00
}
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// moves.w Rn, ea / moves.w ea, Rn
/// </summary>
static void cpuMoveSW(ULO ea, UWO extension)
{
if (cpuGetFlagSupervisor())
{
ULO da = (extension >> 15) & 1;
ULO regno = (extension >> 12) & 7;
if (extension & 0x0800) // From Rn to ea (in dfc)
{
memoryWriteWord((UWO)cpuGetReg(da, regno), ea);
}
else // From ea to Rn (in sfc)
{
UWO data = memoryReadWord(ea);
if (da == 0)
{
cpuSetDRegWord(regno, data);
2013-02-06 04:11:41 +00:00
}
else
{
cpuSetAReg(regno, (ULO)(LON)(WOR) data);
2013-02-06 04:11:41 +00:00
}
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// moves.l Rn, ea / moves.l ea, Rn
/// </summary>
static void cpuMoveSL(ULO ea, UWO extension)
{
if (cpuGetFlagSupervisor())
{
ULO da = (extension >> 15) & 1;
ULO regno = (extension >> 12) & 7;
if (extension & 0x0800) // From Rn to ea (in dfc)
{
memoryWriteLong(cpuGetReg(da, regno), ea);
}
else // From ea to Rn (in sfc)
{
cpuSetDReg(regno, memoryReadLong(ea));
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// Trapcc
/// </summary>
static void cpuTrapcc(ULO cc)
{
if (cc)
{
cpuThrowTrapVException(); // TrapV and Trapcc share the exception vector
return;
}
cpuSetInstructionTime(4);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// Trapcc.w #
/// </summary>
static void cpuTrapccW(ULO cc)
{
cpuGetNextWord();
if (cc)
{
cpuThrowTrapVException(); // TrapV and Trapcc share the exception vector
return;
}
cpuSetInstructionTime(4);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// trapcc.l #
/// </summary>
static void cpuTrapccL(ULO cc)
{
cpuGetNextLong();
if (cc)
{
cpuThrowTrapVException(); // TrapV and Trapcc share the exception vector
return;
}
cpuSetInstructionTime(4);
2013-02-06 04:11:41 +00:00
}
/// <summary>
/// cas.b Dc,Du, ea
/// </summary>
static void cpuCasB(ULO ea, UWO extension)
{
UBY dst = memoryReadByte(ea);
ULO cmp_regno = extension & 7;
UBY res = dst - cpuGetDRegByte(cmp_regno);
cpuSetFlagsCmp(cpuIsZeroB(res), cpuMsbB(res), cpuMsbB(dst), cpuMsbB(cpuGetDRegByte(cmp_regno)));
if (cpuIsZeroB(res))
{
memoryWriteByte(cpuGetDRegByte((extension >> 6) & 7), ea);
}
else
{
cpuSetDRegByte(cmp_regno, dst);
}
cpuSetInstructionTime(4);
}
/// <summary>
/// cas.w Dc,Du, ea
/// </summary>
static void cpuCasW(ULO ea, UWO extension)
{
UWO dst = memoryReadWord(ea);
ULO cmp_regno = extension & 7;
UWO res = dst - cpuGetDRegWord(cmp_regno);
cpuSetFlagsCmp(cpuIsZeroW(res), cpuMsbW(res), cpuMsbW(dst), cpuMsbW(cpuGetDRegWord(cmp_regno)));
if (cpuIsZeroW(res))
{
memoryWriteWord(cpuGetDRegWord((extension >> 6) & 7), ea);
}
else
{
cpuSetDRegWord(cmp_regno, dst);
}
cpuSetInstructionTime(4);
}
/// <summary>
/// cas.l Dc,Du, ea
/// </summary>
static void cpuCasL(ULO ea, UWO extension)
{
ULO dst = memoryReadLong(ea);
ULO cmp_regno = extension & 7;
ULO res = dst - cpuGetDReg(cmp_regno);
cpuSetFlagsCmp(cpuIsZeroL(res), cpuMsbL(res), cpuMsbL(dst), cpuMsbL(cpuGetDReg(cmp_regno)));
if (cpuIsZeroL(res))
{
memoryWriteLong(cpuGetDReg((extension >> 6) & 7), ea);
}
else
{
cpuSetDReg(cmp_regno, dst);
}
cpuSetInstructionTime(4);
}
/// <summary>
/// cas2.w Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
/// </summary>
static void cpuCas2W()
{
UWO extension1 = cpuGetNextWord();
UWO extension2 = cpuGetNextWord();
ULO ea1 = cpuGetReg(extension1 >> 15, (extension1 >> 12) & 7);
ULO ea2 = cpuGetReg(extension2 >> 15, (extension2 >> 12) & 7);
UWO dst1 = memoryReadWord(ea1);
UWO dst2 = memoryReadWord(ea2);
ULO cmp1_regno = extension1 & 7;
ULO cmp2_regno = extension2 & 7;
UWO res1 = dst1 - cpuGetDRegWord(cmp1_regno);
UWO res2 = dst2 - cpuGetDRegWord(cmp2_regno);
if (cpuIsZeroW(res1))
{
cpuSetFlagsCmp(cpuIsZeroW(res2), cpuMsbW(res2), cpuMsbW(dst2), cpuMsbW(cpuGetDRegWord(cmp2_regno)));
}
else
{
cpuSetFlagsCmp(cpuIsZeroW(res1), cpuMsbW(res1), cpuMsbW(dst1), cpuMsbW(cpuGetDRegWord(cmp1_regno)));
}
if (cpuIsZeroW(res1) && cpuIsZeroW(res2))
{
memoryWriteWord(cpuGetDRegWord((extension1 >> 6) & 7), ea1);
memoryWriteWord(cpuGetDRegWord((extension2 >> 6) & 7), ea2);
}
else
{
cpuSetDRegWord(cmp1_regno, dst1);
cpuSetDRegWord(cmp2_regno, dst2);
}
cpuSetInstructionTime(4);
}
/// <summary>
/// cas2.l Dc1:Dc2,Du1:Du2,(Rn1):(Rn2)
/// </summary>
static void cpuCas2L()
{
UWO extension1 = cpuGetNextWord();
UWO extension2 = cpuGetNextWord();
ULO ea1 = cpuGetReg(extension1 >> 15, (extension1 >> 12) & 7);
ULO ea2 = cpuGetReg(extension2 >> 15, (extension2 >> 12) & 7);
ULO dst1 = memoryReadLong(ea1);
ULO dst2 = memoryReadLong(ea2);
ULO cmp1_regno = extension1 & 7;
ULO cmp2_regno = extension2 & 7;
ULO res1 = dst1 - cpuGetDReg(cmp1_regno);
ULO res2 = dst2 - cpuGetDReg(cmp2_regno);
if (cpuIsZeroL(res1))
{
cpuSetFlagsCmp(cpuIsZeroL(res2), cpuMsbL(res2), cpuMsbL(dst2), cpuMsbL(cpuGetDReg(cmp2_regno)));
}
else
{
cpuSetFlagsCmp(cpuIsZeroL(res1), cpuMsbL(res1), cpuMsbL(dst1), cpuMsbL(cpuGetDReg(cmp1_regno)));
}
if (cpuIsZeroL(res1) && cpuIsZeroL(res2))
{
memoryWriteLong(cpuGetDReg((extension1 >> 6) & 7), ea1);
memoryWriteLong(cpuGetDReg((extension2 >> 6) & 7), ea2);
}
else
{
cpuSetDReg(cmp1_regno, dst1);
cpuSetDReg(cmp2_regno, dst2);
}
cpuSetInstructionTime(4);
}
/// <summary>
/// Common code for chk2 ea, Rn / cmp2 ea, Rn
/// </summary>
static void cpuChkCmp(ULO lb, ULO ub, ULO val, BOOLE is_chk2)
{
BOOLE z = (val == lb || val == ub);
BOOLE c = ((lb <= ub) && (val < lb || val > ub)) || ((lb > ub) && (val < lb) && (val > ub));
cpuSetFlagZ(z);
cpuSetFlagC(c);
cpuSetInstructionTime(4);
if (is_chk2 && c)
{
cpuThrowChkException();
}
}
/// <summary>
/// chk2.b ea, Rn / cmp2.b ea, Rn
/// </summary>
static void cpuChkCmp2B(ULO ea, UWO extension)
{
ULO da = (ULO) (extension >> 15);
ULO rn = (ULO) (extension >> 12) & 7;
BOOLE is_chk2 = (extension & 0x0800);
if (da == 1)
{
cpuChkCmp((ULO)(LON)(BYT)memoryReadByte(ea), (ULO)(LON)(BYT)memoryReadByte(ea + 1), cpuGetAReg(rn), is_chk2);
}
else
{
cpuChkCmp((ULO)memoryReadByte(ea), (ULO)memoryReadByte(ea + 1), (ULO)(UBY)cpuGetDReg(rn), is_chk2);
}
}
/// <summary>
/// chk2.w ea, Rn / cmp2.w ea, Rn
/// </summary>
static void cpuChkCmp2W(ULO ea, UWO extension)
{
ULO da = (ULO) (extension >> 15);
ULO rn = (ULO) (extension >> 12) & 7;
BOOLE is_chk2 = (extension & 0x0800);
if (da == 1)
{
cpuChkCmp((ULO)(LON)(WOR)memoryReadWord(ea), (ULO)(LON)(WOR)memoryReadWord(ea + 1), cpuGetAReg(rn), is_chk2);
}
else
{
cpuChkCmp((ULO)memoryReadWord(ea), (ULO)memoryReadWord(ea + 2), (ULO)(UWO)cpuGetDReg(rn), is_chk2);
}
}
/// <summary>
/// chk2.l ea, Rn / cmp2.l ea, Rn
/// </summary>
static void cpuChkCmp2L(ULO ea, UWO extension)
{
ULO da = (ULO) (extension >> 15);
ULO rn = (ULO) (extension >> 12) & 7;
BOOLE is_chk2 = (extension & 0x0800);
cpuChkCmp(memoryReadLong(ea), memoryReadLong(ea + 4), cpuGetReg(da, rn), is_chk2);
}
/// <summary>
/// callm
/// Since this is a coprocessor instruction, this is NOP.
/// This will likely fail, but anything we do here will be wrong anyhow.
/// </summary>
static void cpuCallm(ULO ea, UWO extension)
{
cpuSetInstructionTime(4);
}
/// <summary>
/// rtm
/// Since this is a coprocessor instruction, this is NOP.
/// This will likely fail, but anything we do here will be wrong anyhow.
/// </summary>
static void cpuRtm(ULO da, ULO regno)
{
cpuSetInstructionTime(4);
}
/// <summary>
/// 68030 version only.
///
/// Extension word: 001xxx00xxxxxxxx
/// pflusha
/// pflush fc, mask
/// pflush fc, mask, ea
///
/// Extension word: 001000x0000xxxxx
/// ploadr fc, ea
/// ploadw fc, ea
///
/// Extension word: 010xxxxx00000000 (SRp, CRP, TC)
/// Extension word: 011000x000000000 (MMU status register)
/// Extension word: 000xxxxx00000000 (TT)
/// pmove mrn, ea
/// pmove ea, mrn
/// pmovefd ea, mrn
///
/// Extension word: 100xxxxxxxxxxxxx
/// ptestr fc, ea, #level
/// ptestr fc, ea, #level, An
/// ptestw fc, ea, #level
/// ptestw fc, ea, #level, An
///
/// Since this is a coprocessor instruction, this is NOP.
/// </summary>
static void cpuPflush030(ULO ea, UWO extension)
{
if (cpuGetFlagSupervisor())
{
if ((extension & 0xfde0) == 0x2000)
{
// ploadr, ploadw
}
else if ((extension & 0xe300) == 0x2000)
{
// pflusha, pflush
ULO mode = (extension >> 10) & 7;
ULO mask = (extension >> 5) & 7;
ULO fc = extension & 0x1f;
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
}
/// <summary>
/// pflusha
/// pflush fc, mask
/// pflush fc, mask, ea
///
/// 68040 version only.
///
/// Since this is a coprocessor instruction, this is NOP.
/// </summary>
static void cpuPflush040(ULO opmode, ULO regno)
{
if (cpuGetFlagSupervisor())
{
if (cpuGetModelMajor() != 2) // This is NOP on 68EC040
2013-02-06 04:11:41 +00:00
{
switch (opmode)
{
case 0: //PFLUSHN (An)
break;
case 1: //PFLUSH (An)
break;
case 2: //PFLUSHAN
break;
case 3: //PFLUSHA
break;
2013-02-06 04:11:41 +00:00
}
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
}
/// <summary>
/// ptestr (An)
/// ptestw (An)
///
/// 68040 version only.
///
/// Since this is a coprocessor instruction, this is NOP.
/// </summary>
static void cpuPtest040(ULO rw, ULO regno)
{
if (cpuGetFlagSupervisor())
{
if (cpuGetModelMajor() != 2) // This is NOP on 68EC040
2013-02-06 04:11:41 +00:00
{
if (rw == 0)
{
// ptestr
2013-02-06 04:11:41 +00:00
}
else
{
// ptestw
2013-02-06 04:11:41 +00:00
}
}
}
else
{
cpuThrowPrivilegeViolationException();
return;
}
cpuSetInstructionTime(4);
}
#include "CpuModule_Decl.h"
#include "CpuModule_Data.h"
#include "CpuModule_Profile.h"
2013-02-06 04:11:41 +00:00
#include "CpuModule_Code.h"
cpuOpcodeData cpu_opcode_data_current[65536];
void cpuMakeOpcodeTableForModel(void)
{
ULO opcode;
for (opcode = 0; opcode < 65536; opcode++)
{
if (cpu_opcode_model_mask[opcode] & cpuGetModelMask())
{
cpu_opcode_data_current[opcode] = cpu_opcode_data[opcode];
}
else
{
cpu_opcode_data_current[opcode].instruction_func = cpuIllegalInstruction;
cpu_opcode_data_current[opcode].data[0] = 0;
cpu_opcode_data_current[opcode].data[1] = 0;
cpu_opcode_data_current[opcode].data[2] = 0;
}
}
}
ULO irq_arrival_time = -1;
extern ULO busGetCycle();
2013-02-06 04:11:41 +00:00
ULO cpuExecuteInstruction(void)
{
if (cpuGetRaiseInterrupt())
{
cpuSetUpInterrupt(cpuGetRaiseInterruptLevel());
2013-02-06 04:11:41 +00:00
cpuCheckPendingInterrupts();
return 44;
}
else
{
ULO oldSr = cpuGetSR();
UWO opcode;
#ifdef CPU_INSTRUCTION_LOGGING
cpuCallInstructionLoggingFunc();
#endif
cpuSetOriginalPC(cpuGetPC()); // Store pc and opcode for exception logging
opcode = cpuGetNextWord();
#ifdef CPU_INSTRUCTION_LOGGING
cpuSetCurrentOpcode(opcode);
#endif
cpuSetInstructionTime(0);
cpu_opcode_data_current[opcode].instruction_func(
cpu_opcode_data_current[opcode].data);
2013-02-06 04:11:41 +00:00
if (oldSr & 0xc000)
{
// This instruction was traced
ULO cycles = cpuGetInstructionTime();
cpuThrowTraceException();
cpuSetInstructionTime(cpuGetInstructionTime() + cycles);
}
return cpuGetInstructionTime();
}
}