From 8a167cc5700b0249b0ddd9ab0e9f5a1719fa5060 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= <linus@folkdatorn.se>
Date: Fri, 4 Oct 2024 18:41:46 +0200
Subject: [PATCH 1/2] make imul_trunc generic over signed integers

---
 x86/src/ops/math.rs | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/x86/src/ops/math.rs b/x86/src/ops/math.rs
index 59462d72..aa8967e7 100644
--- a/x86/src/ops/math.rs
+++ b/x86/src/ops/math.rs
@@ -2,7 +2,10 @@ use super::helpers::*;
 use crate::{registers::Flags, x86::CPU};
 use iced_x86::{Instruction, Register};
 use memory::Mem;
-use num_traits::ops::overflowing::OverflowingSub;
+use num_traits::{
+    ops::overflowing::{OverflowingMul, OverflowingSub},
+    Signed,
+};
 
 /// This trait is implemented for u32/u16/u8 and lets us write operations generically
 /// over all those bit sizes.
@@ -808,9 +811,13 @@ pub fn imul_rm8(cpu: &mut CPU, mem: Mem, instr: &Instruction) {
     cpu.regs.set16(Register::AX, res);
 }
 
-fn imul_trunc(x: i32, y: i32, _flags: &mut Flags) -> i32 {
-    // TODO: flags.
-    x.wrapping_mul(y)
+fn imul_trunc<I: OverflowingMul + Signed>(x: I, y: I, flags: &mut Flags) -> I {
+    let (result, flag) = x.overflowing_mul(&y);
+
+    flags.set(Flags::OF, flag);
+    flags.set(Flags::CF, flag);
+
+    result
 }
 
 pub fn imul_r32_rm32(cpu: &mut CPU, mem: Mem, instr: &Instruction) {

From 5a812602c374b0b796af4f98754140d2be6c4915 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= <linus@folkdatorn.se>
Date: Sat, 14 Sep 2024 20:05:59 +0200
Subject: [PATCH 2/2] implement imul_r16_rm16

---
 x86/src/ops/math.rs  | 7 +++++++
 x86/src/ops/table.rs | 1 +
 2 files changed, 8 insertions(+)

diff --git a/x86/src/ops/math.rs b/x86/src/ops/math.rs
index aa8967e7..91dd71ca 100644
--- a/x86/src/ops/math.rs
+++ b/x86/src/ops/math.rs
@@ -841,6 +841,13 @@ pub fn imul_r32_rm32_imm8(cpu: &mut CPU, mem: Mem, instr: &Instruction) {
     cpu.regs.set32(instr.op0_register(), value as u32);
 }
 
+pub fn imul_r16_rm16(cpu: &mut CPU, mem: Mem, instr: &Instruction) {
+    let x = cpu.regs.get16(instr.op0_register()) as i16;
+    let y = op1_rm16(cpu, mem, instr) as i16;
+    let value = imul_trunc(x, y, &mut cpu.flags);
+    cpu.regs.set16(instr.op0_register(), value as u16);
+}
+
 pub fn idiv_rm32(cpu: &mut CPU, mem: Mem, instr: &Instruction) {
     let x = get_edx_eax(cpu) as i64;
     let y = rm32(cpu, mem, instr).get() as i32 as i64;
diff --git a/x86/src/ops/table.rs b/x86/src/ops/table.rs
index da2be50c..39a0ea4f 100644
--- a/x86/src/ops/table.rs
+++ b/x86/src/ops/table.rs
@@ -264,6 +264,7 @@ const OP_TAB: [Option<Op>; 2553] = {
     tab[iced_x86::Code::Imul_r32_rm32 as usize] = Some(imul_r32_rm32);
     tab[iced_x86::Code::Imul_r32_rm32_imm32 as usize] = Some(imul_r32_rm32_imm32);
     tab[iced_x86::Code::Imul_r32_rm32_imm8 as usize] = Some(imul_r32_rm32_imm8);
+    tab[iced_x86::Code::Imul_r16_rm16 as usize] = Some(imul_r16_rm16);
     tab[iced_x86::Code::Idiv_rm32 as usize] = Some(idiv_rm32);
     tab[iced_x86::Code::Idiv_rm16 as usize] = Some(idiv_rm16);
     tab[iced_x86::Code::Idiv_rm8 as usize] = Some(idiv_rm8);