# Path: VM/util.py
# class Instruction(metaclass=InstructionMeta):
#     """
#     This class is here for convenience purposes only since it's much simpler (a.k.a. easier to type) to inherit from a class
#      than to use some weird metaclass. Also, all classes inheriting this one are automagically registered by the metaclass.
#     """
#     ...
# 
# Path: VM/misc.py
# def parity(num: int) -> int:
#     """
#     Calculate the parity of the least significant byte of a number.
#     See: https://graphics.stanford.edu/~seander/bithacks.html#ParityWith64Bits
#     :param num: The byte to calculate the parity of.
#     :return:
#     """
# 
#     return ((((num & 0xFF) * 0x0101010101010101) & 0x8040201008040201) % 0x1FF) & 1
# 
# def sign_extend(num: int, nbytes: int) -> int:
#     # TODO: this is basically converting an unsigned number to signed. Maybe rename the function?
#     """
#     See: https://stackoverflow.com/a/32031543/4354477
#     :param num: The integer to sign-extend
#     :param nbytes: The number of bytes _in that integer_.
#     :return:
#     """
#     if num < 0:
#         return num
#     
#     sign_bit = 1 << (nbytes * 8 - 1)
#     return (num & (sign_bit - 1)) - (num & sign_bit)


import enum
    import logging
from ..util import Instruction
from ..misc import parity, sign_extend
from functools import partialmethod as P
    from ..debug import debug_operand, debug_register_operand
            0x69  : P(self.r_rm_imm, _8bit_imm=False)
            }

    def rm(vm, _8bit: int) -> bool:
        sz = 1 if _8bit else vm.operand_size

        old_eip = vm.eip

        RM, R = vm.process_ModRM()

        if R[1] != 5:
            vm.eip = old_eip
            return False  # This is not IMUL

        type, loc = RM

        src = (type).get(loc, sz, True)
        dst = vm.reg.get(0, sz, True)  # AL/AX/EAX

        tmp_xp = src * dst

        _sz = 2 if sz == 1 else sz
        lo = tmp_xp & MAXVALS[_sz]
        hi = (tmp_xp >> (sz * 8)) & MAXVALS[_sz]

        vm.reg.set(0, _sz, lo)  # (E)AX

        if sz != 1:
            vm.reg.set(2, _sz, hi)  # (E)DX


# Path: VM/util.py
# class Instruction(metaclass=InstructionMeta):
#     """
#     This class is here for convenience purposes only since it's much simpler (a.k.a. easier to type) to inherit from a class
#      than to use some weird metaclass. Also, all classes inheriting this one are automagically registered by the metaclass.
#     """
#     ...
# 
# Path: VM/misc.py
# def parity(num: int) -> int:
#     """
#     Calculate the parity of the least significant byte of a number.
#     See: https://graphics.stanford.edu/~seander/bithacks.html#ParityWith64Bits
#     :param num: The byte to calculate the parity of.
#     :return:
#     """
# 
#     return ((((num & 0xFF) * 0x0101010101010101) & 0x8040201008040201) % 0x1FF) & 1
# 
# def sign_extend(num: int, nbytes: int) -> int:
#     # TODO: this is basically converting an unsigned number to signed. Maybe rename the function?
#     """
#     See: https://stackoverflow.com/a/32031543/4354477
#     :param num: The integer to sign-extend
#     :param nbytes: The number of bytes _in that integer_.
#     :return:
#     """
#     if num < 0:
#         return num
#     
#     sign_bit = 1 << (nbytes * 8 - 1)
#     return (num & (sign_bit - 1)) - (num & sign_bit)


# Path: VM/instructions/math.py
import enum
    import logging
from ..util import Instruction
from ..misc import parity, sign_extend
from functools import partialmethod as P
    from ..debug import debug_operand, debug_register_operand

            0x69  : P(self.r_rm_imm, _8bit_imm=False)
            }

    def rm(vm, _8bit: int) -> bool:
        sz = 1 if _8bit else vm.operand_size

        old_eip = vm.eip

        RM, R = vm.process_ModRM()

        if R[1] != 5:
            vm.eip = old_eip
            return False  # This is not IMUL

        type, loc = RM

        src = (type).get(loc, sz, True)
        dst = vm.reg.get(0, sz, True)  # AL/AX/EAX

        tmp_xp = src * dst

        _sz = 2 if sz == 1 else sz
        lo = tmp_xp & MAXVALS[_sz]
        hi = (tmp_xp >> (sz * 8)) & MAXVALS[_sz]

        vm.reg.set(0, _sz, lo)  # (E)AX

        if sz != 1:
            vm.reg.set(2, _sz, hi)  # (E)DX


        set_flags = sign_extend(tmp_xp >> (sz * 8), sz) != tmp_xp