about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-09-30 22:07:38 -0700
committerKartik Agaram <vc@akkartik.com>2020-09-30 22:09:26 -0700
commitd564633b240cfc0e8bfe49098a6ac49abf688a76 (patch)
treec91a9dd5dea293fcccb46d896bd8f9be1998a889
parent8b215b65cf989235de65827296f5566132e8abeb (diff)
downloadmu-d564633b240cfc0e8bfe49098a6ac49abf688a76.tar.gz
6910 - emulate most floating-point operations
-rw-r--r--023float.cc302
-rw-r--r--033check_operands.cc13
2 files changed, 311 insertions, 4 deletions
diff --git a/023float.cc b/023float.cc
index fbf7ee40..cbd1bc80 100644
--- a/023float.cc
+++ b/023float.cc
@@ -1,5 +1,7 @@
 //: floating-point operations
 
+//:: convert to floating point
+
 :(before "End Initialize Op Names")
 put_new(Name_f3_0f, "2a", "convert integer to floating-point (cvtsi2ss)");
 
@@ -30,6 +32,137 @@ case 0x2a: {  // convert integer to float
   break;
 }
 
+//:: convert floating point to int
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "2d", "convert floating-point to int (cvtss2si)");
+
+:(code)
+void test_cvtss2si() {
+  Xmm[0] = 10.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 2d c0                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (EAX) 000 (XMM0)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: convert x/m32 to EAX\n"
+      "run: x/m32 is XMM0\n"
+      "run: EAX is now 0x0000000a\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x2d: {  // convert float to integer
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "convert x/m32 to " << rname(dest) << end();
+  const float* src = effective_address_float(modrm);
+  Reg[dest].i = *src;
+  trace(Callstack_depth+1, "run") << rname(dest) << " is now 0x" << HEXWORD << Reg[dest].i << end();
+  break;
+}
+
+//:: add
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "58", "add floats (addss)");
+
+:(code)
+void test_addss() {
+  Xmm[0] = 3.0;
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 58 c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: add x/m32 to XMM0\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 5\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x58: {  // add x/m32 to x32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "add x/m32 to " << Xname[dest] << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] += *src;
+  trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
+  break;
+}
+
+//:: subtract
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "5c", "subtract floats (subss)");
+
+:(code)
+void test_subss() {
+  Xmm[0] = 3.0;
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 5c c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: subtract x/m32 from XMM0\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 1\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x5c: {  // subtract x/m32 from x32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "subtract x/m32 from " << Xname[dest] << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] -= *src;
+  trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
+  break;
+}
+
+//:: multiply
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "59", "multiply floats (mulss)");
+
+:(code)
+void test_mulss() {
+  Xmm[0] = 3.0;
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 59 c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: multiply XMM0 by x/m32\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 6\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x59: {  // multiply x32 by x/m32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "multiply " << Xname[dest] << " 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;
+}
+
 //:: divide
 
 :(before "End Initialize Op Names")
@@ -46,7 +179,7 @@ void test_divss() {
       // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
   );
   CHECK_TRACE_CONTENTS(
-      "run: divide x32 by x/m32\n"
+      "run: divide XMM0 by x/m32\n"
       "run: x/m32 is XMM1\n"
       "run: XMM0 is now 1.5\n"
   );
@@ -56,13 +189,178 @@ void test_divss() {
 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();
+  trace(Callstack_depth+1, "run") << "divide " << Xname[dest] << " 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;
 }
 
+//:: min
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "5d", "minimum of two floats (minss)");
+
+:(code)
+void test_minss() {
+  Xmm[0] = 3.0;
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 5d c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: minimum of XMM0 and x/m32\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 2\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x5d: {  // minimum of x32, x/m32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "minimum of " << Xname[dest] << " and x/m32" << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] = min(Xmm[dest], *src);
+  trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
+  break;
+}
+
+//:: max
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "5f", "maximum of two floats (maxss)");
+
+:(code)
+void test_maxss() {
+  Xmm[0] = 3.0;
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 5f c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: maximum of XMM0 and x/m32\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 3\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x5f: {  // maximum of x32, x/m32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "maximum of " << Xname[dest] << " and x/m32" << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] = max(Xmm[dest], *src);
+  trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
+  break;
+}
+
+//:: reciprocal
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "53", "reciprocal of float (rcpss)");
+
+:(code)
+void test_rcpss() {
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 53 c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: reciprocal of x/m32 into XMM0\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 0.5\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x53: {  // reciprocal of x/m32 into x32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "reciprocal of x/m32 into " << Xname[dest] << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] = 1.0 / *src;
+  trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
+  break;
+}
+
+//:: square root
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "51", "square root of float (sqrtss)");
+
+:(code)
+void test_sqrtss() {
+  Xmm[1] = 2.0;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 51 c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: square root of x/m32 into XMM0\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 1.41421\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x51: {  // square root of x/m32 into x32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "square root of x/m32 into " << Xname[dest] << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] = sqrt(*src);
+  trace(Callstack_depth+1, "run") << Xname[dest] << " is now " << Xmm[dest] << end();
+  break;
+}
+
+:(before "End Includes")
+#include <math.h>
+
+//:: inverse square root
+
+:(before "End Initialize Op Names")
+put_new(Name_f3_0f, "52", "inverse square root of float (rsqrtss)");
+
+:(code)
+void test_rsqrtss() {
+  Xmm[1] = 0.01;
+  run(
+      "== code 0x1\n"
+      // op     ModR/M  SIB   displacement  immediate
+      "f3 0f 52 c1                                    \n"
+      // ModR/M in binary: 11 (direct mode) 000 (XMM0) 001 (XMM1)
+  );
+  CHECK_TRACE_CONTENTS(
+      "run: inverse square root of x/m32 into XMM0\n"
+      "run: x/m32 is XMM1\n"
+      "run: XMM0 is now 10\n"
+  );
+}
+
+:(before "End Three-Byte Opcodes Starting With f3 0f")
+case 0x52: {  // inverse square root of x/m32 into x32
+  const uint8_t modrm = next();
+  const uint8_t dest = (modrm>>3)&0x7;
+  trace(Callstack_depth+1, "run") << "inverse square root of x/m32 into " << Xname[dest] << end();
+  const float* src = effective_address_float(modrm);
+  Xmm[dest] = 1.0 / sqrt(*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);
diff --git a/033check_operands.cc b/033check_operands.cc
index bbe2837f..66f74e80 100644
--- a/033check_operands.cc
+++ b/033check_operands.cc
@@ -697,8 +697,17 @@ map</*op*/string, /*bitvector*/uint8_t> Permitted_arguments_f3_0f;
 //// Class M: using ModR/M byte
 //  imm32 imm8  disp32 |disp16  disp8 subop modrm
 //  0     0     0      |0       0     0     1
-put_new(Permitted_arguments_f3_0f, "2a", 0x01);
-put_new(Permitted_arguments_f3_0f, "5e", 0x01);
+put_new(Permitted_arguments_f3_0f, "2a", 0x01);  // convert-to-float
+put_new(Permitted_arguments_f3_0f, "2d", 0x01);  // convert-to-int
+put_new(Permitted_arguments_f3_0f, "51", 0x01);  // square root
+put_new(Permitted_arguments_f3_0f, "52", 0x01);  // inverse square root
+put_new(Permitted_arguments_f3_0f, "53", 0x01);  // reciprocal
+put_new(Permitted_arguments_f3_0f, "58", 0x01);  // add floats
+put_new(Permitted_arguments_f3_0f, "59", 0x01);  // multiply floats
+put_new(Permitted_arguments_f3_0f, "5c", 0x01);  // subtract floats
+put_new(Permitted_arguments_f3_0f, "5d", 0x01);  // minimum of floats
+put_new(Permitted_arguments_f3_0f, "5e", 0x01);  // divide floats
+put_new(Permitted_arguments_f3_0f, "5f", 0x01);  // maximum of floats
 
 :(code)
 void check_arguments_0f(const line& inst, const word& op) {