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

Contents of /trunk/src/cpus/cpu_sparc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 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 /*
2 * Copyright (C) 2005-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_sparc.c,v 1.47 2007/06/28 13:36:47 debug Exp $
29 *
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 "settings.h"
43 #include "symbol.h"
44
45
46 #define DYNTRANS_DUALMODE_32
47 #define DYNTRANS_DELAYSLOT
48 #include "tmp_sparc_head.c"
49
50
51 static char *sparc_regnames[N_SPARC_REG] = SPARC_REG_NAMES;
52 static char *sparc_pregnames[N_SPARC_PREG] = SPARC_PREG_NAMES;
53 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 /*
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 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 return 0;
84
85 cpu->memory_rw = sparc_memory_rw;
86
87 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
92 cpu->instruction_has_delayslot = sparc_cpu_instruction_has_delayslot;
93
94 /* TODO: Separate this into 64-bit vs 32-bit? */
95 cpu->translate_v2p = sparc_translate_v2p;
96
97 if (cpu->is_32bit) {
98 cpu->run_instr = sparc32_run_instr;
99 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 cpu->run_instr = sparc_run_instr;
107 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 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
115 if (cpu_id == 0) {
116 debug("%s", cpu->name);
117
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 }
137
138 /* 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 cpu->cd.sparc.ver |= N_REG_WINDOWS | (MAXTL << SPARC_VER_MAXTL_SHIFT);
143
144 /* Misc. initial settings suitable for userland emulation: */
145 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
150 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 fatal("Fatal internal error: nwindows = %1 is more than %i\n",
159 cpu->cd.sparc.cpu_type.nwindows, N_REG_WINDOWS);
160 exit(1);
161 }
162
163 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 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 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 for (j=16 - strlen(tdefs[i].name); j>0; j--)
189 debug(" ");
190 i++;
191 if ((i % 4) == 0 || tdefs[i].name == NULL)
192 debug("\n");
193 }
194 }
195
196
197 /*
198 * sparc_cpu_dumpinfo():
199 */
200 void sparc_cpu_dumpinfo(struct cpu *cpu)
201 {
202 debug(", %i-bit\n", cpu->cd.sparc.cpu_type.bits);
203 }
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 uint64_t offset;
218 int i, x = cpu->cpu_id;
219 int bits32 = cpu->is_32bit;
220
221 if (gprs) {
222 /* Special registers (pc, ...) first: */
223 symbol = get_symbol_name(&cpu->machine->symbol_context,
224 cpu->pc, &offset);
225
226 debug("cpu%i: pc = 0x", x);
227 if (bits32)
228 debug("%08"PRIx32, (uint32_t) cpu->pc);
229 else
230 debug("%016"PRIx64, (uint64_t) cpu->pc);
231 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
232
233 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 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 if (i == SPARC_ZEROREG) {
266 debug(" ");
267 continue;
268 }
269 debug("%s=", sparc_regnames[i]);
270 debug("0x%08"PRIx32,
271 (uint32_t) cpu->cd.sparc.r[i]);
272 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
283 /* Skip the zero register: */
284 if (i == SPARC_ZEROREG) {
285 debug(" ");
286 continue;
287 }
288
289 debug("%s = ", sparc_regnames[r]);
290 debug("0x%016"PRIx64, (uint64_t)
291 cpu->cd.sparc.r[r]);
292
293 if ((i & 1) < 1)
294 debug(" ");
295 else
296 debug("\n");
297 }
298 }
299 }
300
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 }
368
369
370 /*
371 * 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 case 57:/* return */
414 return 1;
415 }
416 break;
417 }
418
419 return 0;
420 }
421
422
423 /*
424 * 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 int running, uint64_t dumpaddr)
437 {
438 uint64_t offset, tmp;
439 uint32_t iword;
440 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 char *symbol, *mnem, *rd_name, *rs_name;
443
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 if (cpu->is_32bit)
456 debug("%08"PRIx32, (uint32_t) dumpaddr);
457 else
458 debug("%016"PRIx64, (uint64_t) dumpaddr);
459
460 iword = *(uint32_t *)&instr[0];
461 iword = BE32_TO_HOST(iword);
462
463 debug(": %08"PRIx32, iword);
464
465 if (running && cpu->delay_slot)
466 debug(" (d)");
467
468 debug("\t");
469
470
471 /*
472 * Decode the instruction:
473 *
474 * http://www.cs.unm.edu/~maccabe/classes/341/labman/node9.html is a
475 * good quick description of SPARC instruction encoding.
476 */
477
478 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
489 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 debug("0x%"PRIx64, (uint64_t) tmp);
531 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 debug("call\t0x%"PRIx64, (uint64_t) tmp);
552 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 rs_name = sparc_regnames[rs1];
560 rd_name = sparc_regnames[rd];
561 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 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 case 42:/* TODO: something with wim only, on sparc v8? */
619 rs_name = sparc_pregnames[rs1];
620 no_rs2 = 1;
621 break;
622 case 43:/* ? */
623 /* TODO: pre-sparcv9: rd, rs_name = "tbr"; */
624 if (iword == 0x81580000) {
625 mnem = "flushw";
626 no_rs1 = no_rs2 = no_rd = 1;
627 }
628 break;
629 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 case 49:/* ? */
643 if (iword == 0x83880000) {
644 mnem = "restored";
645 no_rs1 = no_rs2 = no_rd = 1;
646 }
647 break;
648 case 50:/* wrpr */
649 rd_name = sparc_pregnames[rd];
650 if (rs1 == SPARC_ZEROREG)
651 no_rs1 = 1;
652 break;
653 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 debug("%%%s", rs_name);
680 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 else if (siconst < 0 && (op2 == 0 ||
691 op2 == 4 || op2 == 20 || op2 == 60))
692 debug("-0x%x", -siconst);
693 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 debug("%%%s", rd_name);
703 break;
704
705 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 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 if ((op2 & 0x30) == 0x10)
727 debug("(%i)", asi);
728 if (!(op2 & 4))
729 debug(",%%%s", sparc_regnames[rd]);
730 break;
731 }
732
733 debug("\n");
734 return sizeof(iword);
735 }
736
737
738 /*
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 #include "tmp_sparc_tail.c"
754

  ViewVC Help
Powered by ViewVC 1.1.26