about summary refs log tree commit diff stats
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
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.
-rw-r--r--013direct_addressing.cc4
-rw-r--r--015immediate_addressing.cc39
-rw-r--r--033check_operands.cc5
-rwxr-xr-xapps/ex14bin0 -> 213 bytes
-rw-r--r--apps/ex14.subx26
5 files changed, 71 insertions, 3 deletions
diff --git a/013direct_addressing.cc b/013direct_addressing.cc
index 729b4d08..2450e54c 100644
--- a/013direct_addressing.cc
+++ b/013direct_addressing.cc
@@ -321,10 +321,8 @@ case 0xaf: {  // multiply r32 by r/m32
   trace(Callstack_depth+1, "run") << "multiply " << rname(arg1) << " by r/m32" << end();
   const int32_t* arg2 = effective_address(modrm);
   int32_t result = Reg[arg1].i * (*arg2);
-  SF = (Reg[arg1].i < 0);
-  ZF = (Reg[arg1].i == 0);
   int64_t full_result = static_cast<int64_t>(Reg[arg1].i) * (*arg2);
-  OF = (Reg[arg1].i != full_result);
+  OF = (result != full_result);
   CF = OF;
   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
   Reg[arg1].i = result;
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;
+}
diff --git a/033check_operands.cc b/033check_operands.cc
index 04492986..28a7458e 100644
--- a/033check_operands.cc
+++ b/033check_operands.cc
@@ -246,6 +246,11 @@ void init_permitted_operands() {
   put(Permitted_operands, "81", 0x43);  // combine
   put(Permitted_operands, "c7", 0x43);  // copy
 
+  //// Class Q: op, ModR/M and imm32
+  //  imm32 imm8  disp32 |disp16  disp8 subop modrm
+  //  1     0     0      |0       0     0     1
+  put(Permitted_operands, "69", 0x41);  // multiply
+
   // End Init Permitted Operands
 }
 
diff --git a/apps/ex14 b/apps/ex14
new file mode 100755
index 00000000..b2792177
--- /dev/null
+++ b/apps/ex14
Binary files differdiff --git a/apps/ex14.subx b/apps/ex14.subx
new file mode 100644
index 00000000..74dd3809
--- /dev/null
+++ b/apps/ex14.subx
@@ -0,0 +1,26 @@
+# Multiply 2 numbers.
+#
+# To run:
+#   $ ./bootstrap translate init.linux apps/ex14.subx -o apps/ex14
+#   $ ./bootstrap run apps/ex14
+# Expected result:
+#   $ echo $?
+#   6
+
+== code
+#   instruction                     effective address                                                   register    displacement    immediate
+# . op          subop               mod             rm32          base        index         scale       r32
+# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+
+Entry:
+    b8/copy-to-eax  1/imm32
+    b9/copy-to-ecx  2/imm32
+    bb/copy-to-ebx  3/imm32
+
+    69/multiply                     3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx                   3/imm32           # ebx = ecx * 3
+
+$exit:
+    # exit(ebx)
+    e8/call  syscall_exit/disp32
+
+# . . vim:nowrap:textwidth=0