about summary refs log tree commit diff stats
path: root/015immediate_addressing.cc
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-03-06 18:31:14 -0800
committerKartik Agaram <vc@akkartik.com>2020-03-06 18:34:27 -0800
commit8f256f1f2ee6a2a49816dd23d26cd120f526bf0b (patch)
tree314294998b527980cdf85ecb51386642bfbe3af4 /015immediate_addressing.cc
parent4c19dd3968d2ce733073774867d97cc96b4277e6 (diff)
downloadmu-8f256f1f2ee6a2a49816dd23d26cd120f526bf0b.tar.gz
6090 - new instruction: multiply by immediate
This is a 3-operand instruction:
  r32 = rm32 * imm32

It looks like https://c9x.me/x86/html/file_module_x86_id_138.html has a
bug, implying the same opcode supports a 2-operand version. I don't see
that in the Intel manual pdf, or at alternative sites like https://www.felixcloutier.com/x86/imul

Native runs seem to validate my understanding.

In the process I also fixed a bug in the existing multiply instruction
0f af: the only flags it sets are OF and CF. The other existing multiply
instruction f7 was doing things right.
Diffstat (limited to '015immediate_addressing.cc')
-rw-r--r--015immediate_addressing.cc39
1 files changed, 39 insertions, 0 deletions
diff --git a/015immediate_addressing.cc b/015immediate_addressing.cc
index a2923b7a..c1363ae1 100644
--- a/015immediate_addressing.cc
+++ b/015immediate_addressing.cc
@@ -1270,3 +1270,42 @@ case 0x68: {
   trace(Callstack_depth+1, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
   break;
 }
+
+//:: multiply
+
+:(before "End Initialize Op Names")
+put_new(Name, "69", "multiply rm32 by imm32 and store result in r32");
+
+:(code)
+void test_multiply_imm32() {
+  Reg[EAX].i = 2;
+  Reg[EBX].i = 3;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "  69     c3                          04 00 00 00 \n"  // EAX = EBX * 4
+      // ModR/M in binary: 11 (direct) 000 (dest EAX) 011 (src EBX)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: multiply r/m32 by 0x00000004 and store result in EAX\n"
+      "run: r/m32 is EBX\n"
+      "run: storing 0x0000000c\n"
+  );
+}
+
+:(before "End Single-Byte Opcodes")
+case 0x69: {
+  const uint8_t modrm = next();
+  const uint8_t rdest = (modrm>>3)&0x7;
+  const int32_t val = next32();
+  trace(Callstack_depth+1, "run") << "multiply r/m32 by 0x" << HEXWORD << val << " and store result in " << rname(rdest) << end();
+  const int32_t* signed_arg1 = effective_address(modrm);
+  int32_t result = *signed_arg1 * val;
+  int64_t full_result = static_cast<int64_t>(*signed_arg1) * val;
+  OF = (result != full_result);
+  CF = OF;
+  trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+  Reg[rdest].i = result;
+  trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[rdest].i << end();
+  break;
+}