Skip to content

Commit

Permalink
Replace softfloat with custom 80-bit float library
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Aug 13, 2018
1 parent 91f56e8 commit e03f44b
Show file tree
Hide file tree
Showing 22 changed files with 1,013 additions and 6,666 deletions.
4 changes: 2 additions & 2 deletions emu/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <stddef.h>
#include "misc.h"
#include "emu/softfloat.h"
#include "emu/float80.h"
#include "emu/memory.h"
#include "emu/tlb.h"

Expand Down Expand Up @@ -102,7 +102,7 @@ struct cpu_state {
};

// fpu
floatx80 fp[8];
float80 fp[8];
union {
word_t fsw;
struct {
Expand Down
2 changes: 1 addition & 1 deletion emu/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ __no_instrument DECODER_RET glue(DECODER_NAME, OP_SIZE)(DECODER_ARGS) {
case 0xda5: TRACE("fucompp st"); FUCOM(); FPOP; FPOP; break;
case 0xde0: TRACE("faddp st, st(i)"); FADD(st_0, st_i); FPOP; break;
case 0xde1: TRACE("fmulp st, st(i)"); FMUL(st_0, st_i); FPOP; break;
case 0xde4: TRACE("fsubrp st, st(i)"); FSUB(st_i, st_0); FPOP; break;
case 0xde4: TRACE("fsubrp st, st(i)"); FSUBR(st_0, st_i); FPOP; break;
case 0xde5: TRACE("fsubp st, st(i)"); FSUB(st_0, st_i); FPOP; break;
case 0xdf5: TRACE("fucomip st"); FUCOMI(); FPOP; break;
default: switch (insn << 8 | modrm.opcode << 4 | modrm.rm_opcode) {
Expand Down
170 changes: 170 additions & 0 deletions emu/float80-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#include <stdio.h>
#include <math.h>
#include "float80.h"

//#define DENORMAL 1e-310
#define DENORMAL 1.11253692925360069155e-308

union f80 {
float80 f;
long double ld;
};

union f80 gf;

static bool bitwise_eq(long double a, long double b) {
union f80 ua = (union f80) a;
union f80 ub = (union f80) b;
return ua.f.signif == ub.f.signif && ua.f.signExp == ub.f.signExp;
}

static int tests_passed = 0;
static int tests_total = 0;
static int suite_passed = 0;
static int suite_total = 0;

#define suite_start() _suite_start(__FUNCTION__)
#define suite_end() _suite_end(__FUNCTION__)
void _suite_start(const char *suite) {
printf("==== %s ====\n", suite);
suite_passed = 0;
suite_total = 0;
}
void _suite_end(const char *suite) {
printf("%s: %d/%d passed (%.0f%%)\n", suite, suite_passed, suite_total, (double) suite_passed / suite_total * 100);
}

void assertf(int cond, const char *msg, ...) {
tests_total++;
suite_total++;
if (cond) {
tests_passed++;
suite_passed++;
}

printf(cond ? "PASS ": "FAIL ");
//if (!cond) asm("int3");
char buf[1024];
va_list args;
va_start(args, msg);
vsprintf(buf, msg, args);
va_end(args);
puts(buf);
}

void test_int_convert() {
suite_start();
union f80 u;
int64_t i;
#define test(x) \
u.f = f80_from_int(x); \
assertf((int64_t) u.ld == x, "f80_from_int(%ld) = %Le", (int64_t) x, u.ld); \
i = f80_to_int(u.f); \
assertf(i == x, "f80_to_int(%Le) = %ld", u.ld, i)

test(0);
test(123); test(-123);
test(9489919999192); test(-9489919999192);
test(INT64_MIN); test(INT64_MAX);
#undef test
suite_end();
}

void test_double_convert() {
suite_start();
union f80 u;
double d;
#define test(x) \
u.f = f80_from_double(x); \
assertf(bitwise_eq(u.ld, x), "f80_from_double(%e) = %Le", (double) x, u.ld); \
d = f80_to_double(u.f); \
assertf(bitwise_eq(d, x), "f80_to_double(%Le) = %e", u.ld, d)

test(0); test(-0);
test(123); test(-123);
test(3991994929919994995881.0);
test(DENORMAL);
test(1e-310);
test(INFINITY); test(-INFINITY);
test(NAN);
#undef test
suite_end();
}

void test_math() {
suite_start();
union f80 ua, ub, u;
long double expected;
#define cop_add +
#define cop_sub -
#define cop_mul *
#define cop_div /
#define _test(op, a, b) \
ua.ld = a; ub.ld = b; \
u.f = f80_##op(ua.f, ub.f); \
expected = (long double) a cop_##op (long double) b; \
assertf(bitwise_eq(u.ld, expected), "f80_"#op"(%Le, %Le) = %Le", ua.ld, ub.ld, u.ld)
#define test(op, a, b) \
_test(op, a, b); \
_test(op, -a, b); \
_test(op, a, -b); \
_test(op, -a, -b)

test(add, 1, 1);
test(add, 123, 123);
test(add, 9942, 13459);
test(add, 222, 0.);
test(add, 0., 0.);
test(add, 12.0499, 91999);
test(add, 1e100, 100);
test(add, 1e-4949l, 1);
test(add, 1e-4949l, 1e-4949l);
test(add, INFINITY, 123);
test(add, INFINITY, INFINITY);
test(add, NAN, 123);
test(add, NAN, NAN);

test(mul, 0, 1);
test(mul, 1, 1);
test(mul, 123, 123);
test(mul, 1e100, 100);
test(mul, 12.3993l, 91934);
test(mul, 1e-4949l, 1);
test(mul, 1e-4949l, 1e-4949l);
test(mul, INFINITY, 11);
test(mul, INFINITY, INFINITY);
test(mul, INFINITY, 0);
test(mul, NAN, 123);
test(mul, NAN, NAN);

test(div, 1, 1);
test(div, 3, 2);
test(div, 0, 1);
test(div, 0, 0);
test(div, 1, 1e1000l);
test(div, 1, 1e-1000l);
test(div, 12.4123331, 934.11223e200);
test(div, 1e-4949l, 10);
test(div, 10, 1e-4949l);
test(div, 1e-4949l, 1e-4949l);
test(div, INFINITY, 100);
test(div, 100, INFINITY);
test(div, INFINITY, INFINITY);
test(div, INFINITY, 0);
test(div, NAN, 123);
test(div, NAN, NAN);
#undef test
suite_end();
}

uint64_t fnmulh(uint64_t a, uint64_t b) {
return ((unsigned __int128) a * b) >> 64;
}

int main() {
test_int_convert();
test_double_convert();
test_math();
printf("%d/%d passed (%.0f%%)", tests_passed, tests_total, (double) tests_passed / tests_total * 100);
return tests_passed == tests_total ? 0 : 1;
}
Loading

0 comments on commit e03f44b

Please sign in to comment.