/[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

Annotation of /trunk/src/cpu_ppc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 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 dpavlin 2 /*
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 dpavlin 12 * $Id: cpu_ppc.c,v 1.85 2005/08/15 05:59:53 debug Exp $
29 dpavlin 2 *
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 dpavlin 12 #define DYNTRANS_DUALMODE_32
69     #define DYNTRANS_32
70     #include "tmp_ppc_head.c"
71 dpavlin 2
72    
73     /*
74     * ppc_cpu_new():
75     *
76     * Create a new PPC cpu object.
77 dpavlin 10 *
78     * Returns 1 on success, 0 if there was no matching PPC processor with
79     * this cpu_type_name.
80 dpavlin 2 */
81 dpavlin 10 int ppc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
82 dpavlin 2 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 dpavlin 10 return 0;
100 dpavlin 2
101 dpavlin 12 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 dpavlin 2 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 dpavlin 12 cpu->is_32bit = (cpu->cd.ppc.bits == 32)? 1 : 0;
118    
119 dpavlin 2 /* 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 dpavlin 10 return 1;
149 dpavlin 2 }
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 dpavlin 12 void reg_access_msr(struct cpu *cpu, uint64_t *valuep, int writeflag)
213 dpavlin 2 {
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 dpavlin 12 debug(" cr = 0x%08x\n", (int)cpu->cd.ppc.cr);
266 dpavlin 2
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 dpavlin 12 int r = (i >> 1) + ((i & 1) << 4);
293 dpavlin 2 if ((i % 2) == 0)
294     debug("cpu%i:", x);
295 dpavlin 12 debug(" r%02i = 0x%016llx ", r,
296     (long long)cpu->cd.ppc.gpr[r]);
297 dpavlin 2 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 dpavlin 12 debug("tb = 0x%08x%08x\n",
306 dpavlin 2 (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 dpavlin 12 * 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 dpavlin 2 * 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 dpavlin 12 case PPC_31_STDX:
819     case PPC_31_STDUX:
820 dpavlin 2 /* 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 dpavlin 12 case PPC_31_STDX: mnem = "stdx"; break;
846     case PPC_31_STDUX: mnem = "stdux"; break;
847 dpavlin 2 }
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 dpavlin 12 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 dpavlin 2 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 dpavlin 12 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 dpavlin 2 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 dpavlin 12 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 dpavlin 2 break;
1109     case PPC_31_SYNC:
1110     debug("%s", power? "dcs" : "sync");
1111     break;
1112 dpavlin 4 case PPC_31_LSWI:
1113 dpavlin 2 case PPC_31_STSWI:
1114 dpavlin 4 rs = (iword >> 21) & 31; /* lwsi uses rt */
1115 dpavlin 2 ra = (iword >> 16) & 31;
1116     nb = (iword >> 11) & 31;
1117 dpavlin 4 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 dpavlin 2 break;
1125 dpavlin 12 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 dpavlin 2 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 dpavlin 12 case PPC_HI6_LMW:
1186 dpavlin 2 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 dpavlin 12 void update_cr0(struct cpu *cpu, uint64_t value)
1244 dpavlin 2 {
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 dpavlin 12 #include "tmp_ppc_tail.c"
1272 dpavlin 2
1273    
1274     #endif /* ENABLE_PPC */

  ViewVC Help
Powered by ViewVC 1.1.26