1/******************************************************************************/ 2/* Mednafen Sega Saturn Emulation Module */ 3/******************************************************************************/ 4/* scu_dsp_common.inc: 5** Copyright (C) 2015-2018 Mednafen Team 6** 7** This program is free software; you can redistribute it and/or 8** modify it under the terms of the GNU General Public License 9** as published by the Free Software Foundation; either version 2 10** of the License, or (at your option) any later version. 11** 12** This program is distributed in the hope that it will be useful, 13** but WITHOUT ANY WARRANTY; without even the implied warranty of 14** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15** GNU General Public License for more details. 16** 17** You should have received a copy of the GNU General Public License 18** along with this program; if not, write to the Free Software Foundation, Inc., 19** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20*/ 21 22#if (defined(__x86_64__) && defined(__code_model_small__) && !defined(__PIC__) && !defined(__pic__)) || SIZEOF_VOID_P <= 4 23 #define DSP_INSTR_BASE_UIPT 0 24 #define DSP_INSTR_RECOVER_TCAST uint32 25#else 26 #define DSP_INSTR_BASE_UIPT ((uintptr_t)DSP_Init) 27 #define DSP_INSTR_RECOVER_TCAST int32 28#endif 29 30// See loop in "SCU_UpdateDSP()" in scu.inc, and END/ENDI handling in scu_dsp_misc.cpp 31enum { DSP_EndCCSubVal = 1000000 }; 32 33void DSP_Init(void) MDFN_COLD; 34void DSP_FinishPRAMDMA(void); 35 36union DSPR48 37{ 38#ifdef MSB_FIRST 39 struct 40 { 41 uint16 dummy; 42 uint16 H; 43 uint32 L; 44 }; 45#else 46 struct 47 { 48 uint32 L; 49 uint16 H; 50 uint16 dummy; 51 }; 52#endif 53 uint64 T; // Upper 16 bits may be non-zero "garbage", so don't assume they're zero in code that reads from this variable. 54}; 55 56struct DSPS 57{ 58 sscpu_timestamp_t LastTS; 59 int32 CycleCounter; 60 int32 T0_Until; 61 // 62 enum 63 { 64 // No execute = 0x00000000 <= 0 65 // Paused + No execute = 0x80000000 <= 0 66 // Paused + Execute = 0x80000001 <= 0 67 // Execute = 0x00000001 > 0 68 STATE_MASK_PAUSE = 0x80000000, 69 STATE_MASK_EXECUTE = 0x00000001, 70 }; 71 int32 State; 72 73 INLINE bool IsRunning(void) // returns true if not stopped and not paused. 74 { 75 return State > 0; 76 } 77 78 uint64 NextInstr; 79 80 uint8 PC; 81 uint8 RA; 82 83 bool FlagZ; 84 bool FlagS; 85 bool FlagV; 86 bool FlagC; 87 88 bool FlagEnd; 89 90 uint8 TOP; 91 uint16 LOP; // 12 bits 92 93 DSPR48 AC; 94 DSPR48 P; 95 96 union 97 { 98 uint8 CT[4]; // 6 bits(each) 99 uint32 CT32; 100 }; 101 102 uint32 RX; 103 uint32 RY; 104 105 uint32 RAO; 106 uint32 WAO; 107 108 uint32 DataRAM[4][64]; 109 110 uint64 ProgRAM[256]; // Upper 32 bits = actual raw instruction, lower 32 bits = horrible emulator handler pointer madness 111 112 // 113 // See comments at top of scu.inc regarding DSP DMA to program RAM. 114 // 115 uint32 PRAMDMABuf[256]; 116 uint32 PRAMDMABufCount; 117}; 118 119 120// ALU Op: bits 26-29 - *16 121// X Op: bits 23-25 - * 8 122// Y Op: bits 17-19 - * 8 123// D1 Op: bits 12-13 - * 4 124MDFN_HIDE extern void (*const DSP_GenFuncTable[2][16][8][8][4])(void); 125 126// Hold/Format/Direction: bits 12-14 127// Hold: bit 14 128// Format: bit 13 129// Direction: bit 12 130// RAM: bits 8-10 131// 132MDFN_HIDE extern void (*const DSP_DMAFuncTable[2][8][8])(void); 133 134// 135// Dest: bits 26-29 136// Condition: bits 19-25 137// 138MDFN_HIDE extern void (*const DSP_MVIFuncTable[2][16][128])(void); 139 140// 141// Condition: bits 19-25 142// 143MDFN_HIDE extern void (*const DSP_JMPFuncTable[2][128])(void); 144 145 146// 147// LPS, BTM, END, ENDI(bits 29-31 = 0x7) 148// bits 27-28 149// 150MDFN_HIDE extern void (*const DSP_MiscFuncTable[2][4])(void); 151 152MDFN_HIDE extern DSPS DSP; 153 154template<bool looped = false> 155static INLINE uint64 DSP_DecodeInstruction(const uint32 instr) 156{ 157 void (*aal)(void); 158 159 switch((instr >> 28) & 0xF) 160 { 161 default: 162 aal = DSP_GenFuncTable[looped][0][0][0][0]; 163 break; 164 165 case 0x0: 166 case 0x1: 167 case 0x2: 168 case 0x3: 169 aal = DSP_GenFuncTable[looped][(instr >> 26) & 0xF][(instr >> 23) & 0x7][(instr >> 17) & 0x7][(instr >> 12) & 0x3]; 170 break; 171 172 case 0x8: 173 case 0x9: 174 case 0xA: 175 case 0xB: 176 aal = DSP_MVIFuncTable[looped][(instr >> 26) & 0xF][(instr >> 19) & 0x7F]; 177 break; 178 179 case 0xC: 180 aal = DSP_DMAFuncTable[looped][(instr >> 12) & 0x7][(instr >> 8) & 0x7]; 181 break; 182 183 case 0xD: 184 aal = DSP_JMPFuncTable[looped][(instr >> 19) & 0x7F]; 185 break; 186 187 case 0xE: 188 case 0xF: 189 aal = DSP_MiscFuncTable[looped][(instr >> 27) & 0x3]; 190 break; 191 } 192 193 return ((uint64)instr << 32) | (uint32)((uintptr_t)aal - DSP_INSTR_BASE_UIPT); 194} 195 196template<bool looped> 197static INLINE uint32 DSP_InstrPre(void) 198{ 199 const uint32 instr = DSP.NextInstr >> 32; 200 201 if(!looped || !DSP.LOP) 202 { 203 DSP.NextInstr = DSP.ProgRAM[DSP.PC]; 204 DSP.PC++; 205 } 206 207 if(looped) 208 DSP.LOP = (DSP.LOP - 1) & 0x0FFF; 209 210 return instr; 211} 212 213template<unsigned cond> 214static INLINE bool DSP_TestCond(void) 215{ 216 if(!(cond & 0x40)) 217 return true; 218 // 219 // 220 // 221 bool ret = false; 222 223 if(cond & 0x1) 224 ret |= DSP.FlagZ; 225 226 if(cond & 0x2) 227 ret |= DSP.FlagS; 228 229 if(cond & 0x4) 230 ret |= DSP.FlagC; 231 232 if(cond & 0x8) 233 ret |= (DSP.T0_Until < DSP.CycleCounter); 234 235 //if(cond & 0x10) // ? 236 237 return ret == (bool)(cond & 0x20); 238} 239 240