/[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 44 - (hide annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 19397 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26