home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
PROGRAM
/
DJEMU106.ZIP
/
EMU387
/
EMU.CC
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-08
|
10KB
|
370 lines
#include <stdio.h>
#include <stdlib.h>
#include "emu.h"
#include "const.h"
int modrm;
#if 0
char saw[256*8];
/* zero here means invalid. If first entry starts with '*', use st(i) */
/* no assumed %EFs here. Indexed by rm(modrm()) */
char *f0[] = {0, 0, 0, 0, 0, 0, 0, 0};
char *fop_9[] = { "*fxch st,%GF" };
char *fop_10[] = { "fnop", 0, 0, 0, 0, 0, 0, 0 };
char *fop_12[] = { "fchs", "fabs", 0, 0, "ftst", "fxam", 0, 0 };
char *fop_13[] = { "fld1", "fldl2t", "fldl2e", "fldpi",
"fldlg2", "fldln2", "fldz", 0 };
char *fop_14[] = { "f2xm1", "fyl2x", "fptan", "fpatan",
"fxtract", "fprem1", "fdecstp", "fincstp" };
char *fop_15[] = { "fprem", "fyl2xp1", "fsqrt", "fsincos",
"frndint", "fscale", "fsin", "fcos" };
char *fop_21[] = { 0, "fucompp", 0, 0, 0, 0, 0, 0 };
char *fop_28[] = { 0, 0, "fclex", "finit", 0, 0, 0, 0 };
char *fop_32[] = { "*fadd %GF,st" };
char *fop_33[] = { "*fmul %GF,st" };
char *fop_36[] = { "*fsubr %GF,st" };
char *fop_37[] = { "*fsub %GF,st" };
char *fop_38[] = { "*fdivr %GF,st" };
char *fop_39[] = { "*fdiv %GF,st" };
char *fop_40[] = { "*ffree %GF" };
char *fop_42[] = { "*fst %GF" };
char *fop_43[] = { "*fstp %GF" };
char *fop_44[] = { "*fucom %GF" };
char *fop_45[] = { "*fucomp %GF" };
char *fop_48[] = { "*faddp %GF,st" };
char *fop_49[] = { "*fmulp %GF,st" };
char *fop_51[] = { 0, "fcompp", 0, 0, 0, 0, 0, 0 };
char *fop_52[] = { "*fsubrp %GF,st" };
char *fop_53[] = { "*fsubp %GF,st" };
char *fop_54[] = { "*fdivrp %GF,st" };
char *fop_55[] = { "*fdivp %GF,st" };
char *fop_60[] = { "fstsw ax", 0, 0, 0, 0, 0, 0, 0 };
char **fspecial[] = { /* 0=use st(i), 1=undefined 0 in fop_* means undefined */
0, 0, 0, 0, 0, 0, 0, 0,
0, fop_9, fop_10, 0, fop_12, fop_13, fop_14, fop_15,
f0, f0, f0, f0, f0, fop_21, f0, f0,
f0, f0, f0, f0, fop_28, f0, f0, f0,
fop_32, fop_33, f0, f0, fop_36, fop_37, fop_38, fop_39,
fop_40, f0, fop_42, fop_43, fop_44, fop_45, f0, f0,
fop_48, fop_49, f0, fop_51, fop_52, fop_53, fop_54, fop_55,
f0, f0, f0, f0, fop_60, f0, f0, f0,
};
char *floatops[] = { /* assumed " %EF" at end of each. mod != 3 only */
/*00*/ "fadd", "fmul", "fcom", "fcomp",
"fsub", "fsubr", "fdiv", "fdivr",
/*08*/ "fld", 0, "fst", "fstp",
"fldenv", "fldcw", "fstenv", "fstcw",
/*16*/ "fiadd", "fimul", "ficomw", "ficompw",
"fisub", "fisubr", "fidiv", "fidivr",
/*24*/ "fild", 0, "fist", "fistp",
"frstor", "fldt", 0, "fstpt",
/*32*/ "faddq", "fmulq", "fcomq", "fcompq",
"fsubq", "fsubrq", "fdivq", "fdivrq",
/*40*/ "fldq", 0, "fstq", "fstpq",
0, 0, "fsave", "fstsww",
/*48*/ "fiaddw", "fimulw", "ficomw", "ficompw",
"fisubw", "fisubrw", "fidivw", "fidivr",
/*56*/ "fildw", 0, "fistw", "fistpw",
"fbldt", "fildq", "fbstpt", "fistpq"
};
#endif
int status_word = 0;
int control_word = 0x77e;
reg regs[8] = {
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
{ SIGN_POS, TW_E, 0, 0x0, 0x0 },
};
int top = 0;
FUNC esc_table[64] = {
emu_00, emu_10, emu_20, emu_30, emu_40, emu_50, emu_60, emu_70,
emu_01, emu_11, emu_21, emu_31, emu_41, emu_51, emu_61, emu_71,
emu_02, emu_12, emu_22, emu_32, emu_42, emu_52, emu_62, emu_72,
emu_03, emu_13, emu_23, emu_33, emu_43, emu_53, emu_63, emu_73,
emu_04, emu_14, emu_24, emu_34, emu_44, emu_54, emu_64, emu_74,
emu_05, emu_15, emu_25, emu_35, emu_45, emu_55, emu_65, emu_75,
emu_06, emu_16, emu_26, emu_36, emu_46, emu_56, emu_66, emu_76,
emu_07, emu_17, emu_27, emu_37, emu_47, emu_57, emu_67, emu_77,
};
int emu_initted = 0;
void emu_entry()
{
if (emu_initted != 0x12345678)
{
emu_initted = 0x12345678;
// eprintf(
// "Installing the 80387 Emulator. Copyright (C) 1991 DJ Delorie.\n"
// "WARNING: This is a TEST version of this emulator. If it doesn't work,\n"
// "then don't use it. Not all of the opcodes are implemented, and the\n"
// "ones that are may not work right in extreme cases. Use at your own risk.\n"
// );
}
// eprintf("eax=0x%08x ebx=0x%08x ecx=0x%08x edx=0x%08x\n", eax, ebx, ecx, edx);
// eprintf("esi=0x%08x edi=0x%08x ebp=0x%08x eip=0x%08x\n", esi, edi, ebp, eip);
if (*eip == 0x66) // operand size - we know what size we need
eip++;
if (*eip == 0x9b) // fwait
return;
#if 0
int see = ((int)(eip[0] & 7) << 8) | eip[1];
if (saw[see] != 42)
{
eprintf("EMU387: %02x %02x %02x %02x - e%d%d", eip[0], eip[1], eip[2], eip[3], eip[0]&7, (eip[1]>>3)&7);
eprintf(" s%d ", eip[1]&7);
int esc = ((eip[0]<<3)&070) | ((eip[1]>>3)&007);
int modrm = eip[1];
if ((modrm>>6) == 3)
if (fspecial[esc])
if (fspecial[esc][0] && (fspecial[esc][0][0] == '*'))
eprintf("%s\n", fspecial[esc][0]+1);
else if (fspecial[esc][modrm&7])
eprintf("%s\n", fspecial[esc][modrm&7]);
else
eprintf("<invalid>\n");
else
eprintf("%s st(i)\n", floatops[esc]);
else
eprintf("%s st(i)\n", floatops[esc]);
saw[see] = 42;
}
#endif
int esc_value = *eip++ & 7;
modrm = *eip++;
esc_value |= (modrm & 070);
(esc_table[esc_value])();
// emu_printall();
}
void emu_bad()
{
eprintf("Unimplemented 80387 Opcode at eip=0x%08x : %02x", eip-2, eip[-2]);
if (eip[-1] > 0277)
eprintf(" %02x", eip[-1]);
else
eprintf(" /%d", (eip[-1]>>3)&7);
eprintf(" - e%d%d", eip[-2]&7, (eip[-1]>>3)&7);
if (eip[-1] > 0277)
eprintf(" s%d", eip[-1]&7);
eprintf("\n");
exception(EX_I);
}
void emu_printall()
{
static char *tag_desc[] = { "Valid", "Zero", "Special", "Empty" };
status_word = status_word & ~SW_TOP;
status_word += (top&7) * SW_TOPS;
eprintf(" SW: 0x%04x top=%d cc=%d%d%d%d ", status_word, top&7,
status_word & SW_C3?1:0, status_word & SW_C2?1:0,
status_word & SW_C1?1:0, status_word & SW_C0?1:0);
eprintf("CW: 0x%04x\n", control_word);
for (int i=0; i<8; i++)
{
reg *r = &st(i);
switch (r->tag)
{
case TW_E:
continue;
eprintf("st(%d) ", i);
break;
case TW_Z:
eprintf("st(%d) %c .0000 0000 0000 0000 ",
i, r->sign ? '-' : '+');
break;
case TW_S:
case TW_V:
eprintf("st(%d) %c .%04x %04x %04x %04x e%+-6d ", i,
r->sign ? '-' : '+',
(long)(r->sigh >> 16),
(long)(r->sigh & 0xFFFF),
(long)(r->sigl >> 16),
(long)(r->sigl & 0xFFFF),
r->exp - EXP_BIAS + 1);
}
eprintf("%s\n", tag_desc[r->tag]);
}
fflush(stderr);
}
static struct {
int type;
char *name;
} ex_names[] = {
EX_SO, "stack overflow",
EX_SU, "stack underflow",
EX_P, "loss of precision",
EX_U, "underflow",
EX_O, "overflow",
EX_Z, "divide by zero",
EX_D, "denormalized operand",
EX_I, "invalid operation",
0,0
};
void exception(int n)
{
int i;
status_word |= n;
if (n == EX_SU)
status_word &= ~SW_C1;
for (i=0; ex_names[i].type; i++)
if (ex_names[i].type == n)
break;
if (ex_names[i].type)
eprintf("80387 Exception: %s!\n", ex_names[i].name);
else
eprintf("80387 Exception: 0x%04x!\n", n);
if (~control_word & n & CW_EXM)
{
emu_printall();
asm("movl $0x4cff,%eax");
asm("int $0x21");
}
}
void setcc(int cc)
{
status_word &= ~(SW_C0|SW_C1|SW_C2|SW_C3);
status_word |= cc & (SW_C0|SW_C1|SW_C2|SW_C3);
}
int full()
{
if (st(7).tag != TW_E)
{
exception(EX_SO);
top--;
r_mov(CONST_NAN, st(0));
return 1;
}
return 0;
}
int empty(int i)
{
if (st(i).tag == TW_E)
{
exception(EX_SU);
return 1;
}
return 0;
}
static int sregval(int reg, int mod)
{
switch (reg)
{
case 0: return eax;
case 1: return ecx;
case 2: return edx;
case 3: return ebx;
case 4: return (mod==-1) ? 0 : esp;
case 5: return mod ? ebp : 0; // data
case 6: return esi;
case 7: return edi;
}
}
static int scale[] = { 1, 2, 4, 8 };
static int getsib()
{
int mod = modrm >> 6;
int sib = *eip++;
int ss = sib>>6;
int index = (sib>>3) & 7;
int base = sib & 7;
int rv = sregval(base, mod) + sregval(index, -1) * scale[ss];
int rv2;
switch (mod)
{
case 1:
rv2 = *(signed char *)eip++;
rv += rv2;
break;
case 0:
if (base != 5)
break;
case 2:
((unsigned char *)&rv2)[0] = *eip++;
((unsigned char *)&rv2)[1] = *eip++;
((unsigned char *)&rv2)[2] = *eip++;
((unsigned char *)&rv2)[3] = *eip++;
rv += rv2;
break;
}
return rv;
}
static int regval(int reg, int mod)
{
switch (reg)
{
case 0: return eax;
case 1: return ecx;
case 2: return edx;
case 3: return ebx;
case 4: return getsib();
case 5: return mod ? ebp : 0; // data
case 6: return esi;
case 7: return edi;
}
}
void *get_modrm()
{
int mod = modrm>>6;
int rm = modrm & 7;
int rv;
switch (mod)
{
case 0:
if (rm == 5)
{
((unsigned char *)&rv)[0] = *eip++;
((unsigned char *)&rv)[1] = *eip++;
((unsigned char *)&rv)[2] = *eip++;
((unsigned char *)&rv)[3] = *eip++;
}
else
rv = regval(rm, mod);
break;
case 1:
if (rm != 4)
rv = (*(signed char *)eip++) + regval(rm, mod);
else
rv = regval(rm, mod);
break;
case 2:
if (rm != 4)
{
((unsigned char *)&rv)[0] = *eip++;
((unsigned char *)&rv)[1] = *eip++;
((unsigned char *)&rv)[2] = *eip++;
((unsigned char *)&rv)[3] = *eip++;
rv += regval(rm, mod);
}
else
rv = regval(rm, mod);
break;
case 3:
eprintf("Attempt to get address from mod = 3\n");
exit(1);
}
// eprintf("modrm returning 0x%x\n", rv);
return (void *)rv;
}