macemu/SheepShaver/src/emul_ppc/emul_ppc.cpp

1662 lines
32 KiB
C++

/*
* 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 <stdio.h>
#include <signal.h>
#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<LOG_SIZE; i++) {
int j = (i + log_ptr) % LOG_SIZE;
fprintf(f, "pc %08x lr %08x ctr %08x cr %08x xer %08x ", log[j].pc, log[j].lr, log[j].ctr, log[j].cr, log[j].xer);
fprintf(f, "r0 %08x r1 %08x r2 %08x r3 %08x ", log[j].r[0], log[j].r[1], log[j].r[2], log[j].r[3]);
fprintf(f, "r4 %08x r5 %08x r6 %08x r7 %08x ", log[j].r[4], log[j].r[5], log[j].r[6], log[j].r[7]);
fprintf(f, "r8 %08x r9 %08x r10 %08x r11 %08x ", log[j].r[8], log[j].r[9], log[j].r[10], log[j].r[11]);
fprintf(f, "r12 %08x r13 %08x r14 %08x r15 %08x ", log[j].r[12], log[j].r[13], log[j].r[14], log[j].r[15]);
fprintf(f, "r16 %08x r17 %08x r18 %08x r19 %08x ", log[j].r[16], log[j].r[17], log[j].r[18], log[j].r[19]);
fprintf(f, "r20 %08x r21 %08x r22 %08x r23 %08x ", log[j].r[20], log[j].r[21], log[j].r[22], log[j].r[23]);
fprintf(f, "r24 %08x r25 %08x r26 %08x r27 %08x ", log[j].r[24], log[j].r[25], log[j].r[26], log[j].r[27]);
fprintf(f, "r28 %08x r29 %08x r30 %08x r31 %08x\n", log[j].r[28], log[j].r[29], log[j].r[30], log[j].r[31]);
#if ENABLE_MON
disass_ppc(f, log[j].pc, log[j].opcode);
#endif
}
fclose(f);
}
#endif
/*
* Dump PPC registers
*/
static void dump(void)
{
// Dump registers
printf(" r0 %08x r1 %08x r2 %08x r3 %08x\n", r[0], r[1], r[2], r[3]);
printf(" r4 %08x r5 %08x r6 %08x r7 %08x\n", r[4], r[5], r[6], r[7]);
printf(" r8 %08x r9 %08x r10 %08x r11 %08x\n", r[8], r[9], r[10], r[11]);
printf("r12 %08x r13 %08x r14 %08x r15 %08x\n", r[12], r[13], r[14], r[15]);
printf("r16 %08x r17 %08x r18 %08x r19 %08x\n", r[16], r[17], r[18], r[19]);
printf("r20 %08x r21 %08x r22 %08x r23 %08x\n", r[20], r[21], r[22], r[23]);
printf("r24 %08x r25 %08x r26 %08x r27 %08x\n", r[24], r[25], r[26], r[27]);
printf("r28 %08x r29 %08x r30 %08x r31 %08x\n", r[28], r[29], r[30], r[31]);
printf(" lr %08x ctr %08x cr %08x xer %08x\n", lr, ctr, cr, xer);
printf(" pc %08x fpscr %08x\n", pc, fpscr);
// Start up mon in real-mode
#if ENABLE_MON
char *arg[4] = {"mon", "-m", "-r", NULL};
mon(3, arg);
#endif
QuitEmulator();
}
/*
* Record result in CR0
*/
static void record(uint32 val)
{
uint32 crf = 0;
if (val == 0)
crf |= 0x20000000;
else if (val & 0x80000000)
crf |= 0x80000000;
else
crf |= 0x40000000;
if (xer & 0x80000000)
crf |= 0x10000000;
cr = (cr & 0x0fffffff) | crf;
}
/*
* Record result in CR1
*/
static inline void record1(void)
{
cr = (cr & 0xf0ffffff) | ((fpscr >> 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<nb; i++) {
switch (i & 3) {
case 0:
r[reg] = ReadMacInt8(addr + i) << 24;
break;
case 1:
r[reg] = (r[reg] & 0xff00ffff) | (ReadMacInt8(addr + i) << 16);
break;
case 2:
r[reg] = (r[reg] & 0xffff00ff) | (ReadMacInt8(addr + i) << 8);
break;
case 3:
r[reg] = (r[reg] & 0xffffff00) | ReadMacInt8(addr + i);
reg = (reg + 1) & 0x1f;
break;
}
}
break;
}
case 536: // srw
r[ra] = r[rd] >> (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<nb; i++) {
switch (i & 3) {
case 0:
r[reg] = ReadMacInt8(addr + i) << 24;
break;
case 1:
r[reg] = (r[reg] & 0xff00ffff) | (ReadMacInt8(addr + i) << 16);
break;
case 2:
r[reg] = (r[reg] & 0xffff00ff) | (ReadMacInt8(addr + i) << 8);
break;
case 3:
r[reg] = (r[reg] & 0xffffff00) | ReadMacInt8(addr + i);
reg = (reg + 1) & 0x1f;
break;
}
}
break;
}
case 598: // sync
break;
case 648: { // subfeo
uint64 tmp = (uint64)r[rb] - (uint64)r[ra];
if (!(xer & 0x20000000))
tmp--;
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 650: { // addeo
uint64 tmp = (uint64)r[ra] + (uint64)r[rb];
if (xer & 0x20000000)
tmp++;
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 661: { // stswx
uint32 addr = r[rb] + (ra ? r[ra] : 0);
int nb = xer & 0x7f;
int reg = rd;
int shift = 24;
for (int i=0; i<nb; i++) {
WriteMacInt8(addr + i, (r[reg] >> 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<nb; i++) {
WriteMacInt8(addr + i, (r[reg] >> 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();
}