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