25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_ppc.c,v 1.45 2006/01/24 21:26:01 debug Exp $ |
* $Id: cpu_ppc.c,v 1.61 2006/07/24 21:14:52 debug Exp $ |
29 |
* |
* |
30 |
* PowerPC/POWER CPU emulation. |
* PowerPC/POWER CPU emulation. |
31 |
*/ |
*/ |
95 |
cpu->cd.ppc.bits = cpu->cd.ppc.cpu_type.bits; |
cpu->cd.ppc.bits = cpu->cd.ppc.cpu_type.bits; |
96 |
cpu->cd.ppc.spr[SPR_PVR] = cpu->cd.ppc.cpu_type.pvr; |
cpu->cd.ppc.spr[SPR_PVR] = cpu->cd.ppc.cpu_type.pvr; |
97 |
|
|
98 |
|
/* cpu->cd.ppc.msr = PPC_MSR_IR | PPC_MSR_DR | |
99 |
|
PPC_MSR_SF | PPC_MSR_FP; */ |
100 |
|
|
101 |
cpu->cd.ppc.spr[SPR_IBAT0U] = 0x00001ffc | BAT_Vs; |
cpu->cd.ppc.spr[SPR_IBAT0U] = 0x00001ffc | BAT_Vs; |
102 |
cpu->cd.ppc.spr[SPR_IBAT0L] = 0x00000000 | BAT_PP_RW; |
cpu->cd.ppc.spr[SPR_IBAT0L] = 0x00000000 | BAT_PP_RW; |
103 |
cpu->cd.ppc.spr[SPR_IBAT1U] = 0xc0001ffc | BAT_Vs; |
cpu->cd.ppc.spr[SPR_IBAT1U] = 0xc0001ffc | BAT_Vs; |
116 |
cpu->is_32bit = (cpu->cd.ppc.bits == 32)? 1 : 0; |
cpu->is_32bit = (cpu->cd.ppc.bits == 32)? 1 : 0; |
117 |
|
|
118 |
if (cpu->is_32bit) { |
if (cpu->is_32bit) { |
119 |
|
cpu->run_instr = ppc32_run_instr; |
120 |
cpu->update_translation_table = ppc32_update_translation_table; |
cpu->update_translation_table = ppc32_update_translation_table; |
121 |
cpu->invalidate_translation_caches = |
cpu->invalidate_translation_caches = |
122 |
ppc32_invalidate_translation_caches; |
ppc32_invalidate_translation_caches; |
123 |
cpu->invalidate_code_translation = |
cpu->invalidate_code_translation = |
124 |
ppc32_invalidate_code_translation; |
ppc32_invalidate_code_translation; |
125 |
} else { |
} else { |
126 |
|
cpu->run_instr = ppc_run_instr; |
127 |
cpu->update_translation_table = ppc_update_translation_table; |
cpu->update_translation_table = ppc_update_translation_table; |
128 |
cpu->invalidate_translation_caches = |
cpu->invalidate_translation_caches = |
129 |
ppc_invalidate_translation_caches; |
ppc_invalidate_translation_caches; |
131 |
ppc_invalidate_code_translation; |
ppc_invalidate_code_translation; |
132 |
} |
} |
133 |
|
|
134 |
cpu->translate_address = ppc_translate_address; |
cpu->translate_v2p = ppc_translate_v2p; |
135 |
|
|
136 |
/* Only show name and caches etc for CPU nr 0 (in SMP machines): */ |
/* Only show name and caches etc for CPU nr 0 (in SMP machines): */ |
137 |
if (cpu_id == 0) { |
if (cpu_id == 0) { |
272 |
*valuep = cpu->cd.ppc.msr; |
*valuep = cpu->cd.ppc.msr; |
273 |
|
|
274 |
if (check_for_interrupts && cpu->cd.ppc.msr & PPC_MSR_EE) { |
if (check_for_interrupts && cpu->cd.ppc.msr & PPC_MSR_EE) { |
275 |
if (cpu->cd.ppc.dec_intr_pending) { |
if (cpu->cd.ppc.dec_intr_pending && |
276 |
|
!(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC)) { |
277 |
ppc_exception(cpu, PPC_EXCEPTION_DEC); |
ppc_exception(cpu, PPC_EXCEPTION_DEC); |
278 |
cpu->cd.ppc.dec_intr_pending = 0; |
cpu->cd.ppc.dec_intr_pending = 0; |
279 |
} else if (cpu->cd.ppc.irq_asserted) |
} else if (cpu->cd.ppc.irq_asserted) |
297 |
cpu->cd.ppc.spr[SPR_SRR1] = (cpu->cd.ppc.msr & 0x87c0ffff); |
cpu->cd.ppc.spr[SPR_SRR1] = (cpu->cd.ppc.msr & 0x87c0ffff); |
298 |
|
|
299 |
if (!quiet_mode) |
if (!quiet_mode) |
300 |
fatal("[ PPC Exception 0x%x; pc=0x%llx ]\n", exception_nr, |
fatal("[ PPC Exception 0x%x; pc=0x%"PRIx64" ]\n", exception_nr, |
301 |
(long long)cpu->pc); |
(long long)cpu->pc); |
302 |
|
|
303 |
/* Disable External Interrupts, Recoverable Interrupt Mode, |
/* Disable External Interrupts, Recoverable Interrupt Mode, |
337 |
|
|
338 |
debug("cpu%i: pc = 0x", x); |
debug("cpu%i: pc = 0x", x); |
339 |
if (bits32) |
if (bits32) |
340 |
debug("%08x", (int)cpu->pc); |
debug("%08"PRIx32, (uint32_t)cpu->pc); |
341 |
else |
else |
342 |
debug("%016llx", (long long)cpu->pc); |
debug("%016"PRIx64, (uint64_t)cpu->pc); |
343 |
debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); |
debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); |
344 |
|
|
345 |
debug("cpu%i: lr = 0x", x); |
debug("cpu%i: lr = 0x", x); |
346 |
if (bits32) |
if (bits32) |
347 |
debug("%08x", (int)cpu->cd.ppc.spr[SPR_LR]); |
debug("%08"PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_LR]); |
348 |
else |
else |
349 |
debug("%016llx", (long long)cpu->cd.ppc.spr[SPR_LR]); |
debug("%016"PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_LR]); |
350 |
debug(" cr = 0x%08x", (int)cpu->cd.ppc.cr); |
debug(" cr = 0x%08"PRIx32, (uint32_t)cpu->cd.ppc.cr); |
351 |
|
|
352 |
if (bits32) |
if (bits32) |
353 |
debug(" "); |
debug(" "); |
355 |
debug("\ncpu%i: ", x); |
debug("\ncpu%i: ", x); |
356 |
debug("ctr = 0x", x); |
debug("ctr = 0x", x); |
357 |
if (bits32) |
if (bits32) |
358 |
debug("%08x", (int)cpu->cd.ppc.spr[SPR_CTR]); |
debug("%08"PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_CTR]); |
359 |
else |
else |
360 |
debug("%016llx", (long long)cpu->cd.ppc.spr[SPR_CTR]); |
debug("%016"PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_CTR]); |
361 |
|
|
362 |
debug(" xer = 0x", x); |
debug(" xer = 0x", x); |
363 |
if (bits32) |
if (bits32) |
364 |
debug("%08x\n", (int)cpu->cd.ppc.spr[SPR_XER]); |
debug("%08"PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_XER]); |
365 |
else |
else |
366 |
debug("%016llx\n", (long long)cpu->cd.ppc.spr[SPR_XER]); |
debug("%016"PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_XER]); |
367 |
|
|
368 |
|
debug("\n"); |
369 |
|
|
370 |
if (bits32) { |
if (bits32) { |
371 |
/* 32-bit: */ |
/* 32-bit: */ |
602 |
|
|
603 |
|
|
604 |
/* |
/* |
605 |
|
* ppc_cpu_tlbdump(): |
606 |
|
* |
607 |
|
* Not currently used for PPC. |
608 |
|
*/ |
609 |
|
void ppc_cpu_tlbdump(struct machine *m, int x, int rawflag) |
610 |
|
{ |
611 |
|
} |
612 |
|
|
613 |
|
|
614 |
|
static void add_response_word(struct cpu *cpu, char *r, uint64_t value, |
615 |
|
size_t maxlen, int len) |
616 |
|
{ |
617 |
|
char *format = (len == 4)? "%08"PRIx64 : "%016"PRIx64; |
618 |
|
if (len == 4) |
619 |
|
value &= 0xffffffffULL; |
620 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
621 |
|
if (len == 4) { |
622 |
|
value = ((value & 0xff) << 24) + |
623 |
|
((value & 0xff00) << 8) + |
624 |
|
((value & 0xff0000) >> 8) + |
625 |
|
((value & 0xff000000) >> 24); |
626 |
|
} else { |
627 |
|
value = ((value & 0xff) << 56) + |
628 |
|
((value & 0xff00) << 40) + |
629 |
|
((value & 0xff0000) << 24) + |
630 |
|
((value & 0xff000000ULL) << 8) + |
631 |
|
((value & 0xff00000000ULL) >> 8) + |
632 |
|
((value & 0xff0000000000ULL) >> 24) + |
633 |
|
((value & 0xff000000000000ULL) >> 40) + |
634 |
|
((value & 0xff00000000000000ULL) >> 56); |
635 |
|
} |
636 |
|
} |
637 |
|
snprintf(r + strlen(r), maxlen - strlen(r), format, (uint64_t)value); |
638 |
|
} |
639 |
|
|
640 |
|
|
641 |
|
/* |
642 |
|
* ppc_cpu_gdb_stub(): |
643 |
|
* |
644 |
|
* Execute a "remote GDB" command. Returns a newly allocated response string |
645 |
|
* on success, NULL on failure. |
646 |
|
*/ |
647 |
|
char *ppc_cpu_gdb_stub(struct cpu *cpu, char *cmd) |
648 |
|
{ |
649 |
|
if (strcmp(cmd, "g") == 0) { |
650 |
|
int i; |
651 |
|
char *r; |
652 |
|
size_t wlen = cpu->is_32bit? |
653 |
|
sizeof(uint32_t) : sizeof(uint64_t); |
654 |
|
size_t len = 1 + 76 * wlen; |
655 |
|
r = malloc(len); |
656 |
|
if (r == NULL) { |
657 |
|
fprintf(stderr, "out of memory\n"); |
658 |
|
exit(1); |
659 |
|
} |
660 |
|
r[0] = '\0'; |
661 |
|
for (i=0; i<128; i++) |
662 |
|
add_response_word(cpu, r, i, len, wlen); |
663 |
|
return r; |
664 |
|
} |
665 |
|
|
666 |
|
if (cmd[0] == 'p') { |
667 |
|
int regnr = strtol(cmd + 1, NULL, 16); |
668 |
|
size_t wlen = cpu->is_32bit? |
669 |
|
sizeof(uint32_t) : sizeof(uint64_t); |
670 |
|
size_t len = 2 * wlen + 1; |
671 |
|
char *r = malloc(len); |
672 |
|
r[0] = '\0'; |
673 |
|
if (regnr >= 0 && regnr <= 31) { |
674 |
|
add_response_word(cpu, r, |
675 |
|
cpu->cd.ppc.gpr[regnr], len, wlen); |
676 |
|
} else if (regnr == 0x40) { |
677 |
|
add_response_word(cpu, r, cpu->pc, len, wlen); |
678 |
|
} else if (regnr == 0x42) { |
679 |
|
add_response_word(cpu, r, cpu->cd.ppc.cr, len, wlen); |
680 |
|
} else if (regnr == 0x43) { |
681 |
|
add_response_word(cpu, r, cpu->cd.ppc.spr[SPR_LR], |
682 |
|
len, wlen); |
683 |
|
} else if (regnr == 0x44) { |
684 |
|
add_response_word(cpu, r, cpu->cd.ppc.spr[SPR_CTR], |
685 |
|
len, wlen); |
686 |
|
} else if (regnr == 0x45) { |
687 |
|
add_response_word(cpu, r, cpu->cd.ppc.spr[SPR_XER], |
688 |
|
len, wlen); |
689 |
|
} else { |
690 |
|
/* Unimplemented: */ |
691 |
|
add_response_word(cpu, r, 0xcc000 + regnr, len, wlen); |
692 |
|
} |
693 |
|
return r; |
694 |
|
} |
695 |
|
|
696 |
|
fatal("ppc_cpu_gdb_stub(): TODO\n"); |
697 |
|
return NULL; |
698 |
|
} |
699 |
|
|
700 |
|
|
701 |
|
/* |
702 |
* ppc_cpu_interrupt(): |
* ppc_cpu_interrupt(): |
703 |
* |
* |
704 |
* 0..31 are used as BeBox interrupt numbers, 32..47 = ISA, |
* 0..31 are used as BeBox interrupt numbers, 32..47 = ISA, |
753 |
* cpu->pc for relative addresses. |
* cpu->pc for relative addresses. |
754 |
*/ |
*/ |
755 |
int ppc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, |
int ppc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, |
756 |
int running, uint64_t dumpaddr, int bintrans) |
int running, uint64_t dumpaddr) |
757 |
{ |
{ |
758 |
int hi6, xo, lev, rt, rs, ra, rb, imm, sh, me, rc, l_bit, oe_bit; |
int hi6, xo, lev, rt, rs, ra, rb, imm, sh, me, rc, l_bit, oe_bit; |
759 |
int spr, aa_bit, lk_bit, bf, bh, bi, bo, mb, nb, bt, ba, bb, fpreg; |
int spr, aa_bit, lk_bit, bf, bh, bi, bo, mb, nb, bt, ba, bb, fpreg; |
1047 |
case PPC_HI6_30: |
case PPC_HI6_30: |
1048 |
xo = (iword >> 2) & 7; |
xo = (iword >> 2) & 7; |
1049 |
switch (xo) { |
switch (xo) { |
1050 |
|
case PPC_30_RLDICL: |
1051 |
case PPC_30_RLDICR: |
case PPC_30_RLDICR: |
1052 |
|
case PPC_30_RLDIMI: /* mb, not me */ |
1053 |
|
mnem = NULL; |
1054 |
|
switch (xo) { |
1055 |
|
case PPC_30_RLDICL: mnem = "rldicl"; break; |
1056 |
|
case PPC_30_RLDICR: mnem = "rldicr"; break; |
1057 |
|
case PPC_30_RLDIMI: mnem = "rldimi"; break; |
1058 |
|
} |
1059 |
rs = (iword >> 21) & 31; |
rs = (iword >> 21) & 31; |
1060 |
ra = (iword >> 16) & 31; |
ra = (iword >> 16) & 31; |
1061 |
sh = ((iword >> 11) & 31) | ((iword & 2) << 4); |
sh = ((iword >> 11) & 31) | ((iword & 2) << 4); |
1062 |
me = ((iword >> 6) & 31) | (iword & 0x20); |
me = ((iword >> 6) & 31) | (iword & 0x20); |
1063 |
rc = iword & 1; |
rc = iword & 1; |
1064 |
debug("rldicr%s\tr%i,r%i,%i,%i", |
debug("%s%s\tr%i,r%i,%i,%i", |
1065 |
rc?".":"", ra, rs, sh, me); |
mnem, rc?".":"", ra, rs, sh, me); |
1066 |
break; |
break; |
1067 |
default: |
default: |
1068 |
debug("unimplemented hi6_30, xo = 0x%x", xo); |
debug("unimplemented hi6_30, xo = 0x%x", xo); |
1229 |
case PPC_31_WRTEEI: |
case PPC_31_WRTEEI: |
1230 |
debug("wrteei\t%i", iword & 0x8000? 1 : 0); |
debug("wrteei\t%i", iword & 0x8000? 1 : 0); |
1231 |
break; |
break; |
1232 |
|
case PPC_31_MTMSRD: |
1233 |
|
/* TODO: Just a guess based on MTMSR */ |
1234 |
|
rs = (iword >> 21) & 31; |
1235 |
|
l_bit = (iword >> 16) & 1; |
1236 |
|
debug("mtmsrd\tr%i", rs); |
1237 |
|
if (l_bit) |
1238 |
|
debug(",%i", l_bit); |
1239 |
|
break; |
1240 |
case PPC_31_ADDZE: |
case PPC_31_ADDZE: |
1241 |
case PPC_31_ADDZEO: |
case PPC_31_ADDZEO: |
1242 |
rt = (iword >> 21) & 31; |
rt = (iword >> 21) & 31; |
1457 |
debug("%s\tr%i,r%i", mnem, ra, rb); |
debug("%s\tr%i,r%i", mnem, ra, rb); |
1458 |
break; |
break; |
1459 |
case PPC_31_SLW: |
case PPC_31_SLW: |
1460 |
|
case PPC_31_SLD: |
1461 |
case PPC_31_SRAW: |
case PPC_31_SRAW: |
1462 |
case PPC_31_SRW: |
case PPC_31_SRW: |
1463 |
case PPC_31_AND: |
case PPC_31_AND: |
1464 |
case PPC_31_ANDC: |
case PPC_31_ANDC: |
1465 |
case PPC_31_NOR: |
case PPC_31_NOR: |
1466 |
|
case PPC_31_EQV: |
1467 |
case PPC_31_OR: |
case PPC_31_OR: |
1468 |
case PPC_31_ORC: |
case PPC_31_ORC: |
1469 |
case PPC_31_XOR: |
case PPC_31_XOR: |
1478 |
switch (xo) { |
switch (xo) { |
1479 |
case PPC_31_SLW: mnem = |
case PPC_31_SLW: mnem = |
1480 |
power? "sl" : "slw"; break; |
power? "sl" : "slw"; break; |
1481 |
|
case PPC_31_SLD: mnem = "sld"; break; |
1482 |
case PPC_31_SRAW: mnem = |
case PPC_31_SRAW: mnem = |
1483 |
power? "sra" : "sraw"; break; |
power? "sra" : "sraw"; break; |
1484 |
case PPC_31_SRW: mnem = |
case PPC_31_SRW: mnem = |
1487 |
case PPC_31_NAND: mnem = "nand"; break; |
case PPC_31_NAND: mnem = "nand"; break; |
1488 |
case PPC_31_ANDC: mnem = "andc"; break; |
case PPC_31_ANDC: mnem = "andc"; break; |
1489 |
case PPC_31_NOR: mnem = "nor"; break; |
case PPC_31_NOR: mnem = "nor"; break; |
1490 |
|
case PPC_31_EQV: mnem = "eqv"; break; |
1491 |
case PPC_31_OR: mnem = "or"; break; |
case PPC_31_OR: mnem = "or"; break; |
1492 |
case PPC_31_ORC: mnem = "orc"; break; |
case PPC_31_ORC: mnem = "orc"; break; |
1493 |
case PPC_31_XOR: mnem = "xor"; break; |
case PPC_31_XOR: mnem = "xor"; break; |
1572 |
debug("%s%s\tr%i,r%i,%i", mnem, |
debug("%s%s\tr%i,r%i,%i", mnem, |
1573 |
rc? "." : "", ra, rs, sh); |
rc? "." : "", ra, rs, sh); |
1574 |
break; |
break; |
1575 |
|
case PPC_31_DSSALL: |
1576 |
|
debug("dssall"); |
1577 |
|
break; |
1578 |
case PPC_31_EIEIO: |
case PPC_31_EIEIO: |
1579 |
debug("%s", power? "eieio?" : "eieio"); |
debug("%s", power? "eieio?" : "eieio"); |
1580 |
break; |
break; |
1597 |
} |
} |
1598 |
debug("%s%s\tr%i,r%i", mnem, rc? "." : "", ra, rs); |
debug("%s%s\tr%i,r%i", mnem, rc? "." : "", ra, rs); |
1599 |
break; |
break; |
|
case 359: |
|
|
debug("TODO: ALTIVEC 359"); |
|
|
break; |
|
1600 |
case PPC_31_LVX: |
case PPC_31_LVX: |
1601 |
debug("lvx\tTODO: ALTIVEC"); |
case PPC_31_LVXL: |
|
break; |
|
1602 |
case PPC_31_STVX: |
case PPC_31_STVX: |
|
debug("stvx\tTODO: ALTIVEC"); |
|
|
break; |
|
1603 |
case PPC_31_STVXL: |
case PPC_31_STVXL: |
1604 |
debug("stvxl\tTODO: ALTIVEC"); |
rs = (iword >> 21) & 31; /* vs for stores, */ |
1605 |
|
ra = (iword >> 16) & 31; /* rs=vl for loads */ |
1606 |
|
rb = (iword >> 11) & 31; |
1607 |
|
rc = iword & 1; |
1608 |
|
switch (xo) { |
1609 |
|
case PPC_31_LVX: mnem = "lvx"; break; |
1610 |
|
case PPC_31_LVXL: mnem = "lvxl"; break; |
1611 |
|
case PPC_31_STVX: mnem = "stvx"; break; |
1612 |
|
case PPC_31_STVXL: mnem = "stvxl"; break; |
1613 |
|
} |
1614 |
|
debug("%s%s\tv%i,r%i,r%i", mnem, rc? "." : "", |
1615 |
|
rs, ra, rb); |
1616 |
break; |
break; |
1617 |
default: |
default: |
1618 |
debug("unimplemented hi6_31, xo = 0x%x", xo); |
debug("unimplemented hi6_31, xo = 0x%x", xo); |
1985 |
|
|
1986 |
#include "tmp_ppc_tail.c" |
#include "tmp_ppc_tail.c" |
1987 |
|
|
1988 |
|
|