1662 lines
32 KiB
C++
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();
|
|
}
|