/* * emul_ppc.cpp - PowerPC processor emulation * * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* TODO: addme addmeo addze addzeo dcbst dcbt dcbtst divwuo fabs fadd fadds fcmpo fcmpu fctiw fctiwz fdiv fdivs fmadd fmadds fmr fmsub fmsubs fmul fmuls fnabs fneg fnmadd fnmadds fnmsub fnmsubs fres frsp frsqrte fsel fsqrt fsqrts fsub fsubs lfdu lfdux lfdx lfs lfsu lfsux lfsx lhbrx lwbrx mcrfs mcrxr mtfsb0 mtfsb1 mtfsfi mulhwu mullwo nego sc stfdu stfdux stfdx stfs stfsu stfsux stfsx sthbrx stwbrx subfo subfme subfmeo subfze subfzeo tw twi CHECK: crxor creqv */ #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "xlowmem.h" #include "emul_op.h" #if ENABLE_MON #include "mon.h" #include "mon_disass.h" #endif #define DEBUG 1 #include "debug.h" #define FLIGHT_RECORDER 1 // PowerPC user mode registers uint32 r[32]; double fr[32]; uint32 lr, ctr; uint32 cr, xer; uint32 fpscr; uint32 pc; // Convert 8-bit field mask (e.g. mtcrf) to bit mask static uint32 field2mask[256]; /* * Flight recorder */ #if FLIGHT_RECORDER struct rec_step { uint32 r[32]; double fr[32]; uint32 lr, ctr; uint32 cr, xer; uint32 fpscr; uint32 pc; uint32 opcode; }; const int LOG_SIZE = 8192; static rec_step log[LOG_SIZE]; static int log_ptr = 0; static void record_step(uint32 opcode) { for (int i=0; i<32; i++) { log[log_ptr].r[i] = r[i]; log[log_ptr].fr[i] = fr[i]; } log[log_ptr].lr = lr; log[log_ptr].ctr = ctr; log[log_ptr].cr = cr; log[log_ptr].xer = xer; log[log_ptr].fpscr = fpscr; log[log_ptr].pc = pc; log[log_ptr].opcode = opcode; log_ptr++; if (log_ptr == LOG_SIZE) log_ptr = 0; } static void dump_log(void) { FILE *f = fopen("log", "w"); if (f == NULL) return; for (int i=0; i> 4) & 0x0f000000); } /* * Convert mask begin/end to mask */ static uint32 mbme2mask(uint32 op) { uint32 mb = (op >> 6) & 0x1f; uint32 me = (op >> 1) & 0x1f; uint32 m = 0; uint32 i; if (mb <= me) for (i=mb; i<=me; i++) m |= 0x80000000 >> i; else { for (i=0; i<=me; i++) m |= 0x80000000 >> i; for (i=mb; i<=31; i++) m |= 0x80000000 >> i; } return m; } /* * Emulate instruction with primary opcode = 19 */ static void emul19(uint32 op) { uint32 exop = (op >> 1) & 0x3ff; uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; switch (exop) { case 0: { // mcrf uint32 crfd = 0x1c - (rd & 0x1c); uint32 crfa = 0x1c - (ra & 0x1c); uint32 crf = (cr >> crfa) & 0xf; cr = (cr & ~(0xf << crfd)) | (crf << crfd); break; } case 16: { // bclr uint32 oldpc = pc; if (!(rd & 4)) { ctr--; if (rd & 2) { if (ctr) goto blr_nobranch; } else { if (!ctr) goto blr_nobranch; } } if (!(rd & 0x10)) { if (rd & 8) { if (!(cr & (0x80000000 >> ra))) goto blr_nobranch; } else { if (cr & (0x80000000 >> ra)) goto blr_nobranch; } } pc = lr & 0xfffffffc; blr_nobranch: if (op & 1) lr = oldpc; break; } case 33: // crnor if ((cr & (0x80000000 >> ra)) || ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) cr &= ~(0x80000000 >> rd); else cr |= 0x80000000 >> rd; break; case 129: // crandc if ((cr & (0x80000000 >> ra)) && !((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) cr |= 0x80000000 >> rd; else cr &= ~(0x80000000 >> rd); break; case 150: // isync break; case 193: { // crxor uint32 mask = 0x80000000 >> rd; cr = (((((cr >> (31 - ra)) ^ (cr >> (31 - ((op >> 11) & 0x1f)))) & 1) << (31 - rd)) & mask) | (cr & ~mask); break; } case 225: // crnand if ((cr & (0x80000000 >> ra)) && ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) cr &= ~(0x80000000 >> rd); else cr |= 0x80000000 >> rd; break; case 257: // crand if ((cr & (0x80000000 >> ra)) && ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) cr |= 0x80000000 >> rd; else cr &= ~(0x80000000 >> rd); break; case 289: { // creqv uint32 mask = 0x80000000 >> rd; cr = (((~((cr >> (31 - ra)) ^ (cr >> (31 - ((op >> 11) & 0x1f)))) & 1) << (31 - rd)) & mask) | (cr & ~mask); break; } case 417: // crorc if ((cr & (0x80000000 >> ra)) || !((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) cr |= 0x80000000 >> rd; else cr &= ~(0x80000000 >> rd); break; case 449: // cror if ((cr & (0x80000000 >> ra)) || ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) cr |= 0x80000000 >> rd; else cr &= ~(0x80000000 >> rd); break; case 528: { // bcctr if (op & 1) lr = pc; if (!(rd & 4)) { ctr--; if (rd & 2) { if (ctr) goto bctr_nobranch; } else { if (!ctr) goto bctr_nobranch; } } if (!(rd & 0x10)) { if (rd & 8) { if (!(cr & (0x80000000 >> ra))) goto bctr_nobranch; } else { if (cr & (0x80000000 >> ra)) goto bctr_nobranch; } } pc = ctr & 0xfffffffc; bctr_nobranch: break; } default: printf("Illegal 19 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); dump(); break; } } /* * Emulate instruction with primary opcode = 31 */ static void emul31(uint32 op) { uint32 exop = (op >> 1) & 0x3ff; uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint32 rb = (op >> 11) & 0x1f; switch (exop) { case 0: { // cmpw uint32 crfd = 0x1c - (rd & 0x1c); uint8 crf = 0; if (r[ra] == r[rb]) crf |= 2; else if ((int32)r[ra] < (int32)r[rb]) crf |= 8; else crf |= 4; if (xer & 0x80000000) crf |= 1; cr = (cr & ~(0xf << crfd)) | (crf << crfd); break; } case 8: { // subfc uint64 tmp = (uint64)r[rb] - (uint64)r[ra]; r[rd] = tmp; if (tmp & 0x100000000LL) xer &= ~0x20000000; else xer |= 0x20000000; if (op & 1) record(r[rd]); break; } case 10: { // addc uint64 tmp = (uint64)r[ra] + (uint64)r[rb]; r[rd] = tmp; if (tmp & 0x100000000LL) xer |= 0x20000000; else xer &= ~0x20000000; if (op & 1) record(r[rd]); break; } case 19: // mfcr r[rd] = cr; break; case 20: // lwarx r[rd] = ReadMacInt32(r[rb] + (ra ? r[ra] : 0)); //!! set reservation bit break; case 23: // lwzx r[rd] = ReadMacInt32(r[rb] + (ra ? r[ra] : 0)); break; case 24: // slw r[ra] = r[rd] << (r[rb] & 0x3f); if (op & 1) record(r[ra]); break; case 26: { // cntlzw uint32 mask = 0x80000000; for (int i=0; i<32; i++, mask>>=1) { if (r[rd] & mask) { r[ra] = i; goto cntlzw_done; } } r[ra] = 32; cntlzw_done:if (op & 1) record(r[ra]); break; } case 28: // and r[ra] = r[rd] & r[rb]; if (op & 1) record(r[ra]); break; case 32: { // cmplw uint32 crfd = 0x1c - (rd & 0x1c); uint8 crf = 0; if (r[ra] == r[rb]) crf |= 2; else if (r[ra] < r[rb]) crf |= 8; else crf |= 4; if (xer & 0x80000000) crf |= 1; cr = (cr & ~(0xf << crfd)) | (crf << crfd); break; } case 40: // subf r[rd] = r[rb] - r[ra]; if (op & 1) record(r[rd]); break; case 55: // lwzux r[ra] += r[rb]; r[rd] = ReadMacInt32(r[ra]); break; case 60: // andc r[ra] = r[rd] & ~r[rb]; if (op & 1) record(r[ra]); break; case 75: // mulhw r[rd] = ((int64)(int32)r[ra] * (int32)r[rb]) >> 32; if (op & 1) record(r[rd]); break; case 86: // dcbf break; case 87: // lbzx r[rd] = ReadMacInt8(r[rb] + (ra ? r[ra] : 0)); break; case 104: // neg if (r[ra] == 0x80000000) r[rd] = 0x80000000; else r[rd] = -(int32)r[ra]; if (op & 1) record(r[rd]); break; case 119: // lbzux r[ra] += r[rb]; r[rd] = ReadMacInt8(r[ra]); break; case 124: // nor r[ra] = ~(r[rd] | r[rb]); if (op & 1) record(r[ra]); break; case 136: { // subfe uint64 tmp = (uint64)r[rb] - (uint64)r[ra]; if (!(xer & 0x20000000)) tmp--; r[rd] = tmp; if (tmp & 0x100000000LL) xer &= ~0x20000000; else xer |= 0x20000000; if (op & 1) record(r[rd]); break; } case 138: { // adde uint64 tmp = (uint64)r[ra] + (uint64)r[rb]; if (xer & 0x20000000) tmp++; r[rd] = tmp; if (tmp & 0x100000000LL) xer |= 0x20000000; else xer &= ~0x20000000; if (op & 1) record(r[rd]); break; } case 144: { // mtcrf uint32 mask = field2mask[(op >> 12) & 0xff]; cr = (r[rd] & mask) | (cr & ~mask); break; } case 150: // stwcx //!! check reserved bit WriteMacInt32(r[rb] + (ra ? r[ra] : 0), r[rd]); record(0); break; case 151: // stwx WriteMacInt32(r[rb] + (ra ? r[ra] : 0), r[rd]); break; case 183: // stwux r[ra] += r[rb]; WriteMacInt32(r[ra], r[rd]); break; case 215: // stbx WriteMacInt8(r[rb] + (ra ? r[ra] : 0), r[rd]); break; case 235: // mullw r[rd] = (int32)r[ra] * (int32)r[rb]; if (op & 1) record(r[rd]); break; case 247: // stbux r[ra] += r[rb]; WriteMacInt8(r[ra], r[rd]); break; case 266: // add r[rd] = r[ra] + r[rb]; if (op & 1) record(r[rd]); break; case 279: // lhzx r[rd] = ReadMacInt16(r[rb] + (ra ? r[ra] : 0)); break; case 284: // eqv r[ra] = ~(r[rd] ^ r[rb]); if (op & 1) record(r[ra]); break; case 311: // lhzux r[ra] += r[rb]; r[rd] = ReadMacInt16(r[ra]); break; case 316: // xor r[ra] = r[rd] ^ r[rb]; if (op & 1) record(r[ra]); break; case 339: { // mfspr uint32 spr = ra | (rb << 5); switch (spr) { case 1: r[rd] = xer; break; case 8: r[rd] = lr; break; case 9: r[rd] = ctr; break; default: printf("Illegal mfspr opcode %08x at %08x\n", op, pc-4); dump(); } break; } case 343: // lhax r[rd] = (int32)(int16)ReadMacInt16(r[rb] + (ra ? r[ra] : 0)); break; case 371: // mftb r[rd] = 0; //!! break; case 375: // lhaux r[ra] += r[rb]; r[rd] = (int32)(int16)ReadMacInt16(r[ra]); break; case 407: // sthx WriteMacInt16(r[rb] + (ra ? r[ra] : 0), r[rd]); break; case 412: // orc r[ra] = r[rd] | ~r[rb]; if (op & 1) record(r[ra]); break; case 439: // sthux r[ra] += r[rb]; WriteMacInt16(r[ra], r[rd]); break; case 444: // or r[ra] = r[rd] | r[rb]; if (op & 1) record(r[ra]); break; case 459: // divwu if (r[rb]) r[rd] = r[ra] / r[rb]; if (op & 1) record(r[rd]); break; case 467: { // mtspr uint32 spr = ra | (rb << 5); switch (spr) { case 1: xer = r[rd] & 0xe000007f; break; case 8: lr = r[rd]; break; case 9: ctr = r[rd]; break; default: printf("Illegal mtspr opcode %08x at %08x\n", op, pc-4); dump(); } break; } case 476: // nand r[ra] = ~(r[rd] & r[rb]); if (op & 1) record(r[ra]); break; case 491: // divw if (r[rb]) r[rd] = (int32)r[ra] / (int32)r[rb]; if (op & 1) record(r[rd]); break; case 520: { // subfco uint64 tmp = (uint64)r[rb] - (uint64)r[ra]; uint32 ov = (r[ra] ^ r[rb]) & ((uint32)tmp ^ r[rb]); r[rd] = tmp; if (tmp & 0x100000000LL) xer &= ~0x20000000; else xer |= 0x20000000; if (ov & 0x80000000) xer |= 0xc0000000; else xer &= ~0x40000000; if (op & 1) record(r[rd]); break; } case 522: { // addco uint64 tmp = (uint64)r[ra] + (uint64)r[rb]; uint32 ov = (r[ra] ^ (uint32)tmp) & (r[rb] ^ (uint32)tmp); r[rd] = tmp; if (tmp & 0x100000000LL) xer |= 0x20000000; else xer &= ~0x20000000; if (ov & 0x80000000) xer |= 0xc0000000; else xer &= ~0x40000000; if (op & 1) record(r[rd]); break; } case 533: { // lswx uint32 addr = r[rb] + (ra ? r[ra] : 0); int nb = xer & 0x7f; int reg = rd; for (int i=0; i> (r[rb] & 0x3f); if (op & 1) record(r[ra]); break; case 597: { // lswi uint32 addr = ra ? r[ra] : 0; int nb = rb ? rb : 32; int reg = rd; for (int i=0; i> shift)); shift -= 8; if ((i & 3) == 3) { shift = 24; reg = (reg + 1) & 0x1f; } } break; } case 725: { // stswi uint32 addr = ra ? r[ra] : 0; int nb = rb ? rb : 32; int reg = rd; int shift = 24; for (int i=0; i> shift)); shift -= 8; if ((i & 3) == 3) { shift = 24; reg = (reg + 1) & 0x1f; } } break; } case 778: { // addo uint32 tmp = r[ra] + r[rb]; uint32 ov = (r[ra] ^ tmp) & (r[rb] ^ tmp); r[rd] = tmp; if (ov & 0x80000000) xer |= 0xc0000000; else xer &= ~0x40000000; if (op & 1) record(r[rd]); break; } case 792: { // sraw uint32 sh = r[rb] & 0x3f; uint32 mask = ~(0xffffffff << sh); if ((r[rd] & 0x80000000) && (r[rd] & mask)) xer |= 0x20000000; else xer &= ~0x20000000; r[ra] = (int32)r[rd] >> sh; if (op & 1) record(r[ra]); break; } case 824: { // srawi uint32 mask = ~(0xffffffff << rb); if ((r[rd] & 0x80000000) && (r[rd] & mask)) xer |= 0x20000000; else xer &= ~0x20000000; r[ra] = (int32)r[rd] >> rb; if (op & 1) record(r[ra]); break; } case 854: // eieio break; case 922: // extsh r[ra] = (int32)(int16)r[rd]; if (op & 1) record(r[ra]); break; case 954: // extsb r[ra] = (int32)(int8)r[rd]; if (op & 1) record(r[ra]); break; case 982: // icbi break; case 1003: // divwo if (r[rb] == 0 || (r[ra] == 0x80000000 && r[rb] == 0xffffffff)) xer |= 0xc0000000; else { r[rd] = (int32)r[ra] / (int32)r[rb]; xer &= ~0x40000000; } if (op & 1) record(r[rd]); break; #if 0 case 1014: // dcbz memset(r[rb] + (ra ? r[ra] : 0), 0, 32); break; #endif default: printf("Illegal 31 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); dump(); break; } } /* * Emulate instruction with primary opcode = 59 */ static void emul59(uint32 op) { uint32 exop = (op >> 1) & 0x3ff; switch (exop) { default: printf("Illegal 59 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); dump(); break; } } /* * Emulate instruction with primary opcode = 63 */ static void emul63(uint32 op) { uint32 exop = (op >> 1) & 0x3ff; uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint32 rb = (op >> 11) & 0x1f; switch (exop) { case 583: // mffs fr[rd] = (double)(uint64)fpscr; if (op & 1) record1(); break; case 711: // mtfsf //!! if (op & 1) record1(); break; default: printf("Illegal 63 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); dump(); break; } } /* * Emulation loop */ void emul_ppc(uint32 start) { pc = start; //uint32 old_val = 0; for (;;) { //uint32 val = ReadMacInt32(0x68fff778); //if (val != old_val) { // printf("insn at %08lx changed %08lx->%08lx\n", pc-4, old_val, val); // old_val = val; //} uint32 op = ReadMacInt32(pc); #if FLIGHT_RECORDER record_step(op); #endif // printf("%08lx at %08lx\n", op, pc); uint32 primop = op >> 26; pc += 4; switch (primop) { case 6: // SheepShaver extensions printf("Extended opcode %08x at %08x (68k pc %08x)\n", op, pc-4, r[24]); switch (op & 0x3f) { case 0: // EMUL_RETURN QuitEmulator(); break; case 1: // EXEC_RETURN //!! dump(); break; default: { // EMUL_OP M68kRegisters r68; WriteMacInt32(XLM_68K_R25, r[25]); WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP); for (int i=0; i<8; i++) r68.d[i] = r[8 + i]; for (int i=0; i<7; i++) r68.a[i] = r[16 + i]; r68.a[7] = r[1]; EmulOp(&r68, r[24], (op & 0x3f) - 2); for (int i=0; i<8; i++) r[8 + i] = r68.d[i]; for (int i=0; i<7; i++) r[16 + i] = r68.a[i]; r[1] = r68.a[7]; WriteMacInt32(XLM_RUN_MODE, MODE_68K); break; } } break; case 7: { // mulli uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[rd] = (int32)r[ra] * (int32)(int16)(op & 0xffff); break; } case 8: { // subfic uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint64 tmp = (uint32)(int32)(int16)(op & 0xffff) - (uint64)r[ra]; r[rd] = tmp; if (tmp & 0x100000000LL) xer &= ~0x20000000; else xer |= 0x20000000; break; } case 10: { // cmpli uint32 crfd = 0x1c - ((op >> 21) & 0x1c); uint32 ra = (op >> 16) & 0x1f; uint32 val = (op & 0xffff); uint8 crf = 0; if (r[ra] == val) crf |= 2; else if (r[ra] < val) crf |= 8; else crf |= 4; if (xer & 0x80000000) crf |= 1; cr = (cr & ~(0xf << crfd)) | (crf << crfd); break; } case 11: { // cmpi uint32 crfd = 0x1c - ((op >> 21) & 0x1c); uint32 ra = (op >> 16) & 0x1f; int32 val = (int32)(int16)(op & 0xffff); uint8 crf = 0; if ((int32)r[ra] == val) crf |= 2; else if ((int32)r[ra] < val) crf |= 8; else crf |= 4; if (xer & 0x80000000) crf |= 1; cr = (cr & ~(0xf << crfd)) | (crf << crfd); break; } case 12: { // addic uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint64 tmp = (uint64)r[ra] + (uint32)(int32)(int16)(op & 0xffff); r[rd] = tmp; if (tmp & 0x100000000LL) xer |= 0x20000000; else xer &= ~0x20000000; break; } case 13: { // addic. uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint64 tmp = (uint64)r[ra] + (uint32)(int32)(int16)(op & 0xffff); r[rd] = tmp; if (tmp & 0x100000000LL) xer |= 0x20000000; else xer &= ~0x20000000; record(r[rd]); break; } case 14: { // addi uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[rd] = (ra ? r[ra] : 0) + (int32)(int16)(op & 0xffff); break; } case 15: { // addis uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[rd] = (ra ? r[ra] : 0) + (op << 16); break; } case 16: { // bc uint32 bo = (op >> 21) & 0x1f; uint32 bi = (op >> 16) & 0x1f; if (op & 1) lr = pc; if (!(bo & 4)) { ctr--; if (bo & 2) { if (ctr) goto bc_nobranch; } else { if (!ctr) goto bc_nobranch; } } if (!(bo & 0x10)) { if (bo & 8) { if (!(cr & (0x80000000 >> bi))) goto bc_nobranch; } else { if (cr & (0x80000000 >> bi)) goto bc_nobranch; } } if (op & 2) pc = (int32)(int16)(op & 0xfffc); else pc += (int32)(int16)(op & 0xfffc) - 4; bc_nobranch: break; } case 18: { // b int32 target = op & 0x03fffffc; if (target & 0x02000000) target |= 0xfc000000; if (op & 1) lr = pc; if (op & 2) pc = target; else pc += target - 4; break; } case 19: emul19(op); break; case 20: { // rlwimi uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint32 sh = (op >> 11) & 0x1f; uint32 mask = mbme2mask(op); r[ra] = (((r[rs] << sh) | (r[rs] >> (32-sh))) & mask) | (r[ra] & ~mask); if (op & 1) record(r[ra]); break; } case 21: { // rlwinm uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint32 sh = (op >> 11) & 0x1f; r[ra] = ((r[rs] << sh) | (r[rs] >> (32-sh))) & mbme2mask(op); if (op & 1) record(r[ra]); break; } case 23: { // rlwnm uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint32 sh = r[(op >> 11) & 0x1f] & 0x1f; r[ra] = ((r[rs] << sh) | (r[rs] >> (32-sh))) & mbme2mask(op); if (op & 1) record(r[ra]); break; } case 24: { // ori uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] = r[rs] | (op & 0xffff); break; } case 25: { // oris uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] = r[rs] | (op << 16); break; } case 26: { // xori uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] = r[rs] ^ (op & 0xffff); break; } case 27: { // xoris uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] = r[rs] ^ (op << 16); break; } case 28: { // andi. uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] = r[rs] & (op & 0xffff); record(r[ra]); break; } case 29: { // andis. uint32 rs = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] = r[rs] & (op << 16); record(r[ra]); break; } case 31: emul31(op); break; case 32: { // lwz uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[rd] = ReadMacInt32(int16(op & 0xffff) + (ra ? r[ra] : 0)); break; } case 33: { // lwzu uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] += int16(op & 0xffff); r[rd] = ReadMacInt32(r[ra]); break; } case 34: { // lbz uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[rd] = ReadMacInt8(int16(op & 0xffff) + (ra ? r[ra] : 0)); break; } case 35: { // lbzu uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] += int16(op & 0xffff); r[rd] = ReadMacInt8(r[ra]); break; } case 36: { // stw uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; WriteMacInt32(int16(op & 0xffff) + (ra ? r[ra] : 0), r[rd]); break; } case 37: { // stwu uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] += int16(op & 0xffff); WriteMacInt32(r[ra], r[rd]); break; } case 38: { // stb uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; WriteMacInt8(int16(op & 0xffff) + (ra ? r[ra] : 0), r[rd]); break; } case 39: { // stbu uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] += int16(op & 0xffff); WriteMacInt8(r[ra], r[rd]); break; } case 40: { // lhz uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[rd] = ReadMacInt16(int16(op & 0xffff) + (ra ? r[ra] : 0)); break; } case 41: { // lhzu uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] += int16(op & 0xffff); r[rd] = ReadMacInt16(r[ra]); break; } case 42: { // lha uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[rd] = (int32)(int16)ReadMacInt16(int16(op & 0xffff) + (ra ? r[ra] : 0)); break; } case 43: { // lhau uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] += int16(op & 0xffff); r[rd] = (int32)(int16)ReadMacInt16(r[ra]); break; } case 44: { // sth uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; WriteMacInt16(int16(op & 0xffff) + (ra ? r[ra] : 0), r[rd]); break; } case 45: { // sthu uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; r[ra] += int16(op & 0xffff); WriteMacInt16(r[ra], r[rd]); break; } case 46: { // lmw uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint32 addr = int16(op & 0xffff) + (ra ? r[ra] : 0); while (rd <= 31) { r[rd] = ReadMacInt32(addr); rd++; addr += 4; } break; } case 47: { // stmw uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; uint32 addr = int16(op & 0xffff) + (ra ? r[ra] : 0); while (rd <= 31) { WriteMacInt32(addr, r[rd]); rd++; addr += 4; } break; } case 50: { // lfd uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; fr[rd] = (double)ReadMacInt64(int16(op & 0xffff) + (ra ? r[ra] : 0)); break; } case 54: { // stfd uint32 rd = (op >> 21) & 0x1f; uint32 ra = (op >> 16) & 0x1f; WriteMacInt64(int16(op & 0xffff) + (ra ? r[ra] : 0), (uint64)fr[rd]); break; } case 59: emul59(op); break; case 63: emul63(op); break; default: printf("Illegal opcode %08x at %08x\n", op, pc-4); dump(); break; } } } static struct sigaction sigsegv_action; static void sigsegv_handler(int sig) { printf("SIGSEGV\n"); dump(); } void init_emul_ppc(void) { // Init field2mask for (int i=0; i<256; i++) { uint32 mask = 0; if (i & 0x01) mask |= 0x0000000f; if (i & 0x02) mask |= 0x000000f0; if (i & 0x04) mask |= 0x00000f00; if (i & 0x08) mask |= 0x0000f000; if (i & 0x10) mask |= 0x000f0000; if (i & 0x20) mask |= 0x00f00000; if (i & 0x40) mask |= 0x0f000000; if (i & 0x80) mask |= 0xf0000000; field2mask[i] = mask; } // Init registers for (int i=0; i<32; i++) { r[i] = 0; fr[i] = 0.0; } lr = ctr = 0; cr = xer = 0; fpscr = 0; r[3] = ROM_BASE + 0x30d000; // Install SIGSEGV handler sigemptyset(&sigsegv_action.sa_mask); sigsegv_action.sa_handler = (__sighandler_t)sigsegv_handler; sigsegv_action.sa_flags = 0; sigsegv_action.sa_restorer = NULL; sigaction(SIGSEGV, &sigsegv_action, NULL); #if FLIGHT_RECORDER && ENABLE_MON // Install "log" command in mon mon_add_command("log", dump_log, "log Dump PowerPC emulation log\n"); #endif } /* * Execute 68k subroutine (must be ended with EXEC_RETURN) * This must only be called by the emul_thread when in EMUL_OP mode * r->a[7] is unused, the routine runs on the caller's stack */ void Execute68k(uint32 pc, M68kRegisters *r) { printf("ERROR: Execute68k() unimplemented\n"); QuitEmulator(); } /* * Execute 68k A-Trap from EMUL_OP routine * r->a[7] is unused, the routine runs on the caller's stack */ void Execute68kTrap(uint16 trap, M68kRegisters *r) { printf("ERROR: Execute68kTrap() unimplemented\n"); QuitEmulator(); } /* * Call MacOS PPC code */ uint32 call_macos(uint32 tvect) { printf("ERROR: call_macos() unimplemented\n"); QuitEmulator(); return 0; } uint32 call_macos1(uint32 tvect, uint32 arg1) { printf("ERROR: call_macos1() unimplemented\n"); QuitEmulator(); return 0; } uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2) { printf("ERROR: call_macos2() unimplemented\n"); QuitEmulator(); return 0; } uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3) { printf("ERROR: call_macos3() unimplemented\n"); QuitEmulator(); return 0; } uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4) { printf("ERROR: call_macos4() unimplemented\n"); QuitEmulator(); return 0; } uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5) { printf("ERROR: call_macos5() unimplemented\n"); QuitEmulator(); return 0; } uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6) { printf("ERROR: call_macos6() unimplemented\n"); QuitEmulator(); return 0; } uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7) { printf("ERROR: call_macos7() unimplemented\n"); QuitEmulator(); return 0; } /* * Atomic operations */ extern int atomic_add(int *var, int v) { int ret = *var; *var += v; return ret; } extern int atomic_and(int *var, int v) { int ret = *var; *var &= v; return ret; } extern int atomic_or(int *var, int v) { int ret = *var; *var |= v; return ret; } extern "C" void get_resource(void); extern "C" void get_1_resource(void); extern "C" void get_ind_resource(void); extern "C" void get_1_ind_resource(void); extern "C" void r_get_resource(void); void get_resource(void) { printf("ERROR: get_resource() unimplemented\n"); QuitEmulator(); } void get_1_resource(void) { printf("ERROR: get_1_resource() unimplemented\n"); QuitEmulator(); } void get_ind_resource(void) { printf("ERROR: get_ind_resource() unimplemented\n"); QuitEmulator(); } void get_1_ind_resource(void) { printf("ERROR: get_1_ind_resource() unimplemented\n"); QuitEmulator(); } void r_get_resource(void) { printf("ERROR: r_get_resource() unimplemented\n"); QuitEmulator(); }