Lots more work on making the frame aui stuff functional.
[dolphin.git] / Source / Core / DSPCore / Src / DSPCore.cpp
blob68731e7ccad4bb2055d877fc42099798e5c1f42e
1 /*====================================================================
3 filename: gdsp_interpreter.cpp
4 project: GCemu
5 created: 2004-6-18
6 mail: duddie@walla.com
8 Copyright (c) 2005 Duddie & Tratax
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 ====================================================================*/
26 #include "Common.h"
27 #include "Thread.h"
28 #include "DSPCore.h"
29 #include "DSPEmitter.h"
30 #include "DSPHost.h"
31 #include "DSPAnalyzer.h"
32 #include "MemoryUtil.h"
34 #include "DSPHWInterface.h"
35 #include "DSPIntUtil.h"
37 SDSP g_dsp;
38 DSPBreakpoints dsp_breakpoints;
39 DSPCoreState core_state = DSPCORE_STOP;
40 DSPEmitter *jit = NULL;
41 Common::Event step_event;
43 static bool LoadRom(const char *fname, int size_in_words, u16 *rom)
45 FILE *pFile = fopen(fname, "rb");
46 const size_t size_in_bytes = size_in_words * sizeof(u16);
47 if (pFile)
49 size_t read_bytes = fread(rom, 1, size_in_bytes, pFile);
50 if (read_bytes != size_in_bytes)
52 PanicAlert("ROM %s too short : %i/%i", fname, (int)read_bytes, (int)size_in_bytes);
53 fclose(pFile);
54 return false;
56 fclose(pFile);
58 // Byteswap the rom.
59 for (int i = 0; i < size_in_words; i++)
60 rom[i] = Common::swap16(rom[i]);
62 return true;
64 PanicAlert("Failed to load DSP Rom : %s",fname);
65 // Always keep ROMs write protected.
66 WriteProtectMemory(g_dsp.irom, size_in_bytes, false);
67 return false;
70 bool DSPCore_Init(const char *irom_filename, const char *coef_filename,
71 bool bUsingJIT)
73 g_dsp.step_counter = 0;
74 jit = NULL;
76 g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE);
77 g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE);
78 g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE);
79 g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE);
81 // Fill roms with zeros.
82 memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE);
83 memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE);
85 // Try to load real ROM contents. Failing this, only homebrew will work correctly with the DSP.
86 LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom);
87 LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef);
89 for (int i = 0; i < 32; i++)
91 g_dsp.r[i] = 0;
94 for (int i = 0; i < 4; i++)
96 g_dsp.reg_stack_ptr[i] = 0;
97 for (int j = 0; j < DSP_STACK_DEPTH; j++)
99 g_dsp.reg_stack[i][j] = 0;
103 // Fill IRAM with HALT opcodes.
104 for (int i = 0; i < DSP_IRAM_SIZE; i++)
106 g_dsp.iram[i] = 0x0021; // HALT opcode
109 // Just zero out DRAM.
110 for (int i = 0; i < DSP_DRAM_SIZE; i++)
112 g_dsp.dram[i] = 0;
115 // Copied from a real console after the custom UCode has been loaded.
116 // These are the indexing wrapping registers.
117 g_dsp.r[DSP_REG_WR0] = 0xffff;
118 g_dsp.r[DSP_REG_WR1] = 0xffff;
119 g_dsp.r[DSP_REG_WR2] = 0xffff;
120 g_dsp.r[DSP_REG_WR3] = 0xffff;
122 g_dsp.r[DSP_REG_SR] |= SR_INT_ENABLE;
123 g_dsp.r[DSP_REG_SR] |= SR_EXT_INT_ENABLE;
125 g_dsp.cr = 0x804;
126 gdsp_ifx_init();
127 // Mostly keep IRAM write protected. We unprotect only when DMA-ing
128 // in new ucodes.
129 WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
131 // Initialize JIT, if necessary
132 if(bUsingJIT)
133 jit = new DSPEmitter();
135 DSPAnalyzer::Analyze();
137 step_event.Init();
139 core_state = DSPCORE_RUNNING;
141 return true;
144 void DSPCore_Shutdown()
146 core_state = DSPCORE_STOP;
148 if(jit) {
149 delete jit;
150 jit = NULL;
152 step_event.Shutdown();
153 FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE);
154 FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
155 FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
156 FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE);
159 void DSPCore_Reset()
161 g_dsp.pc = DSP_RESET_VECTOR;
163 g_dsp.r[DSP_REG_WR0] = 0xffff;
164 g_dsp.r[DSP_REG_WR1] = 0xffff;
165 g_dsp.r[DSP_REG_WR2] = 0xffff;
166 g_dsp.r[DSP_REG_WR3] = 0xffff;
170 void DSPCore_SetException(u8 level)
172 g_dsp.exceptions |= 1 << level;
175 // Comming from the CPU
176 void DSPCore_CheckExternalInterrupt()
178 // check if there is an external interrupt
179 if (! (g_dsp.cr & CR_EXTERNAL_INT))
180 return;
182 if (! dsp_SR_is_flag_set(SR_EXT_INT_ENABLE))
183 return;
185 // Signal the SPU about new mail
186 DSPCore_SetException(EXP_INT);
188 g_dsp.cr &= ~CR_EXTERNAL_INT;
192 void DSPCore_CheckExceptions()
194 // Early out to skip the loop in the common case.
195 if (g_dsp.exceptions == 0)
196 return;
198 for (int i = 7; i > 0; i--) {
199 // Seems exp int are not masked by sr_int_enable
200 if (g_dsp.exceptions & (1 << i)) {
201 if (dsp_SR_is_flag_set(SR_INT_ENABLE) || (i == EXP_INT)) {
203 // store pc and sr until RTI
204 dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
205 dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[DSP_REG_SR]);
207 g_dsp.pc = i * 2;
208 g_dsp.exceptions &= ~(1 << i);
209 if (i == 7)
210 g_dsp.r[DSP_REG_SR] &= ~SR_EXT_INT_ENABLE;
211 else
212 g_dsp.r[DSP_REG_SR] &= ~SR_INT_ENABLE;
213 break;
214 } else {
215 #if defined(_DEBUG) || defined(DEBUGFAST)
216 ERROR_LOG(DSPLLE, "Firing exception %d failed", i);
217 #endif
223 // Delegate to JIT or interpreter as appropriate.
224 // Handle state changes and stepping.
225 int DSPCore_RunCycles(int cycles)
227 static int spare_cycles = 0;
228 if (jit)
230 // DSPCore_CheckExceptions();
231 // DSPCore_CheckExternalInterrupt();
232 spare_cycles = jit->RunForCycles(cycles + spare_cycles);
233 return 0;
236 while (cycles > 0) {
237 reswitch:
238 switch (core_state)
240 case DSPCORE_RUNNING:
241 // Seems to slow things down
242 #if defined(_DEBUG) || defined(DEBUGFAST)
243 cycles = DSPInterpreter::RunCyclesDebug(cycles);
244 #else
245 cycles = DSPInterpreter::RunCycles(cycles);
246 #endif
247 break;
249 case DSPCORE_STEPPING:
250 step_event.Wait();
251 if (core_state != DSPCORE_STEPPING)
252 goto reswitch;
254 DSPInterpreter::Step();
255 cycles--;
257 DSPHost_UpdateDebugger();
258 break;
261 return cycles;
264 void DSPCore_SetState(DSPCoreState new_state)
266 core_state = new_state;
267 // kick the event, in case we are waiting
268 if (new_state == DSPCORE_RUNNING)
269 step_event.Set();
270 // Sleep(10);
271 DSPHost_UpdateDebugger();
274 DSPCoreState DSPCore_GetState()
276 return core_state;
279 void DSPCore_Step()
281 if (core_state == DSPCORE_STEPPING)
282 step_event.Set();
285 void CompileCurrent() {
286 jit->Compile(g_dsp.pc);