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