/******************************************************************************/ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* scu_dsp_common.inc: ** 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. */ // base ptr must match the waterbox base load location! #if (defined(__x86_64__) && defined(__code_model_small__) && !defined(__PIC__) && !defined(__pic__)) || SIZEOF_VOID_P <= 4 #define DSP_INSTR_BASE_UIPT 0x36d00000000ul #define DSP_INSTR_RECOVER_TCAST uint32 #else #define DSP_INSTR_BASE_UIPT ((uintptr_t)DSP_Init) #define DSP_INSTR_RECOVER_TCAST int32 #endif // See loop in "SCU_UpdateDSP()" in scu.inc, and END/ENDI handling in scu_dsp_misc.cpp enum { DSP_EndCCSubVal = 1000000 }; void DSP_Init(void); struct DSP_ITS; union DSPR48 { #ifdef MSB_FIRST struct { uint16 dummy; uint16 H; uint32 L; }; #else struct { uint32 L; uint16 H; uint16 dummy; }; #endif uint64 T; // Upper 16 bits may be non-zero "garbage", so don't assume they're zero in code that reads from this variable. }; struct DSPS { sscpu_timestamp_t LastTS; int32 CycleCounter; int32 T0_Until; // enum { // No execute = 0x00000000 <= 0 // Paused + No execute = 0x80000000 <= 0 // Paused + Execute = 0x80000001 <= 0 // Execute = 0x00000001 > 0 STATE_MASK_PAUSE = 0x80000000, STATE_MASK_EXECUTE = 0x00000001, }; int32 State; INLINE bool IsRunning(void) // returns true if not stopped and not paused. { return State > 0; } uint64 NextInstr; uint8 PC; uint8 RA; bool FlagZ; bool FlagS; bool FlagV; bool FlagC; bool FlagEnd; uint8 TOP; uint16 LOP; // 12 bits DSPR48 AC; DSPR48 P; union { uint8 CT[4]; // 6 bits(each) uint32 CT32; }; uint32 RX; uint32 RY; uint32 RAO; uint32 WAO; uint32 DataRAM[4][64]; uint64 ProgRAM[256]; // Upper 32 bits = actual raw instruction, lower 32 bits = horrible emulator handler pointer madness }; // ALU Op: bits 26-29 - *16 // X Op: bits 23-25 - * 8 // Y Op: bits 17-19 - * 8 // D1 Op: bits 12-13 - * 4 extern void (*const DSP_GenFuncTable[2][16][8][8][4])(void); // Hold/Format/Direction: bits 12-14 // Hold: bit 14 // Format: bit 13 // Direction: bit 12 // RAM: bits 8-10 // extern void (*const DSP_DMAFuncTable[2][8][8])(void); // // Dest: bits 26-29 // Condition: bits 19-25 // extern void (*const DSP_MVIFuncTable[2][16][128])(void); // // Condition: bits 19-25 // extern void (*const DSP_JMPFuncTable[2][128])(void); // // LPS, BTM, END, ENDI(bits 29-31 = 0x7) // bits 27-28 // extern void (*const DSP_MiscFuncTable[2][4])(void); extern DSPS DSP; template static INLINE uint64 DSP_DecodeInstruction(const uint32 instr) { void (*aal)(void); switch((instr >> 28) & 0xF) { default: aal = DSP_GenFuncTable[looped][0][0][0][0]; break; case 0x0: case 0x1: case 0x2: case 0x3: aal = DSP_GenFuncTable[looped][(instr >> 26) & 0xF][(instr >> 23) & 0x7][(instr >> 17) & 0x7][(instr >> 12) & 0x3]; break; case 0x8: case 0x9: case 0xA: case 0xB: aal = DSP_MVIFuncTable[looped][(instr >> 26) & 0xF][(instr >> 19) & 0x7F]; break; case 0xC: aal = DSP_DMAFuncTable[looped][(instr >> 12) & 0x7][(instr >> 8) & 0x7]; break; case 0xD: aal = DSP_JMPFuncTable[looped][(instr >> 19) & 0x7F]; break; case 0xE: case 0xF: aal = DSP_MiscFuncTable[looped][(instr >> 27) & 0x3]; break; } return ((uint64)instr << 32) | (uint32)((uintptr_t)aal - DSP_INSTR_BASE_UIPT); } template static INLINE uint32 DSP_InstrPre(void) { const uint32 instr = DSP.NextInstr >> 32; if(!looped || !DSP.LOP) { DSP.NextInstr = DSP.ProgRAM[DSP.PC]; DSP.PC++; } if(looped) DSP.LOP -= (bool)DSP.LOP; return instr; } template static INLINE bool DSP_TestCond(void) { if(!(cond & 0x40)) return true; // // // bool ret = false; if(cond & 0x1) ret |= DSP.FlagZ; if(cond & 0x2) ret |= DSP.FlagS; if(cond & 0x4) ret |= DSP.FlagC; if(cond & 0x8) ret |= (DSP.T0_Until < DSP.CycleCounter); //if(cond & 0x10) // ? return ret == (bool)(cond & 0x20); }