about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-09-27 21:39:50 -0700
committerKartik Agaram <vc@akkartik.com>2020-09-27 21:39:50 -0700
commitf068bda98e0218df6b551a6cd8e5520255866308 (patch)
tree3d7c399b80c7dbff4b4b4c65178d5c332754af93
parent31e6ed17f84ff5b67803e534cde104b331dd495d (diff)
downloadmu-f068bda98e0218df6b551a6cd8e5520255866308.tar.gz
6886 - floating-point division
-rw-r--r--010vm.cc6
-rw-r--r--023float.cc48
-rw-r--r--033check_operands.cc1
3 files changed, 55 insertions, 0 deletions
diff --git a/010vm.cc b/010vm.cc
index 7aca164b..f2ea4c9d 100644
--- a/010vm.cc
+++ b/010vm.cc
@@ -185,6 +185,9 @@ inline uint32_t read_mem_u32(uint32_t addr) {
 inline int32_t read_mem_i32(uint32_t addr) {
   return static_cast<int32_t>(read_mem_u32(addr));
 }
+inline float read_mem_f32(uint32_t addr) {
+  return static_cast<float>(read_mem_u32(addr));
+}
 
 inline uint8_t* mem_addr_u8(uint32_t addr) {
   uint8_t* result = NULL;
@@ -224,6 +227,9 @@ inline uint32_t* mem_addr_u32(uint32_t addr) {
 inline int32_t* mem_addr_i32(uint32_t addr) {
   return reinterpret_cast<int32_t*>(mem_addr_u32(addr));
 }
+inline float* mem_addr_f32(uint32_t addr) {
+  return reinterpret_cast<float*>(mem_addr_u32(addr));
+}
 // helper for some syscalls. But read-only.
 inline const char* mem_addr_kernel_string(uint32_t addr) {
   return reinterpret_cast<const char*>(mem_addr_u8(addr));
diff --git a/023float.cc b/023float.cc
index e87368cc..fbf7ee40 100644
--- a/023float.cc
+++ b/023float.cc
@@ -29,3 +29,51 @@ case 0x2a: {  // convert integer to float
   trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
   break;
 }
+
+//:: divide
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "5e", "divide floats (divss)");
+
+:(code)
+void test_divss() {
+  Xmm[0] = 3.0;
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 5e c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: divide x32 by x/m32\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 1.5\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x5e: {  // divide x32 by x/m32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "divide x32 by x/m32" << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] /= *src;
+  trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
+  break;
+}
+
+:(code)
+float* effective_address_float(uint8_t modrm) {
+  const uint8_t mod = (modrm>>6);
+  // ignore middle 3 'reg opcode' bits
+  const uint8_t rm = modrm & 0x7;
+  if (mod == 3) {
+    // mod 3 is just register direct addressing
+    trace(Callstack_depth+1, "run") << "x/m32 is " << Xname[rm] << end();
+    return &Xmm[rm];
+  }
+  uint32_t addr = effective_address_number(modrm);
+  trace(Callstack_depth+1, "run") << "effective address contains " << read_mem_f32(addr) << end();
+  return mem_addr_f32(addr);
+}
diff --git a/033check_operands.cc b/033check_operands.cc
index 3e1f12d1..7d73c97f 100644
--- a/033check_operands.cc
+++ b/033check_operands.cc
@@ -689,6 +689,7 @@ map</*op*/string, /*bitvector*/uint8_t> Permitted_operands_f3_0f;
 //  imm32 imm8  disp32 |disp16  disp8 subop modrm
 //  0     0     0      |0       0     0     1
 put_new(Permitted_operands_f3_0f, "2a", 0x01);
+put_new(Permitted_operands_f3_0f, "5e", 0x01);
 
 :(code)
 void check_operands_0f(const line& inst, const word& op) {