1 /*====================================================================
3 filename: gdsp_interpreter.cpp
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 ====================================================================*/
29 #include "DSPEmitter.h"
31 #include "DSPAnalyzer.h"
32 #include "MemoryUtil.h"
34 #include "DSPHWInterface.h"
35 #include "DSPIntUtil.h"
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
);
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
);
59 for (int i
= 0; i
< size_in_words
; i
++)
60 rom
[i
] = Common::swap16(rom
[i
]);
64 PanicAlert("Failed to load DSP Rom : %s",fname
);
65 // Always keep ROMs write protected.
66 WriteProtectMemory(g_dsp
.irom
, size_in_bytes
, false);
70 bool DSPCore_Init(const char *irom_filename
, const char *coef_filename
,
73 g_dsp
.step_counter
= 0;
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
++)
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
++)
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
;
127 // Mostly keep IRAM write protected. We unprotect only when DMA-ing
129 WriteProtectMemory(g_dsp
.iram
, DSP_IRAM_BYTE_SIZE
, false);
131 // Initialize JIT, if necessary
133 jit
= new DSPEmitter();
135 DSPAnalyzer::Analyze();
139 core_state
= DSPCORE_RUNNING
;
144 void DSPCore_Shutdown()
146 core_state
= DSPCORE_STOP
;
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
);
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
))
182 if (! dsp_SR_is_flag_set(SR_EXT_INT_ENABLE
))
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)
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
]);
208 g_dsp
.exceptions
&= ~(1 << i
);
210 g_dsp
.r
[DSP_REG_SR
] &= ~SR_EXT_INT_ENABLE
;
212 g_dsp
.r
[DSP_REG_SR
] &= ~SR_INT_ENABLE
;
215 #if defined(_DEBUG) || defined(DEBUGFAST)
216 ERROR_LOG(DSPLLE
, "Firing exception %d failed", i
);
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;
230 // DSPCore_CheckExceptions();
231 // DSPCore_CheckExternalInterrupt();
232 spare_cycles
= jit
->RunForCycles(cycles
+ spare_cycles
);
240 case DSPCORE_RUNNING
:
241 // Seems to slow things down
242 #if defined(_DEBUG) || defined(DEBUGFAST)
243 cycles
= DSPInterpreter::RunCyclesDebug(cycles
);
245 cycles
= DSPInterpreter::RunCycles(cycles
);
249 case DSPCORE_STEPPING
:
251 if (core_state
!= DSPCORE_STEPPING
)
254 DSPInterpreter::Step();
257 DSPHost_UpdateDebugger();
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
)
271 DSPHost_UpdateDebugger();
274 DSPCoreState
DSPCore_GetState()
281 if (core_state
== DSPCORE_STEPPING
)
285 void CompileCurrent() {
286 jit
->Compile(g_dsp
.pc
);