/[gxemul]/trunk/src/cpus/cpu_sparc.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/cpus/cpu_sparc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 19793 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


1 dpavlin 14 /*
2 dpavlin 24 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 28 * $Id: cpu_sparc.c,v 1.34 2006/07/16 13:32:26 debug Exp $
29 dpavlin 14 *
30     * SPARC CPU emulation.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36     #include <ctype.h>
37    
38     #include "cpu.h"
39     #include "machine.h"
40     #include "memory.h"
41     #include "misc.h"
42     #include "symbol.h"
43    
44 dpavlin 22
45 dpavlin 14 #define DYNTRANS_DUALMODE_32
46 dpavlin 24 #define DYNTRANS_DELAYSLOT
47 dpavlin 14 #include "tmp_sparc_head.c"
48    
49    
50 dpavlin 22 static char *sparc_regnames[N_SPARC_REG] = SPARC_REG_NAMES;
51 dpavlin 24 static char *sparc_pregnames[N_SPARC_PREG] = SPARC_PREG_NAMES;
52 dpavlin 22 static char *sparc_regbranch_names[N_SPARC_REGBRANCH_TYPES] =
53     SPARC_REGBRANCH_NAMES;
54     static char *sparc_branch_names[N_SPARC_BRANCH_TYPES] = SPARC_BRANCH_NAMES;
55     static char *sparc_alu_names[N_ALU_INSTR_TYPES] = SPARC_ALU_NAMES;
56     static char *sparc_loadstore_names[N_LOADSTORE_TYPES] = SPARC_LOADSTORE_NAMES;
57    
58    
59 dpavlin 14 /*
60     * sparc_cpu_new():
61     *
62     * Create a new SPARC cpu object.
63     *
64     * Returns 1 on success, 0 if there was no matching SPARC processor with
65     * this cpu_type_name.
66     */
67     int sparc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
68     int cpu_id, char *cpu_type_name)
69     {
70 dpavlin 22 int any_cache = 0;
71     int i = 0;
72     struct sparc_cpu_type_def cpu_type_defs[] = SPARC_CPU_TYPE_DEFS;
73    
74     /* Scan the cpu_type_defs list for this cpu type: */
75     while (cpu_type_defs[i].name != NULL) {
76     if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
77     break;
78     }
79     i++;
80     }
81     if (cpu_type_defs[i].name == NULL)
82 dpavlin 14 return 0;
83    
84     cpu->memory_rw = sparc_memory_rw;
85    
86 dpavlin 22 cpu->cd.sparc.cpu_type = cpu_type_defs[i];
87     cpu->name = cpu->cd.sparc.cpu_type.name;
88     cpu->byte_order = EMUL_BIG_ENDIAN;
89     cpu->is_32bit = (cpu->cd.sparc.cpu_type.bits == 32)? 1 : 0;
90 dpavlin 14
91 dpavlin 24 cpu->instruction_has_delayslot = sparc_cpu_instruction_has_delayslot;
92    
93 dpavlin 22 if (cpu->is_32bit) {
94 dpavlin 28 cpu->run_instr = sparc32_run_instr;
95 dpavlin 22 cpu->update_translation_table =
96     sparc32_update_translation_table;
97     cpu->invalidate_translation_caches =
98     sparc32_invalidate_translation_caches;
99     cpu->invalidate_code_translation =
100     sparc32_invalidate_code_translation;
101     } else {
102 dpavlin 28 cpu->run_instr = sparc_run_instr;
103 dpavlin 22 cpu->update_translation_table = sparc_update_translation_table;
104     cpu->invalidate_translation_caches =
105     sparc_invalidate_translation_caches;
106     cpu->invalidate_code_translation =
107     sparc_invalidate_code_translation;
108     }
109    
110 dpavlin 14 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
111     if (cpu_id == 0) {
112     debug("%s", cpu->name);
113 dpavlin 22
114     if (cpu->cd.sparc.cpu_type.icache_shift != 0)
115     any_cache = 1;
116     if (cpu->cd.sparc.cpu_type.dcache_shift != 0)
117     any_cache = 1;
118     if (cpu->cd.sparc.cpu_type.l2cache_shift != 0)
119     any_cache = 1;
120    
121     if (any_cache) {
122     debug(" (I+D = %i+%i KB", (int)
123     (1 << (cpu->cd.sparc.cpu_type.icache_shift-10)),
124     (int)(1<<(cpu->cd.sparc.cpu_type.dcache_shift-10)));
125     if (cpu->cd.sparc.cpu_type.l2cache_shift != 0) {
126     debug(", L2 = %i KB",
127     (int)(1 << (cpu->cd.sparc.cpu_type.
128     l2cache_shift-10)));
129     }
130     debug(")");
131     }
132 dpavlin 14 }
133    
134 dpavlin 24 /* After a reset, the Tick register is not readable by user code: */
135     cpu->cd.sparc.tick |= SPARC_TICK_NPT;
136    
137     /* Insert number of Windows and Trap levels into the version reg.: */
138     cpu->cd.sparc.ver |= MAXWIN | (MAXTL << SPARC_VER_MAXTL_SHIFT);
139    
140 dpavlin 28 /* Misc. initial settings suitable for userland emulation: */
141     cpu->cd.sparc.cansave = cpu->cd.sparc.cpu_type.nwindows - 1;
142     cpu->cd.sparc.cleanwin = cpu->cd.sparc.cpu_type.nwindows / 2;
143    
144     if (cpu->cd.sparc.cpu_type.nwindows >= MAXWIN) {
145     fatal("Fatal internal error: nwindows = %1 is more than %i\n",
146     cpu->cd.sparc.cpu_type.nwindows, MAXWIN);
147     exit(1);
148     }
149    
150 dpavlin 14 return 1;
151     }
152    
153    
154     /*
155     * sparc_cpu_list_available_types():
156     *
157     * Print a list of available SPARC CPU types.
158     */
159     void sparc_cpu_list_available_types(void)
160     {
161 dpavlin 22 int i, j;
162     struct sparc_cpu_type_def tdefs[] = SPARC_CPU_TYPE_DEFS;
163    
164     i = 0;
165     while (tdefs[i].name != NULL) {
166     debug("%s", tdefs[i].name);
167 dpavlin 24 for (j=16 - strlen(tdefs[i].name); j>0; j--)
168 dpavlin 22 debug(" ");
169     i++;
170 dpavlin 24 if ((i % 4) == 0 || tdefs[i].name == NULL)
171 dpavlin 22 debug("\n");
172     }
173 dpavlin 14 }
174    
175    
176     /*
177     * sparc_cpu_dumpinfo():
178     */
179     void sparc_cpu_dumpinfo(struct cpu *cpu)
180     {
181 dpavlin 22 debug(", %i-bit\n", cpu->cd.sparc.cpu_type.bits);
182 dpavlin 14 }
183    
184    
185     /*
186     * sparc_cpu_register_dump():
187     *
188     * Dump cpu registers in a relatively readable format.
189     *
190     * gprs: set to non-zero to dump GPRs and some special-purpose registers.
191     * coprocs: set bit 0..3 to dump registers in coproc 0..3.
192     */
193     void sparc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
194     {
195     char *symbol;
196 dpavlin 20 uint64_t offset;
197 dpavlin 22 int i, x = cpu->cpu_id;
198     int bits32 = cpu->is_32bit;
199 dpavlin 14
200     if (gprs) {
201     /* Special registers (pc, ...) first: */
202     symbol = get_symbol_name(&cpu->machine->symbol_context,
203     cpu->pc, &offset);
204    
205 dpavlin 22 debug("cpu%i: pc = 0x", x);
206 dpavlin 14 if (bits32)
207 dpavlin 24 debug("%08"PRIx32, (uint32_t) cpu->pc);
208 dpavlin 14 else
209 dpavlin 24 debug("%016"PRIx64, (uint64_t) cpu->pc);
210 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
211    
212 dpavlin 24 debug("cpu%i: y = 0x%08"PRIx32" ",
213     x, (uint32_t)cpu->cd.sparc.y);
214     debug("icc = ");
215     debug(cpu->cd.sparc.ccr & SPARC_CCR_N? "N" : "n");
216     debug(cpu->cd.sparc.ccr & SPARC_CCR_Z? "Z" : "z");
217     debug(cpu->cd.sparc.ccr & SPARC_CCR_V? "V" : "v");
218     debug(cpu->cd.sparc.ccr & SPARC_CCR_C? "C" : "c");
219     if (!bits32) {
220     debug(" xcc = ");
221     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
222     & SPARC_CCR_N? "N" : "n");
223     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
224     & SPARC_CCR_Z? "Z" : "z");
225     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
226     & SPARC_CCR_V? "V" : "v");
227     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
228     & SPARC_CCR_C? "C" : "c");
229     }
230     debug("\n");
231    
232     if (bits32)
233     debug("cpu%i: psr = 0x%08"PRIx32"\n",
234     x, (uint32_t) cpu->cd.sparc.psr);
235     else
236     debug("cpu%i: pstate = 0x%016"PRIx64"\n",
237     x, (uint64_t) cpu->cd.sparc.pstate);
238    
239 dpavlin 22 if (bits32) {
240     for (i=0; i<N_SPARC_REG; i++) {
241     if ((i & 3) == 0)
242     debug("cpu%i: ", x);
243     /* Skip the zero register: */
244 dpavlin 24 if (i == SPARC_ZEROREG) {
245 dpavlin 22 debug(" ");
246     continue;
247     }
248     debug("%s=", sparc_regnames[i]);
249     debug("0x%08x", (int) cpu->cd.sparc.r[i]);
250     if ((i & 3) < 3)
251     debug(" ");
252     else
253     debug("\n");
254     }
255     } else {
256     for (i=0; i<N_SPARC_REG; i++) {
257     int r = ((i >> 1) & 15) | ((i&1) << 4);
258     if ((i & 1) == 0)
259     debug("cpu%i: ", x);
260 dpavlin 24
261 dpavlin 22 /* Skip the zero register: */
262 dpavlin 24 if (i == SPARC_ZEROREG) {
263 dpavlin 22 debug(" ");
264     continue;
265     }
266 dpavlin 24
267 dpavlin 22 debug("%s = ", sparc_regnames[r]);
268 dpavlin 24 debug("0x%016"PRIx64, (uint64_t)
269 dpavlin 22 cpu->cd.sparc.r[r]);
270 dpavlin 24
271 dpavlin 22 if ((i & 1) < 1)
272     debug(" ");
273     else
274     debug("\n");
275     }
276     }
277 dpavlin 14 }
278     }
279    
280    
281     /*
282     * sparc_cpu_register_match():
283     */
284     void sparc_cpu_register_match(struct machine *m, char *name,
285     int writeflag, uint64_t *valuep, int *match_register)
286     {
287 dpavlin 24 int i, cpunr = 0;
288 dpavlin 14
289     /* CPU number: */
290     /* TODO */
291    
292 dpavlin 24 for (i=0; i<N_SPARC_REG; i++) {
293     if (strcasecmp(name, sparc_regnames[i]) == 0) {
294     if (writeflag && i != SPARC_ZEROREG)
295     m->cpus[cpunr]->cd.sparc.r[i] = *valuep;
296     else
297     *valuep = m->cpus[cpunr]->cd.sparc.r[i];
298     *match_register = 1;
299     }
300     }
301    
302 dpavlin 14 if (strcasecmp(name, "pc") == 0) {
303     if (writeflag) {
304     m->cpus[cpunr]->pc = *valuep;
305 dpavlin 24 } else {
306 dpavlin 14 *valuep = m->cpus[cpunr]->pc;
307 dpavlin 24 }
308 dpavlin 14 *match_register = 1;
309     }
310 dpavlin 24
311     if (strcasecmp(name, "y") == 0) {
312     if (writeflag) {
313     m->cpus[cpunr]->cd.sparc.y = (uint32_t) *valuep;
314     } else {
315     *valuep = (uint32_t) m->cpus[cpunr]->cd.sparc.y;
316     }
317     *match_register = 1;
318     }
319    
320     if (*match_register && m->cpus[cpunr]->is_32bit)
321     (*valuep) &= 0xffffffffULL;
322 dpavlin 14 }
323    
324    
325     /*
326 dpavlin 24 * sparc_cpu_tlbdump():
327     *
328     * Called from the debugger to dump the TLB in a readable format.
329     * x is the cpu number to dump, or -1 to dump all CPUs.
330     *
331     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
332     * just dumped.
333     */
334     void sparc_cpu_tlbdump(struct machine *m, int x, int rawflag)
335     {
336     }
337    
338    
339     static void add_response_word(struct cpu *cpu, char *r, uint64_t value,
340     size_t maxlen, int len)
341     {
342     char *format = (len == 4)? "%08"PRIx64 : "%016"PRIx64;
343     if (len == 4)
344     value &= 0xffffffffULL;
345     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
346     if (len == 4) {
347     value = ((value & 0xff) << 24) +
348     ((value & 0xff00) << 8) +
349     ((value & 0xff0000) >> 8) +
350     ((value & 0xff000000) >> 24);
351     } else {
352     value = ((value & 0xff) << 56) +
353     ((value & 0xff00) << 40) +
354     ((value & 0xff0000) << 24) +
355     ((value & 0xff000000ULL) << 8) +
356     ((value & 0xff00000000ULL) >> 8) +
357     ((value & 0xff0000000000ULL) >> 24) +
358     ((value & 0xff000000000000ULL) >> 40) +
359     ((value & 0xff00000000000000ULL) >> 56);
360     }
361     }
362     snprintf(r + strlen(r), maxlen - strlen(r), format, (uint64_t)value);
363     }
364    
365    
366     /*
367     * sparc_cpu_gdb_stub():
368     *
369     * Execute a "remote GDB" command. Returns a newly allocated response string
370     * on success, NULL on failure.
371     */
372     char *sparc_cpu_gdb_stub(struct cpu *cpu, char *cmd)
373     {
374     if (strcmp(cmd, "g") == 0) {
375     int i;
376     char *r;
377     size_t wlen = cpu->is_32bit?
378     sizeof(uint32_t) : sizeof(uint64_t);
379     size_t len = 1 + 76 * wlen;
380     r = malloc(len);
381     if (r == NULL) {
382     fprintf(stderr, "out of memory\n");
383     exit(1);
384     }
385     r[0] = '\0';
386     /* TODO */
387     for (i=0; i<128; i++)
388     add_response_word(cpu, r, i, len, wlen);
389     return r;
390     }
391    
392     if (cmd[0] == 'p') {
393     int regnr = strtol(cmd + 1, NULL, 16);
394     size_t wlen = sizeof(uint32_t);
395     /* TODO: cpu->is_32bit? sizeof(uint32_t) : sizeof(uint64_t); */
396     size_t len = 2 * wlen + 1;
397     char *r = malloc(len);
398     r[0] = '\0';
399     if (regnr >= 0 && regnr < N_SPARC_REG) {
400     add_response_word(cpu, r,
401     cpu->cd.sparc.r[regnr], len, wlen);
402     } else if (regnr == 0x44) {
403     add_response_word(cpu, r, cpu->pc, len, wlen);
404     /* TODO:
405     20..3f = f0..f31
406     40 = y
407     41 = psr
408     42 = wim
409     43 = tbr
410     45 = npc
411     46 = fsr
412     47 = csr
413     */
414     } else {
415     /* Unimplemented: */
416     add_response_word(cpu, r, 0xcc000 + regnr, len, wlen);
417     }
418     return r;
419     }
420    
421     fatal("sparc_cpu_gdb_stub(): TODO\n");
422     return NULL;
423     }
424    
425    
426     /*
427 dpavlin 14 * sparc_cpu_interrupt():
428     */
429     int sparc_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
430     {
431     fatal("sparc_cpu_interrupt(): TODO\n");
432     return 0;
433     }
434    
435    
436     /*
437     * sparc_cpu_interrupt_ack():
438     */
439     int sparc_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
440     {
441     /* fatal("sparc_cpu_interrupt_ack(): TODO\n"); */
442     return 0;
443     }
444    
445    
446     /*
447 dpavlin 24 * sparc_cpu_instruction_has_delayslot():
448     *
449     * Return 1 if an opcode is a branch, 0 otherwise.
450     */
451     int sparc_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib)
452     {
453     uint32_t iword = *((uint32_t *)&ib[0]);
454     int hi2, op2;
455    
456     iword = BE32_TO_HOST(iword);
457    
458     hi2 = iword >> 30;
459     op2 = (hi2 == 0)? ((iword >> 22) & 7) : ((iword >> 19) & 0x3f);
460    
461     switch (hi2) {
462     case 0: /* conditional branch */
463     switch (op2) {
464     case 1:
465     case 2:
466     case 3: return 1;
467     }
468     break;
469     case 1: /* call */
470     return 1;
471     case 2: /* misc alu instructions */
472     switch (op2) {
473     case 56:/* jump and link */
474     return 1;
475     }
476     break;
477     }
478    
479     return 0;
480     }
481    
482    
483     /*
484 dpavlin 14 * sparc_cpu_disassemble_instr():
485     *
486     * Convert an instruction word into human readable format, for instruction
487     * tracing.
488     *
489     * If running is 1, cpu->pc should be the address of the instruction.
490     *
491     * If running is 0, things that depend on the runtime environment (eg.
492     * register contents) will not be shown, and addr will be used instead of
493     * cpu->pc for relative addresses.
494     */
495     int sparc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
496 dpavlin 24 int running, uint64_t dumpaddr)
497 dpavlin 14 {
498 dpavlin 22 uint64_t offset, tmp;
499 dpavlin 14 uint32_t iword;
500 dpavlin 22 int hi2, op2, rd, rs1, rs2, siconst, btype, tmps, no_rd = 0;
501     int asi, no_rs1 = 0, no_rs2 = 0, jmpl = 0, shift_x = 0, cc, p;
502 dpavlin 24 char *symbol, *mnem, *rd_name, *rs_name;
503 dpavlin 14
504     if (running)
505     dumpaddr = cpu->pc;
506    
507     symbol = get_symbol_name(&cpu->machine->symbol_context,
508     dumpaddr, &offset);
509     if (symbol != NULL && offset==0)
510     debug("<%s>\n", symbol);
511    
512     if (cpu->machine->ncpus > 1 && running)
513     debug("cpu%i: ", cpu->cpu_id);
514    
515 dpavlin 22 if (cpu->is_32bit)
516 dpavlin 24 debug("%08"PRIx32, (uint32_t) dumpaddr);
517 dpavlin 14 else
518 dpavlin 24 debug("%016"PRIx64, (uint64_t) dumpaddr);
519 dpavlin 14
520 dpavlin 22 iword = *(uint32_t *)&instr[0];
521     iword = BE32_TO_HOST(iword);
522 dpavlin 14
523 dpavlin 24 debug(": %08x", iword);
524 dpavlin 14
525 dpavlin 24 if (running && cpu->delay_slot)
526     debug(" (d)");
527    
528     debug("\t");
529    
530    
531 dpavlin 14 /*
532     * Decode the instruction:
533 dpavlin 22 *
534     * http://www.cs.unm.edu/~maccabe/classes/341/labman/node9.html is a
535     * good quick description of SPARC instruction encoding.
536 dpavlin 14 */
537    
538 dpavlin 22 hi2 = iword >> 30;
539     rd = (iword >> 25) & 31;
540     btype = rd & (N_SPARC_BRANCH_TYPES - 1);
541     rs1 = (iword >> 14) & 31;
542     asi = (iword >> 5) & 0xff;
543     rs2 = iword & 31;
544     siconst = (int16_t)((iword & 0x1fff) << 3) >> 3;
545     op2 = (hi2 == 0)? ((iword >> 22) & 7) : ((iword >> 19) & 0x3f);
546     cc = (iword >> 20) & 3;
547     p = (iword >> 19) & 1;
548 dpavlin 14
549 dpavlin 22 switch (hi2) {
550    
551     case 0: switch (op2) {
552    
553     case 0: debug("illtrap\t0x%x", iword & 0x3fffff);
554     break;
555    
556     case 1:
557     case 2:
558     case 3: if (op2 == 3)
559     debug("%s", sparc_regbranch_names[btype & 7]);
560     else
561     debug("%s", sparc_branch_names[btype]);
562     if (rd & 16)
563     debug(",a");
564     tmps = iword;
565     switch (op2) {
566     case 1: tmps <<= 13;
567     tmps >>= 11;
568     if (!p)
569     debug(",pn");
570     debug("\t%%%s,", cc==0 ? "icc" :
571     (cc==2 ? "xcc" : "UNKNOWN"));
572     break;
573     case 2: tmps <<= 10;
574     tmps >>= 8;
575     debug("\t");
576     break;
577     case 3: if (btype & 8)
578     debug("(INVALID)");
579     if (!p)
580     debug(",pn");
581     debug("\t%%%s,", sparc_regnames[rs1]);
582     tmps = ((iword & 0x300000) >> 6)
583     | (iword & 0x3fff);
584     tmps <<= 16;
585     tmps >>= 14;
586     break;
587     }
588     tmp = (int64_t)(int32_t)tmps;
589     tmp += dumpaddr;
590 dpavlin 24 debug("0x%"PRIx64, (uint64_t) tmp);
591 dpavlin 22 symbol = get_symbol_name(&cpu->machine->
592     symbol_context, tmp, &offset);
593     if (symbol != NULL)
594     debug(" \t<%s>", symbol);
595     break;
596    
597     case 4: if (rd == 0) {
598     debug("nop");
599     break;
600     }
601     debug("sethi\t%%hi(0x%x),", (iword & 0x3fffff) << 10);
602     debug("%%%s", sparc_regnames[rd]);
603     break;
604    
605     default:debug("UNIMPLEMENTED hi2=%i, op2=0x%x", hi2, op2);
606     }
607     break;
608    
609     case 1: tmp = (int32_t)iword << 2;
610     tmp += dumpaddr;
611 dpavlin 24 debug("call\t0x%"PRIx64, (uint64_t) tmp);
612 dpavlin 22 symbol = get_symbol_name(&cpu->machine->symbol_context,
613     tmp, &offset);
614     if (symbol != NULL)
615     debug(" \t<%s>", symbol);
616     break;
617    
618     case 2: mnem = sparc_alu_names[op2];
619 dpavlin 24 rs_name = sparc_regnames[rs1];
620     rd_name = sparc_regnames[rd];
621 dpavlin 22 switch (op2) {
622     case 0: /* add */
623     if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
624     mnem = "inc";
625     no_rs1 = no_rs2 = 1;
626     }
627     break;
628     case 2: /* or */
629     if (rs1 == 0) {
630     mnem = "mov";
631     no_rs1 = 1;
632     }
633     break;
634     case 4: /* sub */
635     if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
636     mnem = "dec";
637     no_rs1 = no_rs2 = 1;
638     }
639     break;
640     case 20:/* subcc */
641     if (rd == 0) {
642     mnem = "cmp";
643     no_rd = 1;
644     }
645     break;
646     case 37:/* sll */
647     case 38:/* srl */
648     case 39:/* sra */
649     if (siconst & 0x1000) {
650     siconst &= 0x3f;
651     shift_x = 1;
652     } else
653     siconst &= 0x1f;
654     break;
655 dpavlin 24 case 40:/* rd on pre-sparcv9, membar etc on sparcv9 */
656     no_rs2 = 1;
657     rs_name = "UNIMPLEMENTED";
658     switch (rs1) {
659     case 0: rs_name = "y"; break;
660     case 2: rs_name = "ccr"; break;
661     case 3: rs_name = "asi"; break;
662     case 4: rs_name = "tick"; break;
663     case 5: rs_name = "pc"; break;
664     case 6: rs_name = "fprs"; break;
665     case 15:/* membar etc. */
666     if ((iword >> 13) & 1) {
667     no_rd = 1;
668     mnem = "membar";
669     rs_name = "#TODO";
670     }
671     break;
672     case 23:rs_name = "tick_cmpr"; break; /* v9 ? */
673     }
674     break;
675     case 41:rs_name = "psr";
676     no_rs2 = 1;
677     break;
678     case 42:rs_name = "wim";
679     no_rs2 = 1;
680     break;
681 dpavlin 22 case 43:/* ? */
682 dpavlin 24 /* TODO: pre-sparcv9: rd, rs_name = "tbr"; */
683 dpavlin 22 if (iword == 0x81580000) {
684     mnem = "flushw";
685     no_rs1 = no_rs2 = no_rd = 1;
686     }
687     break;
688 dpavlin 24 case 48:/* wr* (SPARCv8) */
689     mnem = "wr";
690     if (rs1 == SPARC_ZEROREG)
691     no_rs1 = 1;
692     switch (rd) {
693     case 0: rd_name = "y"; break;
694     case 2: rd_name = "ccr"; break;
695     case 3: rd_name = "asi"; break;
696     case 6: rd_name = "fprs"; break;
697     case 23:rd_name = "tick_cmpr"; break; /* v9 ? */
698     default:rd_name = "UNIMPLEMENTED";
699     }
700     break;
701 dpavlin 22 case 49:/* ? */
702     if (iword == 0x83880000) {
703     mnem = "restored";
704     no_rs1 = no_rs2 = no_rd = 1;
705     }
706     break;
707 dpavlin 24 case 50:/* wrpr */
708     rd_name = sparc_pregnames[rd];
709     if (rs1 == SPARC_ZEROREG)
710     no_rs1 = 1;
711     break;
712 dpavlin 22 case 56:/* jmpl */
713     jmpl = 1;
714     if (iword == 0x81c7e008) {
715     mnem = "ret";
716     no_rs1 = no_rs2 = no_rd = 1;
717     }
718     if (iword == 0x81c3e008) {
719     mnem = "retl";
720     no_rs1 = no_rs2 = no_rd = 1;
721     }
722     break;
723     case 61:/* restore */
724     if (iword == 0x81e80000)
725     no_rs1 = no_rs2 = no_rd = 1;
726     break;
727     case 62:if (iword == 0x83f00000) {
728     mnem = "retry";
729     no_rs1 = no_rs2 = no_rd = 1;
730     }
731     break;
732     }
733     debug("%s", mnem);
734     if (shift_x)
735     debug("x");
736     debug("\t");
737     if (!no_rs1)
738 dpavlin 24 debug("%%%s", rs_name);
739 dpavlin 22 if (!no_rs1 && !no_rs2) {
740     if (jmpl)
741     debug("+");
742     else
743     debug(",");
744     }
745     if (!no_rs2) {
746     if ((iword >> 13) & 1) {
747     if (siconst >= -9 && siconst <= 9)
748     debug("%i", siconst);
749 dpavlin 28 else if (siconst < 0 && (op2 == 0 ||
750     op2 == 4 || op2 == 20 || op2 == 60))
751     debug("-0x%x", -siconst);
752 dpavlin 22 else
753     debug("0x%x", siconst);
754     } else {
755     debug("%%%s", sparc_regnames[rs2]);
756     }
757     }
758     if ((!no_rs1 || !no_rs2) && !no_rd)
759     debug(",");
760     if (!no_rd)
761 dpavlin 24 debug("%%%s", rd_name);
762 dpavlin 22 break;
763    
764 dpavlin 28 case 3: mnem = sparc_loadstore_names[op2];
765     switch (op2) {
766     case 0: /* 'lduw' was called only 'ld' in pre-v9 */
767     if (cpu->cd.sparc.cpu_type.v < 9)
768     mnem = "ld";
769     break;
770     }
771     debug("%s\t", mnem);
772 dpavlin 22 if (op2 & 4)
773     debug("%%%s,", sparc_regnames[rd]);
774     debug("[%%%s", sparc_regnames[rs1]);
775     if ((iword >> 13) & 1) {
776     if (siconst > 0)
777     debug("+");
778     if (siconst != 0)
779     debug("%i", siconst);
780     } else {
781     if (rs2 != 0)
782     debug("+%%%s", sparc_regnames[rs2]);
783     }
784     debug("]");
785 dpavlin 28 if ((op2 & 0x30) == 0x10)
786 dpavlin 22 debug("(%i)", asi);
787     if (!(op2 & 4))
788     debug(",%%%s", sparc_regnames[rd]);
789     break;
790 dpavlin 14 }
791    
792     debug("\n");
793     return sizeof(iword);
794     }
795    
796    
797 dpavlin 24 /*
798     * sparc_update_pstate():
799     *
800     * Update the pstate register (64-bit sparcs).
801     */
802     static void sparc_update_pstate(struct cpu *cpu, uint64_t new_pstate)
803     {
804     /* uint64_t old_pstate = cpu->cd.sparc.pstate; */
805    
806     /* TODO: Check individual bits. */
807    
808     cpu->cd.sparc.pstate = new_pstate;
809     }
810    
811    
812 dpavlin 14 #include "tmp_sparc_tail.c"
813    

  ViewVC Help
Powered by ViewVC 1.1.26