"""
Home for the i386 emulation code.
"""
import envi
import envi.bits as e_bits
import envi.memory as e_mem

from envi.archs.i386.regs import *
from envi.archs.i386.disasm import *
from envi.archs.i386 import i386Module

def shiftMask(val, size):
    if size == 1:
        return (val & 0x1f) % 9
    elif size == 2:
        return (val & 0x1f) % 17
    elif size == 4:
        return val & 0x1f
    elif size == 8:
        return val & 0x3f
    else:
        raise Exception("shiftMask is broke in envi/intel.py")

# The indexes for the list of segments in the emulator
SEG_CS = 0
SEG_DS = 1
SEG_ES = 2
SEG_FS = 3
SEG_GS = 4
SEG_SS = 5

# The general purpose register indexes
# (for use in _emu_setGpReg / _emu_getGpReg)
# NOTE: These *must* stay in sync with i386regs first row.
GPR_A  = 0
GPR_C  = 1
GPR_D  = 2
GPR_B  = 3
GPR_SP = 4
GPR_BP = 5
GPR_SI = 6
GPR_DI = 7

class IntelEmulator(i386Module, i386RegisterContext, envi.Emulator):

    def __init__(self):
        # Set ourself up as an arch module *and* register context
        i386Module.__init__(self)

        seglist = [ (0,0xffffffff) for i in range(6) ]
        envi.Emulator.__init__(self, segs=seglist)

        i386RegisterContext.__init__(self)

    def getSegmentIndex(self, op):
        # FIXME this needs to account for push/pop/etc
        if op.prefixes == 0:
            return SEG_DS
        if op.prefixes & PREFIX_ES:
            return SEG_ES
        elif op.prefixes & PREFIX_CS:
            return SEG_CS
        elif op.prefixes & PREFIX_SS:
            return SEG_SS
        elif op.prefixes & PREFIX_DS:
            return SEG_DS
        elif op.prefixes & PREFIX_FS:
            return SEG_FS
        elif op.prefixes & PREFIX_GS:
            return SEG_GS
        return SEG_DS

    def undefFlags(self):
        """
        Used in PDE.
        A flag setting operation has resulted in un-defined value.  Set
        the flags to un-defined as well.
        """
        self.setRegister(REG_EFLAGS, None)

    def setFlag(self, which, state):
        flags = self.getRegister(REG_EFLAGS)
        if state:
            flags |= which
        else:
            flags &= ~which
        self.setRegister(REG_EFLAGS, flags)

    def getFlag(self, which):
        flags = self.getRegister(REG_EFLAGS)
        if flags == None:
            raise envi.PDEUndefinedFlag(self)
        return bool(flags & which)

    def readMemValue(self, addr, size):
        bytes = self.readMemory(addr, size)
        if bytes == None:
            return None
        #FIXME change this (and all uses of it) to passing in format...
        if len(bytes) != size:
            raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes)))
        if size == 1:
            return struct.unpack("B", bytes)[0]
        elif size == 2:
            return struct.unpack("<H", bytes)[0]
        elif size == 4:
            return struct.unpack("<L", bytes)[0]
        elif size == 8:
            return struct.unpack("<Q", bytes)[0]

    def writeMemValue(self, addr, value, size):
        #FIXME change this (and all uses of it) to passing in format...
        if size == 1:
            bytes = struct.pack("B",value & 0xff)
        elif size == 2:
            bytes = struct.pack("<H",value & 0xffff)
        elif size == 4:
            bytes = struct.pack("<L", value & 0xffffffff)
        elif size == 8:
            bytes = struct.pack("<Q", value & 0xffffffffffffffff)
        self.writeMemory(addr, bytes)

    def readMemSignedValue(self, addr, size):
        bytes = self.readMemory(addr, size)
        if bytes == None:
            return None
        if size == 1:
            return struct.unpack("b", bytes)[0]
        elif size == 2:
            return struct.unpack("<h", bytes)[0]
        elif size == 4:
            return struct.unpack("<l", bytes)[0]

    def executeOpcode(self, op):
        # NOTE: If an opcode method returns
        #       other than None, that is the new eip
        meth = self.op_methods.get(op.mnem, None)
        if meth == None:
            raise envi.UnsupportedInstruction(self, op)
        if op.prefixes & PREFIX_REP:
            x = self.doRepPrefix(meth, op)
        else:
            x = meth(op)
        if x == None:
            pc = self.getProgramCounter()
            x = pc+op.size

        self.setProgramCounter(x)

    ###### Conditional Callbacks #####

    # NOTE: for ease of validation, these are in the same order as the Jcc
    # page in the intel manual.  However, duplicate conditions (be/na) are
    # reduced to their earliest (in the manual) form.

    def cond_a(self):
        return self.getFlag(EFLAGS_CF) == 0 and self.getFlag(EFLAGS_ZF) == 0

    def cond_ae(self):
        return self.getFlag(EFLAGS_CF) == 0

    def cond_b(self):
        return self.getFlag(EFLAGS_CF) == 1

    def cond_be(self):
        return self.getFlag(EFLAGS_CF) == 1 or self.getFlag(EFLAGS_ZF) == 1

    def cond_c(self):
        return self.getFlag(EFLAGS_CF) == 1

    def cond_ecxz(self):
        return self.getRegister(REG_ECX) == 0

    def cond_e(self):
        return self.getFlag(EFLAGS_ZF) == 1

    def cond_g(self):
        return self.getFlag(EFLAGS_ZF) == 0 and (self.getFlag(EFLAGS_SF) == self.getFlag(EFLAGS_OF))

    def cond_ge(self):
        return self.getFlag(EFLAGS_SF) == self.getFlag(EFLAGS_OF)

    def cond_l(self):
        return self.getFlag(EFLAGS_SF) != self.getFlag(EFLAGS_OF)

    def cond_le(self):
        return (self.getFlag(EFLAGS_SF) != self.getFlag(EFLAGS_OF) or
                (self.getFlag(EFLAGS_ZF) == 1))

    # Some duplicates
    cond_na = cond_be
    cond_nae = cond_b
    cond_nb = cond_ae
    cond_nbe = cond_a
    cond_nc = cond_ae

    def cond_ne(self):
        return self.getFlag(EFLAGS_ZF) == 0

    # A few more
    cond_ng = cond_le
    cond_nge = cond_l
    cond_nl = cond_ge
    cond_nle = cond_g

    def cond_no(self):
        return self.getFlag(EFLAGS_OF) == 0

    def cond_np(self):
        return self.getFlag(EFLAGS_PF) == 0

    def cond_ns(self):
        return self.getFlag(EFLAGS_SF) == 0

    cond_nz = cond_ne

    def cond_o(self):
        return self.getFlag(EFLAGS_OF) == 1

    def cond_p(self):
        return self.getFlag(EFLAGS_PF) == 1

    cond_pe = cond_p
    cond_po = cond_np

    def cond_s(self):
        return self.getFlag(EFLAGS_SF) == 1

    cond_z = cond_e

    # FROM OTHER INSTRUCTIONS
    cond_nc = cond_ae
    cond_nl = cond_ge

    ###### End Conditional Callbacks #####

    def doPush(self, val):
        esp = self.getRegister(REG_ESP)
        esp -= 4
        self.writeMemValue(esp, val, 4)
        self.setRegister(REG_ESP, esp)

    def doPop(self):
        esp = self.getRegister(REG_ESP)
        val = self.readMemValue(esp, 4)
        self.setRegister(REG_ESP, esp+4)
        return val

    def integerSubtraction(self, op):
        """
        Do the core of integer subtraction but only *return* the
        resulting value rather than assigning it.
        (allows cmp and sub to use the same code)
        """
        # Src op gets sign extended to dst
        #FIXME account for same operand with zero result for PDE
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        if src == None or dst == None:
            self.undefFlags()
            return None

        # So we can either do a BUNCH of crazyness with xor and shifting to
        # get the necissary flags here, *or* we can just do both a signed and
        # unsigned sub and use the results.
        dsize = op.opers[0].tsize
        ssize = op.opers[1].tsize
        # Sign extend immediates where the sizes don't match
        if dsize != ssize:
            src = e_bits.sign_extend(src, ssize, dsize)
            ssize = dsize
        return self.intSubBase(src, dst, ssize, dsize)

    def intSubBase(self, src, dst, ssize, dsize):

        usrc = e_bits.unsigned(src, ssize)
        udst = e_bits.unsigned(dst, dsize)

        ssrc = e_bits.signed(src, ssize)
        sdst = e_bits.signed(dst, dsize)

        ures = udst - usrc
        sres = sdst - ssrc

        #print "dsize/ssize: %d %d" % (dsize, ssize)
        #print "unsigned: %d %d %d" % (usrc, udst, ures)
        #print "signed: %d %d %d" % (ssrc, sdst, sres)

        self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sres, dsize))
        self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(usrc, udst))
        self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(ures, dsize))
        self.setFlag(EFLAGS_SF, e_bits.is_signed(ures, dsize))
        self.setFlag(EFLAGS_ZF, not sres)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ures))

        return ures

    def logicalAnd(self, op):
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        # PDE
        if dst == None or src == None:
            self.undefFlags()
            self.setOperValue(op, 0, None)
            return

        dsize = op.opers[0].tsize
        ssize = op.opers[1].tsize

        # sign-extend an immediate if needed
        if dsize != ssize:
            src = e_bits.sign_extend(src, ssize, dsize)
            ssize = dsize

        # Make sure everybody's on the same bit page.
        dst = e_bits.unsigned(dst, dsize)
        src = e_bits.unsigned(src, ssize)

        res = src & dst

        self.setFlag(EFLAGS_AF, 0) # AF is undefined, but it seems like it is zeroed
        self.setFlag(EFLAGS_OF, 0)
        self.setFlag(EFLAGS_CF, 0)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
        self.setFlag(EFLAGS_ZF, not res)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
        return res

    def doRepPrefix(self, meth, op):
        #FIXME check for opcode family valid to rep
        ret = None
        ecx = self.getRegister(REG_ECX)
        while ecx != 0:
            ret = meth(op)
            ecx -= 1
        self.setRegister(REG_ECX, 0)
        return ret

    def doRepzPrefix(self, meth, op):
        pass

    # Beginning of Instruction methods

    def i_adc(self, op):
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)
        # PDE
        if dst == None or src == None:
            self.undefFlags()
            self.setOperValue(op, 0, None)
            return

        cf = 0
        if self.getFlag(EFLAGS_CF):
            cf = 1

        dstsize = op.opers[0].tsize
        srcsize = op.opers[1].tsize

        if (isinstance(op.opers[1], i386ImmOper) and
            srcsize < dstsize):
            src = e_bits.sign_extend(src, srcsize, dstsize)
            srcsize = dstsize

        #FIXME perhaps unify the add/adc flags/arith code
        res = dst + src + cf

        tsize = op.opers[0].tsize

        self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(res, tsize))
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
        self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(src, dst))
        self.setFlag(EFLAGS_ZF, not res)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(res, tsize))
        self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(res, tsize))

        self.setOperValue(op, 0, res)

    def i_add(self, op):
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        dsize = op.opers[0].tsize
        ssize = op.opers[1].tsize

        #FIXME PDE and flags
        if dst == None or src == None:
            self.undefFlags()
            self.setOperValue(op, 0, None)
            return

        if dsize > ssize:
            src = e_bits.sign_extend(src, ssize, dsize)
            ssize = dsize

        udst = e_bits.unsigned(dst, dsize)
        usrc = e_bits.unsigned(src, ssize)
        sdst = e_bits.signed(dst, dsize)
        ssrc = e_bits.signed(src, ssize)

        ures = udst + usrc
        sres = sdst + ssrc

        self.setFlag(EFLAGS_CF, e_bits.is_unsigned_carry(ures, dsize))
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ures))
        self.setFlag(EFLAGS_AF, e_bits.is_aux_carry(src, dst))
        self.setFlag(EFLAGS_ZF, not ures)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(ures, dsize))
        self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sres, dsize))

        self.setOperValue(op, 0, ures)

    def i_and(self, op):
        #FIXME 24 and 25 opcodes should *not* get sign-extended.
        res = self.logicalAnd(op)
        self.setOperValue(op, 0, res)

    def i_arpl(self, op):
        v1 = self.getOperValue(op, 0)
        v2 = self.getOperValue(op, 1)

        # Mask off the rpl
        r1 = v1 & 3
        r2 = v2 & 3

        if r1 < r2: # If dest rpl < src rpl
            self.setFlag(EFLAGS_ZF, True)
            # Bump 2 bits off the bottom and add r2
            self.setOperValue(op, 0, ((v1 >> 2) << 2) | r2)
        else:
            self.setFlag(EFLAGS_ZF, False)

    def i_bswap(self, op):
        val = self.getOperValue(op, 0)
        tsize = op.opers[0].tsize
        self.setOperValue(op, 0, e_bits.byteswap(val, tsize))

    def i_bsr(self, op):
        val = self.getOperValue(op, 0)

        if val == 0:
            # If the src is 0, set ZF and get out
            self.setFlag(EFLAGS_ZF, True)
            return

        self.setFlag(EFLAGS_ZF, False)

        tsize = op.opers[0].tsize
        rmax = (tsize*8) - 1
        while rmax >= 0:
            if val & (1<<rmax):
                self.setOperValue(op, 1, rmax)
                return
            rmax -= 1

    def doBitTest(self, op):
        val = self.getOperValue(op, 0)
        shift = self.getOperValue(op, 1)
        mask = 1 << shift
        self.setFlag(EFLAGS_CF, val & mask)
        # Return the source and mask for btc/btr
        return val,mask

    def i_bt(self, op):
        self.doBitTest(op)

    def i_btc(self, op):
        # bit test and toggle bit in source
        val, mask = self.doBitTest(op)
        self.setOperValue(op, 0, val ^ mask)

    def i_btr(self, op):
        # bit test (and clear in the source)
        val, mask = self.doBitTest(op)
        mask = e_bits.unsigned(~val, op.opers[0].tsize)
        self.setOperValue(op, 0, val & mask)

    def i_bts(self, op):
        # bit test (and set in the source)
        val, mask = self.doBitTest(op)
        self.setOperValue(op, 0, val | mask)

    def i_call(self, op):
        eip = self.getProgramCounter()
        saved = eip + op.size
        self.doPush(saved)

        val = self.getOperValue(op, 0)
        if val == None:
            raise envi.PDEException(self, "Unknown Call Target")
        return val

    def i_clc(self, op):
        self.setFlag(EFLAGS_CF, False)

    def i_cld(self, op):
        self.setFlag(EFLAGS_DF, False)

    def i_cli(self, op):
        self.setFlag(EFLAGS_IF, False)

    # We include all the possible CMOVcc names just in case somebody
    # gets hinkey with the disassembler.
    def i_cmova(self, op):
        if self.cond_a():    return self.i_mov(op)
    def i_cmovae(self, op):
        if self.cond_ae():   return self.i_mov(op)
    def i_cmovb(self, op):
        if self.cond_b():    return self.i_mov(op)
    def i_cmovbe(self, op):
        if self.cond_be():   return self.i_mov(op)
    def i_cmovc(self, op):
        if self.cond_c():    return self.i_mov(op)
    def i_cmovecxz(self, op):
        if self.cond_ecxz(): return self.i_mov(op)
    def i_cmove(self, op):
        if self.cond_e():    return self.i_mov(op)
    def i_cmovg(self, op):
        if self.cond_g():    return self.i_mov(op)
    def i_cmovge(self, op):
        if self.cond_ge():   return self.i_mov(op)
    def i_cmovl(self, op):
        if self.cond_l():    return self.i_mov(op)
    def i_cmovle(self, op):
        if self.cond_le():   return self.i_mov(op)
    i_cmovna = i_cmovbe
    i_cmovnae = i_cmovb
    i_cmovnb = i_cmovae
    i_cmovnbe = i_cmova
    i_cmovnc = i_cmovae
    def i_cmovne(self, op):
        if self.cond_ne():   return self.i_mov(op)
    i_cmovng = i_cmovle
    i_cmovnge = i_cmovl
    i_cmovnl = i_cmovge
    i_cmovnle = i_cmovg
    def i_cmovno(self, op):
        if self.cond_no():   return self.i_mov(op)
    def i_cmovnp(self, op):
        if self.cond_np():   return self.i_mov(op)
    def i_cmovns(self, op):
        if self.cond_ns():   return self.i_mov(op)
    i_cmovnz = i_cmovne
    def i_cmovo(self, op):
        if self.cond_o():    return self.i_mov(op)
    def i_cmovp(self, op):
        if self.cond_p():    return self.i_mov(op)
    i_cmovpe = i_cmovp
    i_cmovpo = i_cmovnp
    def i_cmovs(self, op):
        if self.cond_s():    return self.i_mov(op)
    i_cmovz = i_cmove

    def i_cmp(self, op):
        self.integerSubtraction(op)

    def doCmps(self, width):
        esi = self.getRegister(REG_ESI)
        edi = self.getRegister(REG_EDI)


        # FIXME che
        sval = self.readMemValue(esi, width)
        dval = self.readMemValue(edi, width)

        self.intSubBase(sval, dval, width, width)

        if self.getFlag(EFLAGS_ZF):
            if self.getFlag(EFLAGS_DF): # decrement
                esi -= width
                edi -= width
            else:
                esi += width
                edi += width
            self.setRegister(REG_ESI, esi)
            self.setRegister(REG_EDI, edi)

    def i_cmpsb(self, op):
        self.doCmps(1)

    def i_cmpsd(self, op):
        """
        Compare the dword pointed at by ds:esi to ds:edi.
        (if equal, update esi/edi by one acording to DF)
        """
        width = 4
        if op.prefixes & PREFIX_OP_SIZE:
            width = 2

        self.doCmps(width)

    def i_cmpxchg(self, op):
        tsize = op.opers[0].tsize
        if tsize == 4:
            areg = REG_EAX
        elif tsize == 1:
            areg = REG_AL
        else:
            areg = REG_AX

        aval = self.getRegister(areg)
        tval = self.getOperValue(op, 0)
        vval = self.getOperValue(op, 1)

        #FIXME eflags... is this supposed to be a real cmp?
        if aval == tval:
            self.setFlag(EFLAGS_ZF, True)
            self.setOperValue(op, 0, vval)
        else:
            self.setFlag(EFLAGS_ZF, False)
            self.setRegister(areg, tval)

    def twoRegCompound(self, topreg, botreg, size):
        """
        Build a compound value where the value of the top reg is shifted and
        or'd with the value of the bot reg ( assuming they are size
        bytes in length).  The return is size * 2 wide (and unsigned).
        """
        top = e_bits.unsigned(self.getRegister(topreg), size)
        bot = e_bits.unsigned(self.getRegister(botreg), size)

        return ((top << (size *8)) | bot)

    def regsFromCompound(self, val, size):
        top = e_bits.unsigned(val >> (size * 8), size)
        bot = e_bits.unsigned(val, size)
        return (top, bot)

    def i_cmpxch8b(self, op):
        size = 4
        dsize = 8
        if op.prefixes & PREFIX_OP_SIZE:
            size = 2
            dsize = 4

        bignum = self.twoRegCompound(REG_EDX, REG_EAX, size)
        testnum = self.getOperValue(op, 0)
        if bignum == testnum:
            self.setFlag(EFLAGS_ZF, 1)
            resval = self.twoRegCompound(REG_ECX, REG_EBX, size)
            self.setOperValue(op, 0, resval)
        else:
            self.setFlag(EFLAGS_ZF, 0)
            edx,eax = self.regsFromCompound(testnum, dsize)
            self.setRegister(REG_EDX, edx)
            self.setRegister(REG_EAX, eax)

    def i_cdq(self, op):
        return self.i_cwd(op)

    def i_cpuid(self, op):
        eax = self.getRegister(REG_EAX)
        print "FIXME: cpuid() returns NONSENSE (eax:0x%.8x)" % eax
        self.setRegister(REG_EAX, 0)
        self.setRegister(REG_EBX, 0)
        self.setRegister(REG_ECX, 0)
        self.setRegister(REG_EDX, 0)

    def i_cwd(self, op):
        #FIXME handle 16 bit variant
        eax = self.getRegister(REG_EAX)
        #PDE
        if eax == None:
            self.setRegister(REG_EDX, None)
            return

        if e_bits.is_signed(eax, 4):
            self.setRegister(REG_EDX, 0xffffffff)
        else:
            self.setRegister(REG_EDX, 0)

    def i_dec(self, op):
        val = self.getOperValue(op, 0)
        if val == None:
            self.undefFlags()
            return
        val -= 1
        self.setOperValue(op, 0, val)
        #FIXME change over to integer subtraction

        self.setFlag(EFLAGS_OF, 0) #FIXME OF
        self.setFlag(EFLAGS_SF, e_bits.is_signed(val, op.opers[0].tsize))
        self.setFlag(EFLAGS_ZF, not val)
        self.setFlag(EFLAGS_AF, 0) #FIXME AF...
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(val))

    def i_div(self, op):
        #FIXME this is probably broke
        oper = op.opers[0]
        val = self.getOperValue(op, 0)
        if val == 0: raise envi.DivideByZero(self)
        if oper.tsize == 1:
            ax = self.getRegister(REG_AX)
            quot = ax / val
            rem  = ax % val
            if quot > 255:
                #FIXME stuff
                print "FIXME: division exception"
            self.setRegister(REG_EAX, (quot << 8) + rem)

        elif oper.tsize == 4:
            #FIXME 16 bit over-ride
            eax = self.getRegister(REG_EAX)
            edx = self.getRegister(REG_EDX)
            tot = (edx << 32) + eax
            quot = tot / val
            rem = tot % val

            if quot > 0xffffffff:
                print "FIXME: division exception"

            self.setRegister(REG_EAX, quot)
            self.setRegister(REG_EDX, rem)

        else:
            raise envi.UnsupportedInstruction(self, op)

    def i_enter(self, op):
        locsize = self.getOperValue(op, 0)
        depth = self.getOperValue(op, 1)
        if depth != 0:
            raise envi.UnsupportedInstruction(self, op)

        esp = self.getRegister(REG_ESP)
        ebp = self.getRegister(REG_EBP)

        esp -= 4 # Room for the base pointer

        self.writeMemValue(esp, ebp, 4)
        self.setRegister(REG_EBP, esp)
        esp -= locsize
        self.setRegister(REG_ESP, esp)

    # FIXME a whole bunch of float instructions whose
    # processing is essentially ignored:
    def i_fldz(self, op):
        pass

    def i_fild(self, op):
        pass

    def i_fstp(self, op):
        pass

    def i_idiv(self, op):
        #FIXME this needs emulation testing!
        tsize = op.opers[0].tsize
        if tsize == 1:
            ax = self.getRegister(REG_AX)
            ax = e_bits.signed(ax, 2)
            d = self.getOperValue(op, 0)
            d = e_bits.signed(d, 1)
            if d == 0: raise envi.DivideByZero(self)
            q = ax / d
            r = ax % d
            res = ((r & 0xff) << 8) | (q & 0xff)
            self.setRegister(REG_AX, res)

        elif tsize == 2:
            val = self.twoRegCompound(REG_DX, REG_AX, 2)
            val = e_bits.signed(val, 4)
            d = self.getOperValue(op, 0)
            d = e_bits.signed(d, 2)
            if d == 0: raise envi.DivideByZero(self)
            q = val / d
            r = val % d

            self.setRegister(REG_AX, q)
            self.setRegister(REG_DX, r)

        elif tsize == 4:
            val = self.twoRegCompound(REG_EDX, REG_EAX, 4)
            val = e_bits.signed(val, 8)
            d = self.getOperValue(op, 0)
            d = e_bits.signed(d, 4)
            if d == 0: raise envi.DivideByZero(self)
            q = val / d
            r = val % d

            self.setRegister(REG_EAX, q)
            self.setRegister(REG_EDX, r)

        else:
            raise envi.UnsupportedInstruction(self, op)

    def i_imul(self, op):
        #FIXME eflags
        # FIXME imul bugs
        ocount = len(op.opers)
        if ocount == 2:
            dst = self.getOperValue(op, 0)
            src = self.getOperValue(op, 1)
            dsize = op.opers[0].tsize
            ssize = op.opers[1].tsize

            # FIXME all these are taken care of in disasm now...
            if dsize > ssize:
                src = e_bits.sign_extend(src, ssize, dsize)
                ssize = dsize

            res = dst * src

            sof = e_bits.is_unsigned_carry(res, dsize)
            self.setFlag(EFLAGS_CF, sof)
            self.setFlag(EFLAGS_OF, sof)

            self.setOperValue(op, 0, res)

        elif ocount == 3:
            dst = self.getOperValue(op, 0)
            src1 = self.getOperValue(op, 1)
            src2 = self.getOperValue(op, 2)

            dsize = op.opers[0].tsize
            ssize1 = op.opers[1].tsize
            ssize2 = op.opers[2].tsize

            if dsize > ssize2: # Only the last operand may be shorter imm
                src2 = e_bits.sign_extend(src2, ssize2, dsize)
                ssize2 = dsize

            res = src1 * src2

            sof = e_bits.is_unsigned_carry(res, dsize)
            self.setFlag(EFLAGS_CF, sof)
            self.setFlag(EFLAGS_OF, sof)

            self.setOperValue(op, 0, res)

        else:
            raise envi.UnsupportedInstruction(self, op)

    def i_in(self, op):
        raise envi.UnsupportedInstruction(self, op)

    def i_inc(self, op):
        size = op.opers[0].tsize
        val = self.getOperValue(op, 0)

        sval = e_bits.signed(val, size)
        sval += 1

        self.setOperValue(op, 0, sval)

        # Another arithmetic op where doing signed and unsigned is easier ;)

        self.setFlag(EFLAGS_OF, e_bits.is_signed_overflow(sval, size))
        self.setFlag(EFLAGS_SF, e_bits.is_signed(sval, size))
        self.setFlag(EFLAGS_ZF, not sval)
        self.setFlag(EFLAGS_AF, (sval & 0xf == 0))
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(sval))

    def i_int(self, op):
        raise envi.UnsupportedInstruction(self, op)

    def i_int3(self, op):
        raise envi.BreakpointHit(self)

    def i_lea(self, op):
        base = self.getOperAddr(op, 1)
        self.setOperValue(op, 0, base)

    def decCounter(self):
        """
        A helper to decrement and return the counter
        """
        ecx = self.getRegister(REG_ECX)
        ecx -= 1
        self.setRegister(REG_ECX, ecx)
        return ecx

    def i_lodsb(self, op):
        esi = self.getRegister(REG_ESI)
        newal = self.readMemoryFormat(esi, "<B")[0]
        self.setRegister(REG_AL, newal)
        if not self.getFlag(EFLAGS_DF):
            esi += 1
        else:
            esi -= 1
        self.setRegister(REG_ESI, esi)
        
    def i_lodsd(self, op):
        esi = self.getRegister(REG_ESI)
        neweax = self.readMemoryFormat(esi, "<L")[0]
        #FIXME figgure out ADDR_SIZE vs OP_SIZE and which is which
        self.setRegister(REG_EAX, neweax)
        if not self.getFlag(EFLAGS_DF):
            esi += 4
        else:
            esi -= 4
        self.setRegister(REG_ESI, esi)

    def i_loop(self, op):
        if self.decCounter() != 0:
            return self.getOperValue(op, 0)

    def i_loopz(self, op):
        if self.decCounter() != 0 and self.cond_e():
            return self.getOperValue(op, 0)

    def i_loopnz(self, op):
        if self.decCounter() != 0 and self.cond_ne():
            return self.getOperValue(op, 0)

    i_loope = i_loopz
    i_loopne = i_loopnz

    def i_leave(self, op):
        ebp = self.getRegister(REG_EBP)
        self.setRegister(REG_ESP, ebp)
        self.setRegister(REG_EBP, self.doPop())

    def i_mov(self, op):
        val = self.getOperValue(op, 1)
        self.setOperValue(op, 0, val)

    def i_movq(self, op):
        val = self.getOperValue(op, 1)
        self.setOperValue(op, 0, val)

    def i_movsb(self, op):
        esi = self.getRegister(REG_ESI)
        edi = self.getRegister(REG_EDI)
        bytes = self.readMemory(esi, 1)
        self.writeMemory(edi, bytes)
        if self.getFlag(EFLAGS_DF):
            self.setRegister(REG_ESI, esi-1)
            self.setRegister(REG_EDI, edi-1)
        else:
            self.setRegister(REG_ESI, esi+1)
            self.setRegister(REG_EDI, edi+1)

    def i_movsd(self, op):
        esi = self.getRegister(REG_ESI)
        edi = self.getRegister(REG_EDI)
        bytes = self.readMemory(esi, 4)
        self.writeMemory(edi, bytes)
        if self.getFlag(EFLAGS_DF):
            self.setRegister(REG_ESI, esi-4)
            self.setRegister(REG_EDI, edi-4)
        else:
            self.setRegister(REG_ESI, esi+4)
            self.setRegister(REG_EDI, edi+4)

    def i_movsx(self, op):
        osize = op.opers[1].tsize
        nsize = op.opers[0].tsize
        val = self.getOperValue(op, 1)
        val = e_bits.sign_extend(val, osize, nsize)
        self.setOperValue(op, 0, val)

    def i_movzx(self, op):
        val = self.getOperValue(op, 1)
        self.setOperValue(op, 0, val)

    def i_mul(self, op):
        #FIXME make sure these work right
        tsize = op.opers[0].tsize

        val = self.getOperValue(op, 0)

        # Return al/ax/eax as needed...
        a = self._emu_getGpReg(GPR_A, tsize)

        res = a * val

        if tsize == 1:
            self.setRegister(REG_AX, res)

        elif tsize == 2:
            d,a = self.regsFromCompound(res, tsize)
            self._emu_setGpReg(GPR_A, a, tsize)
            self._emu_setGpReg(GPR_D, d, tsize)

        # If the high order stuff was used, set CF/OF
        if res >> (tsize * 8):
            self.setFlag(EFLAGS_CF, True)
            self.setFlag(EFLAGS_OF, True)
        else:
            self.setFlag(EFLAGS_CF, False)
            self.setFlag(EFLAGS_OF, False)

    def _emu_setGpReg(self, reg, val, tsize):
        """
        Automagically map all general purpose register accesses
        to their tsize equiv.  Helps clean up a lot of code
        (and makes a nice place for AMD64 to hook ;) )
        """
        if tsize == 1:
            reg += 0x00080000
        elif tsize == 2:
            reg += 0x00100000
        self.setRegister(reg, value)

    def _emu_getGpReg(self, reg, tsize):
        """
        Automagically map all general purpose register accesses
        to their tsize equiv.  Helps clean up a lot of code
        (and makes a nice place for AMD64 to hook ;) )
        """
        if tsize == 1:
            reg += 0x00080000
        elif tsize == 2:
            reg += 0x00100000
        return self.getRegister(reg)

    def i_neg(self, op):
        tsize = op.opers[0].tsize
        val = self.getOperValue(op, 0)
        res = 0 - val
        self.setOperValue(op, 0, res)

        self.setFlag(EFLAGS_CF, val != 0)
        self.setFlag(EFLAGS_ZF, not res)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(res, tsize))
        #FIXME how does neg cause/not cause a carry?
        self.setFlag(EFLAGS_AF, 0) # FIXME EFLAGS_AF

    def i_nop(self, op):
        pass

    def i_not(self, op):
        val = self.getOperValue(op, 0)
        val ^= e_bits.u_maxes[op.opers[0].tsize]
        self.setOperValue(op, 0, val)

    def i_or(self, op):
        dst = self.getOperValue(op, 0)
        dsize = op.opers[0].tsize
        src = self.getOperValue(op, 1)
        ssize = op.opers[1].tsize

        if dsize != ssize:
            src = e_bits.sign_extend(src, ssize, dsize)
            ssize = dsize

        res = dst | src

        self.setOperValue(op, 0, res)

        self.setFlag(EFLAGS_OF, 0)
        self.setFlag(EFLAGS_CF, 0)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
        self.setFlag(EFLAGS_ZF, not res)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))

    def i_pop(self, op):
        val = self.doPop()
        self.setOperValue(op, 0, val)

    def i_popad(self, op):
        #FIXME 16 bit?
        self.setRegister(REG_EDI, self.doPop())
        self.setRegister(REG_ESI, self.doPop())
        self.setRegister(REG_EBP, self.doPop())
        self.doPop() # skip one
        self.setRegister(REG_EBX, self.doPop())
        self.setRegister(REG_EDX, self.doPop())
        self.setRegister(REG_ECX, self.doPop())
        self.setRegister(REG_EAX, self.doPop())

    def i_popfd(self, op):
        eflags = self.doPop()
        self.setRegister(REG_EFLAGS, eflags)

    def i_push(self, op):
        val = self.getOperValue(op, 0)
        if isinstance(op.opers[0], i386ImmOper):
            val = e_bits.sign_extend(val, op.opers[0].tsize, 4) #FIXME 64bit
        self.doPush(val)

    def i_pushad(self, op):
        tmp = self.getRegister(REG_ESP)
        self.doPush(self.getRegister(REG_EAX))
        self.doPush(self.getRegister(REG_ECX))
        self.doPush(self.getRegister(REG_EDX))
        self.doPush(self.getRegister(REG_EBX))
        self.doPush(tmp)
        self.doPush(self.getRegister(REG_EBP))
        self.doPush(self.getRegister(REG_ESI))
        self.doPush(self.getRegister(REG_EDI))

    def i_pushfd(self, op):
        eflags = self.getRegister(REG_EFLAGS)
        self.doPush(eflags)

    def i_jmp(self, op):
        return self.getOperValue(op, 0)

    # We include all the possible Jcc names just in case somebody
    # gets hinkey with the disassembler.
    def i_ja(self, op):
        if self.cond_a():    return self.getOperValue(op, 0)
    def i_jae(self, op):
        if self.cond_ae():   return self.getOperValue(op, 0)
    def i_jb(self, op):
        if self.cond_b():    return self.getOperValue(op, 0)
    def i_jbe(self, op):
        if self.cond_be():   return self.getOperValue(op, 0)
    def i_jc(self, op):
        if self.cond_c():    return self.getOperValue(op, 0)
    def i_jecxz(self, op):
        if self.cond_ecxz(): return self.getOperValue(op, 0)
    def i_je(self, op):
        if self.cond_e():    return self.getOperValue(op, 0)
    def i_jg(self, op):
        if self.cond_g():    return self.getOperValue(op, 0)
    def i_jge(self, op):
        if self.cond_ge():   return self.getOperValue(op, 0)
    def i_jl(self, op):
        if self.cond_l():    return self.getOperValue(op, 0)
    def i_jle(self, op):
        if self.cond_le():   return self.getOperValue(op, 0)
    i_jna = i_jbe
    i_jnae = i_jb
    i_jnb = i_jae
    i_jnbe = i_ja
    i_jnc = i_jae
    def i_jne(self, op):
        if self.cond_ne():   return self.getOperValue(op, 0)
    i_jng = i_jle
    i_jnge = i_jl
    i_jnl = i_jge
    i_jnle = i_jg
    def i_jno(self, op):
        if self.cond_no():   return self.getOperValue(op, 0)
    def i_jnp(self, op):
        if self.cond_np():   return self.getOperValue(op, 0)
    def i_jns(self, op):
        if self.cond_ns():   return self.getOperValue(op, 0)
    i_jnz = i_jne
    def i_jo(self, op):
        if self.cond_o():    return self.getOperValue(op, 0)
    def i_jp(self, op):
        if self.cond_p():    return self.getOperValue(op, 0)
    i_jpe = i_jp
    i_jpo = i_jnp
    def i_js(self, op):
        if self.cond_s():    return self.getOperValue(op, 0)
    i_jz = i_je

    def i_rcl(self, op):
        dsize = op.opers[0].tsize
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        src = src & 0x1f

        # Put that carry bit up there.
        if self.getFlag(EFLAGS_CF):
            dst = dst | (1 << (8 * dsize))

        # Add one to account for carry
        x = ((8*dsize) - src) + 1
        #FIXME is this the one that can end up negative?

        res = (dst << src) | (dst >> x)
        cf = (res >> (8*dsize)) & 1
        res = e_bits.unsigned(res, dsize)

        self.setFlag(EFLAGS_CF, cf)
        if src == 1:
            m1 = e_bits.msb(res, dsize)
            m2 = e_bits.msb(res << 1, dsize)
            self.setFlag(EFLAGS_OF, m1 ^ m2)

        self.setOperValue(op, 0, res)

    def i_rcr(self, op):
        dsize = op.opers[0].tsize
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        src = src & 0x1f
        # Put that carry bit up there.
        if self.getFlag(EFLAGS_CF):
            dst = dst | (1 << (8 * dsize))

        # Add one to account for carry
        x = ((8*dsize) - src) + 1

        res = (dst >> src) | (dst << x)
        cf = (res >> (8*dsize)) & 1
        res = e_bits.unsigned(res, dsize)

        self.setFlag(EFLAGS_CF, cf)
        if src == 1:
            m1 = e_bits.msb(res, dsize)
            m2 = e_bits.msb(res << 1, dsize)
            self.setFlag(EFLAGS_OF, m1 ^ m2)

        self.setOperValue(op, 0, res)

    def i_rdtsc(self, op):
        """
        Read the clock cycle counter into edx:eax
        """
        self.setRegister(REG_EDX, 0)
        self.setRegister(REG_EAX, 0x414141)

    def i_rol(self, op):
        dstSize = op.opers[0].tsize
        count = self.getOperValue(op, 1)
        tempCount = shiftMask(count, dstSize)

        if tempCount > 0: # Yeah, i know...weird. See the intel manual
            while tempCount:
                val = self.getOperValue(op, 0)
                tempCf = e_bits.msb(val, dstSize)
                self.setOperValue(op, 0, (val * 2) + tempCf)
                tempCount -= 1
            val = self.getOperValue(op, 0)
            self.setFlag(EFLAGS_CF, e_bits.lsb(val))
            if count == 1:
                val = self.getOperValue(op, 0)
                cf = self.getFlag(EFLAGS_CF)
                self.setFlag(EFLAGS_OF, e_bits.msb(val, dstSize) ^ cf)
            else:
                self.setFlag(EFLAGS_OF, False)
        
    def i_ror(self, op):
        dstSize = op.opers[0].tsize
        count = self.getOperValue(op, 1)
        tempCount = shiftMask(count, dstSize)

        if tempCount > 0: # Yeah, i know...weird. See the intel manual
            while tempCount:
                val = self.getOperValue(op, 0)
                tempCf = e_bits.lsb(val)
                self.setOperValue(op, 0, (val / 2) + (tempCf * (2 ** dstSize)))
                tempCount -= 1
            val = self.getOperValue(op, 0)
            self.setFlag(EFLAGS_CF, e_bits.msb(val, dstSize))
            if count == 1:
                val = self.getOperValue(op, 0)
                cf = self.getFlag(EFLAGS_CF)
                # FIXME: This may be broke...the manual is kinda flaky here
                self.setFlag(EFLAGS_OF, e_bits.msb(val, dstSize) ^ (e_bits.msb(val, dstSize) - 1))
            else:
                self.setFlag(EFLAGS_OF, False)

    def i_ret(self, op):
        ret = self.doPop()
        if len(op.opers):
            esp = self.getRegister(REG_ESP)
            ival = self.getOperValue(op, 0)
            self.setRegister(REG_ESP, esp+ival)
        return ret

    def i_sal(self, op):
        dsize = op.opers[0].tsize
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        src = src & 0x1f

        # According to intel manual, if src == 0 eflags are not changed
        if src == 0:
            return

        res = dst << src
        cf = (res >> 8*dsize) & 1

        res = e_bits.unsigned(res, dsize)

        self.setFlag(EFLAGS_CF, cf)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
        self.setFlag(EFLAGS_ZF, not res)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
        if src == 1:
            self.setFlag(EFLAGS_OF, not e_bits.msb(res, dsize) == cf)
        else:
            self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo

        self.setOperValue(op, 0, res)

    def i_sar(self, op):
        dsize = op.opers[0].tsize
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        src = src & 0x1f

        # According to intel manual, if src == 0 eflags are not changed
        if src == 0:
            return

        signed = e_bits.msb(dst, dsize)

        res = dst >> src
        cf = (dst >> (src-1)) & 1

        # If it was signed, we need to fill in all those bits we
        # shifted off with ones.
        if signed:
            x = (8*dsize) - src
            umax = e_bits.u_maxes[dsize]
            res |= (umax >> x) << x

        res = e_bits.unsigned(res, dsize)

        self.setFlag(EFLAGS_CF, cf)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
        self.setFlag(EFLAGS_ZF, not res)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
        if src == 1:
            self.setFlag(EFLAGS_OF, False)
        else:
            self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo

        self.setOperValue(op, 0, res)

    def i_shl(self, op):
        return self.i_sal(op)

    def i_shr(self, op):
        dsize = op.opers[0].tsize
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        src = src & 0x1f

        # According to intel manual, if src == 0 eflags are not changed
        if src == 0:
            return

        res = dst >> src
        cf = (dst >> (src-1)) & 1

        res = e_bits.unsigned(res, dsize)

        self.setFlag(EFLAGS_CF, cf)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(res, dsize))
        self.setFlag(EFLAGS_ZF, not res)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(res))
        if src == 1:
            self.setFlag(EFLAGS_OF, False)
        else:
            self.setFlag(EFLAGS_OF, 0) # Undefined, but zero'd on core2 duo

        self.setOperValue(op, 0, res)

    def i_shrd(self, op):
        dsize = op.opers[0].tsize
        bsize = dsize * 8
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)
        cnt = self.getOperValue(op, 2)

        cnt &= 0x1f # Reg gets masked down

        if cnt == 0:
            return

        if cnt > bsize:
            # result is "undfined"
            return

        res = dst >> cnt
        res |= src << (bsize - cnt)

        # We now have the bits masked into res, but it has become
        # wider than the original operand.

        # Ret is masked down to size
        ret = e_bits.unsigned(res, dsize)

        if cnt == 1: # Set OF on sign change
            dsign = e_bits.is_signed(dst, dsize)
            rsign = e_bits.is_signed(ret, dsize)
            self.setFlag(EFLAGS_OF, dsign != rsign)

        # set carry to last shifted bit
        self.setFlag(EFLAGS_CF, (res << bsize) & 1)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize))
        self.setFlag(EFLAGS_ZF, not ret)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret))

        self.setOperValue(op, 0, ret)

    def i_shld(self, op):
        dsize = op.opers[0].tsize
        bsize = dsize * 8
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)
        cnt = self.getOperValue(op, 2)

        cnt &= 0x1f # Reg gets masked down

        if cnt == 0:
            return

        if cnt > bsize:
            return

        res = dst << cnt
        res |= src >> (bsize - cnt)
        ret = e_bits.unsigned(res, dsize)

        if cnt == 1: # Set OF on sign change
            dsign = e_bits.is_signed(dst, dsize)
            rsign = e_bits.is_signed(ret, dsize)
            self.setFlag(EFLAGS_OF, dsign != rsign)

        # set carry to last shifted bit
        self.setFlag(EFLAGS_CF, (dst << (cnt-1)) & 1)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize))
        self.setFlag(EFLAGS_ZF, not ret)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret))

        self.setOperValue(op, 0, ret)

    def i_scasb(self, op):
        al = self.getRegister(REG_AL)
        edi = self.getRegister(REG_EDI)
        base,size = self.segments[SEG_ES]
        memval = ord(self.readMemory(base+edi, 1))
        self.intSubBase(al, memval, 1, 1)
        if self.getFlag(EFLAGS_DF):
            edi -= 1
        else:
            edi += 1
        self.setRegister(REG_EDI, edi)

    def i_scasd(self, op):
        #FIXME probably need to handle oper prefix by hand here...
        eax = self.getRegister(REG_EAX)
        edi = self.getRegister(REG_EDI)
        base,size = self.segments[SEG_ES]
        memval = struct.unpack("<L",self.readMemory(base+edi, 4))[0]
        self.intSubBase(eax, memval, 4, 4)
        if self.getFlag(EFLAGS_DF):
            edi -= 4
        else:
            edi += 4
        self.setRegister(REG_EDI, edi)

    def i_stosb(self, op):
        al = self.getRegister(REG_AL)
        edi = self.getRegister(REG_EDI)
        base,size = self.segments[SEG_ES]
        self.writeMemory(base+edi, chr(al))
        if self.getFlag(EFLAGS_DF):
            edi -= 1
        else:
            edi += 1
        self.setRegister(REG_EDI, edi)

    def i_stosd(self, op):
        eax = self.getRegister(REG_EAX)
        edi = self.getRegister(REG_EDI)
        base,size = self.segments[SEG_ES]
        self.writeMemory(base+edi, struct.pack("<L", eax))
        if self.getFlag(EFLAGS_DF):
            edi -= 4
        else:
            edi += 4
        self.setRegister(REG_EDI, edi)

    # We include all the possible SETcc names just in case somebody
    # gets hinkey with the disassembler.
    def i_seta(self, op):     self.setOperValue(op, 0, int(self.cond_a()))
    def i_setae(self, op):    self.setOperValue(op, 0, int(self.cond_ae()))
    def i_setb(self, op):     self.setOperValue(op, 0, int(self.cond_b()))
    def i_setbe(self, op):    self.setOperValue(op, 0, int(self.cond_be()))
    def i_setc(self, op):     self.setOperValue(op, 0, int(self.cond_c()))
    def i_setecxz(self, op):  self.setOperValue(op, 0, int(self.cond_ecxz()))
    def i_sete(self, op):     self.setOperValue(op, 0, int(self.cond_e()))
    def i_setg(self, op):     self.setOperValue(op, 0, int(self.cond_g()))
    def i_setge(self, op):    self.setOperValue(op, 0, int(self.cond_ge()))
    def i_setl(self, op):     self.setOperValue(op, 0, int(self.cond_l()))
    def i_setle(self, op):    self.setOperValue(op, 0, int(self.cond_le()))
    i_setna = i_setbe
    i_setnae = i_setb
    i_setnb = i_setae
    i_setnbe = i_seta
    i_setnc = i_setae
    def i_setne(self, op):    self.setOperValue(op, 0, int(self.cond_ne()))
    i_setng = i_setle
    i_setnge = i_setl
    i_setnl = i_setge
    i_setnle = i_setg
    def i_setno(self, op):    self.setOperValue(op, 0, int(self.cond_no()))
    def i_setnp(self, op):    self.setOperValue(op, 0, int(self.cond_np()))
    def i_setns(self, op):    self.setOperValue(op, 0, int(self.cond_ns()))
    i_setnz = i_setne
    def i_seto(self, op):     self.setOperValue(op, 0, int(self.cond_o()))
    def i_setp(self, op):     self.setOperValue(op, 0, int(self.cond_p()))
    i_setpe = i_setp
    i_setpo = i_setnp
    def i_sets(self, op):     self.setOperValue(op, 0, int(self.cond_s()))
    i_setz = i_sete

    def i_sbb(self, op):
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        # Much like "integer subtraction" but we need
        # too add in the carry flag
        if src == None or dst == None:
            self.undefFlags()
            return None

        dsize = op.opers[0].tsize
        ssize = op.opers[1].tsize
        # Sign extend immediates where the sizes don't match
        if dsize != ssize:
            src = e_bits.sign_extend(src, ssize, dsize)
            ssize = dsize
        src += self.getFlag(EFLAGS_CF)
        res = self.intSubBase(src, dst, ssize, dsize)
        self.setOperValue(op, 0, res)

    # FIXME scas stuff goes here
    # FIXME conditional byte set goes here
    def i_stc(self, op):
        self.setFlag(EFLAGS_CF, True)

    def i_std(self, op):
        self.setFlag(EFLAGS_DF, True)

    def i_sti(self, op):
        self.setFlag(EFLAGS_IF, True)

    # FIXME stos variants go here
    def i_stosd(self, op):
        eax = self.getRegister(REG_EAX)
        edi = self.getRegister(REG_EDI)
        # FIXME shouldn't have to do this directly
        # FIXME this needs a 32/16 bit mode check
        base,size = self.segments[SEG_ES]
        self.writeMemValue(base+edi, eax, 4)
        # FIXME edi inc must be by oper len
        self.setRegister(REG_EDI, edi+4)

    def i_sub(self, op):
        x = self.integerSubtraction(op)
        if x != None:
            self.setOperValue(op, 0, x)

    def i_test(self, op):
        self.logicalAnd(op)

    def i_wait(self, op):
        print "i_wait() is a stub..."

    def i_xadd(self, op):
        val1 = self.getOperValue(op, 0)
        val2 = self.getOperValue(op, 1)
        temp = val1 + val2
        self.setOperValue(op, 1, val1)
        self.setOperValue(op, 0, temp)

    def i_xchg(self, op):
        temp = self.getOperValue(op, 0)
        self.setOperValue(op, 0, self.getOperValue(op, 1))
        self.setOperValue(op, 1, temp)

    def i_xor(self, op):
        dsize = op.opers[0].tsize
        ssize = op.opers[1].tsize
        dst = self.getOperValue(op, 0)
        src = self.getOperValue(op, 1)

        ret = src ^ dst

        self.setOperValue(op, 0, ret)

        self.setFlag(EFLAGS_CF, 0)
        self.setFlag(EFLAGS_OF, 0)
        self.setFlag(EFLAGS_SF, e_bits.is_signed(ret, dsize))
        self.setFlag(EFLAGS_ZF, not ret)
        self.setFlag(EFLAGS_PF, e_bits.is_parity_byte(ret))
        self.setFlag(EFLAGS_AF, False) # Undefined but actually cleared on amd64 X2

    def i_pxor(self, op):
        return self.i_xor(op)

