493 lines
12 KiB
C++
493 lines
12 KiB
C++
/******************************************************************************/
|
|
/* Mednafen - Multi-system Emulator */
|
|
/******************************************************************************/
|
|
/* m68k.h - Motorola 68000 CPU Emulator
|
|
** Copyright (C) 2015-2016 Mednafen Team
|
|
**
|
|
** 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
|
|
** of the License, 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.,
|
|
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef __MDFN_M68K_H
|
|
#define __MDFN_M68K_H
|
|
|
|
#include "ss.h"
|
|
|
|
class M68K
|
|
{
|
|
public:
|
|
|
|
M68K(const bool rev_e = false) MDFN_COLD;
|
|
~M68K() MDFN_COLD;
|
|
|
|
void Run(int32 run_until_time);
|
|
void Step(void);
|
|
|
|
void Reset(bool powering_up) MDFN_COLD;
|
|
|
|
void SetIPL(uint8 ipl_new);
|
|
void SetExtHalted(bool state);
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
union
|
|
{
|
|
uint32 DA[16];
|
|
struct
|
|
{
|
|
uint32 D[8];
|
|
uint32 A[8];
|
|
};
|
|
};
|
|
int32 timestamp;
|
|
|
|
uint32 PC;
|
|
uint8 SRHB;
|
|
uint8 IPL;
|
|
|
|
bool Flag_Z, Flag_N;
|
|
bool Flag_X, Flag_C, Flag_V;
|
|
|
|
uint32 SP_Inactive;
|
|
uint32 XPending;
|
|
enum
|
|
{
|
|
XPENDING_MASK_INT = 0x0001,
|
|
XPENDING_MASK_NMI = 0x0002,
|
|
XPENDING_MASK_RESET = 0x0010,
|
|
XPENDING_MASK_STOPPED = 0x0100, // via STOP instruction
|
|
XPENDING_MASK_EXTHALTED= 0x1000
|
|
};
|
|
|
|
const bool Revision_E;
|
|
|
|
//private:
|
|
void RecalcInt(void);
|
|
|
|
template<typename T>
|
|
T Read(uint32 addr);
|
|
|
|
uint16 ReadOp(void);
|
|
|
|
template<typename T, bool long_dec = false>
|
|
void Write(uint32 addr, const T val);
|
|
|
|
template<typename T>
|
|
void Push(const T value);
|
|
|
|
template<typename T>
|
|
T Pull(void);
|
|
|
|
enum AddressMode
|
|
{
|
|
DATA_REG_DIR,
|
|
ADDR_REG_DIR,
|
|
|
|
ADDR_REG_INDIR,
|
|
ADDR_REG_INDIR_POST,
|
|
ADDR_REG_INDIR_PRE,
|
|
|
|
ADDR_REG_INDIR_DISP,
|
|
|
|
ADDR_REG_INDIR_INDX,
|
|
|
|
ABS_SHORT,
|
|
ABS_LONG,
|
|
|
|
PC_DISP,
|
|
PC_INDEX,
|
|
|
|
IMMEDIATE
|
|
};
|
|
|
|
//
|
|
// MOVE byte and word: instructions, 2 cycle penalty for source predecrement only
|
|
// 2 cycle penalty for (d8, An, Xn) for both source and dest ams
|
|
// 2 cycle penalty for (d8, PC, Xn) for dest am
|
|
//
|
|
|
|
//
|
|
// Careful on declaration order of HAM objects(needs to be source then dest).
|
|
//
|
|
template<typename T, M68K::AddressMode am>
|
|
struct HAM;
|
|
|
|
void SetC(bool val);
|
|
void SetV(bool val);
|
|
void SetZ(bool val);
|
|
void SetN(bool val);
|
|
void SetX(bool val);
|
|
|
|
bool GetC(void);
|
|
bool GetV(void);
|
|
bool GetZ(void);
|
|
bool GetN(void);
|
|
bool GetX(void);
|
|
|
|
void SetCX(bool val);
|
|
|
|
template<typename T, bool Z_OnlyClear = false>
|
|
void CalcZN(const T val);
|
|
|
|
template<typename T>
|
|
void CalcCX(const uint64& val);
|
|
|
|
uint8 GetCCR(void);
|
|
void SetCCR(uint8 val);
|
|
uint16 GetSR(void);
|
|
void SetSR(uint16 val);
|
|
|
|
uint8 GetIMask(void);
|
|
void SetIMask(uint8 val);
|
|
|
|
bool GetSVisor(void);
|
|
void SetSVisor(bool value);
|
|
bool GetTrace(void);
|
|
void SetTrace(bool value);
|
|
|
|
//
|
|
//
|
|
//
|
|
enum
|
|
{
|
|
VECNUM_RESET_SSP = 0,
|
|
VECNUM_RESET_PC = 1,
|
|
VECNUM_BUS_ERROR = 2,
|
|
VECNUM_ADDRESS_ERROR = 3,
|
|
VECNUM_ILLEGAL = 4,
|
|
VECNUM_ZERO_DIVIDE = 5,
|
|
VECNUM_CHK = 6,
|
|
VECNUM_TRAPV = 7,
|
|
VECNUM_PRIVILEGE = 8,
|
|
VECNUM_TRACE = 9,
|
|
VECNUM_LINEA = 10,
|
|
VECNUM_LINEF = 11,
|
|
|
|
VECNUM_UNINI_INT = 15,
|
|
|
|
VECNUM_SPURIOUS_INT = 24,
|
|
VECNUM_INT_BASE = 24,
|
|
|
|
VECNUM_TRAP_BASE = 32
|
|
};
|
|
|
|
enum
|
|
{
|
|
EXCEPTION_RESET = 0,
|
|
EXCEPTION_BUS_ERROR,
|
|
EXCEPTION_ADDRESS_ERROR,
|
|
EXCEPTION_ILLEGAL,
|
|
EXCEPTION_ZERO_DIVIDE,
|
|
EXCEPTION_CHK,
|
|
EXCEPTION_TRAPV,
|
|
EXCEPTION_PRIVILEGE,
|
|
EXCEPTION_TRACE,
|
|
|
|
EXCEPTION_INT,
|
|
EXCEPTION_TRAP
|
|
};
|
|
|
|
void NO_INLINE Exception(unsigned which, unsigned vecnum);
|
|
|
|
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void ADD(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void ADDX(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
template<bool X_form, typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
DT Subtract(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
|
|
|
|
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void SUB(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
|
|
|
|
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void SUBX(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
|
|
|
|
template<typename DT, M68K::AddressMode DAM>
|
|
void NEG(HAM<DT, DAM> &dst);
|
|
|
|
template<typename DT, M68K::AddressMode DAM>
|
|
void NEGX(HAM<DT, DAM> &dst);
|
|
|
|
template<typename T, typename DT, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void CMP(HAM<T, SAM> &src, HAM<DT, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void CHK(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void OR(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void EOR(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void AND(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
void ORI_CCR(void);
|
|
void ORI_SR(void);
|
|
void ANDI_CCR(void);
|
|
void ANDI_SR(void);
|
|
void EORI_CCR(void);
|
|
void EORI_SR(void);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void MULU(HAM<T, SAM> &src, const unsigned dr);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void MULS(HAM<T, SAM> &src, const unsigned dr);
|
|
|
|
template<bool sdiv>
|
|
void Divide(uint16 divisor, const unsigned dr);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void DIVU(HAM<T, SAM> &src, const unsigned dr);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void DIVS(HAM<T, SAM> &src, const unsigned dr);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void ABCD(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
uint8 DecimalSubtractX(const uint8 src_data, const uint8 dst_data);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void SBCD(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode DAM>
|
|
void NBCD(HAM<T, DAM> &dst);
|
|
|
|
template<typename T, bool reg_to_mem>
|
|
void MOVEP(const unsigned ar, const unsigned dr);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void BTST(HAM<T, TAM> &targ, unsigned wb);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void BCHG(HAM<T, TAM> &targ, unsigned wb);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void BCLR(HAM<T, TAM> &targ, unsigned wb);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void BSET(HAM<T, TAM> &targ, unsigned wb);
|
|
|
|
template<typename T, M68K::AddressMode SAM, M68K::AddressMode DAM>
|
|
void MOVE(HAM<T, SAM> &src, HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void MOVEA(HAM<T, SAM> &src, const unsigned ar);
|
|
|
|
template<bool pseudo_predec, typename T, M68K::AddressMode DAM>
|
|
void MOVEM_to_MEM(const uint16 reglist, HAM<T, DAM> &dst);
|
|
|
|
template<bool pseudo_postinc, typename T, M68K::AddressMode SAM>
|
|
void MOVEM_to_REGS(HAM<T, SAM> &src, const uint16 reglist);
|
|
|
|
template<typename T, M68K::AddressMode TAM, bool Arithmetic, bool ShiftLeft>
|
|
void ShiftBase(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void ASL(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void ASR(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void LSL(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void LSR(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM, bool X_Form, bool ShiftLeft>
|
|
void RotateBase(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void ROL(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void ROR(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void ROXL(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void ROXR(HAM<T, TAM> &targ, unsigned count);
|
|
|
|
#if 0
|
|
static uint8 TAS_Callback(uint8 data)
|
|
{
|
|
CalcZN<uint8>(data);
|
|
SetC(false);
|
|
SetV(false);
|
|
|
|
data |= 0x80;
|
|
return data;
|
|
}
|
|
#endif
|
|
|
|
template<typename T, M68K::AddressMode DAM>
|
|
void TAS(HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode DAM>
|
|
void TST(HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode DAM>
|
|
void CLR(HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode DAM>
|
|
void NOT(HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode DAM>
|
|
void EXT(HAM<T, DAM> &dst);
|
|
|
|
void SWAP(const unsigned dr);
|
|
|
|
void EXG(uint32* a, uint32* b);
|
|
|
|
template<unsigned cc>
|
|
bool TestCond(void);
|
|
|
|
template<unsigned cc>
|
|
void Bxx(uint32 disp);
|
|
|
|
template<unsigned cc>
|
|
void DBcc(const unsigned dr);
|
|
|
|
template<unsigned cc, typename T, M68K::AddressMode DAM>
|
|
void Scc(HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void JSR(HAM<T, TAM> &targ);
|
|
|
|
template<typename T, M68K::AddressMode TAM>
|
|
void JMP(HAM<T, TAM> &targ);
|
|
|
|
template <typename T, M68K::AddressMode DAM>
|
|
void MOVE_from_SR(HAM<T, DAM> &dst);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void MOVE_to_CCR(HAM<T, SAM> &src);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void MOVE_to_SR(HAM<T, SAM> &src);
|
|
|
|
template<bool direction>
|
|
void MOVE_USP(const unsigned ar);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void LEA(HAM<T, SAM> &src, const unsigned ar);
|
|
|
|
template<typename T, M68K::AddressMode SAM>
|
|
void PEA(HAM<T, SAM> &src);
|
|
void UNLK(const unsigned ar);
|
|
void LINK(const unsigned ar);
|
|
void RTE(void);
|
|
void RTR(void);
|
|
void RTS(void);
|
|
void TRAP(const unsigned vf);
|
|
void TRAPV(void);
|
|
void ILLEGAL(const uint16 instr);
|
|
void LINEA(void);
|
|
void LINEF(void);
|
|
void NOP(void);
|
|
void RESET(void);
|
|
void STOP(void);
|
|
|
|
bool CheckPrivilege(void);
|
|
|
|
void InternalStep(void);
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// These externally-provided functions should add >= 4 to M68K::timestamp per call:
|
|
enum { BUS_INT_ACK_AUTO = -1 };
|
|
|
|
uint16 (MDFN_FASTCALL *BusReadInstr)(uint32 A);
|
|
uint8 (MDFN_FASTCALL *BusRead8)(uint32 A);
|
|
uint16 (MDFN_FASTCALL *BusRead16)(uint32 A);
|
|
void (MDFN_FASTCALL *BusWrite8)(uint32 A, uint8 V);
|
|
void (MDFN_FASTCALL *BusWrite16)(uint32 A, uint16 V);
|
|
//
|
|
//
|
|
void (MDFN_FASTCALL *BusRMW)(uint32 A, uint8 (MDFN_FASTCALL *cb)(M68K*, uint8));
|
|
unsigned (MDFN_FASTCALL *BusIntAck)(uint8 level);
|
|
void (MDFN_FASTCALL *BusRESET)(bool state); // Optional; Calling Reset(false) from this callback *is* permitted.
|
|
|
|
//
|
|
//
|
|
//
|
|
void (*DBG_Warning)(const char* format, ...) noexcept MDFN_FORMATSTR(gnu_printf, 1, 2);
|
|
void (*DBG_Verbose)(const char* format, ...) noexcept MDFN_FORMATSTR(gnu_printf, 1, 2);
|
|
//
|
|
//
|
|
//
|
|
public:
|
|
enum
|
|
{
|
|
GSREG_D0 = 0,
|
|
GSREG_D1,
|
|
GSREG_D2,
|
|
GSREG_D3,
|
|
GSREG_D4,
|
|
GSREG_D5,
|
|
GSREG_D6,
|
|
GSREG_D7,
|
|
|
|
GSREG_A0 = 8,
|
|
GSREG_A1,
|
|
GSREG_A2,
|
|
GSREG_A3,
|
|
GSREG_A4,
|
|
GSREG_A5,
|
|
GSREG_A6,
|
|
GSREG_A7,
|
|
|
|
GSREG_PC = 16,
|
|
GSREG_SR,
|
|
GSREG_SSP,
|
|
GSREG_USP
|
|
};
|
|
|
|
uint32 GetRegister(unsigned which, char* special = nullptr, const uint32 special_len = 0);
|
|
void SetRegister(unsigned which, uint32 value);
|
|
INLINE void DupeState(const M68K* const src)
|
|
{
|
|
memcpy(DA, src->DA, 16 * sizeof(uint32));
|
|
timestamp = src->timestamp;
|
|
PC = src->PC;
|
|
SRHB = src->SRHB;
|
|
IPL = src->IPL;
|
|
Flag_Z = src->Flag_Z;
|
|
Flag_N = src->Flag_N;
|
|
Flag_X = src->Flag_X;
|
|
Flag_C = src->Flag_C;
|
|
Flag_V = src->Flag_V;
|
|
SP_Inactive = src->SP_Inactive;
|
|
XPending = src->XPending;
|
|
}
|
|
};
|
|
|
|
#endif
|