#include <stdio.h>
#include <stdint.h>
//#include <SPIRAM24.h>
//#include <avr/progmem.h>
#include "emu.h"
#include "rom.h"

extern void portout(uint16_t portnum, uint16_t value);
extern uint16_t portin(uint16_t portnum);

extern void readdisk(uint8_t drivenum, uint16_t dstseg, uint16_t dstoff, uint16_t cyl, uint16_t sect, uint16_t head, uint16_t sectcount);
extern void insertdisk();

extern void doirq(uint8_t irqnum);
extern uint8_t nextintr();
extern struct structpic {
  uint8_t imr; //mask register
  uint8_t irr; //request register
  uint8_t isr; //service register
  uint8_t icwstep; //used during initialization to keep track of which ICW we're at
  uint8_t icw[5];
  uint8_t intoffset; //interrupt vector offset
  uint8_t priority; //which IRQ has highest priority
  uint8_t autoeoi; //automatic EOI mode
  uint8_t readmode; //remember what to return on read register from OCW3
  uint8_t enabled;
} i8259;

extern uint8_t curkey;
void intcall86(uint8_t intnum);

uint64_t curtimer, lasttimer, timerfreq;

char *biosfile = NULL;
uint8_t byteregtable[8] = { regal, regcl, regdl, regbl, regah, regch, regdh, regbh };

uint8_t parity[0x100];

_bytewordregs_ regs;

uint16_t segregs[6];
uint8_t opcode, segoverride, reptype, bootdrive, hdcount = 0;
uint16_t savecs, saveip, ip, useseg, oldsp;
uint8_t tempcf, oldcf, cf, pf, af, zf, sf, tf, ifl, df, of, nt, iopriv, mode, reg, rm, msw = 0;
uint16_t oper1, oper2, res16, disp16, temp16, dummy, stacksize, frametemp;
uint8_t oper1b, oper2b, res8, disp8, temp8, nestlev, addrbyte;
uint16_t cr0 = 0, cr1 = 0, cr2 = 0, cr3 = 0;
uint32_t ldtr = 0, gdtr = 0, gdtlimit = 0, idtr = 0, idtlimit = 0;
uint32_t temp1, temp2, temp3, temp4, temp5, temp32, tempaddr32, ea;
int32_t result, speed = 0;
uint32_t totalexec;
uint32_t ips[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint16_t *tempwordptr;

uint8_t vidmode, cgabg, blankattr, vidgfxmode, vidcolor;
uint16_t cursx, cursy, cols, rows, vgapage, cursorposition, cursorvisible;
uint8_t updatedscreen, port3da, port6, portout16;
//uint16_t VGA_SC[0xFF], VGA_CRTC[0xFF], VGA_ATTR[0xFF], VGA_GC[0xFF];
uint32_t videobase, textbase, x, y;

uint8_t debugmode, showcsip, verbose, mouseemu;


extern uint8_t * RAM;
extern uint8_t * LORAM; //LORAM[];

void write86(uint32_t addr32, uint8_t value) {
  if (addr32 < NATIVE_RAM) {
    LORAM[addr32] = value;
    return;
  } 
  else if (addr32 < RAM_SIZE) {
    RAM[addr32] = value;
    return;
  } 
  else if ((addr32 >= 0xB8000) && (addr32 < 0xC0000)) {
    VRAM_write(addr32 - 0xB8000UL, value);
  }
}

#define writew86(addr32,value) {write86((addr32),(uint8_t)(value));write86((addr32)+1,(uint8_t)((uint16_t)(value)>>8));}

uint8_t read86(uint32_t addr32) {
  if (addr32 < NATIVE_RAM) {
    switch (addr32) { //some hardcoded values for the BIOS data area
      case 0x410: //0040:0010 is the equipment word
#ifdef VGA
        return (0x41); //video type (0x41 is VGA/EGA, 0x61 is CGA, 0x31 = MDA)
#else
        return (0x61); //video type (0x41 is VGA/EGA, 0x61 is CGA, 0x31 = MDA)
#endif
      case 0x475: //hard drive count
        return (hdcount);
      default:
        return LORAM[addr32];
    }    
  } 
  else if (addr32 < RAM_SIZE) {
    return RAM[addr32];
  } 
  else if ((addr32 >= 0xB8000) && (addr32 < 0xC0000)) {
    addr32 -= 0xB8000UL;
    return VRAM_read(addr32);
  }
  else if (addr32 >= 0xFE000UL) {
    addr32 -= 0xFE000UL;
    return ROM_READ(BIOS, addr32); //BIOS[addr32];
  }
  else if ((addr32 >= 0xD0000) && (addr32 < 0xD0640)) {
    return net_read_ram(addr32 - 0xD0000);
  }
  else if ((addr32 >= 0xE0000) && (addr32 < 0xE0006)) {
    return net_mac[addr32 - 0xE0000];
  }
#ifdef INCLUDE_ROM_BASIC
  else if ((addr32 >= 0xF6000UL) && (addr32 < 0xFA000UL)) {
    addr32 -= 0xF6000UL;
    return ROM_READ(BASICL, addr32); //BASICL[addr32];
  } else if ((addr32 >= 0xFA000UL) && (addr32 < 0xFE000UL)) {
    addr32 -= 0xFA000UL;
    return ROM_READ(BASICH, addr32); //BASICH[addr32];
  }
#endif
  else return 0;
}



#define readw86(addr32) ((uint16_t)read86((addr32))|((uint16_t)read86((addr32)+1)<<8))

//inline void flag_szp8(uint8_t value) {
#define flag_szp8(value) {\
  if (!(value)) zf = 1; else zf = 0;\
  if ((value) & 0x80) sf = 1; else sf = 0;\
  pf = parity[value];\
}

//inline void flag_szp16(uint16_t value) {
#define flag_szp16(value) {\
  if (!(value)) zf = 1; else zf = 0;\
  if (value & 0x8000) sf = 1; else sf = 0;\
  pf = parity[(uint8_t)value];\
}

//inline void flag_log8(uint8_t value) {
#define flag_log8(value) {\
  flag_szp8(value);\
  cf = 0; of = 0;\
}

//inline void flag_log16(uint16_t value) {
#define flag_log16(value) {\
  flag_szp16(value);\
  cf = 0; of = 0;\
}

//inline void flag_adc8(uint8_t v1, uint8_t v2, uint8_t v3) { //v1 = destination operand, v2 = source operand, v3 = carry flag
#define flag_adc8(v1, v2, v3) {\
  uint16_t dst;\
  dst = (uint16_t)(v1) + (uint16_t)(v2) + (uint16_t)(v3);\
  flag_szp8((uint8_t)dst);\
  if (((dst ^ (v1)) & (dst ^ (v2)) & 0x80) == 0x80) of = 1; else of = 0;\
  if (dst & 0xFF00) cf = 1; else cf = 0;\
  if ((((v1) ^ (v2) ^ dst) & 0x10) == 0x10) af = 1; else af = 0;\
}

//inline void flag_adc16(uint16_t v1, uint16_t v2, uint16_t v3) { //v1 = destination operand, v2 = source operand, v3 = carry flag
#define flag_adc16(v1, v2, v3) {\
  uint32_t dst;\
  dst = (uint32_t)(v1) + (uint32_t)(v2) + (uint32_t)(v3);\
  flag_szp16((uint16_t)dst);\
  if ((((dst ^ (v1)) & (dst ^ (v2))) & 0x8000) == 0x8000) of = 1; else of = 0;\
  if (dst & 0xFFFF0000UL) cf = 1; else cf = 0;\
  if ((((v1) ^ (v2) ^ dst) & 0x10) == 0x10) af = 1; else af = 0;\
}

//inline void flag_add8(uint8_t v1, uint8_t v2) { //v1 = destination operand, v2 = source operand
#define flag_add8(v1, v2) {\
  uint16_t dst;\
  dst = (uint16_t)(v1) + (uint16_t)(v2);\
  flag_szp8((uint8_t)dst);\
  if (dst & 0xFF00) cf = 1; else cf = 0;\
  if (((dst ^ (v1)) & (dst ^ (v2)) & 0x80) == 0x80) of = 1; else of = 0;\
  if ((((v1) ^ (v2) ^ dst) & 0x10) == 0x10) af = 1; else af = 0;\
}

//inline void flag_add16(uint16_t v1, uint16_t v2) { //v1 = destination operand, v2 = source operand
#define flag_add16(v1, v2) {\
  uint32_t dst;\
  dst = (uint32_t)(v1) + (uint32_t)(v2);\
  flag_szp16((uint16_t)dst);\
  if (dst & 0xFFFF0000UL) cf = 1; else cf = 0;\
  if (((dst ^ (v1)) & (dst ^ (v2)) & 0x8000) == 0x8000) of = 1; else of = 0;\
  if ((((v1) ^ (v2) ^ dst) & 0x10) == 0x10) af = 1; else af = 0;\
}

//inline void flag_sbb8(uint8_t v1, uint8_t v2, uint8_t v3) { //v1 = destination operand, v2 = source operand, v3 = carry flag
#define flag_sbb8(v1, v2, v3) {\
  uint16_t dst;\
  uint16_t newv2;\
  newv2 = (uint16_t)(v2) + (uint16_t)(v3);\
  dst = (uint16_t)(v1) - (uint16_t)newv2;\
  flag_szp8((uint8_t)dst);\
  if (dst & 0xFF00) cf = 1; else cf = 0;\
  if ((dst ^ (v1)) & ((v1) ^ newv2) & 0x80) of = 1; else of = 0;\
  if (((v1) ^ newv2 ^ dst) & 0x10) af = 1; else af = 0;\
}

//inline void flag_sbb16(uint16_t v1, uint16_t v2, uint16_t v3) { //v1 = destination operand, v2 = source operand, v3 = carry flag
#define flag_sbb16(v1, v2, v3){\
  uint32_t dst;\
  uint32_t newv2;\
  newv2 = (uint32_t)(v2) + (uint32_t)(v3);\
  dst = (uint32_t)v1 - newv2;\
  flag_szp16((uint16_t)dst);\
  if (dst & 0xFFFF0000UL) cf = 1; else cf = 0;\
  if ((dst ^ (v1)) & (v1 ^ newv2) & 0x8000) of = 1; else of = 0;\
  if (((v1) ^ newv2 ^ dst) & 0x10) af = 1; else af = 0;\
}

//inline void flag_sub8(uint8_t v1, uint8_t v2) { //v1 = destination operand, v2 = source operand
#define flag_sub8(v1, v2) {\
  uint16_t dst;\
  dst = (uint16_t)(v1) - (uint16_t)(v2);\
  flag_szp8((uint8_t)dst);\
  if (dst & 0xFF00) cf = 1; else cf = 0;\
  if ((dst ^ (v1)) & ((v1) ^ (v2)) & 0x80) of = 1; else of = 0;\
  if (((v1) ^ (v2) ^ dst) & 0x10) af = 1; else af = 0;\
}

//inline void flag_sub16(uint16_t v1, uint16_t v2) { //v1 = destination operand, v2 = source operand
#define flag_sub16(v1, v2) {\
  uint32_t dst;\
  dst = (uint32_t)(v1) - (uint32_t)(v2);\
  flag_szp16((uint16_t)dst);\
  if (dst & 0xFFFF0000UL) cf = 1; else cf = 0;\
  if ((dst ^ (v1)) & ((v1) ^ (v2)) & 0x8000) of = 1; else of = 0;\
  if (((v1) ^ (v2) ^ dst) & 0x10) af = 1; else af = 0;\
}

//inline void op_adc8() {
#define op_adc8() {\
  res8 = oper1b + oper2b + cf;\
  flag_adc8(oper1b, oper2b, cf);\
}

//inline void op_adc16() {
#define op_adc16() {\
  res16 = oper1 + oper2 + cf;\
  flag_adc16(oper1, oper2, cf);\
}

//inline void op_add8() {
#define op_add8() {\
  res8 = oper1b + oper2b;\
  flag_add8(oper1b, oper2b);\
}

//inline void op_add16() {
#define op_add16() {\
  res16 = oper1 + oper2;\
  flag_add16(oper1, oper2);\
}

//inline void op_and8() {
#define op_and8() {\
  res8 = oper1b & oper2b;\
  flag_log8(res8);\
}

//inline void op_and16() {
#define op_and16() {\
  res16 = oper1 & oper2;\
  flag_log16(res16);\
}

//inline void op_or8() {
#define op_or8() {\
  res8 = oper1b | oper2b;\
  flag_log8(res8);\
}

//inline void op_or16() {
#define op_or16() {\
  res16 = oper1 | oper2;\
  flag_log16(res16);\
}

//inline void op_xor8() {
#define op_xor8() {\
  res8 = oper1b ^ oper2b;\
  flag_log8(res8);\
}

//inline void op_xor16() {
#define op_xor16() {\
  res16 = oper1 ^ oper2;\
  flag_log16(res16);\
}

//inline void op_sub8() {
#define op_sub8() {\
  res8 = oper1b - oper2b;\
  flag_sub8(oper1b, oper2b);\
}

//inline void op_sub16() {
#define op_sub16() {\
  res16 = oper1 - oper2;\
  flag_sub16(oper1, oper2);\
}

//inline void op_sbb8() {
#define op_sbb8() {\
  res8 = oper1b - (oper2b + cf);\
  flag_sbb8(oper1b, oper2b, cf);\
}

//inline void op_sbb16() {
#define op_sbb16() {\
  res16 = oper1 - (oper2 + cf);\
  flag_sbb16(oper1, oper2, cf);\
}

//inline void modregrm() {
#define modregrm() {\
  addrbyte = getmem8(segregs[regcs], ip); StepIP(1);\
  mode = addrbyte >> 6;\
  reg = (addrbyte >> 3) & 7;\
  rm = addrbyte & 7;\
  switch (mode) {\
    case 0:\
      if (rm == 6) {\
        disp16 = getmem16(segregs[regcs], ip);\
        StepIP(2);\
      }\
      if (((rm == 2) || (rm == 3)) && !segoverride) useseg = segregs[regss]; break;\
    case 1:\
      disp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);\
      if (((rm == 2) || (rm == 3) || (rm == 6)) && !segoverride) useseg = segregs[regss]; break;\
    case 2:\
      disp16 = getmem16(segregs[regcs], ip); StepIP(2);\
      if (((rm == 2) || (rm == 3) || (rm == 6)) && !segoverride) useseg = segregs[regss]; break;\
    default:\
      disp8 = 0; disp16 = 0;\
  }\
  if (mode < 3) getea(rm);\
}

//inline void getea(uint8_t rmval) {
#define getea(rmval) {\
  uint32_t tempea;\
  tempea = 0;\
  switch (mode) {\
    case 0:\
      switch (rmval) {\
        case 0: tempea = regs.wordregs[regbx] + regs.wordregs[regsi]; break;\
        case 1: tempea = regs.wordregs[regbx] + regs.wordregs[regdi]; break;\
        case 2: tempea = regs.wordregs[regbp] + regs.wordregs[regsi]; break;\
        case 3: tempea = regs.wordregs[regbp] + regs.wordregs[regdi]; break;\
        case 4: tempea = regs.wordregs[regsi]; break;\
        case 5: tempea = regs.wordregs[regdi]; break;\
        case 6: tempea = disp16; break;\
        case 7: tempea = regs.wordregs[regbx]; break;\
      } break;\
    case 1: case 2:\
      switch (rmval) {\
        case 0: tempea = regs.wordregs[regbx] + regs.wordregs[regsi] + disp16; break;\
        case 1: tempea = regs.wordregs[regbx] + regs.wordregs[regdi] + disp16; break;\
        case 2: tempea = regs.wordregs[regbp] + regs.wordregs[regsi] + disp16; break;\
        case 3: tempea = regs.wordregs[regbp] + regs.wordregs[regdi] + disp16; break;\
        case 4: tempea = regs.wordregs[regsi] + disp16; break;\
        case 5: tempea = regs.wordregs[regdi] + disp16; break;\
        case 6: tempea = regs.wordregs[regbp] + disp16; break;\
        case 7: tempea = regs.wordregs[regbx] + disp16; break;\
      } break;\
  }\
  ea = useseg;\
  ea <<= 4;\
  ea += (tempea & 0xFFFF);\
}

inline void push(uint16_t pushval) {
  putreg16(regsp, getreg16(regsp) - 2);
  //printf("  %04X:%04X PUSH\n", segregs[regss], getreg16(regsp));
  putmem16(segregs[regss], getreg16(regsp), pushval);
}

inline uint16_t pop() {
  uint16_t tempval;
  //printf("  %04X:%04X POP\n", segregs[regss], getreg16(regsp));
  tempval = getmem16(segregs[regss], getreg16(regsp));
  putreg16(regsp, getreg16(regsp) + 2);
  return (tempval);
}

void reset86() {
  uint16_t i, cnt, bitcount;
  segregs[regcs] = 0xFFFF;
  ip = 0x0000;
  segregs[regss] = 0x0000;
  regs.wordregs[regsp] = 0xFFFE;

  //generate parity lookup table
  for (i = 0; i < 256; i++) {
    bitcount = 0;
    for (cnt = 0; cnt < 8; cnt++)
      bitcount += ((i >> cnt) & 1);
    if (bitcount & 1) parity[i] = 0; else parity[i] = 1;
  }
}

/*inline uint16_t readrm16(uint8_t rmval) {
  if (mode < 3) {
    getea(rmval);
    return (read86(ea) | ((uint16_t)read86(ea + 1) << 8));
  } else {
    return (getreg16(rmval));
  }
}*/

#define readrm16(rmval) ( (mode < 3) ? (read86(ea) | ((uint16_t)read86(ea + 1) << 8)) : (getreg16(rmval)) )

/*inline uint8_t readrm8(uint8_t rmval) {
  if (mode < 3) {
    //getea(rmval);
    return (read86(ea));
  } else {
    return (getreg8(rmval));
  }
}*/

#define readrm8(rmval) ( (mode < 3) ? read86(ea) : getreg8(rmval) )

inline void writerm16(uint8_t rmval, uint16_t value) {
//#define writerm16(rmval, value) {
  if (mode < 3) {\
    /*getea(rmval);*/\
    write86(ea, value & 0xFF);\
    write86(ea + 1, value >> 8);\
  } else {\
    putreg16(rmval, value);\
  }\
}

inline void writerm8(uint8_t rmval, uint8_t value) {
//#define writerm8(rmval, value) {
  if (mode < 3) {\
    /*getea(rmval);*/\
    write86(ea, value);\
  } else {\
    putreg8(rmval, value);\
  }\
}

inline uint8_t op_grp2_8(uint8_t cnt) {
  uint16_t s, oldcf, msb;
  uint8_t shift;
  s = oper1b;
  oldcf = cf;
  switch (reg) {
    case 0: //ROL r/m8
      for (shift = 1; shift <= cnt; shift++) {
        if (s & 0x80) cf = 1; else cf = 0;
        s = s << 1;
        s = s | cf;
      }
      if (cnt == 1) of = cf ^ ((s >> 7) & 1);
      break;

    case 1: //ROR r/m8
      for (shift = 1; shift <= cnt; shift++) {
        cf = s & 1;
        s = (s >> 1) | (cf << 7);
      }
      if (cnt == 1) of = (s >> 7) ^ ((s >> 6) & 1);
      break;

    case 2: //RCL r/m8
      for (shift = 1; shift <= cnt; shift++) {
        oldcf = cf;
        if (s & 0x80) cf = 1; else cf = 0;
        s = s << 1;
        s = s | oldcf;
      }
      if (cnt == 1) of = cf ^ ((s >> 7) & 1);
      break;

    case 3: //RCR r/m8
      for (shift = 1; shift <= cnt; shift++) {
        oldcf = cf;
        cf = s & 1;
        s = (s >> 1) | (oldcf << 7);
      }
      if (cnt == 1) of = (s >> 7) ^ ((s >> 6) & 1);
      break;

    case 4: case 6: //SHL r/m8
      for (shift = 1; shift <= cnt; shift++) {
        if (s & 0x80) cf = 1; else cf = 0;
        s = (s << 1) & 0xFF;
      }
      if ((cnt == 1) && (cf == (s >> 7))) of = 0; else of = 1;
      flag_szp8((uint8_t)s); break;

    case 5: //SHR r/m8
      if ((cnt == 1) && (s & 0x80)) of = 1; else of = 0;
      for (shift = 1; shift <= cnt; shift++) {
        cf = s & 1;
        s = s >> 1;
      }
      flag_szp8((uint8_t)s); break;

    case 7: //SAR r/m8
      for (shift = 1; shift <= cnt; shift++) {
        msb = s & 0x80;
        cf = s & 1;
        s = (s >> 1) | msb;
      }
      of = 0;
      flag_szp8((uint8_t)s); break;

  }
  return (s & 0xFF);
}

inline uint16_t op_grp2_16(uint8_t cnt) {
  uint32_t s, oldcf, msb;
  uint8_t shift;
  s = oper1;
  oldcf = cf;
  switch (reg) {
    case 0: //ROL r/m8
      for (shift = 1; shift <= cnt; shift++) {
        if (s & 0x8000) cf = 1; else cf = 0;
        s = s << 1;
        s = s | cf;
      }
      if (cnt == 1) of = cf ^ ((s >> 15) & 1);
      break;

    case 1: //ROR r/m8
      for (shift = 1; shift <= cnt; shift++) {
        cf = s & 1;
        s = (s >> 1) | (cf << 15);
      }
      if (cnt == 1) of = (s >> 15) ^ ((s >> 14) & 1);
      break;

    case 2: //RCL r/m8
      for (shift = 1; shift <= cnt; shift++) {
        oldcf = cf;
        if (s & 0x8000) cf = 1; else cf = 0;
        s = s << 1;
        s = s | oldcf;
      }
      if (cnt == 1) of = cf ^ ((s >> 15) & 1);
      break;

    case 3: //RCR r/m8
      for (shift = 1; shift <= cnt; shift++) {
        oldcf = cf;
        cf = s & 1;
        s = (s >> 1) | (oldcf << 15);
      }
      if (cnt == 1) of = (s >> 15) ^ ((s >> 14) & 1);
      break;

    case 4: case 6: //SHL r/m8
      for (shift = 1; shift <= cnt; shift++) {
        if (s & 0x8000) cf = 1; else cf = 0;
        s = (uint16_t)(s << 1);
      }
      if ((cnt == 1) && (cf == (s >> 15))) of = 0; else of = 1;
      flag_szp16((uint16_t)s); break;

    case 5: //SHR r/m8
      if ((cnt == 1) && (s & 0x8000)) of = 1; else of = 0;
      for (shift = 1; shift <= cnt; shift++) {
        cf = s & 1;
        s = s >> 1;
      }
      flag_szp16((uint16_t)s); break;

    case 7: //SAR r/m8
      for (shift = 1; shift <= cnt; shift++) {
        msb = s & 0x8000;
        cf = s & 1;
        s = (s >> 1) | msb;
      }
      of = 0;
      flag_szp16((uint16_t)s); break;

  }
  return ((uint16_t)s);
}

inline void op_div8(uint16_t valdiv, uint8_t divisor) {
  if (divisor == 0) {
    intcall86(0);
    return;
  }
  if ((valdiv / (uint16_t)divisor) > 0xFF) {
    intcall86(0);
    return;
  }
  regs.byteregs[regah] = valdiv % (uint16_t)divisor;
  regs.byteregs[regal] = valdiv / (uint16_t)divisor;
}

inline void op_idiv8(uint16_t valdiv, uint8_t divisor) {
  uint16_t s1, s2, d1, d2, sign;
  if (divisor == 0) {
    intcall86(0);
    return;
  }
  s1 = valdiv;
  s2 = divisor;
  sign = (((s1 ^ s2) & 0x8000) != 0);
  s1 = (s1 < 0x8000) ? s1 : (uint16_t)(~s1 + 1);
  s2 = (s2 < 0x8000) ? s2 : (uint16_t)(~s2 + 1);
  d1 = s1 / s2;
  d2 = s1 % s2;
  if (d1 & 0xFF00) {
    intcall86(0);
    return;
  }
  if (sign) {
    d1 = (~d1 + 1) & 0xff;
    d2 = (~d2 + 1) & 0xff;
  }
  regs.byteregs[regah] = d2;
  regs.byteregs[regal] = d1;
}

inline void op_grp3_8() {
  oper1 = signext(oper1b); oper2 = signext(oper2b);
  switch (reg) {
    case 0: case 1: //TEST
      flag_log8(oper1b & getmem8(segregs[regcs], ip)); StepIP(1);
      break;

    case 2: //NOT
      res8 = ~oper1b; break;

    case 3: //NEG
      res8 = (~oper1b) + 1;
      flag_sub8(0, oper1b);
      if (res8 == 0) cf = 0; else cf = 1;
      break;

    case 4: //MUL
      temp1 = (uint32_t)oper1b * (uint32_t)regs.byteregs[regal];
      putreg16(regax, (uint16_t)temp1);
      flag_szp8((uint8_t)temp1);
      if (regs.byteregs[regah]) {
        cf = 1;
        of = 1;
      } else {
        cf = 0;
        of = 0;
      }
      break;

    case 5: //IMUL
      oper1 = signext(oper1b);
      temp1 = signext(regs.byteregs[regal]);
      temp2 = oper1;
      if ((temp1 & 0x80) == 0x80) temp1 = temp1 | 0xFFFFFF00UL;
      if ((temp2 & 0x80) == 0x80) temp2 = temp2 | 0xFFFFFF00UL;
      temp3 = (uint16_t)(temp1 * temp2);
      putreg16(regax, (uint16_t)temp3);
      if (regs.byteregs[regah]) {
        cf = 1;
        of = 1;
      } else {
        cf = 0;
        of = 0;
      }
      break;

    case 6: //DIV
      op_div8(getreg16(regax), oper1b);
      break;

    case 7: //IDIV
      op_idiv8(getreg16(regax), oper1b);
      break;
  }
}

void op_div16(uint32_t valdiv, uint16_t divisor) {
  if (divisor == 0) {
    intcall86(0);
    return;
  }
  if ((valdiv / (uint32_t)divisor) > 0xFFFF) {
    intcall86(0);
    return;
  }
  putreg16(regdx, valdiv % (uint32_t)divisor);
  putreg16(regax, valdiv / (uint32_t)divisor);
}

void op_idiv16(uint32_t valdiv, uint16_t divisor) {
  uint32_t d1, d2, s1, s2, sign;
  if (divisor == 0) {
    intcall86(0);
    return;
  }
  s1 = valdiv;
  s2 = divisor;
  s2 = (s2 & 0x8000) ? (s2 | 0xffff0000UL) : s2;
  sign = (((s1 ^ s2) & 0x80000000UL) != 0);
  s1 = (s1 < 0x80000000UL) ? s1 : ((~s1 + 1) & 0xffffffffUL);
  s2 = (s2 < 0x80000000UL) ? s2 : ((~s2 + 1) & 0xffffffffUL);
  d1 = s1 / s2;
  d2 = s1 % s2;
  if (d1 & 0xFFFF0000UL) {
    intcall86(0);
    return;
  }
  if (sign) {
    d1 = (uint16_t)(~d1 + 1);
    d2 = (uint16_t)(~d2 + 1);
  }
  putreg16(regax, d1);
  putreg16(regdx, d2);
}

inline void op_grp3_16() {
  switch (reg) {
    case 0: case 1: //TEST
      flag_log16(oper1 & getmem16(segregs[regcs], ip)); StepIP(2); break;
    case 2: //NOT
      res16 = ~oper1; break;
    case 3: //NEG
      res16 = (~oper1) + 1;
      flag_sub16(0, oper1);
      if (res16) cf = 1; else cf = 0;
      break;
    case 4: //MUL
      temp1 = (uint32_t)oper1 * (uint32_t)getreg16(regax);
      putreg16(regax, (uint16_t)temp1);
      putreg16(regdx, temp1 >> 16);
      flag_szp16((uint16_t)temp1);
      if (getreg16(regdx)) {
        cf = 1;
        of = 1;
      } else {
        cf = 0;
        of = 0;
      }
      break;
    case 5: //IMUL
      temp1 = getreg16(regax);
      temp2 = oper1;
      if (temp1 & 0x8000) temp1 |= 0xFFFF0000UL;
      if (temp2 & 0x8000) temp2 |= 0xFFFF0000UL;
      temp3 = temp1 * temp2;
      putreg16(regax, (uint16_t)temp3); //into register ax
      putreg16(regdx, temp3 >> 16); //into register dx
      if (getreg16(regdx)) {
        cf = 1;
        of = 1;
      } else {
        cf = 0;
        of = 0;
      }
      break;
    case 6: //DIV
      op_div16(((uint32_t)getreg16(regdx) << 16) + (uint32_t)getreg16(regax), oper1); break;
    case 7: //DIV
      op_idiv16(((uint32_t)getreg16(regdx) << 16) + (uint32_t)getreg16(regax), oper1); break;
  }
}

//inline void op_grp5() {
#define op_grp5() {\
  switch (reg) {\
    case 0: /*INC Ev*/\
      oper2 = 1;\
      tempcf = cf;\
      op_add16();\
      cf = tempcf;\
      writerm16(rm, res16); break;\
    case 1: /*DEC Ev*/\
      oper2 = 1;\
      tempcf = cf;\
      op_sub16();\
      cf = tempcf;\
      writerm16(rm, res16); break;\
    case 2: /*CALL Ev*/\
      push(ip);\
      ip = oper1; break;\
    case 3: /*CALL Mp*/\
      push(segregs[regcs]); push(ip);\
      /*getea(rm);*/\
      ip = (uint16_t)read86(ea) + ((uint16_t)read86(ea + 1) << 8);\
      segregs[regcs] = (uint16_t)read86(ea + 2) + ((uint16_t)read86(ea + 3) << 8); break;\
    case 4: /*JMP Ev*/\
      ip = oper1; break;\
    case 5: /*JMP Mp*/\
      /*getea(rm);*/\
      ip = (uint16_t)read86(ea) + ((uint16_t)read86(ea + 1) << 8);\
      segregs[regcs] = (uint16_t)read86(ea + 2) + ((uint16_t)read86(ea + 3) << 8); break;\
    case 6: /*PUSH Ev*/\
      push(oper1); break;\
  }\
}

uint8_t didintr = 0;

void intcall86(uint8_t intnum) {
  didintr = 1;

  switch (intnum) {
    case 0x10: //video services
      if (regs.byteregs[regah] == 0) { //video mode set
#ifdef ADVANCED_CLIENT
      Serial.write(0xFF);
      Serial.write(0x02);
      Serial.write(regs.byteregs[regal]);
      Serial.write(regs.byteregs[regal]); //duplicate for checksum
      Serial.write(0xFE);
      Serial.write(0x02);
#endif
#ifdef USE_DISPLAY
        if (vidmode != regs.byteregs[regal]) clear_display();
        palettereset();
#endif
        vidmode = regs.byteregs[regal];
        //Serial.print("vidmode = "); Serial.println(vidmode);
      }
      break;
    case 0x13: //disk services
      diskhandler();
      return;
    case 0x19: //bootstrap
      //Serial.println("Bootstrap!");
      if (bootdrive < 255) { //read first sector of boot drive into 07C0:0000 and execute it
        regs.byteregs[regdl] = bootdrive;
        readdisk((bootdrive & 0x80) ? bootdrive - 126 : bootdrive, 0x07C0, 0x0000, 0, 1, 0, 1);
        segregs[regcs] = 0x0000; ip = 0x7C00;
      } else {
        segregs[regcs] = 0xF600;  //start ROM BASIC at bootstrap if requested
        ip = 0x0000;
      }
      return;
    case 0xFC:
      net_handler();
      return;
    default:
      break;
  }

  push(makeflagsword());
  push(segregs[regcs]);
  push(ip);
  segregs[regcs] = getmem16(0, ((uint16_t)intnum << 2) + 2);
  ip = getmem16(0, (uint16_t)intnum << 2);
  ifl = 0;
  tf = 0;
}

uint64_t frametimer = 0, didwhen = 0, didticks = 0;
uint32_t makeupticks = 0;
extern float timercomp;
uint64_t timerticks = 0, realticks = 0;
uint64_t lastcountertimer = 0, counterticks = 10000;

#ifdef PROFILING
uint32_t startmicros, endmicros;
uint32_t instrtime[0x100];
#endif

#ifdef PS2_KEYBOARD
extern uint8_t kbloop;
#endif

extern volatile uint8_t timerTick;

void exec86(uint32_t execloops) {
  uint32_t loopcount;
  uint8_t docontinue;
  static uint16_t firstip, trap_toggle = 0;

  for (loopcount = 0; loopcount < execloops; loopcount++) {
    /*Serial.print(segregs[regcs], HEX);
    Serial.write(':');
    Serial.println(ip, HEX);*/
    #ifdef PS2_KEYBOARD
    if (kbloop) {
      uint32_t msnow;
      msnow = micros();
      while ((micros() - msnow) < 20000) { }
      kbloop = 0;
      ps2poll();
    }
    #endif

    if (timerTick) {
      //printf("isr\n");
      timerTick = 0;
      doirq(0);
    }
    
    if (trap_toggle) intcall86(1);
    if (tf)  trap_toggle = 1;
    else trap_toggle = 0;
    if (!trap_toggle && (ifl && (i8259.irr & (~i8259.imr)))) intcall86(nextintr()); //get next interrupt from the i8259, if any
    reptype = 0; segoverride = 0;
    useseg = segregs[regds]; docontinue = 0;
    firstip = ip;
    while (!docontinue) {
      segregs[regcs] = segregs[regcs] & 0xFFFF; ip = ip & 0xFFFF;
      savecs = segregs[regcs]; saveip = ip;
      opcode = getmem8(segregs[regcs], ip); StepIP(1);

      switch (opcode) {
        //segment prefix check
        case 0x2E: //segment segregs[regcs]
          useseg = segregs[regcs]; segoverride = 1; break;
        case 0x3E: //segment segregs[regds]
          useseg = segregs[regds]; segoverride = 1; break;
        case 0x26: //segment segregs[reges]
          useseg = segregs[reges]; segoverride = 1; break;
        case 0x36: //segment segregs[regss]
          useseg = segregs[regss]; segoverride = 1; break;

        //repetition prefix check
        case 0xF3: //REP/REPE/REPZ
          reptype = 1; break;
        case 0xF2: //REPNE/REPNZ
          reptype = 2; break;
        default:
          docontinue = 1;
          break;
      }
    }
    totalexec++;
    //printf("%04X:%04X %02X\n", segregs[regcs], ip, opcode);
    //if ((segregs[regcs]==0xF000) && (ip < 0xE000)) exit(0);

#ifdef PROFILING
    startmicros = micros();
#endif
    switch (opcode) {
      case 0x0: //00 ADD Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        op_add8();
        writerm8(rm, res8);
        break;
      case 0x1: //01 ADD Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        op_add16();
        writerm16(rm, res16);
        break;
      case 0x2: //02 ADD Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        op_add8();
        putreg8(reg, res8);
        break;
      case 0x3: //03 ADD Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        op_add16();
        putreg16(reg, res16);
        break;
      case 0x4: //04 ADD regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        op_add8();
        regs.byteregs[regal] = res8;
        break;
      case 0x5: //05 ADD eAX Iv
        oper1 = (getreg16(regax)); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        op_add16();
        putreg16(regax, res16);
        break;
      case 0x6: //06 PUSH segregs[reges]
        push(segregs[reges]);
        break;
      case 0x7: //07 POP segregs[reges]
        segregs[reges] = pop();
        break;
      case 0x8: //08 OR Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        op_or8();
        writerm8(rm, res8);
        break;
      case 0x9: //09 OR Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        op_or16();
        writerm16(rm, res16);
        break;
      case 0xA: //0A OR Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        op_or8();
        putreg8(reg, res8);
        break;
      case 0xB: //0B OR Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        op_or16();
        if ((oper1 == 0xF802) && (oper2 == 0xF802)) sf = 0; //cheap hack to make Wolf 3D think we're a 286 so it plays
        putreg16(reg, res16);
        break;
      case 0xC: //0C OR regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        op_or8();
        regs.byteregs[regal] = res8;
        break;
      case 0xD: //0D OR eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        op_or16();
        putreg16(regax, res16);
        break;
      case 0xE: //0E PUSH segregs[regcs]
        push(segregs[regcs]);
        break;
      case 0xF: //0F POP CS
        segregs[regcs] = pop();
        break;
      /*case 0xF: //0F 80286+ extended opcodes
          segregs[regcs] = segregs[regcs] & 0xFFFF; ip = ip & 0xFFFF;
          savecs = segregs[regcs]; saveip = ip;
          opcode = getmem8(segregs[regcs], ip); StepIP(1);
          op_286();
          break;*/
      case 0x10: //10 ADC Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        op_adc8();
        writerm8(rm, res8);
        break;
      case 0x11: //11 ADC Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        op_adc16();
        writerm16(rm, res16);
        break;
      case 0x12: //12 ADC Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        op_adc8();
        putreg8(reg, res8);
        break;
      case 0x13: //13 ADC Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        op_adc16();
        putreg16(reg, res16);
        break;
      case 0x14: //14 ADC regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        op_adc8();
        regs.byteregs[regal] = res8;
        break;
      case 0x15: //15 ADC eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        op_adc16();
        putreg16(regax, res16);
        break;
      case 0x16: //16 PUSH segregs[regss]
        push(segregs[regss]);
        break;
      case 0x17: //17 POP segregs[regss]
        segregs[regss] = pop();
        break;
      case 0x18: //18 SBB Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        op_sbb8();
        writerm8(rm, res8);
        break;
      case 0x19: //19 SBB Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        op_sbb16();
        writerm16(rm, res16);
        break;
      case 0x1A: //1A SBB Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        op_sbb8();
        putreg8(reg, res8);
        break;
      case 0x1B: //1B SBB Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        op_sbb16();
        putreg16(reg, res16);
        break;
      case 0x1C: //1C SBB regs.byteregs[regal] Ib;
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        op_sbb8();
        regs.byteregs[regal] = res8;
        break;
      case 0x1D: //1D SBB eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        op_sbb16();
        putreg16(regax, res16);
        break;
      case 0x1E: //1E PUSH segregs[regds]
        push(segregs[regds]);
        break;
      case 0x1F: //1F POP segregs[regds]
        segregs[regds] = pop();
        break;
      case 0x20: //20 AND Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        op_and8();
        writerm8(rm, res8);
        break;
      case 0x21: //21 AND Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        op_and16();
        writerm16(rm, res16);
        break;
      case 0x22: //22 AND Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        op_and8();
        putreg8(reg, res8);
        break;
      case 0x23: //23 AND Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        op_and16();
        putreg16(reg, res16);
        break;
      case 0x24: //24 AND regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        op_and8();
        regs.byteregs[regal] = res8;
        break;
      case 0x25: //25 AND eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        op_and16();
        putreg16(regax, res16);
        break;
      case 0x27: //27 DAA
        if (((regs.byteregs[regal] & 0xF) > 9) || (af == 1)) {
          oper1 = regs.byteregs[regal] + 6;
          regs.byteregs[regal] = oper1 & 255;
          if (oper1 & 0xFF00) cf = 1; else cf = 0;
          af = 1;
        } else af = 0;
        if (((regs.byteregs[regal] & 0xF0) > 0x90) || (cf == 1)) {
          regs.byteregs[regal] = regs.byteregs[regal] + 0x60;
          cf = 1;
        } else cf = 0;
        regs.byteregs[regal] = regs.byteregs[regal] & 255;
        flag_szp8(regs.byteregs[regal]);
        break;
      case 0x28: //28 SUB Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        op_sub8();
        writerm8(rm, res8);
        break;
      case 0x29: //29 SUB Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        op_sub16();
        writerm16(rm, res16);
        break;
      case 0x2A: //2A SUB Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        op_sub8();
        putreg8(reg, res8);
        break;
      case 0x2B: //2B SUB Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        op_sub16();
        putreg16(reg, res16);
        break;
      case 0x2C: //2C SUB regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        op_sub8();
        regs.byteregs[regal] = res8;
        break;
      case 0x2D: //2D SUB eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        op_sub16();
        putreg16(regax, res16);
        break;
      case 0x2F: //2F DAS
        if (((regs.byteregs[regal] & 15) > 9) || (af == 1)) {
          oper1 = regs.byteregs[regal] - 6;
          regs.byteregs[regal] = oper1 & 255;
          if (oper1 & 0xFF00) cf = 1; else cf = 0;
          af = 1;
        } else af = 0;
        if (((regs.byteregs[regal] & 0xF0) > 0x90) || (cf == 1)) {
          regs.byteregs[regal] = regs.byteregs[regal] - 0x60;
          cf = 1;
        } else cf = 0;
        flag_szp8(regs.byteregs[regal]);
        break;
      case 0x30: //30 XOR Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        op_xor8();
        writerm8(rm, res8);
        break;
      case 0x31: //31 XOR Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        op_xor16();
        writerm16(rm, res16);
        break;
      case 0x32: //32 XOR Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        op_xor8();
        putreg8(reg, res8);
        break;
      case 0x33: //33 XOR Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        op_xor16();
        putreg16(reg, res16);
        break;
      case 0x34: //34 XOR regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        op_xor8();
        regs.byteregs[regal] = res8;
        break;
      case 0x35: //35 XOR eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        op_xor16();
        putreg16(regax, res16);
        break;
      case 0x37: //37 AAA ASCII
        if (((regs.byteregs[regal] & 0xF) > 9) || (af == 1)) {
          regs.byteregs[regal] = regs.byteregs[regal] + 6;
          regs.byteregs[regah] = regs.byteregs[regah] + 1;
          af = 1;
          cf = 1;
        } else {
          af = 0;
          cf = 0;
        }
        regs.byteregs[regal] = regs.byteregs[regal] & 0xF;
        break;
      case 0x38: //38 CMP Eb Gb
        modregrm();
        oper1b = readrm8(rm); oper2b = getreg8(reg);
        flag_sub8(oper1b, oper2b);
        break;
      case 0x39: //39 CMP Ev Gv
        modregrm();
        oper1 = readrm16(rm); oper2 = getreg16(reg);
        flag_sub16(oper1, oper2);
        break;
      case 0x3A: //3A CMP Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        flag_sub8(oper1b, oper2b);
        break;
      case 0x3B: //3B CMP Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        flag_sub16(oper1, oper2);
        break;
      case 0x3C: //3C CMP regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        flag_sub8(oper1b, oper2b);
        break;
      case 0x3D: //3D CMP eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        flag_sub16(oper1, oper2);
        break;
      case 0x3F: //3F AAS ASCII
        if (((regs.byteregs[regal] & 0xF) > 9) || (af == 1)) {
          regs.byteregs[regal] = regs.byteregs[regal] - 6;
          regs.byteregs[regah] = regs.byteregs[regah] - 1;
          af = 1;
          cf = 1;
        } else {
          af = 0;
          cf = 0;
        }
        regs.byteregs[regal] = regs.byteregs[regal] & 0xF;
        break;
      case 0x40: //40 INC eAX
        oldcf = cf;
        oper1 = getreg16(regax); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regax, res16);
        break;
      case 0x41: //41 INC eCX
        oldcf = cf;
        oper1 = getreg16(regcx); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regcx, res16);
        break;
      case 0x42: //42 INC eDX
        oldcf = cf;
        oper1 = getreg16(regdx); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regdx, res16);
        break;
      case 0x43: //43 INC eBX
        oldcf = cf;
        oper1 = getreg16(regbx); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regbx, res16);
        break;
      case 0x44: //44 INC eSP
        oldcf = cf;
        oper1 = getreg16(regsp); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regsp, res16);
        break;
      case 0x45: //45 INC eBP
        oldcf = cf;
        oper1 = getreg16(regbp); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regbp, res16);
        break;
      case 0x46: //46 INC eSI
        oldcf = cf;
        oper1 = getreg16(regsi); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regsi, res16);
        break;
      case 0x47: //47 INC eDI
        oldcf = cf;
        oper1 = getreg16(regdi); oper2 = 1;
        op_add16();
        cf = oldcf;
        putreg16(regdi, res16);
        break;
      case 0x48: //48 DEC eAX
        oldcf = cf;
        oper1 = getreg16(regax); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regax, res16);
        break;
      case 0x49: //49 DEC eCX
        oldcf = cf;
        oper1 = getreg16(regcx); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regcx, res16);
        break;
      case 0x4A: //4A DEC eDX
        oldcf = cf;
        oper1 = getreg16(regdx); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regdx, res16);
        break;
      case 0x4B: //4B DEC eBX
        oldcf = cf;
        oper1 = getreg16(regbx); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regbx, res16);
        break;
      case 0x4C: //4C DEC eSP
        oldcf = cf;
        oper1 = getreg16(regsp); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regsp, res16);
        break;
      case 0x4D: //4D DEC eBP
        oldcf = cf;
        oper1 = getreg16(regbp); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regbp, res16);
        break;
      case 0x4E: //4E DEC eSI
        oldcf = cf;
        oper1 = getreg16(regsi); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regsi, res16);
        break;
      case 0x4F: //4F DEC eDI
        oldcf = cf;
        oper1 = getreg16(regdi); oper2 = 1;
        op_sub16();
        cf = oldcf;
        putreg16(regdi, res16);
        break;
      case 0x50: //50 PUSH eAX
        push (getreg16(regax));
        break;
      case 0x51: //51 PUSH eCX
        push (getreg16(regcx));
        break;
      case 0x52: //52 PUSH eDX
        push (getreg16(regdx));
        break;
      case 0x53: //53 PUSH eBX
        push (getreg16(regbx));
        break;
      case 0x54: //54 PUSH eSP
        push (getreg16(regsp) - 2);
        break;
      case 0x55: //55 PUSH eBP
        push (getreg16(regbp));
        break;
      case 0x56: //56 PUSH eSI
        push (getreg16(regsi));
        break;
      case 0x57: //57 PUSH eDI
        push (getreg16(regdi));
        break;
      case 0x58: //58 POP eAX
        putreg16(regax, pop());
        break;
      case 0x59: //59 POP eCX
        putreg16(regcx, pop());
        break;
      case 0x5A: //5A POP eDX
        putreg16(regdx, pop());
        break;
      case 0x5B: //5B POP eBX
        putreg16(regbx, pop());
        break;
      case 0x5C: //5C POP eSP
        putreg16(regsp, pop());
        break;
      case 0x5D: //5D POP eBP
        putreg16(regbp, pop());
        break;
      case 0x5E: //5E POP eSI
        putreg16(regsi, pop());
        break;
      case 0x5F: //5F POP eDI
        putreg16(regdi, pop());
        break;
      case 0x60: //60 PUSHA (80186+)
        oldsp = getreg16(regsp);
        push(getreg16(regax));
        push(getreg16(regcx));
        push(getreg16(regdx));
        push(getreg16(regbx));
        push(oldsp);
        push(getreg16(regbp));
        push(getreg16(regsi));
        push(getreg16(regdi));
        break;
      case 0x61: //61 POPA (80186+)
        putreg16(regdi, pop());
        putreg16(regsi, pop());
        putreg16(regbp, pop());
        dummy = pop();
        putreg16(regbx, pop());
        putreg16(regdx, pop());
        putreg16(regcx, pop());
        putreg16(regax, pop());
        break;
      case 0x68: //68 PUSH Iv (80186+)
        push(getmem16(segregs[regcs], ip)); StepIP(2);
        break;
      case 0x69: //69 IMUL Gv Ev Iv (80186+)
        //print("WE HIT 69h IMUL\r\n");
        modregrm();
        temp1 = readrm16(rm);
        temp2 = getmem16(segregs[regcs], ip); StepIP(2);
        if ((temp1 & 0x8000L) == 0x8000L) temp1 = temp1 | 0xFFFF0000L;
        if ((temp2 & 0x8000L) == 0x8000L) temp2 = temp2 | 0xFFFF0000L;
        temp3 = temp1 * temp2;
        putreg16(reg, temp3 & 0xFFFFL);
        if (temp3 & 0xFFFF0000L) {
          cf = 1;
          of = 1;
        } else {
          cf = 0;
          of = 0;
        }
        break;
      case 0x6A: //6A PUSH Ib (80186+)
        push(getmem8(segregs[regcs], ip)); StepIP(1);
        break;
      case 0x6B: //6B IMUL Gv Eb Ib (80186+)
        //print("WE HIT 6Bh IMUL\r\n");
        modregrm();
        temp1 = readrm16(rm);
        temp2 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if ((temp1 & 0x8000L) == 0x8000L) temp1 = temp1 | 0xFFFF0000L;
        if ((temp2 & 0x8000L) == 0x8000L) temp2 = temp2 | 0xFFFF0000L;
        temp3 = temp1 * temp2;
        putreg16(reg, temp3 & 0xFFFFL);
        if (temp3 & 0xFFFF0000L) {
          cf = 1;
          of = 1;
        } else {
          cf = 0;
          of = 0;
        }
        break;
      //case 0x6C ... 0x6F: //80186 port operations, just act as if they//re NOPs for now...
      //    StepIP(1); //they have a modregrm(); byte we must skip... i may properly emulate these later.
      //    break;
      case 0x6E: //6E OUTSB
        if (reptype && (getreg16(regcx) == 0)) break;
        portout16 = 0;
        portout(regs.wordregs[regdx], getmem16(useseg, getreg16(regsi)));
        if (df) {
          putreg16(regsi, getreg16(regsi) - 1);
          putreg16(regdi, getreg16(regdi) - 1);
        }
        else {
          putreg16(regsi, getreg16(regsi) + 1);
          putreg16(regdi, getreg16(regdi) + 1);
        }
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;
      case 0x6F: //6F OUTSW
        if (reptype && (getreg16(regcx) == 0)) break;
        portout16 = 1;
        portout(regs.wordregs[regdx], getmem16(useseg, getreg16(regsi)));
        if (df) {
          putreg16(regsi, getreg16(regsi) - 2);
          putreg16(regdi, getreg16(regdi) - 2);
        }
        else {
          putreg16(regsi, getreg16(regsi) + 2);
          putreg16(regdi, getreg16(regdi) + 2);
        }
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;

      case 0x70: //70 JO Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (of) ip = ip + temp16;
        break;
      case 0x71: //71 JNO Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!of) ip = ip + temp16;
        break;
      case 0x72: //72 JB Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (cf) ip = ip + temp16;
        break;
      case 0x73: //73 JNB Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!cf) ip = ip + temp16;
        break;
      case 0x74: //74 JZ Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (zf) ip = ip + temp16;
        break;
      case 0x75: //75 JNZ Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!zf) ip = ip + temp16;
        break;
      case 0x76: //76 JBE Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (cf || zf) ip = ip + temp16;
        break;
      case 0x77: //77 JA Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!cf && !zf) ip = ip + temp16;
        break;
      case 0x78: //78 JS Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (sf) ip = ip + temp16;
        break;
      case 0x79: //79 JNS Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!sf) ip = ip + temp16;
        break;
      case 0x7A: //7A JPE Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (pf) ip = ip + temp16;
        break;
      case 0x7B: //7B JPO Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!pf) ip = ip + temp16;
        break;
      case 0x7C: //7C JL Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (sf != of) ip = ip + temp16;
        break;
      case 0x7D: //7D JGE Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (sf == of) ip = ip + temp16;
        break;
      case 0x7E: //7E JLE Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if ((sf != of) || zf) ip = ip + temp16;
        break;
      case 0x7F: //7F JG Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!zf && (sf == of)) ip = ip + temp16;
        break;
      case 0x80: case 0x82: //80/82 GRP1 Eb Ib
        modregrm();
        oper1b = readrm8(rm);
        oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        switch (reg) {
          case 0: op_add8(); break;
          case 1: op_or8(); break;
          case 2: op_adc8(); break;
          case 3: op_sbb8(); break;
          case 4: op_and8(); break;
          case 5: op_sub8(); break;
          case 6: op_xor8(); break;
          case 7: flag_sub8(oper1b, oper2b); break;
          default: break; //to avoid compiler warnings
        }
        if (reg < 7) writerm8(rm, res8);
        break;
      case 0x81: //81 GRP1 Ev Iv
      case 0x83: //83 GRP1 Ev Ib
        modregrm();
        oper1 = readrm16(rm);
        if (opcode == 0x81) {
          oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        } else {
          oper2 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        }
        switch (reg) {
          case 0: op_add16(); break;
          case 1: op_or16(); break;
          case 2: op_adc16(); break;
          case 3: op_sbb16(); break;
          case 4: op_and16(); break;
          case 5: op_sub16(); break;
          case 6: op_xor16(); break;
          case 7: flag_sub16(oper1, oper2); break;
          default: break; //to avoid compiler warnings
        }
        if (reg < 7) writerm16(rm, res16);
        break;
      case 0x84: //84 TEST Gb Eb
        modregrm();
        oper1b = getreg8(reg); oper2b = readrm8(rm);
        flag_log8(oper1b & oper2b);
        break;
      case 0x85: //85 TEST Gv Ev
        modregrm();
        oper1 = getreg16(reg); oper2 = readrm16(rm);
        flag_log16(oper1 & oper2);
        break;
      case 0x86: //86 XCHG Gb Eb
        modregrm();
        oper1b = getreg8(reg);
        putreg8(reg, readrm8(rm));
        writerm8(rm, oper1b);
        break;
      case 0x87: //87 XCHG Gv Ev
        modregrm();
        oper1 = getreg16(reg);
        putreg16(reg, readrm16(rm));
        writerm16(rm, oper1);
        break;
      case 0x88: //88 MOV Eb Gb
        modregrm();
        writerm8(rm, getreg8(reg));
        break;
      case 0x89: //89 MOV Ev Gv
        modregrm();
        writerm16(rm, getreg16(reg));
        break;
      case 0x8A: //8A MOV Gb Eb
        modregrm();
        putreg8(reg, readrm8(rm));
        break;
      case 0x8B: //8B MOV Gv Ev
        modregrm();
        putreg16(reg, readrm16(rm));
        break;
      case 0x8C: //8C MOV Ew Sw
        modregrm();
        writerm16(rm, getsegreg(reg));
        break;
      case 0x8D: //8D LEA Gv M
        modregrm();
        //getea(rm);
        putreg16(reg, ea - segbase(useseg));
        break;
      case 0x8E: //8E MOV Sw Ew
        modregrm();
        putsegreg(reg, readrm16(rm));
        break;
      case 0x8F: //8F POP Ev
        modregrm();
        writerm16(rm, pop());
        break;
      case 0x90: //90 NOP
        break;
      case 0x91: //91 XCHG eCX eAX
        oper1 = getreg16(regcx);
        putreg16(regcx, getreg16(regax));
        putreg16(regax, oper1);
        break;
      case 0x92: //92 XCHG eDX eAX
        oper1 = getreg16(regdx);
        putreg16(regdx, getreg16(regax));
        putreg16(regax, oper1);
        break;
      case 0x93: //93 XCHG eBX eAX
        oper1 = getreg16(regbx);
        putreg16(regbx, getreg16(regax));
        putreg16(regax, oper1);
        break;
      case 0x94: //94 XCHG eSP eAX
        oper1 = getreg16(regsp);
        putreg16(regsp, getreg16(regax));
        putreg16(regax, oper1);
        break;
      case 0x95: //95 XCHG eBP eAX
        oper1 = getreg16(regbp);
        putreg16(regbp, getreg16(regax));
        putreg16(regax, oper1);
        break;
      case 0x96: //96 XCHG eSI eAX
        oper1 = getreg16(regsi);
        putreg16(regsi, getreg16(regax));
        putreg16(regax, oper1);
        break;
      case 0x97: //97 XCHG eDI eAX
        oper1 = getreg16(regdi);
        putreg16(regdi, getreg16(regax));
        putreg16(regax, oper1);
        break;
      case 0x98: //98 CBW
        if ((regs.byteregs[regal] & 0x80) == 0x80) regs.byteregs[regah] = 0xFF; else regs.byteregs[regah] = 0;
        break;
      case 0x99: //99 CWD
        if ((regs.byteregs[regah] & 0x80) == 0x80) putreg16(regdx, 0xFFFF); else putreg16(regdx, 0);
        break;
      case 0x9A: //9A CALL Ap
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        push(segregs[regcs]); push(ip); ip = oper1; segregs[regcs] = oper2;
        break;
      case 0x9B: //9B WAIT
        break;
      case 0x9C: //9C PUSHF
        push(makeflagsword() | 0xF800);
        break;
      case 0x9D: //9D POPF
        temp16 = pop();
        decodeflagsword(temp16);
        break;
      case 0x9E: //9E SAHF
        decodeflagsword ((makeflagsword() & 0xFF00) | regs.byteregs[regah]);
        break;
      case 0x9F: //9F LAHF
        regs.byteregs[regah] = makeflagsword() & 0xFF;
        break;
      case 0xA0: //A0 MOV regs.byteregs[regal] Ob
        regs.byteregs[regal] = getmem8(useseg, getmem16(segregs[regcs], ip)); StepIP(2);
        break;
      case 0xA1: //A1 MOV eAX Ov
        oper1 = getmem16(useseg, getmem16(segregs[regcs], ip)); StepIP(2);
        putreg16(regax, oper1);
        break;
      case 0xA2: //A2 MOV Ob regs.byteregs[regal]
        putmem8(useseg, getmem16(segregs[regcs], ip), regs.byteregs[regal]); StepIP(2);
        break;
      case 0xA3: //A3 MOV Ov eAX
        putmem16(useseg, getmem16(segregs[regcs], ip), getreg16(regax)); StepIP(2);
        break;
      case 0xA4: //A4 MOVSB
        if (reptype && (getreg16(regcx) == 0)) break;
        putmem8(segregs[reges], getreg16(regdi), getmem8(useseg, getreg16(regsi)));
        if (df) {
          putreg16(regsi, getreg16(regsi) - 1);
          putreg16(regdi, getreg16(regdi) - 1);
        }
        else {
          putreg16(regsi, getreg16(regsi) + 1);
          putreg16(regdi, getreg16(regdi) + 1);
        }
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xA5: //A5 MOVSW
        if (reptype && (getreg16(regcx) == 0)) break;
        putmem16(segregs[reges], getreg16(regdi), getmem16(useseg, getreg16(regsi)));
        if (df) {
          putreg16(regsi, getreg16(regsi) - 2);
          putreg16(regdi, getreg16(regdi) - 2);
        }
        else {
          putreg16(regsi, getreg16(regsi) + 2);
          putreg16(regdi, getreg16(regdi) + 2);
        }
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xA6: //A6 CMPSB
        if (reptype && (getreg16(regcx) == 0)) break;
        oper1b = getmem8(useseg, getreg16(regsi)); oper2b = getmem8(segregs[reges], getreg16(regdi));
        if (df) {
          putreg16(regsi, getreg16(regsi) - 1);
          putreg16(regdi, getreg16(regdi) - 1);
        }
        else {
          putreg16(regsi, getreg16(regsi) + 1);
          putreg16(regdi, getreg16(regdi) + 1);
        }
        flag_sub8(oper1b, oper2b);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if ((reptype == 1) && !zf) break;
        else if ((reptype == 2) && (zf == 1)) break;
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xA7: //A7 CMPSW
        if (reptype && (getreg16(regcx) == 0)) break;
        oper1 = getmem16(useseg, getreg16(regsi)); oper2 = getmem16(segregs[reges], getreg16(regdi));
        if (df) {
          putreg16(regsi, getreg16(regsi) - 2);
          putreg16(regdi, getreg16(regdi) - 2);
        }
        else {
          putreg16(regsi, getreg16(regsi) + 2);
          putreg16(regdi, getreg16(regdi) + 2);
        }
        flag_sub16(oper1, oper2);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if ((reptype == 1) && !zf) break;
        if ((reptype == 2) && (zf == 1)) break;
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xA8: //A8 TEST regs.byteregs[regal] Ib
        oper1b = regs.byteregs[regal]; oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        flag_log8(oper1b & oper2b);
        break;
      case 0xA9: //A9 TEST eAX Iv
        oper1 = getreg16(regax); oper2 = getmem16(segregs[regcs], ip); StepIP(2);
        flag_log16(oper1 & oper2);
        break;
      case 0xAA: //AA STOSB
        if (reptype && (getreg16(regcx) == 0)) break;
        putmem8(segregs[reges], getreg16(regdi), regs.byteregs[regal]);
        if (df) putreg16(regdi, getreg16(regdi) - 1);
        else putreg16(regdi, getreg16(regdi) + 1);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xAB: //AB STOSW
        if (reptype && (getreg16(regcx) == 0)) break;
        putmem16(segregs[reges], getreg16(regdi), getreg16(regax));
        if (df) putreg16(regdi, getreg16(regdi) - 2);
        else putreg16(regdi, getreg16(regdi) + 2);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xAC: //AC LODSB
        if (reptype && (getreg16(regcx) == 0)) break;
        regs.byteregs[regal] = getmem8(useseg, getreg16(regsi));
        if (df) putreg16(regsi, getreg16(regsi) - 1);
        else putreg16(regsi, getreg16(regsi) + 1);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xAD: //AD LODSW
        if (reptype && (getreg16(regcx) == 0)) break;
        oper1 = getmem16(useseg, getreg16(regsi));
        putreg16(regax, oper1);
        if (df) putreg16(regsi, getreg16(regsi) - 2);
        else putreg16(regsi, getreg16(regsi) + 2);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xAE: //AE SCASB
        if (reptype && (getreg16(regcx) == 0)) break;
        oper1b = getmem8(segregs[reges], getreg16(regdi)); oper2b = regs.byteregs[regal];
        flag_sub8(oper1b, oper2b);
        if (df) putreg16(regdi, getreg16(regdi) - 1);
        else putreg16(regdi, getreg16(regdi) + 1);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if ((reptype == 1) && !zf) break;
        else if ((reptype == 2) && (zf == 1)) break;
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xAF: //AF SCASW
        if (reptype && (getreg16(regcx) == 0)) break;
        oper1 = getmem16(segregs[reges], getreg16(regdi)); oper2 = getreg16(regax);
        flag_sub16(oper1, oper2);
        if (df) putreg16(regdi, getreg16(regdi) - 2);
        else putreg16(regdi, getreg16(regdi) + 2);
        if (reptype) putreg16(regcx, getreg16(regcx) - 1);
        if ((reptype == 1) && !zf) break;
        else if ((reptype == 2) & (zf == 1)) break;
        if (!reptype) break;
        ip = firstip;
        break;
      case 0xB0: //B0 MOV regs.byteregs[regal] Ib
        regs.byteregs[regal] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB1: //B1 MOV regs.byteregs[regcl] Ib
        regs.byteregs[regcl] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB2: //B2 MOV regs.byteregs[regdl] Ib
        regs.byteregs[regdl] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB3: //B3 MOV regs.byteregs[regbl] Ib
        regs.byteregs[regbl] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB4: //B4 MOV regs.byteregs[regah] Ib
        regs.byteregs[regah] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB5: //B5 MOV regs.byteregs[regch] Ib
        regs.byteregs[regch] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB6: //B6 MOV regs.byteregs[regdh] Ib
        regs.byteregs[regdh] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB7: //B7 MOV regs.byteregs[regbh] Ib
        regs.byteregs[regbh] = getmem8(segregs[regcs], ip); StepIP(1);
        break;
      case 0xB8: //B8 MOV eAX Iv
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        putreg16(regax, oper1);
        break;
      case 0xB9: //B9 MOV eCX Iv
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        putreg16(regcx, oper1);
        break;
      case 0xBA: //BA MOV eDX Iv
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        putreg16(regdx, oper1);
        break;
      case 0xBB: //BB MOV eBX Iv
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        putreg16(regbx, oper1);
        break;
      case 0xBC: //BC MOV eSP Iv
        putreg16(regsp, getmem16(segregs[regcs], ip)); StepIP(2);
        break;
      case 0xBD: //BD MOV eBP Iv
        putreg16(regbp, getmem16(segregs[regcs], ip)); StepIP(2);
        break;
      case 0xBE: //BE MOV eSI Iv
        putreg16(regsi, getmem16(segregs[regcs], ip)); StepIP(2);
        break;
      case 0xBF: //BF MOV eDI Iv
        putreg16(regdi, getmem16(segregs[regcs], ip)); StepIP(2);
        break;
      case 0xC0: //C0 GRP2 byte imm8 (80186+)
        modregrm();
        oper1b = readrm8(rm);
        oper2b = getmem8(segregs[regcs], ip); StepIP(1);
        writerm8(rm, op_grp2_8(oper2b));
        break;
      case 0xC1: //C1 GRP2 word imm8 (80186+)
        modregrm();
        oper1 = readrm16(rm);
        oper2 = getmem8(segregs[regcs], ip); StepIP(1);
        writerm16(rm, op_grp2_16(oper2));
        break;
      case 0xC2: //C2 RET Iw
        oper1 = getmem16(segregs[regcs], ip);
        ip = pop();
        putreg16(regsp, getreg16(regsp) + oper1);
        break;
      case 0xC3: //C3 RET
        ip = pop();
        break;
      case 0xC4: //C4 LES Gv Mp
        modregrm();
        //getea(rm);
        putreg16(reg, read86(ea) + ((uint16_t)read86(ea + 1) << 8));
        segregs[reges] = read86(ea + 2) + ((uint16_t)read86(ea + 3) << 8);
        break;
      case 0xC5: //C5 LDS Gv Mp
        modregrm();
        //getea(rm);
        putreg16(reg, read86(ea) + ((uint16_t)read86(ea + 1) << 8));
        segregs[regds] = read86(ea + 2) + ((uint16_t)read86(ea + 3) << 8);
        break;
      case 0xC6: //C6 MOV Eb Ib
        modregrm();
        writerm8(rm, getmem8(segregs[regcs], ip)); StepIP(1);
        break;
      case 0xC7: //C7 MOV Ev Iv
        modregrm();
        writerm16(rm, getmem16(segregs[regcs], ip)); StepIP(2);
        break;
      case 0xC8: //C8 ENTER (80186+)
        stacksize = getmem16(segregs[regcs], ip); StepIP(2);
        nestlev = getmem8(segregs[regcs], ip); StepIP(1);
        push(getreg16(regbp));
        frametemp = getreg16(regsp);
        if (nestlev) {
          for (temp16 = 1; temp16 < nestlev; temp16++) {
            putreg16(regbp, getreg16(regbp) - 2);
            push(getreg16(regbp));
          }
          push(getreg16(regsp));
        }
        putreg16(regbp, frametemp);
        putreg16(regsp, getreg16(regbp) - stacksize);

        break;
      case 0xC9: //C9 LEAVE (80186+)
        putreg16(regsp, getreg16(regbp));
        putreg16(regbp, pop());

        break;
      case 0xCA: //CA RETF Iw
        oper1 = getmem16(segregs[regcs], ip);
        ip = pop(); segregs[regcs] = pop();
        putreg16(regsp, getreg16(regsp) + oper1);
        break;
      case 0xCB: //CB RETF
        ip = pop();; segregs[regcs] = pop();
        break;
      case 0xCC: //CC INT 3
        intcall86(3);
        break;
      case 0xCD: //CD INT Ib
        oper1 = getmem8(segregs[regcs], ip); StepIP(1);
        intcall86(oper1);
        break;
      case 0xCE: //CE INTO
        if (of) intcall86(4);
        break;
      case 0xCF: //CF IRET
        ip = pop(); segregs[regcs] = pop();
        decodeflagsword(pop());
        //if (net.enabled) net.canrecv = 1;
        break;
      case 0xD0: //D0 GRP2 Eb 1
        modregrm();
        oper1b = readrm8(rm);
        writerm8(rm, op_grp2_8(1));
        break;
      case 0xD1: //D1 GRP2 Ev 1
        modregrm();
        oper1 = readrm16(rm);
        writerm16(rm, op_grp2_16(1));
        break;
      case 0xD2: //D2 GRP2 Eb regs.byteregs[regcl]
        modregrm();
        oper1b = readrm8(rm);
        writerm8(rm, op_grp2_8(regs.byteregs[regcl]));
        break;
      case 0xD3: //D3 GRP2 Ev regs.byteregs[regcl]
        modregrm();
        oper1 = readrm16(rm);
        writerm16(rm, op_grp2_16(regs.byteregs[regcl]));
        break;
      case 0xD4: //D4 AAM I0
        oper1 = getmem8(segregs[regcs], ip); StepIP(1);
        if (!oper1) {
          intcall86(0);  //division by zero
          return;
        }
        regs.byteregs[regah] = (regs.byteregs[regal] / oper1) & 255;
        regs.byteregs[regal] = (regs.byteregs[regal] % oper1) & 255;
        flag_szp16 (getreg16(regax));
        break;
      case 0xD5: //D5 AAD I0
        oper1 = getmem8(segregs[regcs], ip); StepIP(1);
        regs.byteregs[regal] = (regs.byteregs[regah] * oper1 + regs.byteregs[regal]) & 255;
        regs.byteregs[regah] = 0;
        flag_szp16(regs.byteregs[regah] * oper1 + regs.byteregs[regal]);
        sf = 0;
        break;
      case 0xD6: //D6 XLAT on V20/V30, SALC on 8086/8088
        regs.byteregs[regal] = cf;
        break;
      case 0xD7: //D7 XLAT
        putreg8(regal, read86(segbase(useseg) + (uint32_t)getreg16(regbx) + (uint32_t)getreg8(regal)));
        break;
      case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDE: case 0xDD: case 0xDF: //escape
        StepIP(1);
        break;
      case 0xE0: //E0 LOOPNZ Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        putreg16(regcx, getreg16(regcx) - 1);
        if ((getreg16(regcx)) && !zf) ip = ip + temp16;
        break;
      case 0xE1: //E1 LOOPZ Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        putreg16(regcx, (getreg16(regcx)) - 1);
        if ((getreg16(regcx)) && (zf == 1)) ip = ip + temp16;
        break;
      case 0xE2: //E2 LOOP Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        putreg16(regcx, (getreg16(regcx)) - 1);
        if (getreg16(regcx)) ip = ip + temp16;
        break;
      case 0xE3: //E3 JCXZ Jb
        temp16 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        if (!(getreg16(regcx))) ip = ip + temp16;
        break;
      case 0xE4: //E4 IN regs.byteregs[regal] Ib
        oper1b = getmem8(segregs[regcs], ip);
        StepIP(1);
        regs.byteregs[regal] = portin(oper1b);
        break;
      case 0xE5: //E5 IN eAX Ib
        oper1b = getmem8(segregs[regcs], ip);
        StepIP(1);
        putreg16(regax, portin(oper1b));
        break;
      case 0xE6: //E6 OUT Ib regs.byteregs[regal]
        oper1b = getmem8(segregs[regcs], ip);
        StepIP(1);
        portout16 = 0;
        portout(oper1b, regs.byteregs[regal]);
        break;
      case 0xE7: //E7 OUT Ib eAX
        oper1b = getmem8(segregs[regcs], ip);
        StepIP(1);
        portout16 = 1;
        portout(oper1b, (getreg16(regax)));
        break;
      case 0xE8: //E8 CALL Jv
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        push(ip);
        ip = ip + oper1;
        break;
      case 0xE9: //E9 JMP Jv
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        ip = ip + oper1;
        break;
      case 0xEA: //EA JMP Ap
        oper1 = getmem16(segregs[regcs], ip); StepIP(2);
        oper2 = getmem16(segregs[regcs], ip);
        ip = oper1; segregs[regcs] = oper2;
        break;
      case 0xEB: //EB JMP Jb
        oper1 = signext(getmem8(segregs[regcs], ip)); StepIP(1);
        ip = ip + oper1;
        break;
      case 0xEC: //EC IN regs.byteregs[regal] regdx
        oper1 = (getreg16(regdx));
        regs.byteregs[regal] = portin(oper1);
        break;
      case 0xED: //ED IN eAX regdx
        oper1 = (getreg16(regdx));
        putreg16(regax, portin(oper1));
        break;
      case 0xEE: //EE OUT regdx regs.byteregs[regal]
        oper1 = (getreg16(regdx));
        portout16 = 0;
        portout(oper1, regs.byteregs[regal]);
        break;
      case 0xEF: //EF OUT regdx eAX
        oper1 = (getreg16(regdx));
        portout16 = 1;
        portout(oper1, (getreg16(regax)));
        break;
      case 0xF0: //F0 LOCK
      case 0xF4: //F4 HLT
        break;
      case 0xF5: //F5 CMC
        if (!cf) cf = 1; else cf = 0;
        break;
      case 0xF6: //F6 GRP3a Eb
        modregrm();
        oper1b = readrm8(rm);
        op_grp3_8();
        if ((reg > 1) && (reg < 4))     writerm8(rm, res8);

        break;
      case 0xF7: //F7 GRP3b Ev
        modregrm();
        oper1 = readrm16(rm);
        op_grp3_16();
        if ((reg > 1) && (reg < 4)) writerm16(rm, res16);
        break;
      case 0xF8: //F8 CLC
        cf = 0;
        break;
      case 0xF9: //F9 STC
        cf = 1;
        break;
      case 0xFA: //FA CLI
        ifl = 0;
        break;
      case 0xFB: //FB STI
        ifl = 1;
        break;
      case 0xFC: //FC CLD
        df = 0;
        break;
      case 0xFD: //FD STD
        df = 1;
        break;
      case 0xFE: //FE GRP4 Eb
        modregrm();
        oper1b = readrm8(rm); oper2b = 1;
        if (!reg) {
          tempcf = cf;
          res8 = oper1b + oper2b;
          flag_add8(oper1b, oper2b);
          cf = tempcf; writerm8(rm, res8);
        } else {
          tempcf = cf;
          res8 = oper1b - oper2b;
          flag_sub8(oper1b, oper2b);
          cf = tempcf; writerm8(rm, res8);
        }
        break;
      case 0xFF: //FF GRP5 Ev
        modregrm();
        oper1 = readrm16(rm);
        op_grp5();
        break;
      default:
        intcall86(6); //trip invalid opcode exception (this occurs on the 80186+, 8086/8088 CPUs treat them as NOPs
        if (verbose) {
          //if (opcode==0xF) sprintf(msg, "Illegal opcode: %02X @ %04X:%04X\n", opcode, savecs, saveip);
          //else
          //sprintf(msg, "Illegal opcode: %02X %02X @ %04X:%04X\n", opcode, getmem8(savecs, saveip + 1), savecs, saveip);
        }

        break;
    }
#ifdef PROFILING
    endmicros = micros();
    if (instrtime[opcode]) {
      instrtime[opcode] = (instrtime[opcode] + (endmicros - startmicros)) >> 1;
    } else {
      instrtime[opcode] = endmicros - startmicros;
    }
#endif
    //if (!running) return;
  }
}

void testmem() {

}

