/[gxemul]/trunk/src/cpu_ppc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpu_ppc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 31931 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_ppc.c,v 1.85 2005/08/15 05:59:53 debug Exp $
29 *
30 * PowerPC/POWER CPU emulation.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include "misc.h"
39
40
41 #ifndef ENABLE_PPC
42
43
44 #include "cpu_ppc.h"
45
46
47 /*
48 * ppc_cpu_family_init():
49 *
50 * Bogus function.
51 */
52 int ppc_cpu_family_init(struct cpu_family *fp)
53 {
54 return 0;
55 }
56
57
58 #else /* ENABLE_PPC */
59
60
61 #include "cpu.h"
62 #include "cpu_ppc.h"
63 #include "machine.h"
64 #include "memory.h"
65 #include "opcodes_ppc.h"
66 #include "symbol.h"
67
68 #define DYNTRANS_DUALMODE_32
69 #define DYNTRANS_32
70 #include "tmp_ppc_head.c"
71
72
73 /*
74 * ppc_cpu_new():
75 *
76 * Create a new PPC cpu object.
77 *
78 * Returns 1 on success, 0 if there was no matching PPC processor with
79 * this cpu_type_name.
80 */
81 int ppc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
82 int cpu_id, char *cpu_type_name)
83 {
84 int any_cache = 0;
85 int i, found;
86 struct ppc_cpu_type_def cpu_type_defs[] = PPC_CPU_TYPE_DEFS;
87
88 /* Scan the cpu_type_defs list for this cpu type: */
89 i = 0;
90 found = -1;
91 while (i >= 0 && cpu_type_defs[i].name != NULL) {
92 if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
93 found = i;
94 break;
95 }
96 i++;
97 }
98 if (found == -1)
99 return 0;
100
101 cpu->memory_rw = ppc_memory_rw;
102 cpu->update_translation_table = ppc_update_translation_table;
103 cpu->invalidate_translation_caches_paddr =
104 ppc_invalidate_translation_caches_paddr;
105 cpu->invalidate_code_translation_caches =
106 ppc_invalidate_code_translation_caches;
107
108 cpu->cd.ppc.cpu_type = cpu_type_defs[found];
109 cpu->name = cpu->cd.ppc.cpu_type.name;
110 cpu->byte_order = EMUL_BIG_ENDIAN;
111 cpu->cd.ppc.mode = MODE_PPC; /* TODO */
112 cpu->cd.ppc.of_emul_addr = 0xff000000; /* TODO */
113
114 /* Current operating mode: */
115 cpu->cd.ppc.bits = cpu->cd.ppc.cpu_type.bits;
116
117 cpu->is_32bit = (cpu->cd.ppc.bits == 32)? 1 : 0;
118
119 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
120 if (cpu_id == 0) {
121 debug("%s", cpu->cd.ppc.cpu_type.name);
122
123 if (cpu->cd.ppc.cpu_type.icache_shift != 0)
124 any_cache = 1;
125 if (cpu->cd.ppc.cpu_type.dcache_shift != 0)
126 any_cache = 1;
127 if (cpu->cd.ppc.cpu_type.l2cache_shift != 0)
128 any_cache = 1;
129
130 if (any_cache) {
131 debug(" (I+D = %i+%i KB",
132 (int)(1 << (cpu->cd.ppc.cpu_type.icache_shift-10)),
133 (int)(1 << (cpu->cd.ppc.cpu_type.dcache_shift-10)));
134 if (cpu->cd.ppc.cpu_type.l2cache_shift != 0) {
135 debug(", L2 = %i KB",
136 (int)(1 << (cpu->cd.ppc.cpu_type.
137 l2cache_shift-10)));
138 }
139 debug(")");
140 }
141 }
142
143 cpu->cd.ppc.pir = cpu_id;
144
145 /* Some default stack pointer value. TODO: move this? */
146 cpu->cd.ppc.gpr[1] = machine->physical_ram_in_mb * 1048576 - 4096;
147
148 return 1;
149 }
150
151
152 /*
153 * ppc_cpu_list_available_types():
154 *
155 * Print a list of available PPC CPU types.
156 */
157 void ppc_cpu_list_available_types(void)
158 {
159 int i, j;
160 struct ppc_cpu_type_def tdefs[] = PPC_CPU_TYPE_DEFS;
161
162 i = 0;
163 while (tdefs[i].name != NULL) {
164 debug("%s", tdefs[i].name);
165 for (j=10 - strlen(tdefs[i].name); j>0; j--)
166 debug(" ");
167 i++;
168 if ((i % 6) == 0 || tdefs[i].name == NULL)
169 debug("\n");
170 }
171 }
172
173
174 /*
175 * ppc_cpu_dumpinfo():
176 */
177 void ppc_cpu_dumpinfo(struct cpu *cpu)
178 {
179 struct ppc_cpu_type_def *ct = &cpu->cd.ppc.cpu_type;
180
181 debug(" (%i-bit ", cpu->cd.ppc.bits);
182
183 switch (cpu->cd.ppc.mode) {
184 case MODE_PPC:
185 debug("PPC");
186 break;
187 case MODE_POWER:
188 debug("POWER");
189 break;
190 default:
191 debug("_INTERNAL ERROR_");
192 }
193
194 debug(", I+D = %i+%i KB",
195 (1 << ct->icache_shift) / 1024,
196 (1 << ct->dcache_shift) / 1024);
197
198 if (ct->l2cache_shift) {
199 int kb = (1 << ct->l2cache_shift) / 1024;
200 debug(", L2 = %i %cB",
201 kb >= 1024? kb / 1024 : kb,
202 kb >= 1024? 'M' : 'K');
203 }
204
205 debug(")\n");
206 }
207
208
209 /*
210 * reg_access_msr():
211 */
212 void reg_access_msr(struct cpu *cpu, uint64_t *valuep, int writeflag)
213 {
214 if (valuep == NULL) {
215 fatal("reg_access_msr(): NULL\n");
216 return;
217 }
218
219 if (writeflag)
220 cpu->cd.ppc.msr = *valuep;
221
222 /* TODO: Is the little-endian bit writable? */
223
224 cpu->cd.ppc.msr &= ~PPC_MSR_LE;
225 if (cpu->byte_order != EMUL_BIG_ENDIAN)
226 cpu->cd.ppc.msr |= PPC_MSR_LE;
227
228 if (!writeflag)
229 *valuep = cpu->cd.ppc.msr;
230 }
231
232
233 /*
234 * ppc_cpu_register_dump():
235 *
236 * Dump cpu registers in a relatively readable format.
237 *
238 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
239 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
240 */
241 void ppc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
242 {
243 char *symbol;
244 uint64_t offset, tmp;
245 int i, x = cpu->cpu_id;
246 int bits32 = cpu->cd.ppc.bits == 32;
247
248 if (gprs) {
249 /* Special registers (pc, ...) first: */
250 symbol = get_symbol_name(&cpu->machine->symbol_context,
251 cpu->pc, &offset);
252
253 debug("cpu%i: pc = 0x", x);
254 if (bits32)
255 debug("%08x", (int)cpu->pc);
256 else
257 debug("%016llx", (long long)cpu->pc);
258 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
259
260 debug("cpu%i: lr = 0x", x);
261 if (bits32)
262 debug("%08x", (int)cpu->cd.ppc.lr);
263 else
264 debug("%016llx", (long long)cpu->cd.ppc.lr);
265 debug(" cr = 0x%08x\n", (int)cpu->cd.ppc.cr);
266
267 debug("cpu%i: ctr = 0x", x);
268 if (bits32)
269 debug("%08x", (int)cpu->cd.ppc.ctr);
270 else
271 debug("%016llx", (long long)cpu->cd.ppc.ctr);
272
273 debug(" xer = 0x", x);
274 if (bits32)
275 debug("%08x\n", (int)cpu->cd.ppc.xer);
276 else
277 debug("%016llx\n", (long long)cpu->cd.ppc.xer);
278
279 if (bits32) {
280 /* 32-bit: */
281 for (i=0; i<PPC_NGPRS; i++) {
282 if ((i % 4) == 0)
283 debug("cpu%i:", x);
284 debug(" r%02i = 0x%08x ", i,
285 (int)cpu->cd.ppc.gpr[i]);
286 if ((i % 4) == 3)
287 debug("\n");
288 }
289 } else {
290 /* 64-bit: */
291 for (i=0; i<PPC_NGPRS; i++) {
292 int r = (i >> 1) + ((i & 1) << 4);
293 if ((i % 2) == 0)
294 debug("cpu%i:", x);
295 debug(" r%02i = 0x%016llx ", r,
296 (long long)cpu->cd.ppc.gpr[r]);
297 if ((i % 2) == 1)
298 debug("\n");
299 }
300 }
301
302 /* Other special registers: */
303 reg_access_msr(cpu, &tmp, 0);
304 debug("cpu%i: msr = 0x%016llx ", x, (long long)tmp);
305 debug("tb = 0x%08x%08x\n",
306 (int)cpu->cd.ppc.tbu, (int)cpu->cd.ppc.tbl);
307 debug("cpu%i: dec = 0x%08x hdec = 0x%08x\n",
308 x, (int)cpu->cd.ppc.dec, (int)cpu->cd.ppc.hdec);
309 }
310
311 if (coprocs) {
312 debug("cpu%i: fpscr = 0x%08x\n", x, (int)cpu->cd.ppc.fpscr);
313
314 /* TODO: show floating-point values :-) */
315
316 /* TODO: 32-bit fprs on 32-bit PPC cpus? */
317
318 for (i=0; i<PPC_NFPRS; i++) {
319 if ((i % 2) == 0)
320 debug("cpu%i:", x);
321 debug(" f%02i = 0x%016llx ", i,
322 (long long)cpu->cd.ppc.fpr[i]);
323 if ((i % 2) == 1)
324 debug("\n");
325 }
326 }
327 }
328
329
330 /*
331 * ppc_cpu_register_match():
332 */
333 void ppc_cpu_register_match(struct machine *m, char *name,
334 int writeflag, uint64_t *valuep, int *match_register)
335 {
336 int cpunr = 0;
337
338 /* CPU number: */
339
340 /* TODO */
341
342 /* Register name: */
343 if (strcasecmp(name, "pc") == 0) {
344 if (writeflag) {
345 m->cpus[cpunr]->pc = *valuep;
346 } else
347 *valuep = m->cpus[cpunr]->pc;
348 *match_register = 1;
349 } else if (strcasecmp(name, "msr") == 0) {
350 if (writeflag)
351 m->cpus[cpunr]->cd.ppc.msr = *valuep;
352 else
353 *valuep = m->cpus[cpunr]->cd.ppc.msr;
354 *match_register = 1;
355 } else if (strcasecmp(name, "lr") == 0) {
356 if (writeflag)
357 m->cpus[cpunr]->cd.ppc.lr = *valuep;
358 else
359 *valuep = m->cpus[cpunr]->cd.ppc.lr;
360 *match_register = 1;
361 } else if (strcasecmp(name, "cr") == 0) {
362 if (writeflag)
363 m->cpus[cpunr]->cd.ppc.cr = *valuep;
364 else
365 *valuep = m->cpus[cpunr]->cd.ppc.cr;
366 *match_register = 1;
367 } else if (strcasecmp(name, "dec") == 0) {
368 if (writeflag)
369 m->cpus[cpunr]->cd.ppc.dec = *valuep;
370 else
371 *valuep = m->cpus[cpunr]->cd.ppc.dec;
372 *match_register = 1;
373 } else if (strcasecmp(name, "hdec") == 0) {
374 if (writeflag)
375 m->cpus[cpunr]->cd.ppc.hdec = *valuep;
376 else
377 *valuep = m->cpus[cpunr]->cd.ppc.hdec;
378 *match_register = 1;
379 } else if (strcasecmp(name, "ctr") == 0) {
380 if (writeflag)
381 m->cpus[cpunr]->cd.ppc.ctr = *valuep;
382 else
383 *valuep = m->cpus[cpunr]->cd.ppc.ctr;
384 *match_register = 1;
385 } else if (name[0] == 'r' && isdigit((int)name[1])) {
386 int nr = atoi(name + 1);
387 if (nr >= 0 && nr < PPC_NGPRS) {
388 if (writeflag) {
389 m->cpus[cpunr]->cd.ppc.gpr[nr] = *valuep;
390 } else
391 *valuep = m->cpus[cpunr]->cd.ppc.gpr[nr];
392 *match_register = 1;
393 }
394 } else if (strcasecmp(name, "xer") == 0) {
395 if (writeflag)
396 m->cpus[cpunr]->cd.ppc.xer = *valuep;
397 else
398 *valuep = m->cpus[cpunr]->cd.ppc.xer;
399 *match_register = 1;
400 } else if (strcasecmp(name, "fpscr") == 0) {
401 if (writeflag)
402 m->cpus[cpunr]->cd.ppc.fpscr = *valuep;
403 else
404 *valuep = m->cpus[cpunr]->cd.ppc.fpscr;
405 *match_register = 1;
406 } else if (name[0] == 'f' && isdigit((int)name[1])) {
407 int nr = atoi(name + 1);
408 if (nr >= 0 && nr < PPC_NFPRS) {
409 if (writeflag) {
410 m->cpus[cpunr]->cd.ppc.fpr[nr] = *valuep;
411 } else
412 *valuep = m->cpus[cpunr]->cd.ppc.fpr[nr];
413 *match_register = 1;
414 }
415 }
416 }
417
418
419 /*
420 * ppc_cpu_show_full_statistics():
421 *
422 * Show detailed statistics on opcode usage on each cpu.
423 */
424 void ppc_cpu_show_full_statistics(struct machine *m)
425 {
426 fatal("ppc_cpu_show_full_statistics(): TODO\n");
427 }
428
429
430 /*
431 * ppc_cpu_tlbdump():
432 *
433 * Called from the debugger to dump the TLB in a readable format.
434 * x is the cpu number to dump, or -1 to dump all CPUs.
435 *
436 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
437 * just dumped.
438 */
439 void ppc_cpu_tlbdump(struct machine *m, int x, int rawflag)
440 {
441 fatal("ppc_cpu_tlbdump(): TODO\n");
442 }
443
444
445 /*
446 * ppc_cpu_interrupt():
447 */
448 int ppc_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
449 {
450 fatal("ppc_cpu_interrupt(): TODO\n");
451 return 0;
452 }
453
454
455 /*
456 * ppc_cpu_interrupt_ack():
457 */
458 int ppc_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
459 {
460 /* fatal("ppc_cpu_interrupt_ack(): TODO\n"); */
461 return 0;
462 }
463
464
465 /*
466 * ppc_cpu_disassemble_instr():
467 *
468 * Convert an instruction word into human readable format, for instruction
469 * tracing.
470 *
471 * If running is 1, cpu->pc should be the address of the instruction.
472 *
473 * If running is 0, things that depend on the runtime environment (eg.
474 * register contents) will not be shown, and addr will be used instead of
475 * cpu->pc for relative addresses.
476 */
477 int ppc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
478 int running, uint64_t dumpaddr, int bintrans)
479 {
480 int hi6, xo, lev, rt, rs, ra, rb, imm, sh, me, rc, l_bit, oe_bit;
481 int spr, aa_bit, lk_bit, bf, bh, bi, bo, mb, nb, bt, ba, bb, fpreg;
482 int bfa;
483 uint64_t offset, addr;
484 uint32_t iword;
485 char *symbol, *mnem = "ERROR";
486 int power = cpu->cd.ppc.mode == MODE_POWER;
487
488 if (running)
489 dumpaddr = cpu->pc;
490
491 symbol = get_symbol_name(&cpu->machine->symbol_context,
492 dumpaddr, &offset);
493 if (symbol != NULL && offset==0)
494 debug("<%s>\n", symbol);
495
496 if (cpu->machine->ncpus > 1 && running)
497 debug("cpu%i: ", cpu->cpu_id);
498
499 if (cpu->cd.ppc.bits == 32)
500 debug("%08x", (int)dumpaddr);
501 else
502 debug("%016llx", (long long)dumpaddr);
503
504 /* NOTE: Fixed to big-endian. */
505 iword = (instr[0] << 24) + (instr[1] << 16) + (instr[2] << 8)
506 + instr[3];
507
508 debug(": %08x\t", iword);
509
510 /*
511 * Decode the instruction:
512 */
513
514 hi6 = iword >> 26;
515
516 switch (hi6) {
517 case PPC_HI6_MULLI:
518 case PPC_HI6_SUBFIC:
519 rt = (iword >> 21) & 31;
520 ra = (iword >> 16) & 31;
521 imm = (int16_t)(iword & 0xffff);
522 switch (hi6) {
523 case PPC_HI6_MULLI:
524 mnem = power? "muli":"mulli";
525 break;
526 case PPC_HI6_SUBFIC:
527 mnem = power? "sfi":"subfic";
528 break;
529 }
530 debug("%s\tr%i,r%i,%i", mnem, rt, ra, imm);
531 break;
532 case PPC_HI6_CMPLI:
533 case PPC_HI6_CMPI:
534 bf = (iword >> 23) & 7;
535 l_bit = (iword >> 21) & 1;
536 ra = (iword >> 16) & 31;
537 if (hi6 == PPC_HI6_CMPLI) {
538 imm = iword & 0xffff;
539 mnem = "cmpl";
540 } else {
541 imm = (int16_t)(iword & 0xffff);
542 mnem = "cmp";
543 }
544 debug("%s%si\t", mnem, l_bit? "d" : "w");
545 if (bf != 0)
546 debug("cr%i,", bf);
547 debug("r%i,%i", ra, imm);
548 break;
549 case PPC_HI6_ADDIC:
550 case PPC_HI6_ADDIC_DOT:
551 rt = (iword >> 21) & 31;
552 ra = (iword >> 16) & 31;
553 rc = hi6 == PPC_HI6_ADDIC_DOT;
554 imm = (int16_t)(iword & 0xffff);
555 mnem = power? "ai":"addic";
556 if (imm < 0 && !power) {
557 mnem = "subic";
558 imm = -imm;
559 }
560 debug("%s%s\tr%i,r%i,%i", mnem, rc?".":"", rt, ra, imm);
561 break;
562 case PPC_HI6_ADDI:
563 rt = (iword >> 21) & 31;
564 ra = (iword >> 16) & 31;
565 imm = (int16_t)(iword & 0xffff);
566 if (ra == 0)
567 debug("li\tr%i,%i", rt, imm);
568 else {
569 mnem = power? "cal":"addi";
570 if (imm < 0 && !power) {
571 mnem = "subi";
572 imm = -imm;
573 }
574 debug("%s\tr%i,r%i,%i", mnem, rt, ra, imm);
575 }
576 break;
577 case PPC_HI6_ADDIS:
578 rt = (iword >> 21) & 31;
579 ra = (iword >> 16) & 31;
580 imm = (int16_t)(iword & 0xffff);
581 if (ra == 0)
582 debug("lis\tr%i,%i", rt, imm);
583 else
584 debug("%s\tr%i,r%i,%i",
585 power? "cau":"addis", rt, ra, imm);
586 break;
587 case PPC_HI6_BC:
588 aa_bit = (iword & 2) >> 1;
589 lk_bit = iword & 1;
590 bo = (iword >> 21) & 31;
591 bi = (iword >> 16) & 31;
592 /* Sign-extend addr: */
593 addr = (int64_t)(int16_t)(iword & 0xfffc);
594 debug("bc");
595 if (lk_bit)
596 debug("l");
597 if (aa_bit)
598 debug("a");
599 else
600 addr += dumpaddr;
601 debug("\t%i,%i,", bo, bi);
602 if (cpu->cd.ppc.bits == 32)
603 addr &= 0xffffffff;
604 if (cpu->cd.ppc.bits == 32)
605 debug("0x%x", (int)addr);
606 else
607 debug("0x%llx", (long long)addr);
608 symbol = get_symbol_name(&cpu->machine->symbol_context,
609 addr, &offset);
610 if (symbol != NULL)
611 debug("\t<%s>", symbol);
612 break;
613 case PPC_HI6_SC:
614 lev = (iword >> 5) & 0x7f;
615 debug("sc");
616 if (lev != 0) {
617 debug("\t%i", lev);
618 if (lev > 1)
619 debug(" (WARNING! reserved value)");
620 }
621 break;
622 case PPC_HI6_B:
623 aa_bit = (iword & 2) >> 1;
624 lk_bit = iword & 1;
625 /* Sign-extend addr: */
626 addr = (int64_t)(int32_t)((iword & 0x03fffffc) << 6);
627 addr = (int64_t)addr >> 6;
628 debug("b");
629 if (lk_bit)
630 debug("l");
631 if (aa_bit)
632 debug("a");
633 else
634 addr += dumpaddr;
635 if (cpu->cd.ppc.bits == 32)
636 addr &= 0xffffffff;
637 if (cpu->cd.ppc.bits == 32)
638 debug("\t0x%x", (int)addr);
639 else
640 debug("\t0x%llx", (long long)addr);
641 symbol = get_symbol_name(&cpu->machine->symbol_context,
642 addr, &offset);
643 if (symbol != NULL)
644 debug("\t<%s>", symbol);
645 break;
646 case PPC_HI6_19:
647 xo = (iword >> 1) & 1023;
648 switch (xo) {
649 case PPC_19_MCRF:
650 bf = (iword >> 23) & 7;
651 bfa = (iword >> 18) & 7;
652 debug("mcrf\tcr%i,cr%i", bf, bfa);
653 break;
654 case PPC_19_BCLR:
655 case PPC_19_BCCTR:
656 bo = (iword >> 21) & 31;
657 bi = (iword >> 16) & 31;
658 bh = (iword >> 11) & 3;
659 lk_bit = iword & 1;
660 switch (xo) {
661 case PPC_19_BCLR:
662 mnem = power? "bcr" : "bclr"; break;
663 case PPC_19_BCCTR:
664 mnem = power? "bcc" : "bcctr"; break;
665 }
666 debug("%s%s%s\t%i,%i,%i", mnem, lk_bit? "l" : "",
667 bh? (bh==3? "+" : (bh==2? "-" : "?")) : "",
668 bo, bi, bh);
669 break;
670 case PPC_19_ISYNC:
671 debug("%s", power? "ics" : "isync");
672 break;
673 case PPC_19_CRAND:
674 case PPC_19_CRXOR:
675 case PPC_19_CROR:
676 case PPC_19_CRNAND:
677 case PPC_19_CRNOR:
678 case PPC_19_CRANDC:
679 case PPC_19_CREQV:
680 case PPC_19_CRORC:
681 bt = (iword >> 21) & 31;
682 ba = (iword >> 16) & 31;
683 bb = (iword >> 11) & 31;
684 switch (xo) {
685 case PPC_19_CRAND: mnem = "crand"; break;
686 case PPC_19_CRXOR: mnem = "crxor"; break;
687 case PPC_19_CROR: mnem = "cror"; break;
688 case PPC_19_CRNAND: mnem = "crnand"; break;
689 case PPC_19_CRNOR: mnem = "crnor"; break;
690 case PPC_19_CRANDC: mnem = "crandc"; break;
691 case PPC_19_CREQV: mnem = "creqv"; break;
692 case PPC_19_CRORC: mnem = "crorc"; break;
693 }
694 debug("%s\t%i,%i,%i", mnem, bt, ba, bb);
695 break;
696 default:
697 debug("unimplemented hi6_19, xo = 0x%x", xo);
698 }
699 break;
700 case PPC_HI6_RLWIMI:
701 case PPC_HI6_RLWINM:
702 rs = (iword >> 21) & 31;
703 ra = (iword >> 16) & 31;
704 sh = (iword >> 11) & 31;
705 mb = (iword >> 6) & 31;
706 me = (iword >> 1) & 31;
707 rc = iword & 1;
708 switch (hi6) {
709 case PPC_HI6_RLWIMI:
710 mnem = power? "rlimi" : "rlwimi"; break;
711 case PPC_HI6_RLWINM:
712 mnem = power? "rlinm" : "rlwinm"; break;
713 }
714 debug("%s%s\tr%i,r%i,%i,%i,%i",
715 mnem, rc?".":"", ra, rs, sh, mb, me);
716 break;
717 case PPC_HI6_ORI:
718 case PPC_HI6_ORIS:
719 case PPC_HI6_XORI:
720 case PPC_HI6_XORIS:
721 case PPC_HI6_ANDI_DOT:
722 case PPC_HI6_ANDIS_DOT:
723 rs = (iword >> 21) & 31;
724 ra = (iword >> 16) & 31;
725 imm = iword & 0xffff;
726 switch (hi6) {
727 case PPC_HI6_ORI:
728 mnem = power? "oril":"ori";
729 break;
730 case PPC_HI6_ORIS:
731 mnem = power? "oriu":"oris";
732 break;
733 case PPC_HI6_XORI:
734 mnem = power? "xoril":"xori";
735 break;
736 case PPC_HI6_XORIS:
737 mnem = power? "xoriu":"xoris";
738 break;
739 case PPC_HI6_ANDI_DOT:
740 mnem = power? "andil.":"andi.";
741 break;
742 case PPC_HI6_ANDIS_DOT:
743 mnem = power? "andiu.":"andis.";
744 break;
745 }
746 if (hi6 == PPC_HI6_ORI && rs == 0 && ra == 0 && imm == 0)
747 debug("nop");
748 else
749 debug("%s\tr%i,r%i,0x%04x", mnem, ra, rs, imm);
750 break;
751 case PPC_HI6_30:
752 xo = (iword >> 2) & 7;
753 switch (xo) {
754 case PPC_30_RLDICR:
755 rs = (iword >> 21) & 31;
756 ra = (iword >> 16) & 31;
757 sh = ((iword >> 11) & 31) | ((iword & 2) << 4);
758 me = ((iword >> 6) & 31) | (iword & 0x20);
759 rc = iword & 1;
760 debug("rldicr%s\tr%i,r%i,%i,%i",
761 rc?".":"", ra, rs, sh, me);
762 break;
763 default:
764 debug("unimplemented hi6_30, xo = 0x%x", xo);
765 }
766 break;
767 case PPC_HI6_31:
768 xo = (iword >> 1) & 1023;
769 switch (xo) {
770
771 case PPC_31_CMP:
772 case PPC_31_CMPL:
773 bf = (iword >> 23) & 7;
774 l_bit = (iword >> 21) & 1;
775 ra = (iword >> 16) & 31;
776 rb = (iword >> 11) & 31;
777 if (xo == PPC_31_CMPL)
778 mnem = "cmpl";
779 else
780 mnem = "cmp";
781 debug("%s%s\t", mnem, l_bit? "d" : "w");
782 if (bf != 0)
783 debug("cr%i,", bf);
784 debug("r%i,r%i", ra, rb);
785 break;
786 case PPC_31_MFCR:
787 rt = (iword >> 21) & 31;
788 debug("mfcr\tr%i", rt);
789 break;
790 case PPC_31_MFMSR:
791 rt = (iword >> 21) & 31;
792 debug("mfmsr\tr%i", rt);
793 break;
794 case PPC_31_MTCRF:
795 rs = (iword >> 21) & 31;
796 mb = (iword >> 12) & 255; /* actually fxm, not mb */
797 debug("mtcrf\t%i,r%i", mb, rs);
798 break;
799 case PPC_31_MTMSR:
800 rs = (iword >> 21) & 31;
801 l_bit = (iword >> 16) & 1;
802 debug("mtmsr\tr%i", rs);
803 if (l_bit)
804 debug(",%i", l_bit);
805 break;
806 case PPC_31_LBZX:
807 case PPC_31_LBZUX:
808 case PPC_31_LHZX:
809 case PPC_31_LHZUX:
810 case PPC_31_LWZX:
811 case PPC_31_LWZUX:
812 case PPC_31_STBX:
813 case PPC_31_STBUX:
814 case PPC_31_STHX:
815 case PPC_31_STHUX:
816 case PPC_31_STWX:
817 case PPC_31_STWUX:
818 case PPC_31_STDX:
819 case PPC_31_STDUX:
820 /* rs for stores, rt for loads, actually */
821 rs = (iword >> 21) & 31;
822 ra = (iword >> 16) & 31;
823 rb = (iword >> 11) & 31;
824 switch (xo) {
825 case PPC_31_LBZX: mnem = "lbzx"; break;
826 case PPC_31_LBZUX: mnem = "lbzux"; break;
827 case PPC_31_LHZX: mnem = "lhzx"; break;
828 case PPC_31_LHZUX: mnem = "lhzux"; break;
829 case PPC_31_LWZX:
830 mnem = power? "lx" : "lwzx";
831 break;
832 case PPC_31_LWZUX:
833 mnem = power? "lux" : "lwzux";
834 break;
835 case PPC_31_STBX: mnem = "stbx"; break;
836 case PPC_31_STBUX: mnem = "stbux"; break;
837 case PPC_31_STHX: mnem = "sthx"; break;
838 case PPC_31_STHUX: mnem = "sthux"; break;
839 case PPC_31_STWX:
840 mnem = power? "stx" : "stwx";
841 break;
842 case PPC_31_STWUX:
843 mnem = power? "stux" : "stwux";
844 break;
845 case PPC_31_STDX: mnem = "stdx"; break;
846 case PPC_31_STDUX: mnem = "stdux"; break;
847 }
848 debug("%s\tr%i,r%i,r%i", mnem, rs, ra, rb);
849 break;
850 case PPC_31_NEG:
851 case PPC_31_NEGO:
852 rt = (iword >> 21) & 31;
853 ra = (iword >> 16) & 31;
854 oe_bit = (iword >> 10) & 1;
855 rc = iword & 1;
856 switch (xo) {
857 case PPC_31_NEG: mnem = "neg"; break;
858 case PPC_31_NEGO: mnem = "nego"; break;
859 }
860 debug("%s%s\tr%i,r%i", mnem, rc? "." : "", rt, ra);
861 break;
862 case PPC_31_ADDZE:
863 case PPC_31_ADDZEO:
864 rt = (iword >> 21) & 31;
865 ra = (iword >> 16) & 31;
866 oe_bit = (iword >> 10) & 1;
867 rc = iword & 1;
868 switch (xo) {
869 case PPC_31_ADDZE:
870 mnem = power? "aze" : "addze";
871 break;
872 case PPC_31_ADDZEO:
873 mnem = power? "azeo" : "addzeo";
874 break;
875 }
876 debug("%s%s\tr%i,r%i", mnem, rc? "." : "", rt, ra);
877 break;
878 case PPC_31_MTSR:
879 /* Move to segment register (?) */
880 /* TODO */
881 debug("mtsr\tTODO");
882 break;
883 case PPC_31_MTSRIN:
884 case PPC_31_MFSRIN:
885 /* Move to/from segment register indirect */
886 rt = (iword >> 21) & 31;
887 rb = (iword >> 11) & 31;
888 switch (xo) {
889 case PPC_31_MTSRIN: mnem = "mtsrin"; break;
890 case PPC_31_MFSRIN: mnem = "mfsrin"; break;
891 }
892 debug("%s\tr%i,r%i", mnem, rt, rb);
893 break;
894 case PPC_31_ADDC:
895 case PPC_31_ADDCO:
896 case PPC_31_ADDE:
897 case PPC_31_ADDEO:
898 case PPC_31_ADD:
899 case PPC_31_ADDO:
900 case PPC_31_MULHW:
901 case PPC_31_MULHWU:
902 case PPC_31_MULLW:
903 case PPC_31_MULLWO:
904 case PPC_31_SUBF:
905 case PPC_31_SUBFO:
906 case PPC_31_SUBFC:
907 case PPC_31_SUBFCO:
908 case PPC_31_SUBFE:
909 case PPC_31_SUBFEO:
910 case PPC_31_SUBFZE:
911 case PPC_31_SUBFZEO:
912 rt = (iword >> 21) & 31;
913 ra = (iword >> 16) & 31;
914 rb = (iword >> 11) & 31;
915 oe_bit = (iword >> 10) & 1;
916 rc = iword & 1;
917 switch (xo) {
918 case PPC_31_ADDC:
919 mnem = power? "a" : "addc";
920 break;
921 case PPC_31_ADDCO:
922 mnem = power? "ao" : "addco";
923 break;
924 case PPC_31_ADDE:
925 mnem = power? "ae" : "adde";
926 break;
927 case PPC_31_ADDEO:
928 mnem = power? "aeo" : "addeo";
929 break;
930 case PPC_31_ADD:
931 mnem = power? "cax" : "add";
932 break;
933 case PPC_31_ADDO:
934 mnem = power? "caxo" : "addo";
935 break;
936 case PPC_31_MULHW: mnem = "mulhw"; break;
937 case PPC_31_MULHWU: mnem = "mulhwu"; break;
938 case PPC_31_MULLW:
939 mnem = power? "muls" : "mullw";
940 break;
941 case PPC_31_MULLWO:
942 mnem = power? "mulso" : "mullwo";
943 break;
944 case PPC_31_SUBF: mnem = "subf"; break;
945 case PPC_31_SUBFO: mnem = "subfo"; break;
946 case PPC_31_SUBFC:
947 mnem = power? "sf" : "subfc";
948 break;
949 case PPC_31_SUBFCO:
950 mnem = power? "sfo" : "subfco";
951 break;
952 case PPC_31_SUBFE:
953 mnem = power? "sfe" : "subfe";
954 break;
955 case PPC_31_SUBFEO:
956 mnem = power? "sfeo" : "subfeo";
957 break;
958 case PPC_31_SUBFZE:
959 mnem = power? "sfze" : "subfze";
960 break;
961 case PPC_31_SUBFZEO:
962 mnem = power? "sfzeo" : "subfzeo";
963 break;
964 }
965 debug("%s%s\tr%i,r%i,r%i", mnem, rc? "." : "",
966 rt, ra, rb);
967 break;
968 case PPC_31_MFSPR:
969 rt = (iword >> 21) & 31;
970 spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31);
971 switch (spr) {
972 case 8: debug("mflr\tr%i", rt); break;
973 case 272: debug("mfsprg\t0,r%i", rt); break;
974 case 273: debug("mfsprg\t1,r%i", rt); break;
975 case 274: debug("mfsprg\t2,r%i", rt); break;
976 case 275: debug("mfsprg\t3,r%i", rt); break;
977 case 1008: debug("mfdbsr\tr%i", rt); break;
978 default:debug("mfspr\tr%i,spr%i", rt, spr);
979 }
980 break;
981 case PPC_31_TLBIE:
982 /* TODO: what is ra? The IBM online docs didn't say */
983 ra = 0;
984 rb = (iword >> 11) & 31;
985 if (power)
986 debug("tlbi\tr%i,r%i", ra, rb);
987 else
988 debug("tlbie\tr%i", rb);
989 break;
990 case PPC_31_TLBSYNC:
991 debug("tlbsync");
992 break;
993 case PPC_31_MFTB:
994 rt = (iword >> 21) & 31;
995 spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31);
996 debug("mftb%s\tr%i", spr==268? "" :
997 (spr==269? "u" : "?"), rt);
998 break;
999 case PPC_31_CNTLZW:
1000 rs = (iword >> 21) & 31;
1001 ra = (iword >> 16) & 31;
1002 rc = iword & 1;
1003 mnem = power? "cntlz" : "cntlzw";
1004 debug("%s\tr%i,r%i", mnem, rc? "." : "", ra, rs);
1005 break;
1006 case PPC_31_CLF: /* POWER only */
1007 case PPC_31_CLI: /* POWER only */
1008 case PPC_31_DCLST: /* POWER only */
1009 case PPC_31_DCBF: /* PowerPC only */
1010 case PPC_31_DCBI: /* PowerPC only */
1011 case PPC_31_DCBST: /* PowerPC only */
1012 case PPC_31_DCBTST: /* PowerPC only */
1013 case PPC_31_DCBT: /* PowerPC only */
1014 case PPC_31_ICBI: /* PowerPC only */
1015 case PPC_31_DCBZ: /* POWER/PowerPC */
1016 ra = (iword >> 16) & 31;
1017 rb = (iword >> 11) & 31;
1018 switch (xo) {
1019 case PPC_31_CLF: mnem = "clf"; break;
1020 case PPC_31_CLI: mnem = "cli"; break;
1021 case PPC_31_DCLST: mnem = "dclst"; break;
1022 case PPC_31_DCBF: mnem = "dcbf"; break;
1023 case PPC_31_DCBI: mnem = "dcbi"; break;
1024 case PPC_31_DCBST: mnem = "dcbst"; break;
1025 case PPC_31_DCBTST:mnem = "dcbtst"; break;
1026 case PPC_31_DCBT: mnem = "dcbt"; break;
1027 case PPC_31_ICBI: mnem = "icbi"; break;
1028 case PPC_31_DCBZ: mnem = power ?
1029 "dclz" : "dcbz"; break;
1030 }
1031 debug("%s\tr%i,r%i", mnem, ra, rb);
1032 break;
1033 case PPC_31_SLW:
1034 case PPC_31_SRAW:
1035 case PPC_31_SRW:
1036 case PPC_31_AND:
1037 case PPC_31_ANDC:
1038 case PPC_31_NOR:
1039 case PPC_31_OR:
1040 case PPC_31_ORC:
1041 case PPC_31_XOR:
1042 case PPC_31_NAND:
1043 rs = (iword >> 21) & 31;
1044 ra = (iword >> 16) & 31;
1045 rb = (iword >> 11) & 31;
1046 rc = iword & 1;
1047 if (rs == rb && xo == PPC_31_OR)
1048 debug("mr%s\tr%i,r%i", rc? "." : "", ra, rs);
1049 else {
1050 switch (xo) {
1051 case PPC_31_SLW: mnem =
1052 power? "sl" : "slw"; break;
1053 case PPC_31_SRAW: mnem =
1054 power? "sra" : "sraw"; break;
1055 case PPC_31_SRW: mnem =
1056 power? "sr" : "srw"; break;
1057 case PPC_31_AND: mnem = "and"; break;
1058 case PPC_31_NAND: mnem = "nand"; break;
1059 case PPC_31_ANDC: mnem = "andc"; break;
1060 case PPC_31_NOR: mnem = "nor"; break;
1061 case PPC_31_OR: mnem = "or"; break;
1062 case PPC_31_ORC: mnem = "orc"; break;
1063 case PPC_31_XOR: mnem = "xor"; break;
1064 }
1065 debug("%s%s\tr%i,r%i,r%i", mnem,
1066 rc? "." : "", ra, rs, rb);
1067 }
1068 break;
1069 case PPC_31_DCCCI:
1070 ra = (iword >> 16) & 31;
1071 rb = (iword >> 11) & 31;
1072 debug("dccci\tr%i,r%i", ra, rb);
1073 break;
1074 case PPC_31_ICCCI:
1075 ra = (iword >> 16) & 31;
1076 rb = (iword >> 11) & 31;
1077 debug("iccci\tr%i,r%i", ra, rb);
1078 break;
1079 case PPC_31_DIVW:
1080 case PPC_31_DIVWO:
1081 case PPC_31_DIVWU:
1082 case PPC_31_DIVWUO:
1083 rt = (iword >> 21) & 31;
1084 ra = (iword >> 16) & 31;
1085 rb = (iword >> 11) & 31;
1086 oe_bit = (iword >> 10) & 1;
1087 rc = iword & 1;
1088 switch (xo) {
1089 case PPC_31_DIVWU: mnem = "divwu"; break;
1090 case PPC_31_DIVWUO: mnem = "divwuo"; break;
1091 case PPC_31_DIVW: mnem = "divw"; break;
1092 case PPC_31_DIVWO: mnem = "divwo"; break;
1093 }
1094 debug("%s%s\tr%i,r%i,r%i", mnem, rc? "." : "",
1095 rt, ra, rb);
1096 break;
1097 case PPC_31_MTSPR:
1098 rs = (iword >> 21) & 31;
1099 spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31);
1100 switch (spr) {
1101 case 8: debug("mtlr\tr%i", rs); break;
1102 case 272: debug("mtsprg\t0,r%i", rs); break;
1103 case 273: debug("mtsprg\t1,r%i", rs); break;
1104 case 274: debug("mtsprg\t2,r%i", rs); break;
1105 case 275: debug("mtsprg\t3,r%i", rs); break;
1106 default:debug("mtspr\tspr%i,r%i", spr, rs);
1107 }
1108 break;
1109 case PPC_31_SYNC:
1110 debug("%s", power? "dcs" : "sync");
1111 break;
1112 case PPC_31_LSWI:
1113 case PPC_31_STSWI:
1114 rs = (iword >> 21) & 31; /* lwsi uses rt */
1115 ra = (iword >> 16) & 31;
1116 nb = (iword >> 11) & 31;
1117 switch (xo) {
1118 case PPC_31_LSWI:
1119 mnem = power? "lsi" : "lswi"; break;
1120 case PPC_31_STSWI:
1121 mnem = power? "stsi" : "stswi"; break;
1122 }
1123 debug("%s\tr%i,r%i,%i", mnem, rs, ra, nb);
1124 break;
1125 case PPC_31_LHBRX:
1126 case PPC_31_LWBRX:
1127 case PPC_31_STHBRX:
1128 case PPC_31_STWBRX:
1129 rt = (iword >> 21) & 31; /* stores use rs */
1130 ra = (iword >> 16) & 31;
1131 rb = (iword >> 11) & 31;
1132 switch (xo) {
1133 case PPC_31_LHBRX: mnem = "lhbrx"; break;
1134 case PPC_31_LWBRX: mnem = power?
1135 "lbrx" : "lwbrx"; break;
1136 case PPC_31_STHBRX: mnem = "sthbrx"; break;
1137 case PPC_31_STWBRX: mnem = power?
1138 "stbrx" : "stwbrx"; break;
1139 }
1140 debug("%s\tr%i,r%i,r%i", mnem, rt, ra, rb);
1141 break;
1142 case PPC_31_SRAWI:
1143 rs = (iword >> 21) & 31;
1144 ra = (iword >> 16) & 31;
1145 sh = (iword >> 11) & 31;
1146 rc = iword & 1;
1147 mnem = power? "srai" : "srawi";
1148 debug("%s%s\tr%i,r%i,%i", mnem,
1149 rc? "." : "", ra, rs, sh);
1150 break;
1151 case PPC_31_EIEIO:
1152 debug("%s", power? "eieio?" : "eieio");
1153 break;
1154 case PPC_31_EXTSB:
1155 case PPC_31_EXTSH:
1156 case PPC_31_EXTSW:
1157 rs = (iword >> 21) & 31;
1158 ra = (iword >> 16) & 31;
1159 rc = iword & 1;
1160 switch (xo) {
1161 case PPC_31_EXTSB:
1162 mnem = power? "exts" : "extsb";
1163 break;
1164 case PPC_31_EXTSH:
1165 mnem = "extsh";
1166 break;
1167 case PPC_31_EXTSW:
1168 mnem = "extsw";
1169 break;
1170 }
1171 debug("%s%s\tr%i,r%i", mnem, rc? "." : "", ra, rs);
1172 break;
1173 default:
1174 debug("unimplemented hi6_31, xo = 0x%x", xo);
1175 }
1176 break;
1177 case PPC_HI6_LWZ:
1178 case PPC_HI6_LWZU:
1179 case PPC_HI6_LHZ:
1180 case PPC_HI6_LHZU:
1181 case PPC_HI6_LHA:
1182 case PPC_HI6_LHAU:
1183 case PPC_HI6_LBZ:
1184 case PPC_HI6_LBZU:
1185 case PPC_HI6_LMW:
1186 case PPC_HI6_STW:
1187 case PPC_HI6_STWU:
1188 case PPC_HI6_STH:
1189 case PPC_HI6_STHU:
1190 case PPC_HI6_STB:
1191 case PPC_HI6_STBU:
1192 case PPC_HI6_STMW:
1193 case PPC_HI6_LFD:
1194 case PPC_HI6_STFD:
1195 /* NOTE: Loads use rt, not rs, but are otherwise similar
1196 to stores */
1197 rs = (iword >> 21) & 31;
1198 ra = (iword >> 16) & 31;
1199 imm = (int16_t)(iword & 0xffff);
1200 fpreg = 0;
1201 switch (hi6) {
1202 case PPC_HI6_LWZ: mnem = power? "l" : "lwz"; break;
1203 case PPC_HI6_LWZU: mnem = power? "lu" : "lwzu"; break;
1204 case PPC_HI6_LHZ: mnem = "lhz"; break;
1205 case PPC_HI6_LHZU: mnem = "lhzu"; break;
1206 case PPC_HI6_LHA: mnem = "lha"; break;
1207 case PPC_HI6_LHAU: mnem = "lhau"; break;
1208 case PPC_HI6_LBZ: mnem = "lbz"; break;
1209 case PPC_HI6_LBZU: mnem = "lbzu"; break;
1210 case PPC_HI6_STW: mnem = power? "st" : "stw"; break;
1211 case PPC_HI6_STWU: mnem = power? "stu" : "stwu"; break;
1212 case PPC_HI6_STH: mnem = "sth"; break;
1213 case PPC_HI6_STHU: mnem = "sthu"; break;
1214 case PPC_HI6_STB: mnem = "stb"; break;
1215 case PPC_HI6_STBU: mnem = "stbu"; break;
1216 case PPC_HI6_LMW: mnem = power? "lm" : "lmw"; break;
1217 case PPC_HI6_STMW: mnem = power? "stm" : "stmw"; break;
1218 case PPC_HI6_LFD: fpreg = 1; mnem = "lfd"; break;
1219 case PPC_HI6_STFD: fpreg = 1; mnem = "stfd"; break;
1220 }
1221 debug("%s\t", mnem);
1222 if (fpreg)
1223 debug("f");
1224 else
1225 debug("r");
1226 debug("%i,%i(r%i)", rs, imm, ra);
1227 break;
1228 default:
1229 /* TODO */
1230 debug("unimplemented hi6 = 0x%02x", hi6);
1231 }
1232
1233 debug("\n");
1234 return sizeof(iword);
1235 }
1236
1237
1238 /*
1239 * update_cr0():
1240 *
1241 * Sets the top 4 bits of the CR register.
1242 */
1243 void update_cr0(struct cpu *cpu, uint64_t value)
1244 {
1245 int c;
1246
1247 if (cpu->cd.ppc.bits == 64) {
1248 if ((int64_t)value < 0)
1249 c = 8;
1250 else if ((int64_t)value > 0)
1251 c = 4;
1252 else
1253 c = 2;
1254 } else {
1255 if ((int32_t)value < 0)
1256 c = 8;
1257 else if ((int32_t)value > 0)
1258 c = 4;
1259 else
1260 c = 2;
1261 }
1262
1263 /* SO bit, copied from XER: */
1264 c |= ((cpu->cd.ppc.xer >> 31) & 1);
1265
1266 cpu->cd.ppc.cr &= ~((uint32_t)0xf << 28);
1267 cpu->cd.ppc.cr |= ((uint32_t)c << 28);
1268 }
1269
1270
1271 #include "tmp_ppc_tail.c"
1272
1273
1274 #endif /* ENABLE_PPC */

  ViewVC Help
Powered by ViewVC 1.1.26