/*    
	Intp.c	2.3
    	Copyright 1997 Willows Software, Inc. 

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library 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
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.


For more information about the Willows Twin Libraries.

	http://www.willows.com	

To send email to the maintainer of the Willows Twin Libraries.

	mailto:twin@willows.com 

 */
#include <stdio.h>
#include <math.h>
#define     FP87    1
#include "windows.h"
#include "Endian.h"
#include "Types.h"
#include "Intp.h"
#include "Log.h"
#include "DPMI.h"

extern DSCR *LDT;
extern WORD Sel86Flags[];

extern BOOL LoadSegment(UINT);

#if DEBUG
#include <string.h>
char * decode(int opcode, int modrm);
extern char *getenv();
int print = 0;
int small_print = 0;
int segment_print = 0;
int stack_print = 0;
long start_count= -1;
long end_count= -1;
int granularity = 1;
int instr_count = 0;
int print_initialized = 0;
int dbx_cs = 0;
int dbx_ip = 0;
int dbx_stop_count = 0;
void dbx_stop() {
	dbx_stop_count++;
}
#endif

char unknown_msg[] = "unknown opcode [%s] %02x at %04x:%04x\n";
char illegal_msg[] = "illegal opcode [%s] %02x at %04x:%04x\n";
char unsupp_msg[]  = "unsupported opcode [%s] %02x at %04x:%04x\n";

BYTE parity[256] = 
    {PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    PARITY_FLAG, 0, 0, PARITY_FLAG, 0, PARITY_FLAG, PARITY_FLAG, 0,
    0, PARITY_FLAG, PARITY_FLAG, 0, PARITY_FLAG, 0, 0, PARITY_FLAG};

int regs_map[8] = { RAL,rCL,RDL,RBL,RAH,RCH,RDH,RBH};

extern ENV *envp_global;
#include "Segment.h"

void
invoke_data (ENV *envp)
{
    char buf[0x100];

    sprintf(buf,"ERROR: data selector in CS\n cs:ip %x/%x\ncalled from %x:%x",
		HIWORD(envp->trans_addr),LOWORD(envp->trans_addr),
		HIWORD(envp->return_addr),LOWORD(envp->return_addr));
    FatalAppExit(0,buf);
}

#ifdef DEBUG
static WORD debug_opcode = 0;
static WORD debug_ip = 0;
static WORD debug_cs = 0;
static WORD global_debug = 0;
static DWORD instruction_count = 0;
#endif

#ifdef FP87 /* 80x87 emulation stuff by Jerzy */

#define STORE32INT(addr,i32) ( (addr)[0] = (i32), (addr)[1] = (i32)>>8,  \
                               (addr)[2] = (i32)>>16, (addr)[3] = (i32)>>24 )
#define STORE16INT(addr,i16) ( (addr)[0] = (i16), (addr)[1] = (i16)>>8 )
#define GET32INT(addr) ((int) ( ((addr)[3]<<24) | ((addr)[2]<<16) |  \
								   ((addr)[1]<<8) | (addr)[0]) )
#define GET16INT(addr) ((short) (((addr)[1]<<8) | (addr)[0]))

/* the following are given here in Big Endian (target) version only */
#define GET64REAL(dtmp,addr) (  \
		   ((char*)&dtmp)[7] = (addr)[0], ((char*)&dtmp)[6] = (addr)[1], \
		   ((char*)&dtmp)[5] = (addr)[2], ((char*)&dtmp)[4] = (addr)[3], \
		   ((char*)&dtmp)[3] = (addr)[4], ((char*)&dtmp)[2] = (addr)[5], \
		   ((char*)&dtmp)[1] = (addr)[6], ((char*)&dtmp)[0] = (addr)[7], \
		   dtmp )
#define STORE64REAL(addr,dtmp) (  \
		   (addr)[0] = ((char*)&dtmp)[7], (addr)[1] = ((char*)&dtmp)[6], \
		   (addr)[2] = ((char*)&dtmp)[5], (addr)[3] = ((char*)&dtmp)[4], \
		   (addr)[4] = ((char*)&dtmp)[3], (addr)[5] = ((char*)&dtmp)[2], \
		   (addr)[6] = ((char*)&dtmp)[1], (addr)[7] = ((char*)&dtmp)[0]  )
#define GET32REAL(ftmp,addr) (  \
		   ((char*)&ftmp)[3] = (addr)[0], ((char*)&ftmp)[2] = (addr)[1], \
		   ((char*)&ftmp)[1] = (addr)[2], ((char*)&ftmp)[0] = (addr)[3], \
		   ftmp )
#define STORE32REAL(addr,ftmp) (  \
		   (addr)[0] = ((char*)&ftmp)[3], (addr)[1] = ((char*)&ftmp)[2], \
		   (addr)[2] = ((char*)&ftmp)[1], (addr)[3] = ((char*)&ftmp)[0] )
#define EXPONENT(addr) ( ( (((char*)addr)[0] & 0x7f) << 4 ) |  \
						 ( (((char*)addr)[1] & 0xf0) >> 4 )     )
#define BIASEXPONENT(addr) ( ((char*)addr)[0] &= (~0x40),  \
                             ((char*)addr)[0] |= 0x3f,  \
                             ((char*)addr)[1] |= 0xf0 )
#define LD80R(fpreg,r80)  {  \
		i16 = (*(r80+9)<<8) | *(r80+8);  expdif = (i16&0x7fff) - 16383;     \
        if ( expdif > 1023 || expdif < -1022 )                              \
            fprintf(stderr, "This EXT REAL exceeds range of DOUBLE REAL!\n"); \
        expdif += 1023 /*add DOUBLE bias*/;   expdif <<= 4;    \
        if ( i16 & 0x8000 )  expdif |= 0x8000;                 \
        *((char*)fpreg)     = expdif >> 8;         /* <-- Se4..e10 */   \
        *(((char*)fpreg)+1) = expdif&0xf0;         /*  <-- e0..e3 */    \
        *(((char*)fpreg)+1) |= (*(r80+7)<<1) >> 3; /*  <-- m59..m62 */  \
        *(((char*)fpreg)+2)  = (*(r80+7) << 5);    /*  <-- m56..m58 */  \
        *(((char*)fpreg)+2) |= (*(r80+6) >> 3);    /*  <-- m51..m55 */  \
        *(((char*)fpreg)+3)  = (*(r80+6) << 5);    /*  <-- m48..m50 */  \
        *(((char*)fpreg)+3) |= (*(r80+5) >> 3);    /*  <-- m43..m47 */  \
        *(((char*)fpreg)+4)  = (*(r80+5) << 5);    /*  <-- m40..m42 */  \
        *(((char*)fpreg)+4) |= (*(r80+4) >> 3);    /*  <-- m35..m39 */  \
        *(((char*)fpreg)+5)  = (*(r80+4) << 5);    /*  <-- m32..m34 */  \
        *(((char*)fpreg)+5) |= (*(r80+3) >> 3);    /*  <-- m27..m31 */  \
        *(((char*)fpreg)+6)  = (*(r80+3) << 5);    /*  <-- m24..m26 */  \
        *(((char*)fpreg)+6) |= (*(r80+2) >> 3);    /*  <-- m19..m23 */  \
        *(((char*)fpreg)+7)  = (*(r80+2) << 5);    /*  <-- m16..m18 */  \
        *(((char*)fpreg)+7) |= (*(r80+1) >> 3);    /*  <-- m11..m15 */  \
        }
#define ST80R(r80,fpreg)  {  \
        i16 = *((unsigned short *)fpreg);  \
        expdif = ((i16&0x7fff) >> 4) - 1023;  /* get un-biased exponent */  \
        expdif += 16383;  /* add EXT real bias */ \
        if ( i16 & 0x8000 )  expdif |= 0x8000;    \
        *(r80+9) = expdif >> 8;                   \
        *(r80+8) = expdif;                        \
        *(r80+7) = ((i16&0xf)|0x10) << 3;         \
        *(r80+7) |= *(((char*)fpreg)+2) >> 5;     \
        *(r80+6)  = *(((char*)fpreg)+2) << 3;     \
        *(r80+6) |= *(((char*)fpreg)+3) >> 5;     \
        *(r80+5)  = *(((char*)fpreg)+3) << 3;     \
        *(r80+5) |= *(((char*)fpreg)+4) >> 5;     \
        *(r80+4)  = *(((char*)fpreg)+4) << 3;     \
        *(r80+4) |= *(((char*)fpreg)+5) >> 5;     \
        *(r80+3)  = *(((char*)fpreg)+5) << 3;     \
        *(r80+3) |= *(((char*)fpreg)+6) >> 5;     \
        *(r80+2)  = *(((char*)fpreg)+6) << 3;     \
        *(r80+2) |= *(((char*)fpreg)+7) >> 5;     \
        *(r80+1)  = *(((char*)fpreg)+7) << 3;     \
        *(r80)   = 0x0;                           \
		}
#define MUL10(iv) ( (expdif = iv + iv), (iv = iv << 3), expdif + iv )
				 /* This macro reuses Interpreter local expdif as temporary */
extern double  floor(), ceil(), fabs(), fmod(),
			   pow(), sqrt(), exp(), log(), log10(),
               sin(), cos(), tan(), atan2();
#endif

static WORD repeat = 0;

void
invoke_code16(ENV *env)
{
#ifdef FP87 /* 80x87 emulation stuff by Jerzy */
	double fpregs[8], fptemp, fpsrcop;  float m32r;
	unsigned int i64lo, i64hi;  int m32i, expdif;  short i16;
	int fpstt = 0; /* no init. will be done after adding to ENV!!! */
	WORD fpus = 0;  /* C0-2 [in b8..b10],  C3 [in b14] */
	WORD fpuc = 0x37f;  /* Rounding Control (RC) in b10..b11 */
#endif
    union _REGS r;
    register WORD flags;
    register unsigned char *cs;
    register unsigned char *IP;
    register WORD ip=LOWORD(env->trans_addr);
    register int count;
    LPBYTE ds;
    LPBYTE es;
    LPBYTE ss;
    LPBYTE override=0;
    LPBYTE seg=0;
    WORD opcode, modrm;
    DWORD temp=0, sys_ret;
    LONG  signed_temp;
    WORD  transfer_magic;
    WORD disp, offset=0;
    BYTE mod, reg, rm;
    WORD level, op1=0, op2=0;
    BYTE op_1, op_2;
    BOOL allow_override = TRUE;
    BOOL override_flag = FALSE;
    BOOL dir_flag, int_flag, lt_flag=FALSE;
    BOOL prefix;
    BOOL first=FALSE;
    WORD carry, zero, overflow;
    WORD _cs,_es,_ds,_ss,_ip=0,_sel=0;
    char x;
    LONGPROC conv,targ;
#ifdef FP87 /* 80x87 emulation stuff by Jerzy */
	double DPLOG10_2 = log10(2.0), DPLOGE_2 = log(2.0), DPPI = 3.141592654,
	       DPLOG2_E = 1.0/log(2.0), DPLOG2_10 = log(10.0)/log(2.0);
#endif
    _cs = HIWORD(env->trans_addr);
    SET_SEGREG(cs,_cs);
    _es = env->reg.es;
    SET_SEGREG(es,_es);
    _ss = env->reg.ss;
    SET_SEGREG(ss,_ss);
    _ds = env->reg.ds;
    SET_SEGREG(ds,_ds);
    AX = (WORD)env->reg.ax;
    BX = (WORD)env->reg.bx;
    CX = (WORD)env->reg.cx;
    DX = (WORD)env->reg.dx;
    SP = (WORD)(env->reg.sp - (DWORD)ss);
    BP = (WORD)(env->reg.bp - (DWORD)ss);
    SI = (WORD)env->reg.si;
    DI = (WORD)env->reg.di;
    flags = (WORD)env->reg.flags;
    IP = (LPBYTE)(cs + LOWORD(env->trans_addr));

    dir_flag = IS_DF_SET;
    int_flag = IS_IF_SET;

    while (1) {
   	prefix = FALSE;
	opcode = *IP;
#ifdef DEBUG
	if (ip == debug_ip && _cs == debug_cs)
	{
	    count = 0;
	}
	instruction_count++;

	if (!print_initialized) {
		char *ch;

		print_initialized = 1;
		if ( ch = getenv("HSW_START")) {
			if(strstr(ch,"0x") == ch)
				sscanf(ch+2, "%x", &start_count);
			else
				sscanf(ch, "%d", &start_count);
			printf("Starting instruction for print is: %d\n", start_count);
		}
		if ( ch = getenv("HSW_END")) {
			if(strstr(ch,"0x") == ch)
				sscanf(ch+2, "%x", &end_count);
			else
				sscanf(ch, "%d", &end_count);
			printf("  Ending instruction for print is: %d\n", end_count);
		}
		if ( ch = getenv("HSW_GRAN")) {
			if(strstr(ch,"0x") == ch)
				sscanf(ch+2, "%x", &granularity);
			else
				sscanf(ch, "%d", &granularity);
			printf("   Granularity for print is: %d\n", granularity);
		}
		if ( ch = getenv("HSW_SEGMENT_PRINT")) {
			segment_print = 1;
		}
		if ( ch = getenv("HSW_STACK_PRINT")) {
			stack_print = 1;
		}
		if ( ch = getenv("HSW_SHORT_PRINT")) {
			small_print = 1;
		}
		if ( ch = getenv("HSW_DBX_CS")) {
			if(strstr(ch,"0x") == ch)
				sscanf(ch+2, "%x", &dbx_cs);
			else
				sscanf(ch, "%d", &dbx_cs);
			dbx_cs = dbx_cs & 0xffff;
			printf("dbx_stop CS value is: %04x\n", dbx_cs);
		}
		if ( ch = getenv("HSW_DBX_IP")) {
			if(strstr(ch,"0x") == ch)
				sscanf(ch+2, "%x", &dbx_ip);
			else
				sscanf(ch, "%d", &dbx_ip);
			dbx_ip = dbx_ip & 0xffff;
			printf("dbx_stop IP value is: %04x\n", dbx_ip);
		}
	}
	if((instr_count++)==start_count)print=1;
	if(instr_count==end_count)print=0;
	if (dbx_cs)
		if ((dbx_cs == _cs) && (dbx_ip == ip)) dbx_stop();
	if(print && (!(instr_count % granularity))){
		if(small_print)
			printf("%d %04x:%04x %02x %02x\n",
				instr_count, _cs,IP-cs, *IP, *(IP+1));
		else if (segment_print)
			printf("%04x:%04x DS:%04x ES:%04x FS:%04x GS:%04x SS:%04x %d\n",
				_cs, IP-cs, _ds, _es, 0, 0, _ss, instr_count);
		else if (stack_print) {
			unsigned char *sp = ss + SP;
			printf("%04x:%04x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %d\n",
				_cs, IP-cs,*(sp+1),*sp,*(sp+3),*(sp+2),*(sp+5),
				*(sp+4),*(sp+7),*(sp+6),*(sp+9),*(sp+8),*(sp+11),*(sp+10),
				*(sp+13),*(sp+12), *(sp+15),*(sp+14),instr_count);
		} else
			printf("%04x:%04x %02x %02x %04x %04x %04x %04x %04x %04x %04x %04x %s %d\n",
				_cs,IP-cs, *IP, *(IP+1),AX ,BX,CX,DX,SI,
				DI,BP,SP,decode(opcode, *(IP+1)), instr_count);
		fflush(stdout);
	}
#endif
	switch (opcode) { 		    /* Single-byte instructions */

	case ADDbia:
	    temp = AL + *(++IP);
	    AL = LOBYTE(temp);
	    flags = SIGNb | CARRYb | ZEROb | OVFLOWb(AL) | AUXCARRY | PARITY;
	    break;
	case ADDwia:
	    temp = AX + GETWORD(IP+1);
	    IP += 2;
	    AX = LOWORD(temp);
	    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(AX) | AUXCARRY | PARITY;
	    break;
	case PUSHes:
	    PUSHWORD(_es);
	    break;
	case POPes:
	    _es = GETWORD(&ss[SP]);
	    SET_SEGREG(es,_es);
	    SP += 2;
	    break;
	case ORbi:
	    temp = AL | *(++IP);
	    AL = LOBYTE(temp);
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case ORwi:
	    temp = AX | GETWORD(IP+1);
	    AX = LOWORD(temp);
	    IP += 2;
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case PUSHcs:
	    PUSHWORD(_cs);
	    break;
	case TWO_BYTE_ESC:
	    opcode = *(++IP)|0xf00;
	    goto label_rm_opcode;
	case ADCbi:
	    temp = AL + (flags & CARRY_FLAG) + *(++IP);
	    AL = LOBYTE(temp);
	    flags = SIGNb | CARRYb | ZEROb | OVFLOWb(AL) | AUXCARRY | PARITY;
	    break;
	case ADCwi:
	    temp = AX + (flags & CARRY_FLAG) + GETWORD(IP+1);
	    AX = LOWORD(temp);
	    IP += 2;
	    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(AX) | AUXCARRY | PARITY;
	    break;
	case PUSHss:
	    PUSHWORD(_ss);
	    break;
	case POPss:
	    _ss = GETWORD(&ss[SP]);
	    SET_SEGREG(ss,_ss);
	    SP += 2;
	    break;
	case SBBbi:
	    temp = AL - (*(++IP) + (IS_CF_SET));
	    AL = LOBYTE(temp);
	    lt_flag = ((SIGNED char)AL < ((SIGNED char)(*IP) + (IS_CF_SET)));
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
	    if (!lt_flag && IS_SF_SET)
		flags |= OVERFLOW_FLAG;
	    break;
	case SBBwi:
	    op2 = GETWORD(IP+1) + (IS_CF_SET);
	    temp = AX - op2;
	    IP += 2;
	    AX = LOWORD(temp);
	    lt_flag = ((short)AX < (short)op2);
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
	    if (!lt_flag && IS_SF_SET)
		flags |= OVERFLOW_FLAG;
	    break;
	case PUSHds:
	    PUSHWORD(_ds);
	    break;
	case POPds:
	    _ds = GETWORD(&ss[SP]);
	    SET_SEGREG(ds,_ds);
	    SP += 2;
	    break;
	case ANDbi:
	    temp = AL & (*(++IP));
	    AL = LOBYTE(temp);
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case ANDwi:
	    temp = AX & GETWORD(IP+1);
	    AX = LOWORD(temp);
	    IP += 2;
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case SEGes:
	    override = es;
	    override_flag = TRUE;
	    prefix = TRUE;
	    break;
	case DAA:
	    if (((WORD)( AL & 0x0f ) > 9 ) || (IS_AF_SET)) {
		AL += 6;
		SET_AF;
	    } else 
		CLEAR_AF;
	    if ((AL > 0x9f) || (IS_CF_SET)) {
		AL += 0x60;
		SET_CF;
	    } else {
		CLEAR_CF;
	    }
	    break;
	case SUBbi:
	    temp = AL - (*(++IP));
	    AL = LOBYTE(temp);
	    lt_flag = ((SIGNED char)AL < (SIGNED char)(*IP));
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
	    if (!lt_flag && IS_SF_SET)
		flags |= OVERFLOW_FLAG;
	    break;
	case SUBwi:
	    op2 = GETWORD(IP+1);
	    temp = AX - op2;
	    IP += 2;
	    AX = LOWORD(temp);
	    lt_flag = ((short)AX < (short)op2);
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
	    if (!lt_flag && IS_SF_SET)
		flags |= OVERFLOW_FLAG;
	    break;
	case SEGcs:
	    override = cs;
	    override_flag = TRUE;
	    prefix = TRUE;
	    break;
	case DAS:
	    if (((WORD)( AX & 0x0f ) > 9 ) || (IS_AF_SET)) {
		AL -= 6;
		SET_AF;
	    } else {
		CLEAR_AF;
	    }
	    if ((AL > 0x9f) || (IS_CF_SET)) {
		AL -= 0x60;
		SET_CF;
	    } else {
		CLEAR_CF;
	    }
	    break;
	case XORbi:
	    temp = AL ^ (*(++IP));
	    AL = LOBYTE(temp);
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case XORwi:
	    temp = AX ^ GETWORD(IP+1);
	    AX = LOWORD(temp);
	    IP += 2;
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case SEGss:
	    override = ss;
	    override_flag = TRUE;
	    prefix = TRUE;
	    break;
	case AAA:
	    if (((WORD)( AX & 0x0f ) > 9 ) || (IS_AF_SET)) {
		AL += 6;
		AH += 1; 
		SET_CF_AF;
	    } 
	    else
		CLEAR_CF_AF;
	    AL &= 0x0f;
	    break;
	case CMPbi:
	    temp = AL - (*(++IP));
	    lt_flag = ((SIGNED char)AL < (SIGNED char)(*IP));
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
	    if (!lt_flag && IS_SF_SET)
		flags |= OVERFLOW_FLAG;
	    break;
	case CMPwi:
	    op2 = GETWORD(IP+1);
	    temp = AX - op2;
	    lt_flag = ((short)AX < (short)op2);
	    IP += 2;
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
	    if (!lt_flag && IS_SF_SET)
		flags |= OVERFLOW_FLAG;
	    break;
	case SEGds:
	    override = ds;
	    override_flag = TRUE;
	    prefix = TRUE;
	    break;
	case AAS:
	    if (((WORD)( AX & 0x0f ) > 9 ) || (IS_AF_SET)) {
		AL -= 6;
		AH -= 1;
		SET_CF_AF;
	    } 
	    else
		CLEAR_CF_AF;
	    AL &= 0x0f;
	    break;
	case INCax:
	case INCcx:
	case INCdx:
	case INCbx:
	case INCsp:
	case INCbp:
	case INCsi:
	case INCdi:
	    reg = RM(opcode);
	    temp = REGW(reg);
	    temp++;
	    flags = SIGNw | ZEROw | OVFLOWw(REGW(reg)) | AUXCARRY | PARITY | IS_CF_SET;
	    REGW(reg) = LOWORD(temp);
	    break;
	case DECax:
	case DECcx:
	case DECdx:
	case DECbx:
	case DECsp:
	case DECbp:
	case DECsi:
	case DECdi:
	    reg = RM(opcode);
	    temp = REGW(reg);
	    temp--;
	    flags = SIGNw | ZEROw | OVFLOWw(REGW(reg)) | AUXCARRY | PARITY | IS_CF_SET;
	    REGW(reg) = LOWORD(temp);
	    break;
	case PUSHax:
	case PUSHcx:
	case PUSHdx:
	case PUSHbx:
	case PUSHsp:
	case PUSHbp:
	case PUSHsi:
	case PUSHdi:
	    reg = RM(opcode);
	    PUSHWORD(REGW(reg));
	    break;
	case POPax:
	case POPcx:
	case POPdx:
	case POPbx:
	case POPsp:
	case POPbp:
	case POPsi:
	case POPdi:
	    reg = RM(opcode);
	    POPWORD(REGW(reg));
	    break;
	case PUSHA:
	    op2 = SP;
	    PUSHWORD(AX);
	    PUSHWORD(CX);
	    PUSHWORD(DX);
	    PUSHWORD(BX);
	    PUSHWORD(op2);
	    PUSHWORD(BP);
	    PUSHWORD(SI);
	    PUSHWORD(DI);
	    break;
	case POPA:
	    POPWORD(DI);
	    POPWORD(SI);
	    POPWORD(BP);
	    SP += 2;
	    POPWORD(BX);
	    POPWORD(DX);
	    POPWORD(CX);
	    POPWORD(AX);
	    break;
	case 0x62:    /* illegal on 8086 */
	case 0x63:    /* illegal on 8086 */
	case 0x64:    /* illegal on 8086 */
	case 0x65:    /* illegal on 8086 */
	case 0x66:    /* illegal on 8086 */
	case 0x67:    /* illegal on 8086 */
	    fprintf(stderr,illegal_msg,"illegal on 8086",
		opcode,_cs, IP-cs);
	    break;    
	case PUSHwi:
	    ss[--SP] = *(IP+2);
	    ss[--SP] = *(IP+1);
	    IP += 2;
	    break;
	case PUSHbi:
	    ss[--SP] =((*(++IP)) & 0x80) ? 0xff : 0;
	    ss[--SP] = *IP;
	    break;
	case 0x6c:    /* illegal on 8086 */
	case 0x6d:    /* illegal on 8086 */
	case 0x6e:    /* illegal on 8086 */
	case 0x6f:    /* illegal on 8086 */
	    fprintf(stderr,illegal_msg,"illegal on 8086",
		opcode,_cs, IP-cs);
	    break;    
	case JO:
	    IP++;
	    if (IS_OF_SET) JUMP(IP);
	    break;
	case JNO:
	    IP++;
	    if (!IS_OF_SET) JUMP(IP);
	    break;
	case JB_JNAE:
	    IP++;
	    if (IS_CF_SET) JUMP(IP);
	    break;
	case JNB_JAE:
	    IP++;
	    if (!IS_CF_SET) JUMP(IP);
	    break;
	case JE_JZ:
	    IP++;
	    if (IS_ZF_SET) JUMP(IP);
	    break;
	case JNE_JNZ:
	    IP++;
	    if (!IS_ZF_SET) JUMP(IP);
	    break;
	case JBE_JNA:
	    IP++;
	    if (IS_CF_SET || IS_ZF_SET) JUMP(IP);
	    break;
	case JNBE_JA:
	    IP++;
	    if (!(IS_CF_SET || IS_ZF_SET)) JUMP(IP);
	    break;
	case JS:
	    IP++;
	    if (IS_SF_SET) JUMP(IP);
	    break;
	case JNS:
	    IP++;
	    if (!(IS_SF_SET)) JUMP(IP);
	    break;
	case JP_JPE:
	    IP++;
	    if (IS_PF_SET) JUMP(IP);
	    break;
	case JNP_JPO:
	    IP++;
	    if (!IS_PF_SET) JUMP(IP);
	    break;
	case JL_JNGE:
	    IP++;
	    if (IS_SF_SET ^ IS_OF_SET) JUMP(IP);
	    break;
	case JNL_JGE:
	    IP++;
	    if (!(IS_SF_SET ^ IS_OF_SET)) JUMP(IP);
	    break;
	case JLE_JNG:
	    IP++;
	    if ((IS_SF_SET ^ IS_OF_SET) || IS_ZF_SET) JUMP(IP);
	    break;
	case JNLE_JG:
	    IP++;
	    if (!(IS_SF_SET ^ IS_OF_SET) && !(IS_ZF_SET)) JUMP(IP);
	    break;
	case NOP:
	    break;
	case XCHGcx:
	    temp = AX;
	    AX = CX;
	    CX = temp;
	    break;
	case XCHGdx:
	    temp = AX;
	    AX = DX;
	    DX = temp;
	    break;
	case XCHGbx:
	    temp = AX;
	    AX = BX;
	    BX = temp;
	    break;
	case XCHGsp:
	    temp = AX;
	    AX = SP;
	    SP = temp;
	    break;
	case XCHGbp:
	    temp = AX;
	    AX = BP;
	    BP = temp;
	    break;
	case XCHGsi:
	    temp = AX;
	    AX = SI;
	    SI = temp;
	    break;
	case XCHGdi:
	    temp = AX;
	    AX = DI;
	    DI = temp;
	    break;
	case CBW:
	    AH = (AL & 0x80) ? 0xff : 0;
	    break;
	case CWD:
	    DX = (AX & 0x8000) ? 0xffff : 0;
	    break;
	case CALLld:
	    PUSHWORD(_cs);
	    ip = IP - cs + 5;
	    PUSHWORD(ip);
	    _ip = GETWORD(IP+1);
	    _sel = GETWORD(IP+3);
	    transfer_magic = (WORD)GetSelectorType(_sel);
	    if (transfer_magic != TRANSFER_CODE16) {

		SEGIMAGE *lpSegImage;
		UINT ord;

		FillEnv;
		if (transfer_magic == TRANSFER_CALLBACK) {
		    ord = _ip >> 3;
		    lpSegImage = &((SEGIMAGE *)
			(*(long *)(GetPhysicalAddress(_sel))))[ord];
		    targ = (LONGPROC)(lpSegImage->targ);
		    conv = (LONGPROC)(lpSegImage->conv);
		    LOGSTR((LF_INTERFACE,"do_ext: %s\n",GetProcName(_sel,ord)));
		    (conv)(env,targ);
		    GetEnv;
		    LOGSTR((LF_INTERFACE,"do_ext: ax=%x dx=%x\n",AX,DX));
		    IP = cs + ip - 1;
		}
		else if (transfer_magic == TRANSFER_BINARY) {
		    ord = _ip >> 3;
		    lpSegImage = &((SEGIMAGE *)
			(*(long *)(GetPhysicalAddress(_sel))))[ord];
		    targ = (LONGPROC)(lpSegImage->targ);
		    conv = (LONGPROC)(lpSegImage->conv);
		    LOGSTR((LF_INTERFACE,
			"do_ext: calling binary thunk %x:%x\n",_sel,_ip));
		    (conv)(env,targ);
		    GetEnv;
		    LOGSTR((LF_INTERFACE,"do_ext: ax=%x dx=%x\n",AX,DX));
		    IP = cs + ip - 1;
		}
		else if (transfer_magic == TRANSFER_DATA) 
		    invoke_data(env);
		else {
		   return;
		}
	    }
	    else {
		_cs = _sel;
		SET_SEGREG(cs,_cs);
		IP = cs + _ip - 1;
	    }
	    break;
	case WAIT:
	    break;
	case PUSHF:
	    if (dir_flag) 
		SET_DF;
	    else CLEAR_DF;
	    if (int_flag)
		SET_IF;
	    else CLEAR_IF;
	    PUSHWORD(flags);
	    break;
	case POPF:
	    POPWORD(flags);
	    dir_flag = IS_DF_SET;
	    break;
	case SAHF:
	    flags = (unsigned short)AH;
	    break;
	case LAHF:
	    AH = LOBYTE(flags);
	    break;
	case MOVmal:
	    offset = GETWORD(IP+1);
	    if (override_flag)
	       seg = override;
	    else
	       seg = ds;
	    AL = seg[offset];
	    IP += 2;
	    break;
	case MOVmax:
	    offset = GETWORD(IP+1);
	    if (override_flag)
	       seg = override;
	    else
	       seg = ds;
	    AX = GETWORD(&seg[offset]);
	    IP += 2;
	    break;
	case MOValm:
	    offset = GETWORD(IP+1);
	    if (override_flag) 
	       seg = override;
	    else 
	       seg = ds;
	    seg[offset] = AL;
	    IP += 2;
	    break;
	case MOVaxm:
	    offset = GETWORD(IP+1);
	    if (override_flag) 
	       seg = override;
	    else 
	       seg = ds;
	    seg[offset] = AL;
	    seg[offset+1] = AH;
	    IP += 2;
	    break;
	case MOVSb:	    /* 0xa4  */
	    count = (repeat) ? CX : 1;
	    if (override_flag)
	       seg = override;
	    else
	       seg = ds;
	    while (count--) {
		es[DI] = seg[SI];
		if (dir_flag) {
		   SI--;
		   DI--;
		} 
		else {
		   SI++;
		   DI++;
		}
	    }
	    if (repeat) {
		CX = 0;
		repeat = 0;
	    }	    
	    break;
	case MOVSw:	    /* 0xa5  */
	    count = (repeat) ? CX : 1;
	    if (override_flag) 
	       seg = override;
	    else 
	       seg = ds;
	    while (count--) {
		if (dir_flag) {
		   es[DI+1] = seg[SI+1];
		   es[DI] = seg[SI];
		   SI -= 2;
		   DI -= 2;
		} 
		else {
		   es[DI] = seg[SI];
		   es[DI+1] = seg[SI+1];
		   SI += 2;
		   DI += 2;
		}
	    }
	    if (repeat) {
		CX = 0;
		repeat = 0;
	    }    
	    break;
	case CMPSb:	    /* 0xa6  */
	    count = (repeat) ? CX : 1;
	    if (override_flag)
		seg = override;
	    else
		seg = ds;
	    switch (repeat) {
		case REP:
		    zero = TRUE;
		    while (count && zero) {
			op_1 = seg[SI];
			temp = op_1 - es[DI];
			lt_flag = ((SIGNED char)op_1 < (SIGNED char)es[DI]);
			if (temp != 0)
			    zero = FALSE;
			if (dir_flag) {
			    DI--;
			    SI--;
			}
			else {
			    DI++;
			    SI++;
			}
			count--;
		    }
		    break;
		case REPNE:
		    zero = FALSE;
		    while (count && !zero) {
			op_1 = seg[SI];
			temp = op_1 - es[DI];
			lt_flag = ((SIGNED char)op_1 < (SIGNED char)es[DI]);
			if (temp == 0)
			    zero = TRUE;
			if (dir_flag) {
			    DI--;
			    SI--;
			}
			else {
			    DI++;
			    SI++;
			}
			count--;
		    }
		    break;
		default:	/* no REP prefix */
		    op_1 = seg[SI];
		    temp = op_1 - es[DI];
		    lt_flag = ((SIGNED char)op_1 < (SIGNED char)es[DI]);
		    if (dir_flag) {
			DI--;
			SI--;
		    }
		    else {
			DI++;
			SI++;
		    }
		    break;
	    }
	    if (repeat) {
		CX = count;
		repeat = 0;
	    }
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
		if (!lt_flag && IS_SF_SET)
		    flags |= OVERFLOW_FLAG;
	    break;
	case CMPSw:
	    count = (repeat) ? CX : 1;
	    if (override_flag)
		seg = override;
	    else
		seg = ds;
	    switch (repeat) {
		case REP:
		    zero = TRUE;
		    while (count && zero) {
			op1 = GETWORD(&seg[SI]);
			op2 = GETWORD(&es[DI]);
			temp = op1 - op2;
			lt_flag = ((short)op1 < (short)op2);
			if (temp != 0)
			    zero = FALSE;
			if (dir_flag) {
			    DI -= 2;
			    SI -= 2;
			}
			else {
			    DI += 2;
			    SI += 2;
			}
			count--;
		    }
		    break;
		case REPNE:
		    zero = FALSE;
		    while (count && !zero) {
			op1 = GETWORD(&seg[SI]);
			op2 = GETWORD(&es[DI]);
			temp = op1 - op2;
			lt_flag = ((short)op1 < (short)op2);
			if (temp == 0)
			    zero = TRUE;
			if (dir_flag) {
			    DI -= 2;
			    SI -= 2;
			}
			else {
			    DI += 2;
			    SI += 2;
			}
			count--;
		    }
		    break;
		default:	/* no REP prefix */
		    op1 = GETWORD(&seg[SI]);
		    op2 = GETWORD(&es[DI]);
		    temp = op1 - op2;
		    lt_flag = ((short)op1 < (short)op2);
		    if (dir_flag) {
			DI -= 2;
			SI -= 2;
		    }
		    else {
			DI += 2;
			SI += 2;
		    }
		    break;
	    }
	    if (repeat) {
		CX = count;
		repeat = 0;
	    }
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case TESTbi:
	    temp = AL & (*(++IP));
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case TESTwi:
	    temp = AX & GETWORD(IP+1);
	    IP += 2;
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case STOSb:
	    count = (repeat) ? CX : 1;

	    while (count--) {
		es[DI] = AL;
		(dir_flag) ? DI-- : DI++;
	    }
	    if (repeat) {
		CX = 0;
		repeat = 0;
	    }
	    break;
	case STOSw:
	    count = (repeat) ? CX : 1;
	    while (count--) {
		PUTWORD(&es[DI],AX);
		(dir_flag) ? (DI -= 2) : (DI += 2);
	    }
	    if (repeat) {
		CX = 0;
		repeat = 0;
	    }    
	    break;
	case LODSb:
	    if (override_flag)
		seg = override;
	    else
		seg = ds;
	    AL = seg[SI];
	    (dir_flag) ? SI-- : SI++;
	    break;
	case LODSw:
	    offset = SI;
	    if (override_flag) {
		seg = override;
	    }
	    else
		seg = ds;
	    AX = GETWORD(&seg[offset]);
	    if (dir_flag)
	       SI -= 2;
	    else
	       SI += 2;
	    break;
	case SCASb:
	    count = (repeat) ? CX : 1;
	    switch (repeat) {
		case REP:
		    zero = TRUE;
		    while (count && zero) {
			temp = AL - es[DI];
			lt_flag = ((SIGNED char)AL < (SIGNED char)es[DI]);
			if (temp != 0)
			    zero = FALSE;
			(dir_flag) ? DI-- : DI++;
			count--;
		    }
		    break;
		case REPNE:
		    zero = FALSE;
		    while (count && !zero) {
			temp = AL - es[DI];
			lt_flag = ((int)(char)AL < (int)(char)es[DI]);
			if (temp == 0)
			    zero = TRUE;
			(dir_flag) ? DI-- : DI++;
			count--;
		    }
		    break;
		default:	/* no REP prefix */
		    temp = AL - es[DI];
		    lt_flag = ((SIGNED char)AL < (SIGNED char)es[DI]);
		    (dir_flag) ? DI-- : DI++;
		    break;
	    }
	    if (repeat) {
		CX = count;
		repeat = 0;
	    }
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case SCASw:
	    count = (repeat) ? CX : 1;
	    switch (repeat) {
		case REP:
		    zero = TRUE;
		    while (count && zero) {
			op1 = GETWORD(&es[DI]);
			temp = AX - op1;
			lt_flag = ((short)AX < (short)op1);
			if (temp != 0)
			    zero = FALSE;
			(dir_flag) ? (DI -= 2) : (DI += 2);
			count--;
		    }
		    break;
		case REPNE:
		    zero = FALSE;
		    while (count && !zero) {
			op1 = GETWORD(&es[DI]);
			temp = AX - op1;
			lt_flag = ((short)AX < (short)op1);
			if (temp == 0)
			    zero = TRUE;
			(dir_flag) ? (DI -= 2) : (DI += 2);
			count--;
		    }
		    break;
		default:	/* no REP prefix */
		    op1 = GETWORD(&es[DI]);
		    temp = AX - op1;
		    lt_flag = ((short)AX < (short)op1);
		    (dir_flag) ? (DI -= 2) : (DI += 2);
		    break;
	    }
	    if (repeat) {
		CX = count;
		repeat = 0;
	    }
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
	    if (!lt_flag && IS_SF_SET)
		flags |= OVERFLOW_FLAG;
	    break;
	case MOVial:
	    AL = *(++IP);
	    break;
	case MOVicl:
	    CL = *(++IP);
	    break;
	case MOVidl:
	    DL = *(++IP);
	    break;
	case MOVibl:
	    BL = *(++IP);
	    break;
	case MOViah:
	    AH = *(++IP);
	    break;
	case MOVich:
	    CH = *(++IP);
	    break;
	case MOVidh:
	    DH = *(++IP);
	    break;
	case MOVibh:
	    BH = *(++IP);
	    break;
	case MOViax:
	    AX = GETWORD(IP+1);
	    IP += 2;
	    break;
	case MOVicx:
	    CX = GETWORD(IP+1);
	    IP += 2;
	    break;
	case MOVidx:
	    DX = GETWORD(IP+1);
	    IP += 2;
	    break;
	case MOVibx:
	    BX = GETWORD(IP+1);
	    IP += 2;
	    break;
	case MOVisp:
	    SP = GETWORD(IP+1);
	    IP += 2;
	    break;
	case MOVibp:
	    BP = GETWORD(IP+1);
	    IP += 2;
	    break;
	case MOVisi:
	    SI = GETWORD(IP+1);
	    IP += 2;
	    break;
	case MOVidi:
	    DI = GETWORD(IP+1);
	    IP += 2;
	    break;
	case RETisp:
	    POPWORD(ip);
	    SP += GETWORD(IP+1);
	    IP = cs + ip - 1;
	    break;
	case RET:
	    POPWORD(ip);
	    IP = cs + ip - 1;
	    break;
	case ENTER:    /* 0xc8  */
	    PUSHWORD(BP);
	    temp = SP;
	    level = *(IP+3);
	    if (level > 0) {
		while (level--) {
		    BP -= 2;
		    PUSHWORD(ss[BP]);
		}
		PUSHWORD(temp);
	    }
	    BP = temp;
	    SP -= GETWORD(IP+1);
	    IP += 3;
	    break;    
	case LEAVE:    /* 0xc9 */
	    SP = BP;
	    BP = GETWORD(&ss[SP]);
	    SP += 2;	    
	    break;    
	case RETlisp:
	    POPWORD(ip);
	    POPWORD(_sel);
	    SP += GETWORD(IP+1);
	    transfer_magic = (WORD)GetSelectorType(_sel);
	    if (transfer_magic != TRANSFER_CODE16) {
		_ip = ip;
		FillEnv;
		if (transfer_magic == TRANSFER_DATA)
		    invoke_data(env);
		else
		    return;
	    }
	    else {
		_cs = _sel;
		SET_SEGREG(cs,_cs);
		IP = cs + ip - 1;
	    }
	    break;
	case RETl:
	    POPWORD(ip);
	    POPWORD(_sel);
	    transfer_magic = (WORD)GetSelectorType(_sel);
	    if (transfer_magic != TRANSFER_CODE16) {
		_ip = ip;
		FillEnv;
		if (transfer_magic == TRANSFER_DATA)
		    invoke_data(env);
		else
		    return;
	    }
	    else {
		_cs = _sel;
		SET_SEGREG(cs,_cs);
		IP = cs + ip - 1;
	    }
	    break;
	case INT3:
	    fprintf(stderr,unsupp_msg,"INT3",
		IP,_cs,IP-cs);
	    break;
	case INT:
	    ip = (WORD)(IP - cs);
	    PUSHWORD(ip);
	    PUSHWORD(_cs);
	    if (dir_flag)
		SET_DF;
	    else  CLEAR_DF;
	    PUSHWORD(flags);
	    FillEnv;
	    INT_handler((WORD)(*(++IP)),env);
	    GetEnv;
	    break;
	case INTO:
	    fprintf(stderr,"INTO at %x:%x\n",
		_cs,(IP-cs));
	    break;
	case IRET:
	    fprintf(stderr,"Call to IRET at %x:%x\n",
		_cs,IP-cs);
	    break;
	case AAM:
	    AX = ((AL / 10) << 8) + (AL % 10);
	    if (AX == 0) SET_ZF;
	    if (AX & 0x8000) SET_SF;
	    break;
	case AAD:
	    AX = (0xff & ((AH * (10 * 256)) + AL));
	    if (AX == 0) SET_ZF;
	    if (AX & 0x8000) SET_SF;
	    break;
	case 0xd6:    /* illegal on 8086 and 80x86*/
	    fprintf(stderr,illegal_msg,"illegal on 8086",
		cs[ip],_cs, IP-cs);
	    break;    
	case XLAT:
	    if (override_flag)
		seg = override;
	    else seg = ds;
	    AL = seg[BX + (unsigned char)AL];
	    break;

#ifdef FP87 /* 80x87 emulation stuff by Jerzy */
        case ESC0:
        case ESC1:
        case ESC2:
        case ESC3:
        case ESC4:
        case ESC5:
        case ESC6:
        case ESC7:
            opcode = (opcode << 3) | ((unsigned char)( *(IP+1) & 0x38) >> 3);
            goto label_rm_opcode;
#else
	case ESC0:
	    break;
	case ESC1:
	    break;
	case ESC2:
	    break;
	case ESC3:
	    break;
	case ESC4:
	    break;
	case ESC5:
	    break;
	case ESC6:
	    break;
	case ESC7:
	    break;
#endif

	case LOOPNZ_LOOPNE:
	    IP++;
	    if ((--CX != 0) && (!IS_ZF_SET)) {
		JUMP(IP);
	    }
	    break;
	case LOOPZ_LOOPE:
	    IP++;
	    if ((--CX != 0) && (IS_ZF_SET)) {
		JUMP(IP);
	    }
	    break;
	case LOOP:
	    IP++;
	    if (--CX != 0) {
		JUMP(IP);
	    }
	    break;
	case JCXZ:
	    IP++;
	    if (CX == 0) {
		JUMP(IP);
	    }
	    break;

	case INb:
	case INw:
	    fprintf(stderr,"%4.4x:%4.4x\t%2.2x IN%s %x\n",
		_cs,IP-cs,
		opcode,opcode == INb?"B":"W",*(IP+1));
	    IP++;
	    break;

	case OUTb:
	case OUTw:
	    fprintf(stderr,"%4.4x:%4.4x\t%2.2x OUT%s %x\n",
		_cs,IP-cs,
		opcode,opcode == OUTb?"B":"W",*(IP+1));
	    IP++;
	    break;
	case CALLd:
	    PUSHWORD(IP-cs+3);		/* falls through */
	case JMPd:
	    ip = (IP - cs) + (short)GETWORD(IP+1) + 3;
	    IP = cs + ip - 1;
	    break;
	case JMPld:
	    _sel = GETWORD(IP+3);
	    _ip = GETWORD(IP+1);
 	    transfer_magic = (WORD)GetSelectorType(_sel);
	    if (transfer_magic != TRANSFER_CODE16) {
	
		SEGIMAGE *lpSegImage;
		UINT ord;

		FillEnv;
		if (transfer_magic == TRANSFER_CALLBACK) {
		    ord = _ip >> 3;
		    lpSegImage = &((SEGIMAGE *)
			(*(long *)(GetPhysicalAddress(_sel))))[ord];
		    targ = (LONGPROC)(lpSegImage->targ);
		    conv = (LONGPROC)(lpSegImage->conv);
		    LOGSTR((LF_INTERFACE,
				"do_ext: sel %x, ord %x - %s\n",_sel,ord,
				GetProcName(_sel,ord)));
		    (conv)(env,targ);	
		    GetEnv;
		    LOGSTR((LF_INTERFACE,"do_ext: ax=%x dx=%x\n",AX,DX));
		}
		else if (transfer_magic == TRANSFER_BINARY) {
		    ord = _ip >> 3;
		    lpSegImage = &((SEGIMAGE *)
			(*(long *)(GetPhysicalAddress(_sel))))[ord];
		    targ = (LONGPROC)(lpSegImage->targ);
		    conv = (LONGPROC)(lpSegImage->conv);
		    LOGSTR((LF_INTERFACE,
			"do_ext: jumping to binary thunk %x:%x\n",_sel,_ip));
		    (conv)(env,targ);	
		}
		else if (transfer_magic == TRANSFER_DATA) 
		    invoke_data(env);
		else {
		    return;
	        }
	    }
	    else {
		_cs = _sel;
		SET_SEGREG(cs,_cs);
		IP = cs + _ip - 1;
	    }
	    break;
	case JMPsid:
	    IP++;
	    JUMP(IP);
	    break;
	case INvb:
	case INvw:
	    fprintf(stderr,"%4.4x:%4.4x\t%2.2x INV%s\n",
		_cs,IP-cs,
		opcode,opcode == INvb?"B":"W");
	    break;

	case OUTvb:
	case OUTvw:
	    fprintf(stderr,"%4.4x:%4.4x\t%2.2x OUTV%s\n",
		_cs,IP-cs,
		opcode,opcode == OUTvb?"B":"W");
	    break;

	case LOCK:
	    break;
	case 0xf1:    /* illegal on 8086 and 80x86 */
	    fprintf(stderr,illegal_msg,"f1",
		opcode,_cs, IP-cs);
	    break;    
	case REP:
	case REPNE:
	    repeat = opcode;
	    prefix = TRUE;
	    break;
	case HLT:
	    return;
	    
	case CMC:
	    flags ^= CARRY_FLAG;
	    break;
	case CLC:
	    CLEAR_CF;
	    break;
	case STC:
	    SET_CF;
	    break;
	case CLI:
	    int_flag = FALSE;
	    break;
	case STI:
	    int_flag = TRUE;
	    break;
	case CLD:
	    dir_flag = FALSE;
	    break;
	case STD:
	    dir_flag = TRUE;
	    break;
      default:		/*  Mod R/M instructions  */
	label_rm_opcode:
#ifdef DEBUG
	  if (global_debug) printf("Opcode - %x ",opcode);
#endif
	  modrm = *(++IP);
	  mod = MOD(modrm);	    /* 11000000 */
	  reg = RG(modrm);	     /* 00111000 */
	  rm  = RM(modrm);	     /* 00000111 */
	  op2 = 0;
	  disp = 0;
	  allow_override = TRUE;
	  switch (mod) {
	      case 1:				/* One-byte DISP */
	       	  if ((*(++IP)) & 0x80)
		      disp = (WORD)(*IP) | 0xff00;
		  else
		      disp = (WORD)(*IP);
		  break;
	      case 2:		/* Two-byte DISP */
		  disp = GETWORD(IP+1);
		  IP += 2;
		  break;
	      default:
		  break;	    
	  }
	  if (MOD_MEM) {	       /* MOD_REG - register addressing    */ 
	      switch (rm) {
		  case 0:
		      offset = LOWORD(BX+SI+disp);	    
		      break;
		  case 1:
		      offset = LOWORD(BX+DI+disp);    
		      break;
		  case 2:
		      offset = LOWORD(BP+SI+disp);
		      allow_override = override_flag;
		      break;
		  case 3:
		      offset = LOWORD(BP+DI+disp);
		      allow_override = override_flag;
		      break;
		  case 4:
		      offset = LOWORD(SI+disp);
		      break;
		  case 5:
		      offset = LOWORD(DI+disp);
		      break;
		  case 6:
		      if (!mod) {
			  offset = GETWORD(IP+1);
			  IP += 2;
		      }
		      else {
			  offset = LOWORD(BP+disp);
			  allow_override = override_flag;
		      }
		      break;
		  case 7:
		      offset = LOWORD(BX+disp);
		      break;
	      }	
	      if (allow_override)
		  if (override_flag)    /* SEG prefix     */ 
		      seg = override;
		  else
		      seg = ds;
	      else		  /* Addressing by BP - use SS, no override */
		  seg = ss;
	 }
#ifdef DEBUG
if (global_debug) {
    printf("mod - %x, reg - %x, rm - %x, disp - %x, ",mod,reg,rm,disp);
}
#endif
	switch (opcode) {
	case ADDbfrm:
	    if (MOD_REG) {
		temp = REGB(reg) + REGB(rm);
		flags = SIGNb | CARRYb | ZEROb | OVFLOWb(REGB(rm)) | AUXCARRY | PARITY;
		REGB(rm) = LOBYTE(temp);
	    }
	    else {
		temp = REGB(reg) + seg[offset];
		flags = SIGNb | CARRYb | ZEROb | OVFLOWb(seg[offset]) | AUXCARRY | PARITY;
		seg[offset] = LOBYTE(temp);
	    }
	    break;
	case ADDwfrm:
	    if (MOD_REG) {
		temp = REGW(reg) + REGW(rm);
		flags = SIGNw | CARRYw | ZEROw | OVFLOWw(REGW(rm)) | AUXCARRY | PARITY;
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		op1 = GETWORD(&seg[offset]);
		temp = REGW(reg) + op1;
		flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op1) | AUXCARRY | PARITY;
		PUTWORD(&seg[offset],temp);
	    }
	    break;
	case ADDbtrm:
	    if (MOD_REG) 
		temp = REGB(reg) + REGB(rm);
	    else
		temp = REGB(reg) + seg[offset];
	    flags = SIGNb | CARRYb | ZEROb | OVFLOWb(REGB(reg)) | AUXCARRY | PARITY;
	    REGB(reg) = LOBYTE(temp);
	    break;
	case ADDwtrm:
	    if (MOD_REG)
		temp = REGW(reg) + REGW(rm);
	    else
		temp = REGW(reg) + GETWORD(&seg[offset]);
	    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(REGW(reg))| AUXCARRY | PARITY;
	    REGW(reg) = LOWORD(temp);
	    break;
	case ORbfrm:
	    if (MOD_REG) {
		temp = REGB(reg) | REGB(rm);
		REGB(rm) = LOBYTE(temp);
	    }
	    else {
		temp = REGB(reg) | seg[offset];
		seg[offset] = LOBYTE(temp);
	    }
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case ORwfrm:
	    if (MOD_REG) {
		temp = REGW(reg) | REGW(rm);
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		temp = REGW(reg) | GETWORD(&seg[offset]);
		PUTWORD(&seg[offset],temp);
	    }
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case ORbtrm:
	    if (MOD_REG) 
		temp = REGB(reg) | REGB(rm);
	    else
		temp = REGB(reg) | seg[offset];
	    REGB(reg) = LOBYTE(temp);
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case ORwtrm:
	    if (MOD_REG) 
		temp = REGW(reg) | REGW(rm);
	    else
		temp = REGW(reg) | GETWORD(&seg[offset]);
	    REGW(reg) = LOWORD(temp);
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case VER:
	    if (MOD_REG)
		_sel = REGW(rm);
	    else
		_sel = GETWORD(&seg[offset]);
	    if ((_sel & 0x7) != 0x7)
		CLEAR_ZF;
	    else {
		temp = Sel86Flags[GetSelectorType(_sel)];
		if ((reg == 4) &&		/* VERR */
		    (!(temp & DF_CODE) ||
		    ((temp & DF_CODE) && (temp & DF_CREADABLE))))
		    SET_ZF;
		else if ((reg == 5) &&		/* VERW */
			 (!(temp & DF_CODE) && (temp & DF_DWRITEABLE)))
		    SET_ZF;
		else
		    CLEAR_ZF;
	    }
	    break;
	case LAR:
	    if (MOD_REG)
		_sel = REGW(rm);
	    else
		_sel = GETWORD(&seg[offset]);
	    if ((_sel & 0x7) != 0x7)
		CLEAR_ZF;
	    else {
		temp = (Sel86Flags[GetSelectorType(_sel)] << 8) & 0xffff;
		REGW(reg) = temp;
		SET_ZF;
	    }
	    break;
	case LSL:
	    if (MOD_REG)
		_sel = REGW(rm);
	    else
		_sel = GETWORD(&seg[offset]);
	    if ((_sel & 0x7) != 0x7)
		CLEAR_ZF;
	    else {
		temp = (WORD)GetSelectorLimit(_sel);
		REGW(reg) = temp;
		SET_ZF;
	    }
	    break;
	case ADCbfrm:
	    if (MOD_REG) { 
		temp = REGB(reg) + REGB(rm) + (flags & CARRY_FLAG);
		flags = SIGNb | CARRYb | ZEROb | OVFLOWb(REGB(rm)) | AUXCARRY | PARITY;
		REGB(rm) = LOBYTE(temp);
	    }
	    else {    
		temp = REGB(reg) + seg[offset] + (flags & CARRY_FLAG);
		flags = SIGNb | CARRYb | ZEROb | OVFLOWb(seg[offset]) | AUXCARRY | PARITY;
		seg[offset] = LOBYTE(temp);
	    }
	    break;
	case ADCwfrm:
	    if (MOD_REG) { 
		temp = REGW(reg) + REGW(rm) + (flags & CARRY_FLAG);
		flags = SIGNw | CARRYw | ZEROw | OVFLOWw(REGW(rm)) | AUXCARRY | PARITY;
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		op1 = GETWORD(&seg[offset]); 
		temp = REGW(reg) + op1 + (flags & CARRY_FLAG);
		flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op1) | AUXCARRY | PARITY;
		PUTWORD(&seg[offset],temp);
	    }
	    break;
	case ADCbtrm:
	    if (MOD_REG)  
		temp = REGB(reg) + REGB(rm) + (flags & CARRY_FLAG);
	    else 
		temp = REGB(reg) + GETWORD(&seg[offset]) + (flags & CARRY_FLAG);
	    REGB(reg) = LOBYTE(temp);
	    flags = SIGNb | CARRYb | ZEROb | OVFLOWb(REGB(reg)) | AUXCARRY | PARITY;
	    break;
	case ADCwtrm:
	    if (MOD_REG)  
		temp = REGW(reg) + REGW(rm) + (flags & CARRY_FLAG);
	    else 
		temp = REGW(reg) + GETWORD(&seg[offset]) + (flags & CARRY_FLAG);
	    REGW(reg) = LOWORD(temp);
	    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(REGW(reg)) | AUXCARRY | PARITY;
	    break;
	case SBBbfrm:
	    if (MOD_REG) { 
		temp = REGB(rm) - (REGB(reg) + (IS_CF_SET));
				lt_flag = ((SIGNED char)REGB(rm) < ((SIGNED char)REGB(reg) +
						IS_CF_SET));
		flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
		REGB(rm) = LOWORD(temp);
	    }
	    else {
		temp = seg[offset] - (REGB(reg) + (IS_CF_SET));
				lt_flag = ((SIGNED char)seg[offset] < ((SIGNED char)REGB(reg) + 
						IS_CF_SET));
		flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
		seg[offset] = LOBYTE(temp);
	    }
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case SBBwfrm:
	    if (MOD_REG) { 
		temp = REGW(rm) - (REGW(reg) + (IS_CF_SET));
				lt_flag = ((short)REGW(rm) < ((short)REGW(reg) + 
						(IS_CF_SET)));
		flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		op1 = GETWORD(&seg[offset]); 
		temp = op1 - (REGW(reg) + (IS_CF_SET));
				lt_flag = ((short)op1 < ((short)REGW(reg) +
						(IS_CF_SET)));
		flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
		PUTWORD(&seg[offset],temp);
	    }
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case SBBbtrm:
	    if (MOD_REG) { 
		temp = REGB(reg) - (REGB(rm) + (IS_CF_SET));
				lt_flag = ((SIGNED char)REGB(reg) < ((SIGNED char)REGB(rm) +
						IS_CF_SET));
			}
	    else {
		temp = REGB(reg) - (seg[offset] + (IS_CF_SET));
				lt_flag = ((SIGNED char)REGB(reg) < ((SIGNED char)seg[offset] + 
						(IS_CF_SET)));
			}
	    REGB(reg) = LOWORD(temp);
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case SBBwtrm:
	    if (MOD_REG) { 
		temp = REGW(reg) - (REGW(rm) + (IS_CF_SET));
				lt_flag = ((short)REGW(reg) < ((short)REGW(rm) + 
						(IS_CF_SET)));
			}
	    else {
				op2 = GETWORD(&seg[offset]);
		temp = REGW(reg) - (op2 + (IS_CF_SET));
				lt_flag = ((short)REGW(reg) < ((short)op2 + 
						(IS_CF_SET)));
			}
	    REGW(reg) = LOWORD(temp);
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case ANDbfrm:
	    if (MOD_REG) {
		temp = REGB(reg) & REGB(rm);
		REGB(rm) = LOBYTE(temp);
	    }
	    else {
		temp = REGB(reg) & seg[offset];
		seg[offset] = LOBYTE(temp);
	    }
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case ANDwfrm:
	    if (MOD_REG) {
		temp = REGW(reg) & REGW(rm);
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		temp = REGW(reg) & ((seg[offset+1] << 8) | seg[offset]);
		PUTWORD(&seg[offset],temp);
	    }
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case ANDbtrm:
	    if (MOD_REG) 
		temp = REGB(reg) & REGB(rm);
	    else
		temp = REGB(reg) & seg[offset];
	    flags = SIGNb | ZEROb | PARITY;
	    REGB(reg) = LOBYTE(temp);
	    break;
	case ANDwtrm:
	    if (MOD_REG)
		temp = REGW(reg) & REGW(rm);
	    else
		temp = REGW(reg) & GETWORD(&seg[offset]);
	    flags = SIGNw | ZEROw | PARITY;
	    REGW(reg) = LOWORD(temp);
	    break;
	case SUBbfrm:
	    if (MOD_REG) { 
		temp = REGB(rm) - REGB(reg);
				lt_flag = ((SIGNED char)REGB(rm) < (SIGNED char)REGB(reg));
		flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
		REGB(rm) = LOBYTE(temp);
	    }
	    else {
		temp = seg[offset] - REGB(reg);
				lt_flag = ((SIGNED char)seg[offset] < (SIGNED char)REGB(reg));
		flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
		seg[offset] = LOBYTE(temp);
	    }
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case SUBwfrm:
	    if (MOD_REG) { 
		temp = REGW(rm) - REGW(reg);
				lt_flag = ((short)REGW(rm) < (short)REGW(reg));
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		op1 = GETWORD(&seg[offset]); 
		temp = op1 - REGW(reg);
				lt_flag = ((short)op1 < (short)REGW(reg));
		PUTWORD(&seg[offset],temp);
	    }
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case SUBbtrm:
			op_1 = ((MOD_REG) ? REGB(rm) : seg[offset]);
	    temp = REGB(reg) - op_1;
			lt_flag = ((SIGNED char)REGB(reg) < (SIGNED char)op_1);
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    REGB(reg) = LOBYTE(temp);
	    break;
	case SUBwtrm:
			op2 = ((MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]));
	    temp = REGW(reg) - op2;
			lt_flag = ((short)REGW(reg) < (short)op2);
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    REGW(reg) = LOWORD(temp);
	    break;
	case XORbfrm:
	    if (MOD_REG) {
		temp = REGB(reg) ^ REGB(rm);
		REGB(rm) = LOBYTE(temp);
	    }
	    else {
		temp = REGB(reg) ^ seg[offset];
		seg[offset] = LOBYTE(temp);
	    }
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case XORwfrm:
	    if (MOD_REG) {
		temp = REGW(reg) ^ REGW(rm);
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		temp = REGW(reg) ^ GETWORD(&seg[offset]);
		PUTWORD(&seg[offset],temp);
	    }
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case XORbtrm:
	    if (MOD_REG) 
		temp = REGB(reg) ^ REGB(rm);
	    else
		temp = REGB(reg) ^ seg[offset];
	    REGB(reg) = LOBYTE(temp);
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case XORwtrm:
	    if (MOD_REG) 
		temp = REGW(reg) ^ REGW(rm);
	    else
		temp = REGW(reg) ^ GETWORD(&seg[offset]);
	    REGW(reg) = LOWORD(temp);
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case CMPbfrm:
	    if (MOD_REG) {  
		temp = REGB(rm) - REGB(reg);
				lt_flag = ((SIGNED char)REGB(rm) < (SIGNED char)REGB(reg));
	    }
	    else  {
		temp = seg[offset] - REGB(reg);
				lt_flag = ((SIGNED char)seg[offset] < (SIGNED char)REGB(reg));
	    }
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case CMPwfrm:
	    op1 = ((MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]));
	    temp = op1 - REGW(reg);
			lt_flag = ((short)op1 < (short)REGW(reg));
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case CMPbtrm:
			op_1 = ((MOD_REG) ? REGB(rm) : seg[offset]);
	    temp = REGB(reg) - op_1;
			lt_flag = ((SIGNED char)REGB(reg) < (SIGNED char)op_1);
	    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case CMPwtrm:
			op2 = ((MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]));
	    temp = REGW(reg) - op2;
			lt_flag = ((short)REGW(reg) < (short)op2);
	    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
	    break;
	case IMULwrm:
	    if (MOD_REG)
	    	op2 = REGW(rm);
	    else
		op2 = GETWORD(&seg[offset]);
	    signed_temp = ((short)GETWORD(IP+1)) * (short)op2;
	    REGW(reg) = LOWORD(signed_temp);
	    flags = /* CARRY & OVERF */ 
	((((signed_temp >> 15) == 0x1ffff) || (!(signed_temp >> 15)))? 0 : 0x801);
		IP += 2;
	    break;
	case IMULbrm:
	    if (MOD_REG)
	    	op2 = REGW(rm);
	    else
		op2 = GETWORD(&seg[offset]);
	    signed_temp = ((SIGNED char)(*(++IP))) * ((short)op2);
	    REGW(reg) = LOWORD(signed_temp);
	    flags =
/* CARRY & OVERF */ 
		((((signed_temp >> 15) == 0x1ffff) || (!(signed_temp >> 15)))? 0 : 0x801);
	    break;
	case IMMEDbrm:	    /* 0x80  */
	    op_1 = *(++IP);
	    op_2 = (MOD_REG) ? REGB(rm) : seg[offset];
	    switch (reg) {
		case ADD:
		    temp = op_1 + op_2;
		    flags = SIGNb | CARRYb | ZEROb | OVFLOWb(op_2) | AUXCARRY | PARITY;
		    break;
		case OR:
		    temp = op_2 | op_1;
		    flags = SIGNb | ZEROb | PARITY;
		    break;
		case ADC:
		    flags = SIGNb | CARRYb | ZEROb | OVFLOWb(op_2) | AUXCARRY | PARITY;
		    temp = op_1 + op_2 + IS_CF_SET;
		    break;
		case SBB:
		    temp = op_2 - (op_1 + IS_CF_SET);
		    flags = SIGNb | CARRYb | ZEROb | OVFLOWb(op_2) | AUXCARRY | PARITY;
		    break;
		case AND:
		    temp = op_2 & op_1;
		    flags = SIGNb | ZEROb | PARITY;
		    break;
		case SUB:
		case CMP:
		    temp = op_2 - op_1;
		    flags = SIGNb | CARRYb | ZEROb | AUXCARRY | PARITY;
		    		lt_flag = ((SIGNED char)op_2 < (SIGNED char)op_1); 
	 	    		if (!lt_flag && IS_SF_SET)
		    			flags |= OVERFLOW_FLAG;
		    break;
		case XOR:
		    temp = op_2 ^ op_1;
		    flags = SIGNb | ZEROb | PARITY;
		    break;
	    }	
	    if (reg != CMP)
		if (MOD_REG)
		    REGB(rm) = LOBYTE(temp);
		else
		    seg[offset] = LOBYTE(temp);
	    break;
	case IMMEDwrm:	    /* 0x81  */
	    op1 = GETWORD(IP+1);
	    IP += 2;
	    op2 = (MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]);
	    switch (reg) {
		case ADD:
		    temp = op1 + op2;
		    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op2) | AUXCARRY | PARITY;
		    break;
		case OR:
		    temp = op2 | op1;
		    flags = SIGNw | ZEROw | PARITY;
		    break;
		case ADC:
		    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op2) | AUXCARRY | PARITY;
		    temp = op1 + op2 + IS_CF_SET;
		    break;
		case SBB:
		    temp = op2 - (op1 + IS_CF_SET);
		    		lt_flag = ((short)op2 < ((short)op1 + 
						(IS_CF_SET)));
		    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
	 	    		if (!lt_flag && IS_SF_SET)
		    			flags |= OVERFLOW_FLAG;
		    break;
		case AND:
		    temp = op2 & op1;
		    flags = SIGNw | ZEROw | PARITY;
		    break;
		case SUB:
		    temp = op2 - op1;
					lt_flag = ((short)op2 < (short)op1);
		    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op2) | AUXCARRY | PARITY;
			if (!lt_flag && IS_SF_SET)
				flags |= OVERFLOW_FLAG;
		    break;
		case XOR:
		    temp = op2 ^ op1;
		    flags = SIGNw | ZEROw | PARITY;
		    break;
		case CMP:
		    temp = op2 - op1;
					lt_flag = ((short)op2 < (short)op1);
		    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
					if (!lt_flag && IS_SF_SET)
						flags |= OVERFLOW_FLAG;
		    break;
	    }	
	    if (reg != CMP)
		if (MOD_REG)
		    REGW(rm) = LOWORD(temp);
		else 
		    PUTWORD(&seg[offset],temp);
	    break;
	case IMMEDbrm2:    /* illegal on 80x86 */
	    fprintf(stderr,illegal_msg,"immedbrm2",
		opcode,_cs, IP-cs);
	    break;
	case IMMEDisrm:	    /* 0x83  */
	    op1 = *(++IP);
	    if (op1 & 0x80)	/* sign-extended */
		op1 = op1 | 0xff00;
	    op2 = (MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]);
	    switch (reg) {
		case ADD:
		    temp = op1 + op2;
		    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op2) | AUXCARRY | PARITY;
		    break;
		case OR:
		    temp = op2 | op1;
		    flags = SIGNw |  ZEROw | PARITY;
		    break;
		case ADC:
		    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op2) | AUXCARRY | PARITY;
		    temp = op1 + op2 + IS_CF_SET;
		    break;
		case SBB:
		    temp = op2 - (op1 + IS_CF_SET);
		    flags = SIGNw | CARRYw | ZEROw | OVFLOWw(op2) | AUXCARRY | PARITY;
		    break;
		case AND:
		    temp = op2 & op1;
		    flags = SIGNw |  ZEROw | PARITY;
		    break;
		case SUB:
		    temp = op2 - op1;
					lt_flag = ((short)op2 - (short)op1);
		    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
					if (!lt_flag && IS_SF_SET)
						flags |= OVERFLOW_FLAG;
		    break;
		case XOR:
		    temp = op2 ^ op1;
		    flags = SIGNw |  ZEROw | PARITY;
		    break;
		case CMP:
		    temp = op2 - op1;
					lt_flag = ((short)op2 - (short)op1);
		    flags = SIGNw | CARRYw | ZEROw | AUXCARRY | PARITY;
					if (!lt_flag && IS_SF_SET)
						flags |= OVERFLOW_FLAG;
		break;
	    }	
	    if (reg != CMP)
		if (MOD_REG)
		    REGW(rm) = LOWORD(temp);
		else 
		    PUTWORD(&seg[offset],temp);
	    break;
	case TESTbrm:
	    if (MOD_REG) 
		temp = REGB(reg) & REGB(rm);
	    else 
		temp = REGB(reg) & seg[offset];
	    flags = SIGNb | ZEROb | PARITY;
	    break;
	case TESTwrm:
	    if (MOD_REG) 
		temp = REGW(reg) & REGW(rm);
	    else 
		temp = REGW(reg) & GETWORD(&seg[offset]);
	    flags = SIGNw | ZEROw | PARITY;
	    break;
	case XCHGbrm:
	    temp = REGB(reg);
	    if (MOD_REG) {
		REGB(reg) = REGB(rm);
		REGB(rm) = temp;
	    }
	    else {
		REGB(reg) = seg[offset];
		seg[offset] = temp;
	    }
	    break;
	case XCHGwrm:
	    temp = REGW(reg);
	    if (MOD_REG) {
		REGW(reg) = REGW(rm);
		REGW(rm) = LOWORD(temp);
	    }
	    else {
		REGW(reg) = GETWORD(&seg[offset]);
		PUTWORD(&seg[offset],temp);
	    }
	    break;
	case MOVbfrm:
	    if (MOD_REG) 
		REGB(rm) = REGB(reg);
	    else
		seg[offset] = REGB(reg);
	    break;
	case MOVwfrm:
	    if (MOD_REG)
		REGW(rm) = REGW(reg);
	    else 
		PUTWORD(&seg[offset],REGW(reg));
	    break;
	case MOVbtrm:
	    if (MOD_REG) 
		REGB(reg) = REGB(rm);
	    else
		REGB(reg) = seg[offset];
	    break;
	case MOVwtrm:
	    if (MOD_REG)
		REGW(reg) = REGW(rm);
	    else 
		REGW(reg) = GETWORD(&seg[offset]);
	    break;
	case MOVsrtrm:
	    switch (reg) {
		case 0:
		    op2 = _es;
		    break;
		case 1:
		    op2 = _cs;
		    break;
		case 2:
		    op2 = _ss;
		    break;
		case 3:
		    op2 = _ds;
		    break;
	    }
	    if (MOD_REG) 
		REGW(rm) = op2;
	    else { 
		PUTWORD(&seg[offset],op2);
	    }
	    break;
	case LEA:
	    REGW(reg) = offset;
	    break;
	case MOVsrfrm:
	    if (MOD_REG) 
		op2 = REGW(rm);
	    else
		op2 = GETWORD(&seg[offset]);
	    switch (reg) {
		case 0:
		    _es = op2;
		    SET_SEGREG(es,_es);
		    break;
		case 2:
		    _ss = op2;
		    SET_SEGREG(ss,_ss);
		    break;
		case 3:
		    _ds = op2;
		    SET_SEGREG(ds,_ds);
		    break;
		default:
		    fprintf(stderr, illegal_msg, "movsrfrm",
			opcode,_cs, IP-cs);
	    }    
	    break;
	case POPrm:
	    if (!reg) {
		seg[offset] = ss[SP++];
		seg[offset+1] = ss[SP++];
	    }
	    break;
	case SHIFTbi:
	    count = *(++IP);
	    first = TRUE;
			overflow = 0;
	    carry = IS_CF_SET;
	    if (MOD_REG)
		op2 = REGB(rm);
	    else
		op2 = seg[offset];
	    while (count--) {
		switch (reg) {
		    case ROL:
			temp = (op2 << 1) | ((WORD)(op2 & 0x80) >> 7);
			if (first) {
			    overflow = OVFLOWb(op2);
			    first = FALSE;
			}
			break;
		    case ROR:
			temp = (op2 >> 1) | ((op2 & 0x1) << 7);
			if (first) {
			    overflow = OVFLOWb(op2);
			    first = FALSE;
			}
			break;
		    case RCL:
			temp = (op2 << 1) | carry;
			if (first) {
			    overflow = OVFLOWb(op2);
			    first = FALSE;
			}
			break;
		     case RCR:
			temp = (carry) ? ((op2 >> 1) | 0x80) : ((op2 >> 1) & 0x17f);
			if (first) {
			    overflow = OVFLOWb(op2);
			    first = FALSE;
			}
			break;
		    case SHL:
			temp = (op2 << 1) & 0x1fe;
			break;
		    case SHR:    
			temp = (op2 >> 1) & 0x17f;
			break;
		    case SAR:
			temp = (op2 & 0x80) ? ((op2 >> 1) | 0x80) : ((op2 >> 1) & 0x17f);
			break;
		    default:
			break;
		}
		carry = op2 & 0x1;
		op2 = LOBYTE(temp);
	    }
	    if((*IP) != 0) {
		if (MOD_REG)
		    REGB(rm) = LOBYTE(temp);
		else
		    seg[offset] = LOBYTE(temp);
		flags =
	       /* SIGN */ ((reg >= SHL) ? SIGNb :0) |
	       /* CARRY */ ((carry) ? 0x1 : 0) | 
	       /* ZERO */ ((reg >= SHL) ? ZEROb : 0) |
	       /* OVERFLOW */((reg < SHL) ? (overflow) : 0) |
	       /* PARITY */ ((reg >= SHL) ? PARITY : 0);
	    }  
	    break;
	case SHIFTwi:
	    count = *(++IP);
	    carry = IS_CF_SET;
	    overflow = 0;
	    first = TRUE;
	    if (MOD_REG)
		op2 = REGW(rm);
	    else
		op2 = GETWORD(&seg[offset]);
	    while (count--) {
		switch (reg) {
		    case ROL:
			temp = (op2 << 1) | ((WORD)(op2 & 0x8000) >> 15);
			if (first) {
			    overflow = OVFLw;
			    first = FALSE;
			}
			break;
		    case ROR:    
			temp = (op2 >> 1) | ((op2 & 0x1) << 15);
			if (first) {
			    overflow = OVFLw;
			    first = FALSE;
			}
			break;
		    case RCL:
			temp = (op2 << 1) | carry;
			if (first) {
			    overflow = OVFLw;
			    first = FALSE;
			}
			break;
		    case RCR:
			temp = (carry) ? ((op2 >> 1) | 0x8000) : ((op2 >> 1) & 0x17fff);
			if (first) {
			    overflow = OVFLw;
			    first = FALSE;
			}
			break;
		    case SHL:    
			temp = (op2 << 1) & 0x1fffe;
			break;
		    case SHR:
			temp = (op2 >> 1) & 0x17fff;
			break;
		    case SAR:
			temp = (op2 & 0x8000) ? ((op2 >> 1) | 0x8000) : ((op2 >> 1) & 0x17fff);
			break;
		    default:
			break;
		}
		carry = op2 & 0x1;
		op2 = LOWORD(temp);
	    }
	    if ((*IP) != 0) {
		if (MOD_REG)
		      REGW(rm) = LOWORD(temp);
		else 
		    PUTWORD(&seg[offset],temp);
		flags =
		  /* SIGN */   ((reg >= SHL) ? SIGNw      : 0) |
		  /* CARRY */       ((carry) ? 0x1	: 0) | 
		  /* ZERO */   ((reg >= SHL) ? ZEROw      : 0) |
		  /* OVERFLOW */((reg < SHL) ? (overflow) : 0) |
		  /* PARITY */ ((reg >= SHL) ? PARITY     : 0);
	    } 
	    break;
	case LES: 
	    REGW(reg) = GETWORD(&seg[offset]);
	    _es = GETWORD(&seg[offset+2]);
	    SET_SEGREG(es,_es);
	    break;
	case LDS:
	    REGW(reg) = GETWORD(&seg[offset]);
	    _ds = GETWORD(&seg[offset+2]);
	    SET_SEGREG(ds,_ds);
	    break;
	case MOVbirm:
	    if (reg == 0)
	    if (MOD_REG)
		REGB(rm) = *(++IP);
	    else
		seg[offset] = *(++IP);
	    break;
	case MOVwirm:
	    if (reg == 0)
	    if (MOD_REG) {
		REGW(rm) = GETWORD(IP+1);
		IP += 2;
			}
	    else {
		seg[offset] = *(++IP);
		seg[offset+1] = *(++IP);
#ifdef LATER
		*((LPWORD)&seg[offset]) = *(LPWORD)(IP+1);
#endif
	    }
	    break;
	case SHIFTb:	    /* 0xd0  */
	    if (MOD_REG)
	       op2 = REGB(rm);
	    else
	       op2 = seg[offset];
	    switch (reg) {
		case ROL:
		    temp = (op2 << 1) | ((WORD)(op2 & 0x80) >> 7);
		    flags = OVFLb | CARRYb;
		    break;
		case ROR:
		    temp = (op2 >> 1) | ((op2 & 0x1) << 7);
		    flags = OVFLb | 
		      /* CARRY */ (op2 & 0x1);
		    break;
		case RCL:
		    temp = (op2 << 1) | IS_CF_SET;
		    flags = OVFLb | CARRYb;
		    break;
		case RCR:
		    temp = (IS_CF_SET) ? ((op2 >> 1) | 0x80) : ((op2 >> 1) & 0x17f);
		    flags = OVFLb | 
		      /* CARRY */ (op2 & 0x1);
		    break;
		case SHL:
		    temp = (op2 << 1) & 0x1fe;
		    flags = SIGNb | CARRYb | ZEROb | OVFLb | PARITY;
		    break;
		case SHR:
		    temp = (op2 >> 1) & 0x17f;
		    flags = SIGNb | ZEROb | OVFLb | PARITY |
		      /* CARRY */ (op2 & 0x1);
		    break;
		case SAR:
		    temp = (op2 & 0x80) ? ((op2 >> 1) | 0x80) : ((op2 >> 1) & 0x17f);
		    flags = SIGNb | ZEROb | OVFLb | PARITY |
		      /* CARRY */ (op2 & 0x1);
		    break;
		default:
		    break;
	    }
	    if (MOD_REG)
	       REGB(rm) = LOBYTE(temp);
	    else
	       seg[offset] = LOBYTE(temp);
	    break;
	case SHIFTw:	    /* 0xd1  */
	    if (MOD_REG)
	       op2 = REGW(rm);
	    else
	       op2 = GETWORD(&seg[offset]);
	    switch (reg) {
		case ROL:
		    temp = (op2 << 1) | ((WORD)(op2 & 0x8000) >> 15);
		    flags = CARRYw | OVFLw;
		    break;
		case ROR:
		    temp = (op2 >> 1) | ((op2 & 0x1) << 15);
		    flags = OVFLw |
		      /* CARRY */ (op2 & 0x1);
		    break;
		case RCL:
		    temp = (op2 << 1) | IS_CF_SET;
		    flags = CARRYw | OVFLw;
		    break;
		case RCR:
		    temp = (IS_CF_SET) ? ((op2 >> 1) | 0x8000) : ((op2 >> 1) & 0x17fff);
		    flags = OVFLw |
		      /* CARRY */ (op2 & 0x1);
		    break;
		case SHL:
		    temp = (op2 << 1) & 0x1fffe;
		    flags = SIGNw | CARRYw | ZEROw | OVFLw | PARITY;
		    break;
		case SHR:
		    temp = (op2 >> 1) & 0x17fff;
		    flags = SIGNw | ZEROw | OVFLw | PARITY |
		      /* CARRY */ (op2 & 0x1);
		    break;
		case SAR:
		    temp = (op2 & 0x8000) ? ((op2 >> 1) | 0x8000) : ((op2 >> 1) & 0x17fff);
		    flags = SIGNw | ZEROw | OVFLw | PARITY |
		      /* CARRY */ (op2 & 0x1);
		    break;
		default:
		    break;
	    }
	    if (MOD_REG)
		REGW(rm) = LOWORD(temp);
	    else 
		PUTWORD(&seg[offset],temp);
	    break;
	case SHIFTbv:	    /* 0xd2  */
	    count = CL;
	    carry = IS_CF_SET;
	    overflow = 0;
	    first = TRUE;
	    if (MOD_REG)
		op2 = REGB(rm);
	    else
		op2 = seg[offset];
	    while (count--) {
		switch (reg) {
		    case ROL:
			carry = (WORD)(op2 & 0x80) >> 7;
			temp = (op2 << 1) | carry;
			if (first) {
			    overflow = OVFLb;
			    first = FALSE;
			}
			break;
		    case ROR:    
			temp = (op2 >> 1) | ((op2 & 0x1) << 7);
			if (first) {
			    overflow = OVFLb;
			    first = FALSE;
			}
			carry = op2 & 0x1;
			break;
		    case RCL:
			temp = (op2 << 1) | carry;
			if (first) {
			    overflow = OVFLb;
			 first = FALSE;
			}
			carry = (WORD)(op2 & 0x80) >> 7;
			break;
		    case RCR:    
			temp = (carry) ? ((op2 >> 1) | 0x80) : ((op2 >> 1) & 0x17f);
			if (first) {
			    overflow = OVFLb;
			    first = FALSE;
			}
			carry = op2 & 0x1;
			break;
		    case SHL:
			temp = (op2 << 1) & 0x1fe;
			carry = (WORD)((WORD)(op2 & 0x80) >> 7);
			break;
		    case SHR:
			temp = (op2 >> 1) & 0x17f;
			carry = op2 & 0x1;
			break;
		    case SAR:    
			temp = (op2 & 0x80) ? ((op2 >> 1) | 0x80) : ((op2 >> 1) & 0x17f);
			carry = op2 & 0x1;
			break;
		    default:
			break;
		}
		op2 = LOBYTE(temp);
	    }
	    if (CL != 0) {
		if (MOD_REG)
		    REGB(rm) = LOBYTE(temp);
		else
		    seg[offset] = LOBYTE(temp);
		flags =
		   /* SIGN */ ((reg >= SHL) ? SIGNb : 0) |
		   /* CARRY */ ((carry) ? 0x1 : 0) | 
		   /* ZERO */ ((reg >= SHL) ? ZEROb : 0) |
		   /* OVERFLOW */ ((reg < SHL) ? overflow : 0) |
		   /* PARITY */ ((reg >= SHL) ? PARITY : 0);
	    }   
	    break;
	case SHIFTwv:	    /* 0xd3  */
	    count = CL;
	    carry = IS_CF_SET;
	    overflow = 0;
	    if (MOD_REG)
		op2 = REGW(rm);
	    else
		op2 = GETWORD(&seg[offset]);
	    while (count--) {
		switch (reg) {
		    case ROL:    
			carry = (op2 >> 15) & 0x1;
			temp = (op2 << 1) | carry;
			if (first) {
			    overflow = OVFLw;
			    first = FALSE;
			}
			break;
		    case ROR:
			carry = op2 & 0x1;
			temp = (op2 >> 1) | (carry << 15);
			if (first) {
			    overflow = OVFLw;
			       first = FALSE;
			}
			break;
		    case RCL:
			temp = (op2 << 1) | carry;
			if (first) {
			    overflow = OVFLw;
			    first = FALSE;
			}
			carry = (op2 >> 15) & 0x1;
			break;
		    case RCR:    
			temp = (carry) ? ((op2 >> 1) | 0x8000) : ((op2 >> 1) & 0x17fff);
			if (first) {
			    overflow = OVFLw;
			    first = FALSE;
			}
			carry = op2 & 0x1;
			break;
		    case SHL:    
			temp = (op2 << 1) & 0x1fffe;
			carry = (op2 >> 15) & 0x1;
			break;
		    case SHR:    
			temp = (op2 >> 1) & 0x17fff;
			carry = op2 & 0x1;
			break;
		    case SAR:
			temp = (op2 & 0x8000) ? ((op2 >> 1) | 0x8000) : ((op2 >> 1) & 0x17fff);
			break;
		     default:
			break;
	       }
	       op2 = LOWORD(temp);
	    }
	    if (CL != 0) {
		if (MOD_REG)
		    REGW(rm) = LOWORD(temp);
		else 
		    PUTWORD(&seg[offset],temp);
	       flags =
	       /* SIGN */ ((reg >= SHL) ? SIGNw :0) |
	       /* CARRY */ ((carry) ? 0x1 : 0) | 
	       /* ZERO */ ((reg >= SHL) ? ZEROw : 0) |
	       /* OVERFLOW */ ((reg < SHL) ? overflow : 0) |
	       /* PARITY */ ((reg >= SHL) ? PARITY : 0);
	    } 
	    break;
	case GRPlbrm:	    /* 0xf6  */
	    op2 = (MOD_REG) ? REGB(rm) : seg[offset];
	    switch (reg) {
		case TEST:
		    op1 = *(++IP);
		    temp = op1 & op2;
		    flags = SIGNb | ZEROb | PARITY;
		    break;
		case NOT:
		    temp = ~op2;
		    if (MOD_REG)
			REGB(rm) = LOBYTE(temp);
		    else
			seg[offset] = LOBYTE(temp);
		    break;
		case NEG:
		    temp = 0 - op2;
		    if (MOD_REG)
			REGB(rm) = LOBYTE(temp);
		    else
			seg[offset] = LOBYTE(temp);    
		    flags = SIGNb | ZEROb | OVFLb | PARITY |
		      /* CARRY */ ((op2 == 0) ? 0 : 0x1);
		    break;
		case MUL:
		    temp = AL * op2;
		    AX = LOWORD(temp);
		    flags =
		      /* CARRY & OVERF */ ((AH == 0) ? 0 : 0x801);     
		    break;
		case IMUL:
		    signed_temp = (char)AL * (short)op2;
		    AX = LOWORD(signed_temp);
		    flags = 
		      /* CARRY & OVERF */ (((AH == 0) || (AH == 0xff)) ? 0 : 0x801);
		    break;
		case DIV:    
		    temp = AX / op2;
		    AH = LOBYTE(AX % op2);
		    AL = LOBYTE(temp);
		    break;
		case IDIV:
		    if (op2 & 0x80)
		    op2 |= 0xff00;
		    temp = (short)AX / (short)op2;
		    AH = LOBYTE((short)AX % (short)op2);
		    AL = LOBYTE(temp);
		    break; 
		default:
		    break;
	    }
	    break;
	case GRPlwrm:	    /* 0xf7  */
	    op2 = (MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]);
	    switch (reg) {
		case TEST:    
		    op1 = GETWORD(IP+1);
		    IP += 2;
		    temp = op1 & op2;
		    flags = SIGNw | ZEROw | PARITY;
		    break;
		case NOT:
		    temp = ~op2;
		    if (MOD_REG)
			REGW(rm) = LOWORD(temp);
		    else 
			PUTWORD(&seg[offset],temp);
		    break;
		case NEG:
		    temp = 0 - op2;
		    if (MOD_REG)
			REGW(rm) = LOWORD(temp);
		    else 
			PUTWORD(&seg[offset],temp);
		    flags = SIGNw | ZEROw | OVFLw | PARITY |
		      /* CARRY */ ((op2 == 0) ? 0 : 0x1);
		    break;
		case MUL:
		    temp = AX * op2;
		    AX = LOWORD(temp);
		    DX = HIWORD(temp);
		    flags =
		      /* CARRY & OVERF */ ((DX == 0) ? 0 : 0x801); 
		    break;
		case IMUL:
		    signed_temp = (short)AX * (short)op2;
		    AX = LOWORD(signed_temp);
		    DX = HIWORD(signed_temp);
		    flags =
		      /* CARRY & OVERF */ (((DX == 0) || (DX == 0xffff)) ? 0 : 0x801); 
		    break;
		case DIV:
		    temp = (long)(((long)((DX << 16) | AX)) / (short)op2);
		    DX = LOWORD((long)((long)((DX << 16) | AX) % (short)op2));
		    AX = LOWORD(temp);
		    break;
		case IDIV:    
		    signed_temp = (long)((long)((DX << 16) | AX) / (short)op2);
		    DX = LOWORD((long)((long)((DX << 16) | AX) % (short)op2));
		    AX = LOWORD(signed_temp);
		    break; 
		default:
		    break;
	    }
	    break;
	case GRP2brm:
	    switch (reg) {
		case INC:    
		    if (MOD_REG) {
			op1 = REGB(rm)++;
			temp = REGB(rm);
		    }
		    else {
			op1 = seg[offset]++;
			temp = seg[offset];
		    }
		    flags = SIGNb | IS_CF_SET | ZEROb | OVFLOWb(op1) | AUXCARRY | PARITY; 
		    break;
		case DEC:    
		    if (MOD_REG) {
			op1 = REGB(rm)--;
			temp = REGB(rm);
		    }
		    else {
			op1 = seg[offset]--;
			temp = seg[offset];
		    }
		    flags = SIGNb | IS_CF_SET | ZEROb | OVFLOWb(op1) | AUXCARRY | PARITY; 
		    break;
		default:
		    break;    
	    }
	    break;
	case GRP2wrm:
	    switch (reg) {
		case INC:
		    if (MOD_REG) {
			op1 = REGW(rm)++;
			temp = REGW(rm);
		    }
		    else {
			op1 = GETWORD(&seg[offset]);
			temp = ++op1;
			PUTWORD(&seg[offset],(WORD)temp);
		    }
		    flags = SIGNw | IS_CF_SET | ZEROw | OVFLOWw(op1) | AUXCARRY | PARITY; 
		    break;
		case DEC:
		    if (MOD_REG) {
			op1 = REGW(rm)--;
			temp = REGW(rm);
		    }
		    else {
			op1 = GETWORD(&seg[offset]);
			temp = --op1;
			PUTWORD(&seg[offset],(WORD)temp);
		    }
		    flags = SIGNw | IS_CF_SET | ZEROw | OVFLOWw(op1) | AUXCARRY | PARITY; 
		    break;
		case 2:	    /* CALL near */
		    PUSHWORD(IP-cs+1);
		    IP = cs +
			(((MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]))
				& 0xffff);
		    IP--;
		    break;
		case 3:	    /* CALL far */
		    PUSHWORD(_cs);
		    ip = IP - cs + 1;
		    PUSHWORD(ip);
		    _ip = GETWORD(&seg[offset]);
		    _sel = GETWORD(&seg[offset+2]);
	    	    transfer_magic = (WORD)GetSelectorType(_sel);
	 	    if (transfer_magic != TRANSFER_CODE16) {

			SEGIMAGE *lpSegImage;
			UINT ord;

			FillEnv;
			if (transfer_magic == TRANSFER_CALLBACK) {
			    ord = _ip >> 3;
			    lpSegImage = &((SEGIMAGE *)
				(*(long *)(GetPhysicalAddress(_sel))))[ord];
			    targ = (LONGPROC)(lpSegImage->targ);
			    conv = (LONGPROC)(lpSegImage->conv);
		    	    LOGSTR((LF_INTERFACE,
				"do_ext: sel %x, ord %x - %s\n",
				_sel,ord,GetProcName(_sel,ord)));
		    	    (conv)(env,targ);
			    GetEnv;
		    	    LOGSTR((LF_INTERFACE,
					"do_ext: AX=%4.4x DX=%4.4x\n",AX,DX));
			    IP = cs + ip - 1;
			}
			else if (transfer_magic == TRANSFER_BINARY) {
			    ord = _ip >> 3;
			    lpSegImage = &((SEGIMAGE *)
				(*(long *)(GetPhysicalAddress(_sel))))[ord];
			    targ = (LONGPROC)(lpSegImage->targ);
			    conv = (LONGPROC)(lpSegImage->conv);
			    LOGSTR((LF_INTERFACE,
			"do_ext: calling binary thunk %x:%x\n",_sel,_ip));
			    (conv)(env,targ);	
			    GetEnv;
		    	    LOGSTR((LF_INTERFACE,
					"do_ext: AX=%4.4x DX=%4.4x\n",AX,DX));
			    IP = cs + ip - 1;
			}
			else {
			if (transfer_magic == TRANSFER_DATA)
			    invoke_data(env);
			else
			    return;
			}
	    	    }
	    	    else {
			_cs = _sel;
			SET_SEGREG(cs,_cs);
			IP = cs + _ip - 1;
	    	    }
	    	    break;
		case 4:	    /* JUMP near */
		    ip = (MOD_REG) ? REGW(rm) : GETWORD(&seg[offset]);
		    IP = cs + ip - 1;
		    break;
		case 5:	    /* JUMP far */
		    _sel = GETWORD(&seg[offset+2]);
		    _ip = GETWORD(&seg[offset]);
	    	    transfer_magic = (WORD)GetSelectorType(_sel);
		    if (transfer_magic != TRANSFER_CODE16) {

			SEGIMAGE *lpSegImage;
			UINT ord;

			FillEnv;
			if (transfer_magic == TRANSFER_CALLBACK) {
			    ord = _ip >> 3;
			    lpSegImage = &((SEGIMAGE *)
				(*(long *)(GetPhysicalAddress(_sel))))[ord];
			    targ = (LONGPROC)(lpSegImage->targ);
			    conv = (LONGPROC)(lpSegImage->conv);
			    LOGSTR((LF_INTERFACE,
					"do_ext: jmp far mod %x, ord %x\n",
				_sel>>3,ord));
			    (conv)(env,targ);	
			}
			else if (transfer_magic == TRANSFER_BINARY) {
			    ord = _ip >> 3;
			    lpSegImage = &((SEGIMAGE *)
				(*(long *)(GetPhysicalAddress(_sel))))[ord];
			    targ = (LONGPROC)(lpSegImage->targ);
			    conv = (LONGPROC)(lpSegImage->conv);
			    LOGSTR((LF_INTERFACE,
				"do_ext: jmp far binary thunk %x:%x\n",
				_sel,_ip));
			    (conv)(env,targ);	
			}
			else {
			if (transfer_magic == TRANSFER_DATA)
			    invoke_data(env);
			else
			    return;
			}
	    	    }
	    	    else {
			_cs = _sel;
			SET_SEGREG(cs,_cs);
			IP = cs + _ip - 1;
	    	    }
	    	    break;
		case 6:	/* PUSHmw  */
		    ss[--SP] = seg[offset+1];
		    ss[--SP] = seg[offset];
		    break;
		default:
		    break;
	    }
	    break;

#ifdef FP87 /* 80x87 emulation stuff by Jerzy */
        case FADDm32r_sti:
            fpregs[fpstt] += (MOD_MEM)?  GET32REAL(m32r,&seg[offset]):
                             /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            break;    
        case FMULm32r_sti:
            fpregs[fpstt] *= (MOD_MEM)?  GET32REAL(m32r,&seg[offset]):
                             /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            break;    
        case FCOMm32r_sti:
            fpsrcop = (MOD_MEM)? GET32REAL(m32r,&seg[offset]):
                      /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            break;
        case FCOMPm32r_sti:
            fpsrcop = (MOD_MEM)? GET32REAL(m32r,&seg[offset]):
                      /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            fpstt++;  fpstt &= 0x7;
            break;
        case FSUBm32r_sti:
            fpsrcop = (MOD_MEM)? GET32REAL(m32r,&seg[offset]):
                      /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            fpregs[fpstt] -= fpsrcop;
            break;
        case FSUBRm32r_sti:
            fpsrcop = (MOD_MEM)? GET32REAL(m32r,&seg[offset]):
                      /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            fpregs[fpstt] = fpsrcop - fpregs[fpstt];
            break;
        case FDIVm32r_sti:
            fpsrcop = (MOD_MEM)? GET32REAL(m32r,&seg[offset]):
                      /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            fpregs[fpstt] /= fpsrcop;
            break;
        case FDIVRm32r_sti:
            fpsrcop = (MOD_MEM)? GET32REAL(m32r,&seg[offset]):
                      /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            fpregs[fpstt] = fpsrcop / fpregs[fpstt];
            break;
        case FLDm32r_sti:
            fpsrcop = (MOD_MEM)? GET32REAL(m32r,&seg[offset]):
                      /*MOD_REG*/ fpregs[(fpstt+rm)&0x7];
            fpstt--;  fpstt &= 0x7;
            fpregs[fpstt] = fpsrcop;
            break;
        case FXCH:
            fptemp = fpregs[(fpstt+rm)&0x7];
			fpregs[(fpstt+rm)&0x7] = fpregs[fpstt];
			fpregs[fpstt] = fptemp;
            break;
        case FSTm32r_FNOP:
            if ( MOD_MEM ) /* FSTm32r */ {
                m32r = fpregs[fpstt];
                STORE32REAL(&seg[offset],m32r);
            }
            /* else FNOP, do nothing */
            break;
        case FSTPm32r:
            m32r = fpregs[fpstt];
            STORE32REAL(&seg[offset],m32r);
            fpstt++;  fpstt &= 0x7;
            break;
        case FD9SLASH4:
            if ( MOD_MEM ) /*FLDENV*/ {
                fpus = GET16INT(seg + offset + 2); /* 14-byte env-record */
                fpstt = (fpus>>11) & 0x7;
                fpuc = GET16INT(seg + offset);
                break;
            }
            switch( modrm ) {
              case FABS:
                if ( fpregs[fpstt] < 0.0 )  fpregs[fpstt] = -fpregs[fpstt];
                break;
              case FCHS:
                fpregs[fpstt] = -fpregs[fpstt];
                break;
              case FTST:
                fpsrcop = 0.0;
                fpus &= (~0x4500);   /* (C3,C2,C0) <-- 000 */
                if ( fpregs[fpstt] < fpsrcop )
                    fpus |= 0x100;   /* (C3,C2,C0) <-- 001 */
                else if ( fpregs[fpstt] == fpsrcop )
                    fpus |= 0x4000;  /* (C3,C2,C0) <-- 100 */
                /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
                /* else ( not comparable ) fpus |= 0x4500 */
                break;
              case FXAM:
                fpuc &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
                if ( fpregs[fpstt] < 0.0 )
                     fpuc |= 0x200; /* C1 <-- 1 */
                expdif = EXPONENT(&fpregs[fpstt]);
                if ( expdif == 0x7ff ) {
                    i64hi = *((int *)&fpregs[fpstt]) & 0xfffff;
                    i64lo = *(((int *)&fpregs[fpstt]) + 1);
                    fpuc |= (i64hi == 0 && i64lo == 0)?
                                0x500 /*Infinity*/: 0x100 /*NaN*/;
                }
				else if ( expdif == 0x0 ) {
                    i64hi = *((int *)&fpregs[fpstt]) & 0xfffff;
                    i64lo = *(((int *)&fpregs[fpstt]) + 1);
                    fpuc |= (i64hi == 0 && i64lo == 0)?
                                0x4000 /*Zero*/: 0x4400 /*Denormal*/;
                }
                break;
            }
            break;
        case FLDCONST:
            if ( MOD_MEM ) /*FLDCW*/ {
                fpuc = GET16INT(&seg[offset]);
                /* NOT FULLY IMPLEMENTED YET!!! (requires a sys call) */
                break;
            }
            switch( modrm ) {
              case FLD1:
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = 1.0;
                break;
              case FLDL2T:
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = DPLOG2_10;
                break;
              case FLDL2E:
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = DPLOG2_E;
                break;
              case FLDPI:
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = DPPI;
                break;
              case FLDLG2:
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = DPLOG10_2;
                break;
              case FLDLN2:
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = DPLOGE_2;
                break;
              case FLDZ:
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = 0.0;
                break;
            }
            break;
        case FD9SLASH6:
            if ( MOD_MEM ) /*FSTENV*/ {
                fpus &= (~0x3800);
                fpus |= (fpstt&0x7)<<11;
                STORE16INT( (seg+offset+2), fpus);  /* 14-byte env-record */
                STORE16INT( (seg+offset), fpuc);
                break;
            }
            switch( modrm ) {
              case F2XM1:
                fpregs[fpstt] = pow(2.0,fpregs[fpstt]) - 1.0; 
                break;
              case FYL2X:
                fptemp = log(fpregs[fpstt]) / log(2.0); /* log2(ST) */
                fpregs[(fpstt+1)&0x7] *= fptemp;
                fpstt++; fpstt &= 0x7;
                break;
              case FPTAN:
                fpregs[fpstt] = tan(fpregs[fpstt]);
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = 1.0;
                fpus &= (~0x400);  /* C2 <-- 0 */
                /* the above code is for  |arg| < 2**52 only */
                break;
              case FPATAN:
                fpregs[(fpstt+1)&0x7] = atan2(fpregs[fpstt+1],fpregs[fpstt]);
                fpstt++; fpstt &= 0x7;
                break;
              case FXTRACT:
                fpsrcop = fpregs[fpstt];
                expdif = EXPONENT(&fpregs[fpstt]) - 1023 /*DP exponent bias*/;
                fpregs[fpstt] = expdif;
                fpstt--;  fpstt &= 0x7;
                BIASEXPONENT(&fpsrcop);
                fpregs[fpstt] = fpsrcop;
                break;
              case FPREM1:
                expdif = EXPONENT(&fpregs[fpstt]) - 
                         EXPONENT(&fpregs[(fpstt+1)&0x7]);
                if ( expdif < 53 ) {
                    fpregs[fpstt] = fmod(fpregs[fpstt],fpregs[(fpstt+1)&0x7]);
                    fpus &= (~0x400);  /* C2 <-- 0 */
                    /* (C0,C1,C3) <-- b0..b2 of the double (ST/ST(1)) ???*/
                }
                else {
                    fpus |= 0x400;  /* C2 <-- 1 */
                    fptemp = pow(2.0, ((double)(expdif-50)) );
                    fpsrcop = (fpregs[fpstt] / fpregs[(fpstt+1)&0x7]) / fptemp;
                    /* fpsrcop = integer obtained by rounding to the nearest */
                    fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
                                  floor(fpsrcop): ceil(fpsrcop);
                    fpregs[fpstt] = fpregs[fpstt] - 
                                    fpregs[(fpstt+1)&0x7] * fpsrcop * fptemp;
                }
                break;
              case FDECSTP:
                fpstt--; fpstt &= 0x7;
                break;
              case FINCSTP:
                fpstt++; fpstt &= 0x7;
                break;
            }
            break;
        case FD9SLASH7:
            if ( MOD_MEM ) /*FSTCW*/ {
                STORE16INT(&seg[offset],fpuc);
                break;
            }
            switch( modrm ) {
              case FPREM:
                expdif = EXPONENT(&fpregs[fpstt]) - 
                         EXPONENT(&fpregs[(fpstt+1)&0x7]);
                if ( expdif < 53 ) {
                    fpregs[fpstt] = fmod(fpregs[fpstt],fpregs[(fpstt+1)&0x7]);
                    fpus &= (~0x400);  /* C2 <-- 0 */
                    /* (C0,C1,C3) <-- b0..b2 of the double (ST/ST(1)) ???*/
                }
                else {
                    fpus |= 0x400;  /* C2 <-- 1 */
                    fptemp = pow(2.0, ((double)(expdif-50)) );
                    fpsrcop = (fpregs[fpstt] / fpregs[(fpstt+1)&0x7]) / fptemp;
                    /* fpsrcop = integer obtained by chopping */
                    fpsrcop = (fpsrcop < 0.0)?
                                  -(floor(fabs(fpsrcop))): floor(fpsrcop);
                    fpregs[fpstt] = fpregs[fpstt] - 
                                    fpregs[(fpstt+1)&0x7] * fpsrcop * fptemp;
                }
                break;
              case FYL2XP1:
                fptemp = log(fpregs[fpstt]+1.0) / log(2.0); /* log2(ST+1.0) */
                fpregs[(fpstt+1)&0x7] *= fptemp;
                fpstt++; fpstt &= 0x7;
                break;
              case FSQRT:
                fpregs[fpstt] = sqrt(fpregs[fpstt]);
                break;
              case FSINCOS:
                fpsrcop = fpregs[fpstt];
                fpregs[fpstt] = sin(fpsrcop);
                fpstt--; fpstt &= 0x7;
                fpregs[fpstt] = cos(fpsrcop);
                fpus &= (~0x400);  /* C2 <-- 0 */
                /* the above code is for  |arg| < 2**53 only */
                break;
              case FRNDINT:
                fpsrcop = fpregs[fpstt];
                if ( (fpuc&0xc00) == 0xc00 ) /*(Chop) Truncate towards zero*/ {
                    if ( fpsrcop < 0.0 )
                         fpregs[fpstt] = -(floor(fabs(fpsrcop)));
                    else fpregs[fpstt] = floor(fpsrcop);
                }
                else if ( (fpuc&0xc00) == 0x0 ) /*Round to the nearest*/ {
                    if ( (fpsrcop-floor(fpsrcop)) < (ceil(fpsrcop)-fpsrcop) )
                         fpregs[fpstt] = floor(fpsrcop);
                    else fpregs[fpstt] = ceil(fpsrcop);
                }
                else if ( (fpuc&0xc00) == 0x400 ) /*Round down (toward -INF)*/
                    fpregs[fpstt] = floor(fpsrcop);
                else  /*Round up (toward +INF)*/
                    fpregs[fpstt] = ceil(fpsrcop);
                break;
              case FSCALE:
                fpsrcop = 2.0; 
                fpregs[fpstt] *= pow(fpsrcop,fpregs[(fpstt+1)&0x7]); 
                break;
              case FSIN:
                fpregs[fpstt] = sin(fpregs[fpstt]);
                fpus &= (~0x400);  /* C2 <-- 0 */
                /* the above code is for  |arg| < 2**53 only */
                break;
              case FCOS:
                fpregs[fpstt] = cos(fpregs[fpstt]);
                fpus &= (~0x400);  /* C2 <-- 0 */
                /* the above code is for  |arg5 < 2**63 only */
                break;
            }
            break;
        case FADDm32i:
            fpregs[fpstt] += GET32INT(&seg[offset]);
            break;
        case FMULm32i:
            fpregs[fpstt] *= GET32INT(&seg[offset]);
            break;
        case FICOMm32i:
            fpsrcop = GET32INT(&seg[offset]);
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            break;
        case FICOMPm32i:
            fpsrcop = GET32INT(&seg[offset]);
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            fpstt++;  fpstt &= 0x7;
            break;
        case FADDm64r_tosti:
            if ( MOD_MEM )
                 fpregs[fpstt] += GET64REAL(fptemp,&seg[offset]);
            else fpregs[(fpstt+rm)&0x7] += fpregs[fpstt];
            break;    
        case FMULm64r_tosti:
            if ( MOD_MEM )
                 fpregs[fpstt] *= GET64REAL(fptemp,&seg[offset]);
            else fpregs[(fpstt+rm)&0x7] *= fpregs[fpstt];
            break;    
        case FCOMm64r:
            fpsrcop = GET64REAL(fptemp,&seg[offset]);
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            break;
        case FCOMPm64r:
            fpsrcop = GET64REAL(fptemp,&seg[offset]);
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            fpstt++;  fpstt &= 0x7;
            break;
        case FISUBm32i:
            fpsrcop = GET32INT(&seg[offset]);
            fpregs[fpstt] /= fpsrcop;
			break;
        case FISUBRm32i_FUCOMPPst1:
            if ( MOD_MEM ) {
                fpsrcop = GET32INT(&seg[offset]);
                fpregs[fpstt] = fpsrcop - fpregs[fpstt];
            }
            else /* FUCOMPPst1 */ {
                fpsrcop = fpregs[(fpstt+1)&0x7];
                fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
                if ( fpregs[fpstt] < fpsrcop )
                    fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
                else if ( fpregs[fpstt] == fpsrcop )
                    fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
                /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
                /* else ( not comparable ) fpus |= 0x4500 */
                fpstt++;  fpstt &= 0x7;
                fpstt++;  fpstt &= 0x7;
            }
            break;
        case FIDIVm32i:
            fpsrcop = GET32INT(&seg[offset]);
            fpregs[fpstt] /= fpsrcop;
			break;
        case FIDIVRm32i:
            fpsrcop = GET32INT(&seg[offset]);
            fpregs[fpstt] = fpsrcop / fpregs[fpstt];
            break;
        case FILDm32i:
            fpstt--;  fpstt &= 0x7;
            fpregs[fpstt] = GET32INT(&seg[offset]);
            break;
        case FISTm32i:
            fpsrcop = fpregs[fpstt];
            if ( (fpuc&0xc00) == 0xc00 ) /*(Chop) Truncate towards zero*/
                fpsrcop = (fpsrcop<0.0)? -floor(fabs(fpsrcop)): floor(fpsrcop);
            else if ( (fpuc&0xc00) == 0x0 ) /*Round to the nearest*/
                fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
                              floor(fpsrcop): ceil(fpsrcop);
            else if ( (fpuc&0xc00) == 0x400 ) /*Round down (toward -INF)*/
                fpsrcop = floor(fpsrcop);
            else  /*Round up (toward +INF)*/
                fpsrcop = ceil(fpsrcop);
            m32i = fpsrcop;
            STORE32INT(&seg[offset],m32i);
            break;
        case FISTPm32i:
            fpsrcop = fpregs[fpstt];
            if ( (fpuc&0xc00) == 0xc00 ) /*(Chop) Truncate towards zero*/
                fpsrcop = (fpsrcop<0.0)? -floor(fabs(fpsrcop)): floor(fpsrcop);
            else if ( (fpuc&0xc00) == 0x0 ) /*Round to the nearest*/
                fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
                              floor(fpsrcop): ceil(fpsrcop);
            else if ( (fpuc&0xc00) == 0x400 ) /*Round down (toward -INF)*/
                fpsrcop = floor(fpsrcop);
            else  /*Round up (toward +INF)*/
                fpsrcop = ceil(fpsrcop);
            m32i = fpsrcop;
            STORE32INT(&seg[offset],m32i);
            fpstt++;  fpstt &= 0x7;
            break;
        case FLDm80r:
            LD80R(&fpregs[fpstt],(seg+offset))
            break;
        case FSTPm80r:
            ST80R((seg+offset),&fpregs[fpstt])
            fpstt++;  fpstt &= 0x7;
            break;
        case FRSTORm94B_FINIT_FCLEX:
            fpus = 0x0; /* C0..C3 cleared, stack_top = R0, no exceptions set */
            if ( MOD_MEM ) {
                fpuc = GET16INT(seg + offset);
                fpus = GET16INT(seg + offset + 2); /* 14-byte env-record */
                fpstt = (fpus>>11) & 0x7;
                for ( i16 = 0;  i16 < 8;  i16++ ) {
                    LD80R( &fpregs[(fpstt+i16)&0x7], (seg+offset+14+i16*10));
                }
            }
            else if ( modrm == 0xe3 ) /*FINIT*/ {
                fpus = 0;  fpstt = 0;
                fpuc = 0x37f;
            }
            else if ( modrm == 0xe2 ) /*FCLEX*/ {
                fpus &= 0x7f00;
            }
            break;
        case FSUBm64r_FSUBRfromsti:
            if ( MOD_MEM ) {
                 fpregs[fpstt] -= GET64REAL(fptemp,&seg[offset]);
            }
            else fpregs[(fpstt+rm)&0x7] -= fpregs[fpstt];
            break;
        case FSUBRm64r_FSUBfromsti:
            if ( MOD_MEM ) {
                 fpregs[fpstt] = GET64REAL(fptemp,&seg[offset]) -fpregs[fpstt];
            }
            else fpregs[(fpstt+rm)&0x7] = fpregs[fpstt]-fpregs[(fpstt+rm)&0x7];
            break;
        case FDIVm64r_FDIVRtosti:
            if ( MOD_MEM ) {
                 fpregs[fpstt] /= GET64REAL(fptemp,&seg[offset]);
            }
            else fpregs[(fpstt+rm)&0x7] /= fpregs[fpstt];
            break;
        case FDIVRm64r_FDIVtosti:
            if ( MOD_MEM ) {
                 fpregs[fpstt] = GET64REAL(fptemp,&seg[offset]) /fpregs[fpstt];
            }
            else fpregs[(fpstt+rm)&0x7] = fpregs[fpstt]/fpregs[(fpstt+rm)&0x7];
            break;
        case FLDm64r_FFREE:
            if ( MOD_MEM ) {
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = GET64REAL(fptemp,&seg[offset]);
            }
            /* else FFREE, do nothing */
            break;
        case FSTm64r_sti:
            if ( MOD_MEM ) {
                 fptemp = fpregs[fpstt];
                 STORE64REAL(&seg[offset],fptemp);
            }
            else fpregs[(fpstt+rm)&0x7] = fpregs[fpstt];
            break;
        case FSTPm64r_sti:
            if ( MOD_MEM ) {
                 fptemp = fpregs[fpstt];
                 STORE64REAL(&seg[offset],fptemp);
            }
            else fpregs[(fpstt+rm)&0x7] = fpregs[fpstt];
            fpstt++;  fpstt &= 0x7;
            break;
        case FUCOMsti:
            fpsrcop = fpregs[(fpstt+rm)&0x7];
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            break;
        case FUCOMPsti:
            fpsrcop = fpregs[(fpstt+rm)&0x7];
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            fpstt++;  fpstt &= 0x7;
            break;
        case FSAVEm94B:
            STORE16INT( (seg+offset), fpuc);
            fpus |= (fpstt&0x7)<<11;
            STORE16INT( (seg+offset+2), fpus); /* 14-byte env-record */
            for ( i16 = 0;  i16 < 8;  i16++ ) {
                ST80R( (seg+offset+14+i16*10), &fpregs[(fpstt+i16)&0x7]);
            }
            break;
        case FSTSWm16i:
			STORE16INT(&seg[offset],fpus);
			break;
        case FADDm16i_tostipop:
            if ( MOD_MEM )
                fpregs[fpstt] += GET16INT(&seg[offset]);
            else {
                fpregs[(fpstt+rm)&0x7] += fpregs[fpstt];
                fpstt++; fpstt &= 0x7;
            }
            break;    
        case FMULm16i_tostipop:
            if ( MOD_MEM )
                fpregs[fpstt] *= GET16INT(&seg[offset]);
            else {
                fpregs[(fpstt+rm)&0x7] *= fpregs[fpstt];
                fpstt++; fpstt &= 0x7;
            }
            break;    
        case FICOMPm16i_FCOMPPst1:
            if ( MOD_MEM ) {
                fpsrcop = GET16INT(&seg[offset]);
                fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
                if ( fpregs[fpstt] < fpsrcop )
                    fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
                else if ( fpregs[fpstt] == fpsrcop )
                    fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
                /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
                /* else ( not comparable ) fpus |= 0x4500 */
                fpstt++;  fpstt &= 0x7;
            }
            else /* FCOMPPst1 */ {
                fpsrcop = fpregs[(fpstt+1)&0x7];
                fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
                if ( fpregs[fpstt] < fpsrcop )
                    fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
                else if ( fpregs[fpstt] == fpsrcop )
                    fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
                /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
                /* else ( not comparable ) fpus |= 0x4500 */
                fpstt++;  fpstt &= 0x7;
                fpstt++;  fpstt &= 0x7;
            }
            break;
        case FICOMm16i:
            fpsrcop = GET16INT(&seg[offset]);
            fpus &= (~0x4500);	/* (C3,C2,C0) <-- 000 */
            if ( fpregs[fpstt] < fpsrcop )
                fpus |= 0x100;	/* (C3,C2,C0) <-- 001 */
            else if ( fpregs[fpstt] == fpsrcop )
                fpus |= 0x4000;	/* (C3,C2,C0) <-- 100 */
            /* else if ( fpregs[fpstt] > fpsrcop )  do nothing */
            /* else ( not comparable ) fpus |= 0x4500 */
            break;
        case FISUBm16i_FSUBRPfromsti:
            if ( MOD_MEM )
                fpregs[fpstt] -= GET16INT(&seg[offset]);
            else {
                fpregs[(fpstt+rm)&0x7] -= fpregs[fpstt];
                fpstt++;  fpstt &= 0x7;
            }
            break;
        case FISUBRm16i_FSUBPfromsti:
            if ( MOD_MEM )
                fpregs[fpstt] = GET16INT(&seg[offset]) - fpregs[fpstt];
            else {
                fpregs[(fpstt+rm)&0x7] = fpregs[fpstt] -fpregs[(fpstt+rm)&0x7];
                fpstt++;  fpstt &= 0x7;
            }
            break;
        case FIDIVm16i_FDIVRPtosti:
            if ( MOD_MEM )
                fpregs[fpstt] /= GET16INT(&seg[offset]);
            else {
                fpregs[(fpstt+rm)&0x7] /= fpregs[fpstt];
                fpstt++;  fpstt &= 0x7;
            }
            break;
        case FIDIVRm16i_FDIVPtosti:
            if ( MOD_MEM )
                fpregs[fpstt] = GET16INT(&seg[offset]) / fpregs[fpstt];
            else {
                fpregs[(fpstt+rm)&0x7] = fpregs[fpstt] /fpregs[(fpstt+rm)&0x7];
                fpstt++;  fpstt &= 0x7;
            }
            break;
        case FILDm16i:
            fpstt--;  fpstt &= 0x7;
            fpregs[fpstt] = GET16INT(&seg[offset]);
			break;
        case FISTm16i:
            fpsrcop = fpregs[fpstt];
            if ( (fpuc&0xc00) == 0xc00 ) /*(Chop) Truncate towards zero*/
                fpsrcop = (fpsrcop<0.0)? -floor(fabs(fpsrcop)): floor(fpsrcop);
            else if ( (fpuc&0xc00) == 0x0 ) /*Round to the nearest*/
                fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
                              floor(fpsrcop): ceil(fpsrcop);
            else if ( (fpuc&0xc00) == 0x400 ) /*Round down (toward -INF)*/
                fpsrcop = floor(fpsrcop);
            else  /*Round up (toward +INF)*/
                fpsrcop = ceil(fpsrcop);
            i16 = fpsrcop;
            STORE16INT(&seg[offset],i16);
			break;
        case FISTPm16i:
            fpsrcop = fpregs[fpstt];
            if ( (fpuc&0xc00) == 0xc00 ) /*(Chop) Truncate towards zero*/
                fpsrcop = (fpsrcop<0.0)? -floor(fabs(fpsrcop)): floor(fpsrcop);
            else if ( (fpuc&0xc00) == 0x0 ) /*Round to the nearest*/
                fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
                              floor(fpsrcop): ceil(fpsrcop);
            else if ( (fpuc&0xc00) == 0x400 ) /*Round down (toward -INF)*/
                fpsrcop = floor(fpsrcop);
            else  /*Round up (toward +INF)*/
                fpsrcop = ceil(fpsrcop);
            i16 = fpsrcop;
            STORE16INT(&seg[offset],i16);
            fpstt++;  fpstt &= 0x7;
			break;
        case FBLDm80dec_FSTSWax:
            if ( MOD_MEM ) /*FBLDm80dec*/ {
                /* in this code, seg/m32i will be used as temporary ptr/int */
                seg += offset + 8;
                if ( *seg-- != 0 || (*seg & 0xf0) != 0 ) /* d15..d17 non-zero*/
                    fprintf(stderr,
                        "This BCD number exceeds the range of DOUBLE REAL!\n");
                m32i = *seg--;  /* <-- d14 */
                m32i = MUL10(m32i) + (*seg >> 4);  /* <-- val * 10 + d13 */
                m32i = MUL10(m32i) + (*seg & 0xf); /* <-- val * 10 + d12 */
                seg--;
                m32i = MUL10(m32i) + (*seg >> 4);  /* <-- val * 10 + d11 */
                m32i = MUL10(m32i) + (*seg & 0xf); /* <-- val * 10 + d10 */
                seg--;
                m32i = MUL10(m32i) + (*seg >> 4);  /* <-- val * 10 + d9 */
                m32i = MUL10(m32i) + (*seg & 0xf); /* <-- val * 10 + d8 */
                seg--;
                fpsrcop += ((double)m32i) * 100000000.0;
                m32i = (*seg >> 4);  /* <-- d7 */
                m32i = MUL10(m32i) + (*seg & 0xf); /* <-- val * 10 + d6 */
                seg--;
                m32i = MUL10(m32i) + (*seg >> 4);  /* <-- val * 10 + d5 */
                m32i = MUL10(m32i) + (*seg & 0xf); /* <-- val * 10 + d4 */
                seg--;
                m32i = MUL10(m32i) + (*seg >> 4);  /* <-- val * 10 + d3 */
                m32i = MUL10(m32i) + (*seg & 0xf); /* <-- val * 10 + d2 */
                seg--;
                m32i = MUL10(m32i) + (*seg >> 4);  /* <-- val * 10 + d1 */
                m32i = MUL10(m32i) + (*seg & 0xf); /* <-- val * 10 + d0 */
                fpsrcop += ((double)m32i);
                if ( *(seg+9) & 0x80 )  fpsrcop = -fpsrcop;
                fpstt--;  fpstt &= 0x7;
                fpregs[fpstt] = fpsrcop;
            }
			else AX = fpus;
			break;
        case FILDm64i:
			i64lo = GET32INT((seg+offset));
			i64hi = GET32INT((seg+offset+4));
            fpstt--;  fpstt &= 0x7;
			signed_temp = 0;
			if ( i64hi & 0x80000000 ) {
                signed_temp = -1;
                i64lo = ~i64lo;
                i64hi = ~i64hi;
                if ( i64lo == 0xffffffff )  i64hi += 1;
                i64lo += 1;
            }
			if ( i64hi & 0xffe00000 )
                fprintf(stderr,"This 64-bit INT exceeds range of DOUBLE R!\n");
            fptemp = 4294967296.0 * ((double)i64hi) + ((double)i64lo);
            if ( signed_temp < 0 )  fptemp = -fptemp;
            fpregs[fpstt] = fptemp;
			break;
        case FBSTPm80dec:
            fpsrcop = fpregs[fpstt];
            if ( (fpuc&0xc00) == 0xc00 ) /*(Chop) Truncate towards zero*/
                fpsrcop = (fpsrcop<0.0)? -floor(fabs(fpsrcop)): floor(fpsrcop);
            else if ( (fpuc&0xc00) == 0x0 ) /*Round to the nearest*/
                fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
                              floor(fpsrcop): ceil(fpsrcop);
            else if ( (fpuc&0xc00) == 0x400 ) /*Round down (toward -INF)*/
                fpsrcop = floor(fpsrcop);
            else  /*Round up (toward +INF)*/
                fpsrcop = ceil(fpsrcop);
            if ( fpsrcop < 0.0 ) {
                 *(seg+offset+9) = 0xff;
                 fpsrcop = -fpsrcop;
            }
			else *(seg+offset+9) = 0x0;
            for ( seg += (offset + 8), i16 = 0;  i16 < 9;  i16++ ) *seg-- = 0;
            for ( seg++;  fpsrcop != 0.0;  seg++ ) {
                fptemp = floor(fpsrcop/10.0);
                i16 = ((int)(fpsrcop - fptemp*10.0));
                if ( fptemp == 0.0 )  { *seg = i16; break; }
                fpsrcop = fptemp;
                fptemp = floor(fpsrcop/10.0);
                *seg = i16 | (((int)(fpsrcop - fptemp*10.0)) << 4);
                fpsrcop = fptemp;
            }
            fpstt++;  fpstt &= 0x7;
			break;
        case FISTPm64i:
            fpsrcop = fpregs[fpstt];
            if ( (fpuc&0xc00) == 0xc00 ) /*(Chop) Truncate towards zero*/
                fpsrcop = (fpsrcop<0.0)? -floor(fabs(fpsrcop)): floor(fpsrcop);
            else if ( (fpuc&0xc00) == 0x0 ) /*Round to the nearest*/
                fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
                              floor(fpsrcop): ceil(fpsrcop);
            else if ( (fpuc&0xc00) == 0x400 ) /*Round down (toward -INF)*/
                fpsrcop = floor(fpsrcop);
            else  /*Round up (toward +INF)*/
                fpsrcop = ceil(fpsrcop);
            signed_temp = 0;
            if ( fpsrcop < 0.0 ) {
                signed_temp = -1;
                fpsrcop = -fpsrcop;
            }
            i64lo = ((unsigned int)fmod(fpsrcop,4294967296.0));
            i64hi = ((unsigned int)fpsrcop/4294967296.0);
            if ( signed_temp < 0 ) {
                i64lo = ~i64lo;
                i64hi = ~i64hi;
                if ( i64lo == 0xffffffff )  i64hi += 1;
                i64lo += 1;
            }
            STORE32INT((seg+offset),i64lo);
            STORE32INT((seg+offset+4),i64hi);
            fpstt++;  fpstt &= 0x7;
			break;
#endif

	default:
	    fprintf(stderr, unknown_msg,"default reg=???",
		opcode,_cs, ip);
	    break;    
	}
    }
	if (!prefix) 
	override_flag = FALSE;
	IP++;

#ifdef DEBUG
		ip = IP - cs;
if (global_debug ) {
printf("\nInstruction count %d, opcode = %x\n",instruction_count,opcode);
printf("ax %04x, bx %04x, cx %04x, dx %04x, si %04x, di %04x, ip %04x\nsp %04x, bp %04x, cs %04x, ss %04x, ds %04x, es %04x\n",    AX,BX,CX,DX,SI,DI,ip,SP,BP,
_cs,_ss,_ds,_es);
printf ("cs - %x\n",cs);
printf("op1 - %x, op2 - %x, temp - %x, flags %x\n\n", op1,op2,temp,flags);
}
#endif
    }
}

#ifdef DEBUG
char *inst[256] = { "ADDbfrm", "ADDwfrm", "ADDbtrm", "ADDwtrm", "ADDbia", 
		"ADDwia", "PUSHes", "POPes", "ORbfrm", "ORwfrm", "ORbtrm", "ORwtrm", 
		"ORbi", "ORwi", "PUSHcs", "TwoByteEscape", "ADCbfrm", "ADCwfrm", 
		"ADCbtrm", "ADCwtrm",
        "ADCbi", "ADCwi", "PUSHss", "POPss", "SBBbfrm", "SBBwfrm", "SBBbtrm",
        "SBBwtrm", "SBBbi", "SBBwi", "PUSHds", "POPds", "ANDbfrm", "ANDwfrm",
        "ANDbtrm", "ANDwtrm", "ANDbi", "ANDwi", "SEGes", "DAA", "SUBbfrm",
        "SUBwfrm", "SUBbtrm", "SUBwtrm", "SUBbi", "SUBwi", "SEGcs", "DAS",
        "XORbfrm", "XORwfrm", "XORbtrm", "XORwtrm", "XORbi", "XORwi", "SEGss",
        "AAA", "CMPbfrm", "CMPwfrm", "CMPbtrm", "CMPwtrm", "CMPbi", "CMPwi",
        "SEGds", "AAS", "INCax", "INCcx", "INCdx", "INCbx", "INCsp", "INCbp",
        "INCsi", "INCdi", "DECax", "DECcx", "DECdx", "DECbx", "DECsp", "DECbp",
        "DECsi", "DECdi", "PUSHax", "PUSHcx", "PUSHdx", "PUSHbx", "PUSHsp",
        "PUSHbp", "PUSHsi", "PUSHdi", "POPax", "POPcx", "POPdx", "POPbx",
        "POPsp", "POPbp", "POPsi", "POPdi", "PUSHA", "POPA", "BOUND", "ARPL",
        "SEGfs", "SEGgs", "OPER32", "ADDR32", "PUSHwi", "IMULwrm",
        "PUSHbi", "IMULbrm", "INSb", "INSw", "OUTSb", "OUTSw", "JO", "JNO",
        "JB_JNAE", "JNB_JAE", "JE_JZ", "JNE_JNZ", "JBE_JNA", "JNBE_JA",
        "JS", "JNS", "JP_JPE", "JNP_JPO", "JL_JNGE", "JNL_JGE", "JLE_JNG",
        "JNLE_JG", "IMMEDbrm", "IMMEDwrm", "IMMEDbrm2", "IMMEDisrm", "TESTbrm",
        "TESTwrm", "XCHGbrm", "XCHGwrm", "MOVbfrm", "MOVwfrm", "MOVbtrm",
        "MOVwtrm", "MOVsrtrm", "LEA", "MOVsrfrm", "POPrm", "NOP", "XCHGcx",
        "XCHGdx", "XCHGbx", "XCHGsp", "XCHGbp", "XCHGsi", "XCHGdi", "CBW",
        "CWD", "CALLl", "WAIT", "PUSHF", "POPF", "SAHF", "LAHF", "MOVmal",
        "MOVmax", "MOValm", "MOVaxm", "MOVSb", "MOVSw", "CMPSb", "CMPSw",
        "TESTbi", "TESTwi", "STOSb", "STOSw", "LODSb", "LODSw", "SCASb",
        "SCASw", "MOVial", "MOVicl", "MOVidl", "MOVibl", "MOViah", "MOVich",
        "MOVidh", "MOVibh", "MOViax", "MOVicx", "MOVidx", "MOVibx", "MOVisp",
        "MOVibp", "MOVisi", "MOVidi", "SHIFTbi", "SHIFTwi", "RETisp", "RET",
        "LES", "LDS", "MOVbirm", "MOVwirm", "ENTER", "LEAVE", "RETlisp", "RETl",
        "INT3", "INT", "INTO", "IRET", "SHIFTb", "SHIFTw", "SHIFTbv", "SHIFTwv",
        "AAM", "AAD", "ILLEGAL", "XLAT", "ESC0", "ESC1", "ESC2", "ESC3", "ESC4",
        "ESC5", "ESC6", "ESC7", "LOOPNZ_LOOPNE", "LOOPZ_LOOPE", "LOOP", "JCXZ",
        "INb", "INw", "OUTb", "OUTw", "CALLd", "JMPd", "JMPld", "JMPsid",
        "INvb", "INvw", "OUTvb", "OUTvw", "LOCK", "ILLEGAL", "REPNE", "REP",
        "HLT", "CMC", "GRP1brm", "GRP1wrm", "CLC", "STC", "CLI", "STI", "CLD",
        "STD", "GRP2brm", "GRP2wrm", };

char *
decode(int opcode, int modrm)
{
	return(inst[opcode]);

}
#endif /* DEBUG */		

#ifdef	AG_DEBUG	/* *AG_DEBUG* */
extern LPOBJHEAD lpModuleHead;
#include	"Module.h"

/* Fill lpBuff with the name of the module that contains selector wSel and
 * return the segment number of the segment referred to by the selector
 * (segment number as in the NE image). nMax is the size of buffer pointed to
 * by lpBuff
 * Returns -1 on error
 */
static WORD
AGGetSegment(WORD wSel, LPSTR lpBuff, int nMax)
{
	register LPOBJHEAD	lpObjHead;
    register LPMODULEINFO lpModuleTmp;
	register WORD	wTmp = wSel >> 3;

	for (lpObjHead = lpModuleHead; lpObjHead->lpObjNext;
		lpObjHead = (LPOBJHEAD)(lpObjHead->lpObjNext)) {
		lpModuleTmp = (LPMODULEINFO)lpObjHead;
		if ((wTmp >=  lpModuleTmp->wSelBase) &&
			(wTmp < (WORD)(lpModuleTmp->wSelBase + lpModuleTmp->wSegCount))) {
			strncpy(lpBuff, lpModuleTmp->lpModuleName, nMax);
			return(wTmp - lpModuleTmp->wSelBase);
		}
	}
	strncpy(lpBuff, "ALLOC", nMax);
	return wSel;
}

/* Prints information from environment ENV, lot better than 'print *env' in 
 * dbx. Would have preffered 'envp' but then the macros wouldn't work
 */
void
print_env(ENV *env)
{
	register int	i, j;
    union _REGS	r;
    WORD	_cs, _es, _ds, _ss, _ip, _flags;
	LPBYTE	cs, ds, ss, es, ip;
	char	cFlags[16];
	LPSTR	lpFlagsSet =   "    ODITSZ A P C";
	LPSTR	lpFlagsUnset = "____oditsz_a_p_c";
	char	cModName1[32];
	char	cModName2[32];

	/* Stuff from env structure */
	_ip = LOWORD(env->trans_addr);
    _cs = HIWORD(env->trans_addr);
    cs = GetPhysicalAddress(_cs);
    _es = env->reg.es;
    es = GetPhysicalAddress(_es);
    _ss = env->reg.ss;
    ss = GetPhysicalAddress(_ss);
    _ds = env->reg.ds;
    ds = GetPhysicalAddress(_ds);
    AX = (WORD)(env->reg.ax);
    BX = (WORD)(env->reg.bx);
    CX = (WORD)(env->reg.cx);
    DX = (WORD)(env->reg.dx);
    SP = (WORD)(env->reg.sp - (DWORD)ss);
    BP = (WORD)(env->reg.bp - (DWORD)ss);
    SI = (WORD)(env->reg.si);
    DI = (WORD)(env->reg.di);
    _flags = (WORD)(env->reg.flags);
    ip = (LPBYTE)(cs + _ip);

	/* Create a flag string */
	strcpy(cFlags, lpFlagsUnset);
	for (i = 0; i < 16; i++) {
		j = _flags & (1 << i);
		if (j)
			cFlags[15 - i] = lpFlagsSet[15 - i];
	}

	/* Print 'em all */
	fprintf(stdout, "AX 0x%04X  BX 0x%04X  CX 0x%04X  DX 0x%04X  SI 0x%04X  DI 0x%04X  BP 0x%04X\n", AX, BX, CX, DX, SI, DI, BP);
	fprintf(stdout, "CS 0x%04X  IP 0x%04X  SS 0x%04X  SP 0x%04X  DS 0x%04X  ES 0x%04X  FL 0x%04X\n", _cs, _ip, _ss, SP, _ds, _es, _flags);
	fprintf(stdout, "Flags: %s\n", cFlags);
	fprintf(stdout, "Physical Address:\n");
	fprintf(stdout, "cs    0x%08X  ss    0x%08X  ds    0x%08X  es    0x%08X\n",
		cs, ss, ds, es);
	fprintf(stdout, "ds_si 0x%08X  ds_di 0x%08X  ds_dx 0x%08X  es_bx 0x%08X\n",
		ds + SI, ds + DI, ds + DX, es + BX);
	fprintf(stdout, "cs_ip 0x%08X  ss_sp 0x%08X  ss_bp 0x%08X\n", 
		ip, env->reg.sp, env->reg.bp);

	fprintf(stdout, "Module and segment numbers:\n");
	fprintf(stdout, "CS 0x%04x(%s)\tDS 0x%04x(%s)\n", 
		AGGetSegment(_cs, cModName1, sizeof(cModName1)), cModName1,
		AGGetSegment(_ds, cModName2, sizeof(cModName2)), cModName2);
	fprintf(stdout, "ES 0x%04x(%s)\tSS 0x%04x(%s)\n", 
		AGGetSegment(_es, cModName1, sizeof(cModName1)), cModName1,
		AGGetSegment(_ss, cModName2, sizeof(cModName2)), cModName2);

	fprintf(stdout, "\n\n");
	fflush(stdout);
}
#endif
