/******************************************************************************/ /* 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 T Read(uint32 addr); uint16 ReadOp(void); template void Write(uint32 addr, const T val); template void Push(const T value); template 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 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 void CalcZN(const T val); template 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 void ADD(HAM &src, HAM &dst); template void ADDX(HAM &src, HAM &dst); template DT Subtract(HAM &src, HAM &dst); template void SUB(HAM &src, HAM &dst); template void SUBX(HAM &src, HAM &dst); template void NEG(HAM &dst); template void NEGX(HAM &dst); template void CMP(HAM &src, HAM &dst); template void CHK(HAM &src, HAM &dst); template void OR(HAM &src, HAM &dst); template void EOR(HAM &src, HAM &dst); template void AND(HAM &src, HAM &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 void MULU(HAM &src, const unsigned dr); template void MULS(HAM &src, const unsigned dr); template void Divide(uint16 divisor, const unsigned dr); template void DIVU(HAM &src, const unsigned dr); template void DIVS(HAM &src, const unsigned dr); template void ABCD(HAM &src, HAM &dst); uint8 DecimalSubtractX(const uint8 src_data, const uint8 dst_data); template void SBCD(HAM &src, HAM &dst); template void NBCD(HAM &dst); template void MOVEP(const unsigned ar, const unsigned dr); template void BTST(HAM &targ, unsigned wb); template void BCHG(HAM &targ, unsigned wb); template void BCLR(HAM &targ, unsigned wb); template void BSET(HAM &targ, unsigned wb); template void MOVE(HAM &src, HAM &dst); template void MOVEA(HAM &src, const unsigned ar); template void MOVEM_to_MEM(const uint16 reglist, HAM &dst); template void MOVEM_to_REGS(HAM &src, const uint16 reglist); template void ShiftBase(HAM &targ, unsigned count); template void ASL(HAM &targ, unsigned count); template void ASR(HAM &targ, unsigned count); template void LSL(HAM &targ, unsigned count); template void LSR(HAM &targ, unsigned count); template void RotateBase(HAM &targ, unsigned count); template void ROL(HAM &targ, unsigned count); template void ROR(HAM &targ, unsigned count); template void ROXL(HAM &targ, unsigned count); template void ROXR(HAM &targ, unsigned count); #if 0 static uint8 TAS_Callback(uint8 data) { CalcZN(data); SetC(false); SetV(false); data |= 0x80; return data; } #endif template void TAS(HAM &dst); template void TST(HAM &dst); template void CLR(HAM &dst); template void NOT(HAM &dst); template void EXT(HAM &dst); void SWAP(const unsigned dr); void EXG(uint32* a, uint32* b); template bool TestCond(void); template void Bxx(uint32 disp); template void DBcc(const unsigned dr); template void Scc(HAM &dst); template void JSR(HAM &targ); template void JMP(HAM &targ); template void MOVE_from_SR(HAM &dst); template void MOVE_to_CCR(HAM &src); template void MOVE_to_SR(HAM &src); template void MOVE_USP(const unsigned ar); template void LEA(HAM &src, const unsigned ar); template void PEA(HAM &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