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.58 2006/06/16 18:31:26 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; |
160 |
/* Some default stack pointer value. TODO: move this? */ |
/* Some default stack pointer value. TODO: move this? */ |
161 |
cpu->cd.ppc.gpr[1] = machine->physical_ram_in_mb * 1048576 - 4096; |
cpu->cd.ppc.gpr[1] = machine->physical_ram_in_mb * 1048576 - 4096; |
162 |
|
|
163 |
|
ppc_init_64bit_dummy_tables(cpu); |
164 |
|
|
165 |
/* |
/* |
166 |
* NOTE/TODO: Ugly hack for OpenFirmware emulation: |
* NOTE/TODO: Ugly hack for OpenFirmware emulation: |
167 |
*/ |
*/ |
296 |
cpu->cd.ppc.spr[SPR_SRR1] = (cpu->cd.ppc.msr & 0x87c0ffff); |
cpu->cd.ppc.spr[SPR_SRR1] = (cpu->cd.ppc.msr & 0x87c0ffff); |
297 |
|
|
298 |
if (!quiet_mode) |
if (!quiet_mode) |
299 |
fatal("[ PPC Exception 0x%x; pc=0x%llx ]\n", exception_nr, |
fatal("[ PPC Exception 0x%x; pc=0x%"PRIx64" ]\n", exception_nr, |
300 |
(long long)cpu->pc); |
(long long)cpu->pc); |
301 |
|
|
302 |
/* Disable External Interrupts, Recoverable Interrupt Mode, |
/* Disable External Interrupts, Recoverable Interrupt Mode, |
336 |
|
|
337 |
debug("cpu%i: pc = 0x", x); |
debug("cpu%i: pc = 0x", x); |
338 |
if (bits32) |
if (bits32) |
339 |
debug("%08x", (int)cpu->pc); |
debug("%08"PRIx32, (uint32_t)cpu->pc); |
340 |
else |
else |
341 |
debug("%016llx", (long long)cpu->pc); |
debug("%016"PRIx64, (uint64_t)cpu->pc); |
342 |
debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); |
debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); |
343 |
|
|
344 |
debug("cpu%i: lr = 0x", x); |
debug("cpu%i: lr = 0x", x); |
345 |
if (bits32) |
if (bits32) |
346 |
debug("%08x", (int)cpu->cd.ppc.spr[SPR_LR]); |
debug("%08"PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_LR]); |
347 |
else |
else |
348 |
debug("%016llx", (long long)cpu->cd.ppc.spr[SPR_LR]); |
debug("%016"PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_LR]); |
349 |
debug(" cr = 0x%08x", (int)cpu->cd.ppc.cr); |
debug(" cr = 0x%08"PRIx32, (uint32_t)cpu->cd.ppc.cr); |
350 |
|
|
351 |
if (bits32) |
if (bits32) |
352 |
debug(" "); |
debug(" "); |
354 |
debug("\ncpu%i: ", x); |
debug("\ncpu%i: ", x); |
355 |
debug("ctr = 0x", x); |
debug("ctr = 0x", x); |
356 |
if (bits32) |
if (bits32) |
357 |
debug("%08x", (int)cpu->cd.ppc.spr[SPR_CTR]); |
debug("%08"PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_CTR]); |
358 |
else |
else |
359 |
debug("%016llx", (long long)cpu->cd.ppc.spr[SPR_CTR]); |
debug("%016"PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_CTR]); |
360 |
|
|
361 |
debug(" xer = 0x", x); |
debug(" xer = 0x", x); |
362 |
if (bits32) |
if (bits32) |
363 |
debug("%08x\n", (int)cpu->cd.ppc.spr[SPR_XER]); |
debug("%08"PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_XER]); |
364 |
else |
else |
365 |
debug("%016llx\n", (long long)cpu->cd.ppc.spr[SPR_XER]); |
debug("%016"PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_XER]); |
366 |
|
|
367 |
|
debug("\n"); |
368 |
|
|
369 |
if (bits32) { |
if (bits32) { |
370 |
/* 32-bit: */ |
/* 32-bit: */ |
601 |
|
|
602 |
|
|
603 |
/* |
/* |
604 |
|
* ppc_cpu_tlbdump(): |
605 |
|
* |
606 |
|
* Not currently used for PPC. |
607 |
|
*/ |
608 |
|
void ppc_cpu_tlbdump(struct machine *m, int x, int rawflag) |
609 |
|
{ |
610 |
|
} |
611 |
|
|
612 |
|
|
613 |
|
static void add_response_word(struct cpu *cpu, char *r, uint64_t value, |
614 |
|
size_t maxlen, int len) |
615 |
|
{ |
616 |
|
char *format = (len == 4)? "%08"PRIx64 : "%016"PRIx64; |
617 |
|
if (len == 4) |
618 |
|
value &= 0xffffffffULL; |
619 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
620 |
|
if (len == 4) { |
621 |
|
value = ((value & 0xff) << 24) + |
622 |
|
((value & 0xff00) << 8) + |
623 |
|
((value & 0xff0000) >> 8) + |
624 |
|
((value & 0xff000000) >> 24); |
625 |
|
} else { |
626 |
|
value = ((value & 0xff) << 56) + |
627 |
|
((value & 0xff00) << 40) + |
628 |
|
((value & 0xff0000) << 24) + |
629 |
|
((value & 0xff000000ULL) << 8) + |
630 |
|
((value & 0xff00000000ULL) >> 8) + |
631 |
|
((value & 0xff0000000000ULL) >> 24) + |
632 |
|
((value & 0xff000000000000ULL) >> 40) + |
633 |
|
((value & 0xff00000000000000ULL) >> 56); |
634 |
|
} |
635 |
|
} |
636 |
|
snprintf(r + strlen(r), maxlen - strlen(r), format, (uint64_t)value); |
637 |
|
} |
638 |
|
|
639 |
|
|
640 |
|
/* |
641 |
|
* ppc_cpu_gdb_stub(): |
642 |
|
* |
643 |
|
* Execute a "remote GDB" command. Returns a newly allocated response string |
644 |
|
* on success, NULL on failure. |
645 |
|
*/ |
646 |
|
char *ppc_cpu_gdb_stub(struct cpu *cpu, char *cmd) |
647 |
|
{ |
648 |
|
if (strcmp(cmd, "g") == 0) { |
649 |
|
int i; |
650 |
|
char *r; |
651 |
|
size_t wlen = cpu->is_32bit? |
652 |
|
sizeof(uint32_t) : sizeof(uint64_t); |
653 |
|
size_t len = 1 + 76 * wlen; |
654 |
|
r = malloc(len); |
655 |
|
if (r == NULL) { |
656 |
|
fprintf(stderr, "out of memory\n"); |
657 |
|
exit(1); |
658 |
|
} |
659 |
|
r[0] = '\0'; |
660 |
|
for (i=0; i<128; i++) |
661 |
|
add_response_word(cpu, r, i, len, wlen); |
662 |
|
return r; |
663 |
|
} |
664 |
|
|
665 |
|
if (cmd[0] == 'p') { |
666 |
|
int regnr = strtol(cmd + 1, NULL, 16); |
667 |
|
size_t wlen = cpu->is_32bit? |
668 |
|
sizeof(uint32_t) : sizeof(uint64_t); |
669 |
|
size_t len = 2 * wlen + 1; |
670 |
|
char *r = malloc(len); |
671 |
|
r[0] = '\0'; |
672 |
|
if (regnr >= 0 && regnr <= 31) { |
673 |
|
add_response_word(cpu, r, |
674 |
|
cpu->cd.ppc.gpr[regnr], len, wlen); |
675 |
|
} else if (regnr == 0x40) { |
676 |
|
add_response_word(cpu, r, cpu->pc, len, wlen); |
677 |
|
} else if (regnr == 0x42) { |
678 |
|
add_response_word(cpu, r, cpu->cd.ppc.cr, len, wlen); |
679 |
|
} else if (regnr == 0x43) { |
680 |
|
add_response_word(cpu, r, cpu->cd.ppc.spr[SPR_LR], |
681 |
|
len, wlen); |
682 |
|
} else if (regnr == 0x44) { |
683 |
|
add_response_word(cpu, r, cpu->cd.ppc.spr[SPR_CTR], |
684 |
|
len, wlen); |
685 |
|
} else if (regnr == 0x45) { |
686 |
|
add_response_word(cpu, r, cpu->cd.ppc.spr[SPR_XER], |
687 |
|
len, wlen); |
688 |
|
} else { |
689 |
|
/* Unimplemented: */ |
690 |
|
add_response_word(cpu, r, 0xcc000 + regnr, len, wlen); |
691 |
|
} |
692 |
|
return r; |
693 |
|
} |
694 |
|
|
695 |
|
fatal("ppc_cpu_gdb_stub(): TODO\n"); |
696 |
|
return NULL; |
697 |
|
} |
698 |
|
|
699 |
|
|
700 |
|
/* |
701 |
* ppc_cpu_interrupt(): |
* ppc_cpu_interrupt(): |
702 |
* |
* |
703 |
* 0..31 are used as BeBox interrupt numbers, 32..47 = ISA, |
* 0..31 are used as BeBox interrupt numbers, 32..47 = ISA, |
752 |
* cpu->pc for relative addresses. |
* cpu->pc for relative addresses. |
753 |
*/ |
*/ |
754 |
int ppc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, |
int ppc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, |
755 |
int running, uint64_t dumpaddr, int bintrans) |
int running, uint64_t dumpaddr) |
756 |
{ |
{ |
757 |
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; |
758 |
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; |
1046 |
case PPC_HI6_30: |
case PPC_HI6_30: |
1047 |
xo = (iword >> 2) & 7; |
xo = (iword >> 2) & 7; |
1048 |
switch (xo) { |
switch (xo) { |
1049 |
|
case PPC_30_RLDICL: |
1050 |
case PPC_30_RLDICR: |
case PPC_30_RLDICR: |
1051 |
|
case PPC_30_RLDIMI: /* mb, not me */ |
1052 |
|
mnem = NULL; |
1053 |
|
switch (xo) { |
1054 |
|
case PPC_30_RLDICL: mnem = "rldicl"; break; |
1055 |
|
case PPC_30_RLDICR: mnem = "rldicr"; break; |
1056 |
|
case PPC_30_RLDIMI: mnem = "rldimi"; break; |
1057 |
|
} |
1058 |
rs = (iword >> 21) & 31; |
rs = (iword >> 21) & 31; |
1059 |
ra = (iword >> 16) & 31; |
ra = (iword >> 16) & 31; |
1060 |
sh = ((iword >> 11) & 31) | ((iword & 2) << 4); |
sh = ((iword >> 11) & 31) | ((iword & 2) << 4); |
1061 |
me = ((iword >> 6) & 31) | (iword & 0x20); |
me = ((iword >> 6) & 31) | (iword & 0x20); |
1062 |
rc = iword & 1; |
rc = iword & 1; |
1063 |
debug("rldicr%s\tr%i,r%i,%i,%i", |
debug("%s%s\tr%i,r%i,%i,%i", |
1064 |
rc?".":"", ra, rs, sh, me); |
mnem, rc?".":"", ra, rs, sh, me); |
1065 |
break; |
break; |
1066 |
default: |
default: |
1067 |
debug("unimplemented hi6_30, xo = 0x%x", xo); |
debug("unimplemented hi6_30, xo = 0x%x", xo); |
1228 |
case PPC_31_WRTEEI: |
case PPC_31_WRTEEI: |
1229 |
debug("wrteei\t%i", iword & 0x8000? 1 : 0); |
debug("wrteei\t%i", iword & 0x8000? 1 : 0); |
1230 |
break; |
break; |
1231 |
|
case PPC_31_MTMSRD: |
1232 |
|
/* TODO: Just a guess based on MTMSR */ |
1233 |
|
rs = (iword >> 21) & 31; |
1234 |
|
l_bit = (iword >> 16) & 1; |
1235 |
|
debug("mtmsrd\tr%i", rs); |
1236 |
|
if (l_bit) |
1237 |
|
debug(",%i", l_bit); |
1238 |
|
break; |
1239 |
case PPC_31_ADDZE: |
case PPC_31_ADDZE: |
1240 |
case PPC_31_ADDZEO: |
case PPC_31_ADDZEO: |
1241 |
rt = (iword >> 21) & 31; |
rt = (iword >> 21) & 31; |
1456 |
debug("%s\tr%i,r%i", mnem, ra, rb); |
debug("%s\tr%i,r%i", mnem, ra, rb); |
1457 |
break; |
break; |
1458 |
case PPC_31_SLW: |
case PPC_31_SLW: |
1459 |
|
case PPC_31_SLD: |
1460 |
case PPC_31_SRAW: |
case PPC_31_SRAW: |
1461 |
case PPC_31_SRW: |
case PPC_31_SRW: |
1462 |
case PPC_31_AND: |
case PPC_31_AND: |
1463 |
case PPC_31_ANDC: |
case PPC_31_ANDC: |
1464 |
case PPC_31_NOR: |
case PPC_31_NOR: |
1465 |
|
case PPC_31_EQV: |
1466 |
case PPC_31_OR: |
case PPC_31_OR: |
1467 |
case PPC_31_ORC: |
case PPC_31_ORC: |
1468 |
case PPC_31_XOR: |
case PPC_31_XOR: |
1477 |
switch (xo) { |
switch (xo) { |
1478 |
case PPC_31_SLW: mnem = |
case PPC_31_SLW: mnem = |
1479 |
power? "sl" : "slw"; break; |
power? "sl" : "slw"; break; |
1480 |
|
case PPC_31_SLD: mnem = "sld"; break; |
1481 |
case PPC_31_SRAW: mnem = |
case PPC_31_SRAW: mnem = |
1482 |
power? "sra" : "sraw"; break; |
power? "sra" : "sraw"; break; |
1483 |
case PPC_31_SRW: mnem = |
case PPC_31_SRW: mnem = |
1486 |
case PPC_31_NAND: mnem = "nand"; break; |
case PPC_31_NAND: mnem = "nand"; break; |
1487 |
case PPC_31_ANDC: mnem = "andc"; break; |
case PPC_31_ANDC: mnem = "andc"; break; |
1488 |
case PPC_31_NOR: mnem = "nor"; break; |
case PPC_31_NOR: mnem = "nor"; break; |
1489 |
|
case PPC_31_EQV: mnem = "eqv"; break; |
1490 |
case PPC_31_OR: mnem = "or"; break; |
case PPC_31_OR: mnem = "or"; break; |
1491 |
case PPC_31_ORC: mnem = "orc"; break; |
case PPC_31_ORC: mnem = "orc"; break; |
1492 |
case PPC_31_XOR: mnem = "xor"; break; |
case PPC_31_XOR: mnem = "xor"; break; |
1571 |
debug("%s%s\tr%i,r%i,%i", mnem, |
debug("%s%s\tr%i,r%i,%i", mnem, |
1572 |
rc? "." : "", ra, rs, sh); |
rc? "." : "", ra, rs, sh); |
1573 |
break; |
break; |
1574 |
|
case PPC_31_DSSALL: |
1575 |
|
debug("dssall"); |
1576 |
|
break; |
1577 |
case PPC_31_EIEIO: |
case PPC_31_EIEIO: |
1578 |
debug("%s", power? "eieio?" : "eieio"); |
debug("%s", power? "eieio?" : "eieio"); |
1579 |
break; |
break; |
1596 |
} |
} |
1597 |
debug("%s%s\tr%i,r%i", mnem, rc? "." : "", ra, rs); |
debug("%s%s\tr%i,r%i", mnem, rc? "." : "", ra, rs); |
1598 |
break; |
break; |
|
case 359: |
|
|
debug("TODO: ALTIVEC 359"); |
|
|
break; |
|
1599 |
case PPC_31_LVX: |
case PPC_31_LVX: |
1600 |
debug("lvx\tTODO: ALTIVEC"); |
case PPC_31_LVXL: |
|
break; |
|
1601 |
case PPC_31_STVX: |
case PPC_31_STVX: |
|
debug("stvx\tTODO: ALTIVEC"); |
|
|
break; |
|
1602 |
case PPC_31_STVXL: |
case PPC_31_STVXL: |
1603 |
debug("stvxl\tTODO: ALTIVEC"); |
rs = (iword >> 21) & 31; /* vs for stores, */ |
1604 |
|
ra = (iword >> 16) & 31; /* rs=vl for loads */ |
1605 |
|
rb = (iword >> 11) & 31; |
1606 |
|
rc = iword & 1; |
1607 |
|
switch (xo) { |
1608 |
|
case PPC_31_LVX: mnem = "lvx"; break; |
1609 |
|
case PPC_31_LVXL: mnem = "lvxl"; break; |
1610 |
|
case PPC_31_STVX: mnem = "stvx"; break; |
1611 |
|
case PPC_31_STVXL: mnem = "stvxl"; break; |
1612 |
|
} |
1613 |
|
debug("%s%s\tv%i,r%i,r%i", mnem, rc? "." : "", |
1614 |
|
rs, ra, rb); |
1615 |
break; |
break; |
1616 |
default: |
default: |
1617 |
debug("unimplemented hi6_31, xo = 0x%x", xo); |
debug("unimplemented hi6_31, xo = 0x%x", xo); |
1984 |
|
|
1985 |
#include "tmp_ppc_tail.c" |
#include "tmp_ppc_tail.c" |
1986 |
|
|
1987 |
|
|