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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 12582 byte(s)
0.3.8
1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_sparc.c,v 1.11 2005/12/11 21:34:43 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 "symbol.h"
43
44
45 #define DYNTRANS_DUALMODE_32
46 #include "tmp_sparc_head.c"
47
48
49 static char *sparc_regnames[N_SPARC_REG] = SPARC_REG_NAMES;
50 static char *sparc_regbranch_names[N_SPARC_REGBRANCH_TYPES] =
51 SPARC_REGBRANCH_NAMES;
52 static char *sparc_branch_names[N_SPARC_BRANCH_TYPES] = SPARC_BRANCH_NAMES;
53 static char *sparc_alu_names[N_ALU_INSTR_TYPES] = SPARC_ALU_NAMES;
54 static char *sparc_loadstore_names[N_LOADSTORE_TYPES] = SPARC_LOADSTORE_NAMES;
55
56
57 /*
58 * sparc_cpu_new():
59 *
60 * Create a new SPARC cpu object.
61 *
62 * Returns 1 on success, 0 if there was no matching SPARC processor with
63 * this cpu_type_name.
64 */
65 int sparc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
66 int cpu_id, char *cpu_type_name)
67 {
68 int any_cache = 0;
69 int i = 0;
70 struct sparc_cpu_type_def cpu_type_defs[] = SPARC_CPU_TYPE_DEFS;
71
72 /* Scan the cpu_type_defs list for this cpu type: */
73 while (cpu_type_defs[i].name != NULL) {
74 if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
75 break;
76 }
77 i++;
78 }
79 if (cpu_type_defs[i].name == NULL)
80 return 0;
81
82 cpu->memory_rw = sparc_memory_rw;
83
84 cpu->cd.sparc.cpu_type = cpu_type_defs[i];
85 cpu->name = cpu->cd.sparc.cpu_type.name;
86 cpu->byte_order = EMUL_BIG_ENDIAN;
87 cpu->is_32bit = (cpu->cd.sparc.cpu_type.bits == 32)? 1 : 0;
88
89 if (cpu->is_32bit) {
90 cpu->update_translation_table =
91 sparc32_update_translation_table;
92 cpu->invalidate_translation_caches =
93 sparc32_invalidate_translation_caches;
94 cpu->invalidate_code_translation =
95 sparc32_invalidate_code_translation;
96 } else {
97 cpu->update_translation_table = sparc_update_translation_table;
98 cpu->invalidate_translation_caches =
99 sparc_invalidate_translation_caches;
100 cpu->invalidate_code_translation =
101 sparc_invalidate_code_translation;
102 }
103
104 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
105 if (cpu_id == 0) {
106 debug("%s", cpu->name);
107
108 if (cpu->cd.sparc.cpu_type.icache_shift != 0)
109 any_cache = 1;
110 if (cpu->cd.sparc.cpu_type.dcache_shift != 0)
111 any_cache = 1;
112 if (cpu->cd.sparc.cpu_type.l2cache_shift != 0)
113 any_cache = 1;
114
115 if (any_cache) {
116 debug(" (I+D = %i+%i KB", (int)
117 (1 << (cpu->cd.sparc.cpu_type.icache_shift-10)),
118 (int)(1<<(cpu->cd.sparc.cpu_type.dcache_shift-10)));
119 if (cpu->cd.sparc.cpu_type.l2cache_shift != 0) {
120 debug(", L2 = %i KB",
121 (int)(1 << (cpu->cd.sparc.cpu_type.
122 l2cache_shift-10)));
123 }
124 debug(")");
125 }
126 }
127
128 return 1;
129 }
130
131
132 /*
133 * sparc_cpu_list_available_types():
134 *
135 * Print a list of available SPARC CPU types.
136 */
137 void sparc_cpu_list_available_types(void)
138 {
139 int i, j;
140 struct sparc_cpu_type_def tdefs[] = SPARC_CPU_TYPE_DEFS;
141
142 i = 0;
143 while (tdefs[i].name != NULL) {
144 debug("%s", tdefs[i].name);
145 for (j=10 - strlen(tdefs[i].name); j>0; j--)
146 debug(" ");
147 i++;
148 if ((i % 6) == 0 || tdefs[i].name == NULL)
149 debug("\n");
150 }
151 }
152
153
154 /*
155 * sparc_cpu_dumpinfo():
156 */
157 void sparc_cpu_dumpinfo(struct cpu *cpu)
158 {
159 debug(", %i-bit\n", cpu->cd.sparc.cpu_type.bits);
160 }
161
162
163 /*
164 * sparc_cpu_register_dump():
165 *
166 * Dump cpu registers in a relatively readable format.
167 *
168 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
169 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
170 */
171 void sparc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
172 {
173 char *symbol;
174 uint64_t offset;
175 int i, x = cpu->cpu_id;
176 int bits32 = cpu->is_32bit;
177
178 if (gprs) {
179 /* Special registers (pc, ...) first: */
180 symbol = get_symbol_name(&cpu->machine->symbol_context,
181 cpu->pc, &offset);
182
183 debug("cpu%i: pc = 0x", x);
184 if (bits32)
185 debug("%08x", (int)cpu->pc);
186 else
187 debug("%016llx", (long long)cpu->pc);
188 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
189
190 if (bits32) {
191 for (i=0; i<N_SPARC_REG; i++) {
192 if ((i & 3) == 0)
193 debug("cpu%i: ", x);
194 /* Skip the zero register: */
195 if (i==0) {
196 debug(" ");
197 continue;
198 }
199 debug("%s=", sparc_regnames[i]);
200 debug("0x%08x", (int) cpu->cd.sparc.r[i]);
201 if ((i & 3) < 3)
202 debug(" ");
203 else
204 debug("\n");
205 }
206 } else {
207 for (i=0; i<N_SPARC_REG; i++) {
208 int r = ((i >> 1) & 15) | ((i&1) << 4);
209 if ((i & 1) == 0)
210 debug("cpu%i: ", x);
211 /* Skip the zero register: */
212 if (r==0) {
213 debug(" ");
214 continue;
215 }
216 debug("%s = ", sparc_regnames[r]);
217 debug("0x%016llx", (long long)
218 cpu->cd.sparc.r[r]);
219 if ((i & 1) < 1)
220 debug(" ");
221 else
222 debug("\n");
223 }
224 }
225 }
226 }
227
228
229 /*
230 * sparc_cpu_register_match():
231 */
232 void sparc_cpu_register_match(struct machine *m, char *name,
233 int writeflag, uint64_t *valuep, int *match_register)
234 {
235 int cpunr = 0;
236
237 /* CPU number: */
238
239 /* TODO */
240
241 /* Register name: */
242 if (strcasecmp(name, "pc") == 0) {
243 if (writeflag) {
244 m->cpus[cpunr]->pc = *valuep;
245 } else
246 *valuep = m->cpus[cpunr]->pc;
247 *match_register = 1;
248 }
249 }
250
251
252 /*
253 * sparc_cpu_interrupt():
254 */
255 int sparc_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
256 {
257 fatal("sparc_cpu_interrupt(): TODO\n");
258 return 0;
259 }
260
261
262 /*
263 * sparc_cpu_interrupt_ack():
264 */
265 int sparc_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
266 {
267 /* fatal("sparc_cpu_interrupt_ack(): TODO\n"); */
268 return 0;
269 }
270
271
272 /*
273 * sparc_cpu_disassemble_instr():
274 *
275 * Convert an instruction word into human readable format, for instruction
276 * tracing.
277 *
278 * If running is 1, cpu->pc should be the address of the instruction.
279 *
280 * If running is 0, things that depend on the runtime environment (eg.
281 * register contents) will not be shown, and addr will be used instead of
282 * cpu->pc for relative addresses.
283 */
284 int sparc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
285 int running, uint64_t dumpaddr, int bintrans)
286 {
287 uint64_t offset, tmp;
288 uint32_t iword;
289 int hi2, op2, rd, rs1, rs2, siconst, btype, tmps, no_rd = 0;
290 int asi, no_rs1 = 0, no_rs2 = 0, jmpl = 0, shift_x = 0, cc, p;
291 char *symbol, *mnem;
292
293 if (running)
294 dumpaddr = cpu->pc;
295
296 symbol = get_symbol_name(&cpu->machine->symbol_context,
297 dumpaddr, &offset);
298 if (symbol != NULL && offset==0)
299 debug("<%s>\n", symbol);
300
301 if (cpu->machine->ncpus > 1 && running)
302 debug("cpu%i: ", cpu->cpu_id);
303
304 if (cpu->is_32bit)
305 debug("%08x", (int)dumpaddr);
306 else
307 debug("%016llx", (long long)dumpaddr);
308
309 iword = *(uint32_t *)&instr[0];
310 iword = BE32_TO_HOST(iword);
311
312 debug(": %08x\t", iword);
313
314 /*
315 * Decode the instruction:
316 *
317 * http://www.cs.unm.edu/~maccabe/classes/341/labman/node9.html is a
318 * good quick description of SPARC instruction encoding.
319 */
320
321 hi2 = iword >> 30;
322 rd = (iword >> 25) & 31;
323 btype = rd & (N_SPARC_BRANCH_TYPES - 1);
324 rs1 = (iword >> 14) & 31;
325 asi = (iword >> 5) & 0xff;
326 rs2 = iword & 31;
327 siconst = (int16_t)((iword & 0x1fff) << 3) >> 3;
328 op2 = (hi2 == 0)? ((iword >> 22) & 7) : ((iword >> 19) & 0x3f);
329 cc = (iword >> 20) & 3;
330 p = (iword >> 19) & 1;
331
332 switch (hi2) {
333
334 case 0: switch (op2) {
335
336 case 0: debug("illtrap\t0x%x", iword & 0x3fffff);
337 break;
338
339 case 1:
340 case 2:
341 case 3: if (op2 == 3)
342 debug("%s", sparc_regbranch_names[btype & 7]);
343 else
344 debug("%s", sparc_branch_names[btype]);
345 if (rd & 16)
346 debug(",a");
347 tmps = iword;
348 switch (op2) {
349 case 1: tmps <<= 13;
350 tmps >>= 11;
351 if (!p)
352 debug(",pn");
353 debug("\t%%%s,", cc==0 ? "icc" :
354 (cc==2 ? "xcc" : "UNKNOWN"));
355 break;
356 case 2: tmps <<= 10;
357 tmps >>= 8;
358 debug("\t");
359 break;
360 case 3: if (btype & 8)
361 debug("(INVALID)");
362 if (!p)
363 debug(",pn");
364 debug("\t%%%s,", sparc_regnames[rs1]);
365 tmps = ((iword & 0x300000) >> 6)
366 | (iword & 0x3fff);
367 tmps <<= 16;
368 tmps >>= 14;
369 break;
370 }
371 tmp = (int64_t)(int32_t)tmps;
372 tmp += dumpaddr;
373 debug("0x%llx", (long long)tmp);
374 symbol = get_symbol_name(&cpu->machine->
375 symbol_context, tmp, &offset);
376 if (symbol != NULL)
377 debug(" \t<%s>", symbol);
378 break;
379
380 case 4: if (rd == 0) {
381 debug("nop");
382 break;
383 }
384 debug("sethi\t%%hi(0x%x),", (iword & 0x3fffff) << 10);
385 debug("%%%s", sparc_regnames[rd]);
386 break;
387
388 default:debug("UNIMPLEMENTED hi2=%i, op2=0x%x", hi2, op2);
389 }
390 break;
391
392 case 1: tmp = (int32_t)iword << 2;
393 tmp += dumpaddr;
394 debug("call\t0x%llx", (long long)tmp);
395 symbol = get_symbol_name(&cpu->machine->symbol_context,
396 tmp, &offset);
397 if (symbol != NULL)
398 debug(" \t<%s>", symbol);
399 break;
400
401 case 2: mnem = sparc_alu_names[op2];
402 switch (op2) {
403 case 0: /* add */
404 if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
405 mnem = "inc";
406 no_rs1 = no_rs2 = 1;
407 }
408 break;
409 case 2: /* or */
410 if (rs1 == 0) {
411 mnem = "mov";
412 no_rs1 = 1;
413 }
414 break;
415 case 4: /* sub */
416 if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
417 mnem = "dec";
418 no_rs1 = no_rs2 = 1;
419 }
420 break;
421 case 20:/* subcc */
422 if (rd == 0) {
423 mnem = "cmp";
424 no_rd = 1;
425 }
426 break;
427 case 37:/* sll */
428 case 38:/* srl */
429 case 39:/* sra */
430 if (siconst & 0x1000) {
431 siconst &= 0x3f;
432 shift_x = 1;
433 } else
434 siconst &= 0x1f;
435 break;
436 case 43:/* ? */
437 if (iword == 0x81580000) {
438 mnem = "flushw";
439 no_rs1 = no_rs2 = no_rd = 1;
440 }
441 break;
442 case 49:/* ? */
443 if (iword == 0x83880000) {
444 mnem = "restored";
445 no_rs1 = no_rs2 = no_rd = 1;
446 }
447 break;
448 case 56:/* jmpl */
449 jmpl = 1;
450 if (iword == 0x81c7e008) {
451 mnem = "ret";
452 no_rs1 = no_rs2 = no_rd = 1;
453 }
454 if (iword == 0x81c3e008) {
455 mnem = "retl";
456 no_rs1 = no_rs2 = no_rd = 1;
457 }
458 break;
459 case 61:/* restore */
460 if (iword == 0x81e80000)
461 no_rs1 = no_rs2 = no_rd = 1;
462 break;
463 case 62:if (iword == 0x83f00000) {
464 mnem = "retry";
465 no_rs1 = no_rs2 = no_rd = 1;
466 }
467 break;
468 }
469 debug("%s", mnem);
470 if (shift_x)
471 debug("x");
472 debug("\t");
473 if (!no_rs1)
474 debug("%%%s", sparc_regnames[rs1]);
475 if (!no_rs1 && !no_rs2) {
476 if (jmpl)
477 debug("+");
478 else
479 debug(",");
480 }
481 if (!no_rs2) {
482 if ((iword >> 13) & 1) {
483 if (siconst >= -9 && siconst <= 9)
484 debug("%i", siconst);
485 else
486 debug("0x%x", siconst);
487 } else {
488 debug("%%%s", sparc_regnames[rs2]);
489 }
490 }
491 if ((!no_rs1 || !no_rs2) && !no_rd)
492 debug(",");
493 if (!no_rd)
494 debug("%%%s", sparc_regnames[rd]);
495 break;
496
497 case 3: debug("%s\t", sparc_loadstore_names[op2]);
498 if (op2 & 4)
499 debug("%%%s,", sparc_regnames[rd]);
500 debug("[%%%s", sparc_regnames[rs1]);
501 if ((iword >> 13) & 1) {
502 if (siconst > 0)
503 debug("+");
504 if (siconst != 0)
505 debug("%i", siconst);
506 } else {
507 if (rs2 != 0)
508 debug("+%%%s", sparc_regnames[rs2]);
509 }
510 debug("]");
511 if (asi != 0)
512 debug("(%i)", asi);
513 if (!(op2 & 4))
514 debug(",%%%s", sparc_regnames[rd]);
515 break;
516 }
517
518 debug("\n");
519 return sizeof(iword);
520 }
521
522
523 #include "tmp_sparc_tail.c"
524

  ViewVC Help
Powered by ViewVC 1.1.26