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

Annotation of /upstream/0.3.8/src/cpus/cpu_sparc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 12582 byte(s)
0.3.8
1 dpavlin 14 /*
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 dpavlin 22 * $Id: cpu_sparc.c,v 1.11 2005/12/11 21:34:43 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     #include "tmp_sparc_head.c"
47    
48    
49 dpavlin 22 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 dpavlin 14 /*
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 dpavlin 22 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 dpavlin 14 return 0;
81    
82     cpu->memory_rw = sparc_memory_rw;
83    
84 dpavlin 22 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 dpavlin 14
89 dpavlin 22 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 dpavlin 14 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
105     if (cpu_id == 0) {
106     debug("%s", cpu->name);
107 dpavlin 22
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 dpavlin 14 }
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 dpavlin 22 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 dpavlin 14 }
152    
153    
154     /*
155     * sparc_cpu_dumpinfo():
156     */
157     void sparc_cpu_dumpinfo(struct cpu *cpu)
158     {
159 dpavlin 22 debug(", %i-bit\n", cpu->cd.sparc.cpu_type.bits);
160 dpavlin 14 }
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 dpavlin 20 uint64_t offset;
175 dpavlin 22 int i, x = cpu->cpu_id;
176     int bits32 = cpu->is_32bit;
177 dpavlin 14
178     if (gprs) {
179     /* Special registers (pc, ...) first: */
180     symbol = get_symbol_name(&cpu->machine->symbol_context,
181     cpu->pc, &offset);
182    
183 dpavlin 22 debug("cpu%i: pc = 0x", x);
184 dpavlin 14 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 dpavlin 22 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 dpavlin 14 }
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 dpavlin 22 uint64_t offset, tmp;
288 dpavlin 14 uint32_t iword;
289 dpavlin 22 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 dpavlin 14
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 dpavlin 22 if (cpu->is_32bit)
305 dpavlin 14 debug("%08x", (int)dumpaddr);
306     else
307 dpavlin 22 debug("%016llx", (long long)dumpaddr);
308 dpavlin 14
309 dpavlin 22 iword = *(uint32_t *)&instr[0];
310     iword = BE32_TO_HOST(iword);
311 dpavlin 14
312     debug(": %08x\t", iword);
313    
314     /*
315     * Decode the instruction:
316 dpavlin 22 *
317     * http://www.cs.unm.edu/~maccabe/classes/341/labman/node9.html is a
318     * good quick description of SPARC instruction encoding.
319 dpavlin 14 */
320    
321 dpavlin 22 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 dpavlin 14
332 dpavlin 22 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 dpavlin 14 }
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