1 /*
2 * PearPC
3 * ppc_cpu.cc
4 *
5 * Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
6 * Portions Copyright (C) 2004 Apple Computer, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
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
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <cstring>
23 #include <cstdio>
24
25 #include "system/systhread.h"
26 #include "system/arch/sysendian.h"
27 //#include "tools/snprintf.h"
28 #include "cpu/cpu.h"
29 #include "cpu/debug.h"
30 #include "info.h"
31 //#include "io/pic/pic.h"
32 //#include "debug/debugger.h"
33 #include "tracers.h"
34 #include "ppc_cpu.h"
35 #include "ppc_dec.h"
36 #include "ppc_fpu.h"
37 #include "ppc_exc.h"
38 #include "ppc_mmu.h"
39 #include "ppc_tools.h"
40 #include "uae/ppc.h"
41
42 //#include "io/graphic/gcard.h"
43
44 PPC_CPU_State gCPU;
45 //Debugger *gDebugger;
46
47 static bool gSinglestep = false;
48
49 bool activate = false;
ppc_debug_hook()50 static inline void ppc_debug_hook()
51 {
52 }
53
54 sys_mutex exception_mutex;
55
ppc_cpu_atomic_raise_ext_exception()56 void PPCCALL ppc_cpu_atomic_raise_ext_exception()
57 {
58 sys_lock_mutex(exception_mutex);
59 gCPU.ext_exception = true;
60 gCPU.exception_pending = true;
61 sys_unlock_mutex(exception_mutex);
62 }
63
ppc_cpu_atomic_cancel_ext_exception()64 void PPCCALL ppc_cpu_atomic_cancel_ext_exception()
65 {
66 sys_lock_mutex(exception_mutex);
67 gCPU.ext_exception = false;
68 if (!gCPU.dec_exception) gCPU.exception_pending = false;
69 sys_unlock_mutex(exception_mutex);
70 }
71
ppc_cpu_atomic_raise_dec_exception()72 static void ppc_cpu_atomic_raise_dec_exception()
73 {
74 sys_lock_mutex(exception_mutex);
75 gCPU.dec_exception = true;
76 gCPU.exception_pending = true;
77 sys_unlock_mutex(exception_mutex);
78 }
79
80
ppc_do_dec(int val)81 static void ppc_do_dec(int val)
82 {
83 if (gCPU.pdec == 0) {
84 gCPU.exception_pending = true;
85 gCPU.dec_exception = true;
86 gCPU.pdec = (uint64)0xffffffff * TB_TO_PTB_FACTOR;
87 uae_ppc_wakeup();
88 } else {
89 uint64 oldpdec = gCPU.pdec;
90 gCPU.pdec -= val;
91 if (gCPU.pdec > oldpdec) {
92 gCPU.pdec = 0;
93 }
94 }
95 }
96
ppc_cpu_get_dec(void)97 uint64_t PPCCALL ppc_cpu_get_dec(void)
98 {
99 return gCPU.pdec;
100 }
101
ppc_cpu_do_dec(int val)102 void PPCCALL ppc_cpu_do_dec(int val)
103 {
104 ppc_do_dec(val);
105 }
106
107 static uint ops = 0;
108 static int ppc_trace;
109
ppc_cpu_run_single(int count)110 void PPCCALL ppc_cpu_run_single(int count)
111 {
112 while (count != 0) {
113 if (count > 0)
114 count--;
115 gCPU.npc = gCPU.pc+4;
116 if ((gCPU.pc & ~0xfff) == gCPU.effective_code_page) {
117 gCPU.current_opc = ppc_word_from_BE(*((uint32*)(&gCPU.physical_code_page[gCPU.pc & 0xfff])));
118 ppc_debug_hook();
119 } else {
120 int ret;
121 if ((ret = ppc_direct_effective_memory_handle_code(gCPU.pc & ~0xfff, gCPU.physical_code_page))) {
122 if (ret == PPC_MMU_EXC) {
123 gCPU.pc = gCPU.npc;
124 continue;
125 } else {
126 PPC_CPU_ERR("?\n");
127 }
128 }
129 gCPU.effective_code_page = gCPU.pc & ~0xfff;
130 continue;
131 }
132 if (ppc_trace)
133 ht_printf("%08x %04x\n", gCPU.pc, gCPU.current_opc);
134 ppc_exec_opc();
135 ops++;
136 gCPU.ptb++;
137 ppc_do_dec(1);
138 if ((ops & 0x3ffff)==0) {
139 /* if (pic_check_interrupt()) {
140 gCPU.exception_pending = true;
141 gCPU.ext_exception = true;
142 }*/
143 if ((ops & 0x0fffff)==0) {
144 // uint32 j=0;
145 // ppc_read_effective_word(0xc046b2f8, j);
146
147 //ht_printf("@%08x (%u ops) pdec: %08x lr: %08x\n", gCPU.pc, ops, gCPU.pdec, gCPU.lr);
148 #if 0
149 extern uint32 PIC_enable_low;
150 extern uint32 PIC_enable_high;
151 ht_printf("enable ");
152 int x = 1;
153 for (int i=0; i<31; i++) {
154 if (PIC_enable_low & x) {
155 ht_printf("%d ", i);
156 }
157 x<<=1;
158 }
159 x=1;
160 for (int i=0; i<31; i++) {
161 if (PIC_enable_high & x) {
162 ht_printf("%d ", 32+i);
163 }
164 x<<=1;
165 }
166 ht_printf("\n");
167 #endif
168 }
169 }
170
171 gCPU.pc = gCPU.npc;
172
173 extern int debugger_active, pause_emulation;
174 extern void sleep_millis(int);
175 while ((debugger_active || pause_emulation) && count < 0) {
176 sleep_millis(10);
177 }
178
179 if (gCPU.exception_pending) {
180 if (gCPU.stop_exception) {
181 gCPU.stop_exception = false;
182 if (!gCPU.dec_exception && !gCPU.ext_exception) gCPU.exception_pending = false;
183 break;
184 }
185 if (gCPU.msr & MSR_EE) {
186 sys_lock_mutex(exception_mutex);
187 if (gCPU.ext_exception) {
188 ppc_exception(PPC_EXC_EXT_INT);
189 gCPU.ext_exception = false;
190 gCPU.pc = gCPU.npc;
191 if (!gCPU.dec_exception) gCPU.exception_pending = false;
192 sys_unlock_mutex(exception_mutex);
193 continue;
194 }
195 if (gCPU.dec_exception) {
196 ppc_exception(PPC_EXC_DEC);
197 gCPU.dec_exception = false;
198 //ht_printf("pdec exp %08x\n", gCPU.pc);
199 gCPU.pc = gCPU.npc;
200 gCPU.exception_pending = false;
201 sys_unlock_mutex(exception_mutex);
202 continue;
203 }
204 sys_unlock_mutex(exception_mutex);
205 PPC_CPU_ERR("no interrupt, but signaled?!\n");
206 }
207 }
208 #ifdef PPC_CPU_ENABLE_SINGLESTEP
209 if (gCPU.msr & MSR_SE) {
210 if (gCPU.singlestep_ignore) {
211 gCPU.singlestep_ignore = false;
212 } else {
213 ppc_exception(PPC_EXC_TRACE2);
214 gCPU.pc = gCPU.npc;
215 continue;
216 }
217 }
218 #endif
219 }
220 }
221
ppc_cpu_run_continuous(void)222 void PPCCALL ppc_cpu_run_continuous(void)
223 {
224 PPC_CPU_TRACE("execution started at %08x\n", gCPU.pc);
225 gCPU.effective_code_page = 0xffffffff;
226 ops = 0;
227 ppc_cpu_run_single(-1);
228 }
229
ppc_cpu_stop()230 void PPCCALL ppc_cpu_stop()
231 {
232 sys_lock_mutex(exception_mutex);
233 gCPU.stop_exception = true;
234 gCPU.exception_pending = true;
235 sys_unlock_mutex(exception_mutex);
236 }
237
ppc_get_clock_frequency(int cpu)238 uint64 ppc_get_clock_frequency(int cpu)
239 {
240 return PPC_CLOCK_FREQUENCY;
241 }
242
ppc_get_bus_frequency(int cpu)243 uint64 ppc_get_bus_frequency(int cpu)
244 {
245 return PPC_BUS_FREQUENCY;
246 }
247
ppc_get_timebase_frequency(int cpu)248 uint64 ppc_get_timebase_frequency(int cpu)
249 {
250 return PPC_TIMEBASE_FREQUENCY;
251 }
252
253
ppc_machine_check_exception()254 void ppc_machine_check_exception()
255 {
256 PPC_CPU_ERR("machine check exception\n");
257 }
258
ppc_cpu_get_gpr(int cpu,int i)259 uint32 ppc_cpu_get_gpr(int cpu, int i)
260 {
261 return gCPU.gpr[i];
262 }
263
ppc_cpu_set_gpr(int cpu,int i,uint32 newvalue)264 void ppc_cpu_set_gpr(int cpu, int i, uint32 newvalue)
265 {
266 gCPU.gpr[i] = newvalue;
267 }
268
ppc_cpu_set_msr(int cpu,uint32 newvalue)269 void ppc_cpu_set_msr(int cpu, uint32 newvalue)
270 {
271 gCPU.msr = newvalue;
272 }
273
274 // Handle as CPU reset
ppc_cpu_set_pc(int cpu,uint32 newvalue)275 void PPCCALL ppc_cpu_set_pc(int cpu, uint32 newvalue)
276 {
277 gCPU.srr[0] = gCPU.pc;
278 gCPU.srr[1] = gCPU.msr & 0xff73;
279 gCPU.pc = newvalue;
280 gCPU.msr &= MSR_ILE | MSR_ME | MSR_IP;
281 if (gCPU.msr & MSR_ILE)
282 gCPU.msr |= MSR_LE;
283 }
284
ppc_cpu_get_pc(int cpu)285 uint32 ppc_cpu_get_pc(int cpu)
286 {
287 return gCPU.pc;
288 }
289
ppc_cpu_get_pvr(int cpu)290 uint32 ppc_cpu_get_pvr(int cpu)
291 {
292 return gCPU.pvr;
293 }
294
295 #if 0
296 void ppc_cpu_map_framebuffer(uint32 pa, uint32 ea)
297 {
298 // use BAT for framebuffer
299 gCPU.dbatu[0] = ea|(7<<2)|0x3;
300 gCPU.dbat_bl17[0] = ~(BATU_BL(gCPU.dbatu[0])<<17);
301 gCPU.dbatl[0] = pa;
302 }
303 #endif
304
ppc_set_singlestep_v(bool v,const char * file,int line,const char * format,...)305 void ppc_set_singlestep_v(bool v, const char *file, int line, const char *format, ...)
306 {
307 char buffer[200];
308 va_list arg;
309 va_start(arg, format);
310 ht_printf("singlestep %s from %s:%d, info: ", v ? "set" : "cleared", file, line);
311 vsprintf(buffer, format, arg);
312 ht_printf("%s\n", buffer);
313 va_end(arg);
314 uae_ppc_crash();
315 gSinglestep = v;
316 }
317
ppc_set_singlestep_nonverbose(bool v)318 void ppc_set_singlestep_nonverbose(bool v)
319 {
320 gSinglestep = v;
321 }
322
323 #define CPU_KEY_PVR "cpu_pvr"
324
325 //#include "configparser.h"
326
ppc_cpu_init(uint32 pvr)327 bool PPCCALL ppc_cpu_init(uint32 pvr)
328 {
329 memset(&gCPU, 0, sizeof gCPU);
330 gCPU.pvr = pvr; //gConfig->getConfigInt(CPU_KEY_PVR);
331 gCPU.hid[1] = 0x80000000;
332 gCPU.msr = MSR_IP;
333
334 ppc_dec_init();
335 // initialize srs (mostly for prom)
336 // for (int i=0; i<16; i++) {
337 // gCPU.sr[i] = 0x2aa*i;
338 // }
339 sys_create_mutex(&exception_mutex);
340
341 PPC_CPU_WARN("You are using the generic CPU!\n");
342 PPC_CPU_WARN("This is much slower than the just-in-time compiler and\n");
343 PPC_CPU_WARN("should only be used for debugging purposes or if there's\n");
344 PPC_CPU_WARN("no just-in-time compiler for your platform.\n");
345
346 return true;
347 }
348
ppc_cpu_free(void)349 void PPCCALL ppc_cpu_free(void)
350 {
351 sys_destroy_mutex(exception_mutex);
352 }
353
354 #if 0
355 void ppc_cpu_init_config()
356 {
357 gConfig->acceptConfigEntryIntDef("cpu_pvr", 0x000c0201);
358 }
359 #endif
360