/[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 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19863 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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 30 * $Id: cpu_sparc.c,v 1.35 2006/07/23 12:40:24 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 dpavlin 30 case 42:/* TODO: something with wim only, on sparc v8? */
679     rs_name = sparc_pregnames[rs1];
680 dpavlin 24 no_rs2 = 1;
681     break;
682 dpavlin 22 case 43:/* ? */
683 dpavlin 24 /* TODO: pre-sparcv9: rd, rs_name = "tbr"; */
684 dpavlin 22 if (iword == 0x81580000) {
685     mnem = "flushw";
686     no_rs1 = no_rs2 = no_rd = 1;
687     }
688     break;
689 dpavlin 24 case 48:/* wr* (SPARCv8) */
690     mnem = "wr";
691     if (rs1 == SPARC_ZEROREG)
692     no_rs1 = 1;
693     switch (rd) {
694     case 0: rd_name = "y"; break;
695     case 2: rd_name = "ccr"; break;
696     case 3: rd_name = "asi"; break;
697     case 6: rd_name = "fprs"; break;
698     case 23:rd_name = "tick_cmpr"; break; /* v9 ? */
699     default:rd_name = "UNIMPLEMENTED";
700     }
701     break;
702 dpavlin 22 case 49:/* ? */
703     if (iword == 0x83880000) {
704     mnem = "restored";
705     no_rs1 = no_rs2 = no_rd = 1;
706     }
707     break;
708 dpavlin 24 case 50:/* wrpr */
709     rd_name = sparc_pregnames[rd];
710     if (rs1 == SPARC_ZEROREG)
711     no_rs1 = 1;
712     break;
713 dpavlin 22 case 56:/* jmpl */
714     jmpl = 1;
715     if (iword == 0x81c7e008) {
716     mnem = "ret";
717     no_rs1 = no_rs2 = no_rd = 1;
718     }
719     if (iword == 0x81c3e008) {
720     mnem = "retl";
721     no_rs1 = no_rs2 = no_rd = 1;
722     }
723     break;
724     case 61:/* restore */
725     if (iword == 0x81e80000)
726     no_rs1 = no_rs2 = no_rd = 1;
727     break;
728     case 62:if (iword == 0x83f00000) {
729     mnem = "retry";
730     no_rs1 = no_rs2 = no_rd = 1;
731     }
732     break;
733     }
734     debug("%s", mnem);
735     if (shift_x)
736     debug("x");
737     debug("\t");
738     if (!no_rs1)
739 dpavlin 24 debug("%%%s", rs_name);
740 dpavlin 22 if (!no_rs1 && !no_rs2) {
741     if (jmpl)
742     debug("+");
743     else
744     debug(",");
745     }
746     if (!no_rs2) {
747     if ((iword >> 13) & 1) {
748     if (siconst >= -9 && siconst <= 9)
749     debug("%i", siconst);
750 dpavlin 28 else if (siconst < 0 && (op2 == 0 ||
751     op2 == 4 || op2 == 20 || op2 == 60))
752     debug("-0x%x", -siconst);
753 dpavlin 22 else
754     debug("0x%x", siconst);
755     } else {
756     debug("%%%s", sparc_regnames[rs2]);
757     }
758     }
759     if ((!no_rs1 || !no_rs2) && !no_rd)
760     debug(",");
761     if (!no_rd)
762 dpavlin 24 debug("%%%s", rd_name);
763 dpavlin 22 break;
764    
765 dpavlin 28 case 3: mnem = sparc_loadstore_names[op2];
766     switch (op2) {
767     case 0: /* 'lduw' was called only 'ld' in pre-v9 */
768     if (cpu->cd.sparc.cpu_type.v < 9)
769     mnem = "ld";
770     break;
771     }
772     debug("%s\t", mnem);
773 dpavlin 22 if (op2 & 4)
774     debug("%%%s,", sparc_regnames[rd]);
775     debug("[%%%s", sparc_regnames[rs1]);
776     if ((iword >> 13) & 1) {
777     if (siconst > 0)
778     debug("+");
779     if (siconst != 0)
780     debug("%i", siconst);
781     } else {
782     if (rs2 != 0)
783     debug("+%%%s", sparc_regnames[rs2]);
784     }
785     debug("]");
786 dpavlin 28 if ((op2 & 0x30) == 0x10)
787 dpavlin 22 debug("(%i)", asi);
788     if (!(op2 & 4))
789     debug(",%%%s", sparc_regnames[rd]);
790     break;
791 dpavlin 14 }
792    
793     debug("\n");
794     return sizeof(iword);
795     }
796    
797    
798 dpavlin 24 /*
799     * sparc_update_pstate():
800     *
801     * Update the pstate register (64-bit sparcs).
802     */
803     static void sparc_update_pstate(struct cpu *cpu, uint64_t new_pstate)
804     {
805     /* uint64_t old_pstate = cpu->cd.sparc.pstate; */
806    
807     /* TODO: Check individual bits. */
808    
809     cpu->cd.sparc.pstate = new_pstate;
810     }
811    
812    
813 dpavlin 14 #include "tmp_sparc_tail.c"
814    

  ViewVC Help
Powered by ViewVC 1.1.26