/******************************************************************************/ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* sh7095.h: ** 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_SH7095_H #define __MDFN_SH7095_H class SH7095 final { public: SH7095(const char* const name_arg, const unsigned dma_event_id_arg, uint8 (*exivecfn_arg)(void)) MDFN_COLD; ~SH7095() MDFN_COLD; void Init(void) MDFN_COLD; void ForceInternalEventUpdates(void); void AdjustTS(int32 delta, bool force_set = false); void TruePowerOn(void) MDFN_COLD; void Reset(bool power_on_reset, bool from_internal_wdt = false) MDFN_COLD; void SetNMI(bool level); void SetIRL(unsigned level); void SetMD5(bool level); void SetFTI(bool state); void SetFTCI(bool state); INLINE void SetExtHalt(bool state) { ExtHalt = state; if(ExtHalt) SetPEX(PEX_PSEUDO_EXTHALT); // Only SetPEX() here, ClearPEX() is called in the pseudo exception handling code as necessary. } template void Step(void); //private: uint32 R[16]; uint32 PC; // Control registers union { struct { uint32 SR; uint32 GBR; uint32 VBR; }; uint32 CtrlRegs[3]; }; sscpu_timestamp_t timestamp; sscpu_timestamp_t MA_until; sscpu_timestamp_t MM_until; sscpu_timestamp_t write_finish_timestamp; #if 0 sscpu_timestamp_t WB_until[16]; #endif INLINE void SetT(bool new_value) { SR &= ~1; SR |= new_value; } INLINE bool GetT(void) { return SR & 1; } INLINE bool GetS(void) { return (bool)(SR & 0x002); } INLINE bool GetQ(void) { return (bool)(SR & 0x100); } INLINE bool GetM(void) { return (bool)(SR & 0x200); } INLINE void SetQ(bool new_q) { SR = (SR &~ 0x100) | (new_q << 8); } INLINE void SetM(bool new_m) { SR = (SR &~ 0x200) | (new_m << 9); } // System registers union { struct { uint32 MACH; uint32 MACL; uint32 PR; }; uint32 SysRegs[3]; }; INLINE uint64 GetMAC64(void) { return MACL | ((uint64)MACH << 32); } INLINE void SetMAC64(uint64 nv) { MACL = nv; MACH = nv >> 32; } enum // must be in range of 0 ... 7 { PEX_POWERON = 0, PEX_RESET = 1, PEX_CPUADDR = 2, PEX_DMAADDR = 3, PEX_INT = 4, PEX_NMI = 5, PEX_PSEUDO_DMABURST = 6, PEX_PSEUDO_EXTHALT = 7 }; enum { EPENDING_PEXBITS_SHIFT = 16 }; enum { EPENDING_OP_OR = 0xFF000000 }; uint32 EPending; INLINE void SetPEX(const unsigned which) { EPending |= (1U << (which + EPENDING_PEXBITS_SHIFT)); EPending |= EPENDING_OP_OR; } INLINE void ClearPEX(const unsigned which) { EPending &= ~(1U << (which + EPENDING_PEXBITS_SHIFT)); if(!(EPending & (0xFF << EPENDING_PEXBITS_SHIFT))) EPending = 0; } uint32 Pipe_ID; uint32 Pipe_IF; enum { EXCEPTION_POWERON = 0,// Power-on EXCEPTION_RESET, // "Manual" reset EXCEPTION_ILLINSTR, // General illegal instruction EXCEPTION_ILLSLOT, // Slot illegal instruction EXCEPTION_CPUADDR, // CPU address error EXCEPTION_DMAADDR, // DMA Address error EXCEPTION_NMI, // NMI EXCEPTION_BREAK, // User break EXCEPTION_TRAP, // Trap instruction EXCEPTION_INT, // Interrupt }; enum { VECNUM_POWERON = 0, // Power-on VECNUM_RESET = 2, // "Manual" reset VECNUM_ILLINSTR = 4, // General illegal instruction VECNUM_ILLSLOT = 6, // Slot illegal instruction VECNUM_CPUADDR = 9, // CPU address error VECNUM_DMAADDR = 10, // DMA Address error VECNUM_NMI = 11, // NMI VECNUM_BREAK = 12, // User break VECNUM_TRAP_BASE = 32, // Trap instruction VECNUM_INT_BASE = 64, // Interrupt }; enum { EPENDING_IVECNUM_SHIFT = 8, // 8 bits EPENDING_E_SHIFT = 16, // 8 bits EPENDING_IPRIOLEV_SHIFT = 28 // 4 bits }; template uint32 Exception(const unsigned exnum, const unsigned vecnum); // // // uint32 IBuffer; uint32 (MDFN_FASTCALL *MRFPI[8])(uint32 A); uint8 (MDFN_FASTCALL *MRFP8[8])(uint32 A); uint16 (MDFN_FASTCALL *MRFP16[8])(uint32 A); uint32 (MDFN_FASTCALL *MRFP32[8])(uint32 A); void (MDFN_FASTCALL *MWFP8[8])(uint32 A, uint8); void (MDFN_FASTCALL *MWFP16[8])(uint32 A, uint16); void (MDFN_FASTCALL *MWFP32[8])(uint32 A, uint32); // // // Cache: // // struct { // Rather than have separate validity bits, we're putting an INvalidity bit(invalid when =1) // in the upper bit of the Tag variables. uint32 Tag[4]; uint8 LRU; alignas(4) uint8 Data[4][16]; } Cache[64]; uint8 CCR; void SetCCR(uint8 V); enum { CCR_CE = 0x01 }; // Cache Enable enum { CCR_ID = 0x02 }; // Instruction Replacement Disable enum { CCR_OD = 0x04 }; // Data Replacement Disable enum { CCR_TW = 0x08 }; // Two-Way Mode enum { CCR_CP = 0x10 }; // Cache Purge enum { CCR_W0 = 0x40 }; // enum { CCR_W1 = 0x80 }; // void AssocPurge(const uint32 A); template void Write_UpdateCache(uint32 A, T V); // // End cache stuff // // // // Interrupt controller registers and related state // // void INTC_Reset(void) MDFN_COLD; bool NMILevel; uint8 IRL; uint16 IPRA; uint16 IPRB; uint16 VCRWDT; uint16 VCRA; uint16 VCRB; uint16 VCRC; uint16 VCRD; uint16 ICR; // // // uint16 BCR1, BCR1M; // // // uint8 SBYCR; bool Standby; // // // Free-running timer registers and related state // // struct { sscpu_timestamp_t lastts; // Internal timestamp related. bool FTI; bool FTCI; uint16 FRC; uint16 OCR[2]; uint16 FICR; uint8 TIER; uint8 FTCSR; uint8 FTCSRM; // Bits set to 1 like FTCSR, but unconditionally reset all bits to 0 on FTCSR read. uint8 TCR; uint8 TOCR; uint8 RW_Temp; } FRT; void FRT_Reset(void) MDFN_COLD; void FRT_CheckOCR(void); void FRT_ClockFRC(void); void FRT_WDT_Update(void); void FRT_WDT_Recalc_NET(void); uint32 FRT_WDT_ClockDivider; sscpu_timestamp_t FRT_WDT_NextTS; // // // Watchdog timer registers and related state. // // struct { uint8 WTCSR; // We don't let a CPU program set bit3 to 1, but we do set bit3 to 1 as part of the standby NMI recovery process(for internal use). uint8 WTCSRM; uint8 WTCNT; uint8 RSTCSR; uint8 RSTCSRM; } WDT; void WDT_Reset(bool from_internal_wdt) MDFN_COLD; // Reset-reset only, NOT standby reset! void WDT_StandbyReset(void) MDFN_COLD; // // DMA unit registers and related state // bool DMA_RunCond(unsigned ch); bool DMA_InBurst(void); void DMA_CheckEnterBurstHack(void); void DMA_DoTransfer(unsigned ch); sscpu_timestamp_t DMA_Update(sscpu_timestamp_t); // Takes/return external timestamp void DMA_StartSG(void); const unsigned event_id_dma; sscpu_timestamp_t dma_lastts; // External SH7095_mem_timestamp related. int32 DMA_ClockCounter; int32 DMA_SGCounter; // When negative, smaller granularity scheduling for DMA_Update() bool DMA_RoundRobinRockinBoppin; struct { uint32 SAR; uint32 DAR; uint32 TCR; // 24-bit, value of 0 = 2^24 tranfers uint16 CHCR; uint16 CHCRM; uint8 VCR; uint8 DRCR; } DMACH[2]; uint8 DMAOR; uint8 DMAORM; // // // Division unit registers and related state // // void DIVU_S32_S32(void); void DIVU_S64_S32(void); sscpu_timestamp_t divide_finish_timestamp; uint32 DVSR; uint32 DVDNT; uint32 DVDNTH; uint32 DVDNTL; uint32 DVDNTH_Shadow; uint32 DVDNTL_Shadow; uint16 VCRDIV; uint8 DVCR; #if 0 struct { uint8 SMR; // Mode uint8 BRR; // Bit rate uint8 SCR; // Control uint8 TDR; // Transmit data uint8 SSR; // Status uint8 RDR; // Receive data uint8 RSR; // Receive shift register uint8 TSR; // Transmit shift register } SCI; #endif const char* const cpu_name; // // // bool ExtHalt; uint8 (*const ExIVecFetch)(void); uint8 GetPendingInt(uint8*); void RecalcPendingIntPEX(void); template INLINE void FetchIF(bool ForceIBufferFill); template void DoIDIF_Real(void); template T ExtBusRead(uint32 A); template void ExtBusWrite(uint32 A, T V); template void OnChipRegWrite(uint32 A, uint32 V); template T OnChipRegRead(uint32 A); template T MemReadRT(uint32 A); template T MemRead(uint32 A); template void MemWriteRT(uint32 A, T V); template void MemWrite(uint32 A, T V); template INLINE void Branch(uint32 target); template INLINE void CondRelBranch(bool cond, uint32 disp); template INLINE void UCDelayBranch(uint32 target); template INLINE void UCRelDelayBranch(uint32 disp); // // // // // // public: enum { // GSREG_PC_ID and GSREG_PC_IF are only valid when Step() was called most recently(but they may be invalid // for a while after , too...). GSREG_PC_ID = 0, GSREG_PC_IF, GSREG_PID, GSREG_PIF, GSREG_EP, GSREG_RPC, GSREG_R0, GSREG_R1, GSREG_R2, GSREG_R3, GSREG_R4, GSREG_R5, GSREG_R6, GSREG_R7, GSREG_R8, GSREG_R9, GSREG_R10, GSREG_R11, GSREG_R12, GSREG_R13, GSREG_R14, GSREG_R15, GSREG_SR, GSREG_GBR, GSREG_VBR, GSREG_MACH, GSREG_MACL, GSREG_PR, // // // GSREG_NMIL, GSREG_IRL, GSREG_IPRA, GSREG_IPRB, GSREG_VCRWDT, GSREG_VCRA, GSREG_VCRB, GSREG_VCRC, GSREG_VCRD, GSREG_ICR, // // // GSREG_DVSR, GSREG_DVDNT, GSREG_DVDNTH, GSREG_DVDNTL, GSREG_DVDNTHS, GSREG_DVDNTLS, GSREG_VCRDIV, GSREG_DVCR, // // // GSREG_WTCSR, GSREG_WTCSRM, GSREG_WTCNT, GSREG_RSTCSR, GSREG_RSTCSRM, // // // GSREG_DMAOR, GSREG_DMAORM, GSREG_DMA0_SAR, GSREG_DMA0_DAR, GSREG_DMA0_TCR, GSREG_DMA0_CHCR, GSREG_DMA0_CHCRM, GSREG_DMA0_VCR, GSREG_DMA0_DRCR, GSREG_DMA1_SAR, GSREG_DMA1_DAR, GSREG_DMA1_TCR, GSREG_DMA1_CHCR, GSREG_DMA1_CHCRM, GSREG_DMA1_VCR, GSREG_DMA1_DRCR, GSREG_FRC, GSREG_OCR0, GSREG_OCR1, GSREG_FICR, GSREG_TIER, GSREG_FTCSR, GSREG_FTCSRM, GSREG_TCR, GSREG_TOCR, GSREG_RWT, }; uint32 GetRegister(const unsigned id, char* const special, const uint32 special_len); void SetRegister(const unsigned id, const uint32 value) MDFN_COLD; void CheckRWBreakpoints(void (*MRead)(unsigned len, uint32 addr), void (*MWrite)(unsigned len, uint32 addr)) const; static void Disassemble(const uint16 instr, const uint32 PC, char* buffer, uint16 (*DisPeek16)(uint32), uint32 (*DisPeek32)(uint32)); private: uint32 PC_IF, PC_ID; // Debug-related variables. }; #endif