home *** CD-ROM | disk | FTP | other *** search
- #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;
- }
-