diff options
author | Kartik Agaram <vc@akkartik.com> | 2020-09-30 22:07:38 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2020-09-30 22:09:26 -0700 |
commit | d564633b240cfc0e8bfe49098a6ac49abf688a76 (patch) | |
tree | c91a9dd5dea293fcccb46d896bd8f9be1998a889 | |
parent | 8b215b65cf989235de65827296f5566132e8abeb (diff) | |
download | mu-d564633b240cfc0e8bfe49098a6ac49abf688a76.tar.gz |
6910 - emulate most floating-point operations
-rw-r--r-- | 023float.cc | 302 | ||||
-rw-r--r-- | 033check_operands.cc | 13 |
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) { |