2002-02-04 16:58:13 +00:00
|
|
|
/*
|
|
|
|
* emul_ppc.cpp - PowerPC processor emulation
|
|
|
|
*
|
2008-01-01 09:47:39 +00:00
|
|
|
* SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig
|
2002-02-04 16:58:13 +00:00
|
|
|
*
|
|
|
|
* 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
|
2017-12-02 17:21:13 +00:00
|
|
|
const char *arg[4] = {"mon", "-m", "-r", NULL};
|
2002-02-04 16:58:13 +00:00
|
|
|
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;
|
|
|
|
|
[Michael Schmitt]
Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts.
Problem
-------
Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists".
SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000.
The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas.
On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails.
Solution
--------
The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address.
This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously.
Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase.
A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area.
Impact
------
The change to make ROMBase a variable is throughout all hosts & addressing modes.
The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before.
This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0.
Changes to main_unix.cpp
------------------------
1. Real addressing mode no longer defines a RAM_BASE constant.
2. The base address of the Mac ROM (ROMBase) is defined and exported by this program.
3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address.
4. Changed and rearranged the allocation of RAM and ROM areas.
Before it worked like this:
- Allocate ROM area
- If can, attempt to allocate RAM at address zero
- If RAM not allocated at 0, allocate at fixed address
We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is:
- If can, attempt to allocate RAM at address zero
- If RAM not allocated at 0
if REAL addressing
allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary
else (direct addressing)
allocate RAM at fixed address
- If ROM hasn't been allocated yet, allocate at fixed address
5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded.
6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address.
7. Change subsequent code from using constant ROM_BASE to variable ROMBase.
Changes to Other Programs
-------------------------
emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp:
Change from constant ROM_BASE to variable ROMBase.
ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000.
ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations.
main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code.
cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE.
user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
|
|
|
r[3] = ROMBase + 0x30d000;
|
2002-02-04 16:58:13 +00:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|