From 00ec13cb6e6b0cb9cba2a0d8b29f5d21e40d6c02 Mon Sep 17 00:00:00 2001 From: Theodore Dubois Date: Tue, 30 Oct 2018 14:41:39 -0700 Subject: [PATCH] Implement log base 2 (fyl2x) --- emu/decode.h | 1 + emu/float80.c | 36 ++++++++++++++++++++++++++++++++++++ emu/float80.h | 2 ++ emu/fpu.c | 5 +++++ emu/fpu.h | 1 + emu/interp/fpu.h | 1 + jit/gen.c | 1 + 7 files changed, 47 insertions(+) diff --git a/emu/decode.h b/emu/decode.h index e9593f8f4d..cbfa084d91 100644 --- a/emu/decode.h +++ b/emu/decode.h @@ -608,6 +608,7 @@ __no_instrument DECODER_RET glue(DECODER_NAME, OP_SIZE)(DECODER_ARGS) { case 0xd950: TRACE("fld1"); FLDC(one); break; case 0xd955: TRACE("fldln2"); FLDC(ln2); break; case 0xd956: TRACE("fldz"); FLDC(zero); break; + case 0xd961: TRACE("fyl2x"); FYL2X(); break; case 0xd970: TRACE("fprem"); FPREM(); break; case 0xd974: TRACE("frndint"); FRNDINT(); break; case 0xdf40: TRACE("fnstsw ax"); FSTSW(reg_a); break; diff --git a/emu/float80.c b/emu/float80.c index fea6668b90..587ccc0380 100644 --- a/emu/float80.c +++ b/emu/float80.c @@ -417,3 +417,39 @@ bool f80_eq(float80 a, float80 b) { if (f80_iszero(a)) b.sign = 0; return a.sign == b.sign && a.exp == b.exp && a.signif == b.signif; } + +bool f80_lte(float80 a, float80 b) { + return f80_lt(a, b) || f80_eq(a, b); +} +bool f80_gt(float80 a, float80 b) { + return !f80_lte(a, b); +} + +float80 f80_log2(float80 x) { + float80 zero = f80_from_int(0); + float80 one = f80_from_int(1); + float80 two = f80_from_int(2); + + int ipart = 0; + while (f80_lt(x, one)) { + ipart--; + x = f80_mul(x, two); + } + while (f80_gt(x, two)) { + ipart++; + x = f80_div(x, two); + } + float80 res = f80_from_int(ipart); + + float80 bit = one; + while (f80_gt(bit, zero)) { + while (f80_lte(x, two) && f80_gt(bit, zero)) { + x = f80_mul(x, x); + bit = f80_div(bit, two); + } + res = f80_add(res, bit); + x = f80_div(x, two); + } + return res; +} + diff --git a/emu/float80.h b/emu/float80.h index 9c209b9ab8..c9152e3e2d 100644 --- a/emu/float80.h +++ b/emu/float80.h @@ -46,4 +46,6 @@ extern __thread enum f80_rounding_mode f80_rounding_mode; #define F80_NAN ((float80) {.signif = 0xc000000000000000, .exp = 0x7fff, .sign = 0}) #define F80_INF ((float80) {.signif = 0x8000000000000000, .exp = 0x7fff, .sign = 0}) +float80 f80_log2(float80 x); + #endif diff --git a/emu/fpu.c b/emu/fpu.c index b51f4c53e0..7124569ec4 100644 --- a/emu/fpu.c +++ b/emu/fpu.c @@ -86,6 +86,11 @@ void fpu_rndint(struct cpu_state *cpu) { ST(0) = f80_from_int(f80_to_int(ST(0))); } +void fpu_yl2x(struct cpu_state *cpu) { + ST(1) = f80_mul(ST(1), f80_log2(ST(0))); + fpu_pop(cpu); +} + void fpu_ucom(struct cpu_state *cpu, int i) { cpu->c1 = 0; cpu->c0 = f80_lt(ST(0), ST(i)); diff --git a/emu/fpu.h b/emu/fpu.h index 26de0126a3..6d6cd05c0c 100644 --- a/emu/fpu.h +++ b/emu/fpu.h @@ -38,6 +38,7 @@ void fpu_ldm80(struct cpu_state *cpu, float80 *f); void fpu_prem(struct cpu_state *cpu); void fpu_rndint(struct cpu_state *cpu); +void fpu_yl2x(struct cpu_state *cpu); void fpu_ucom(struct cpu_state *cpu, int i); void fpu_abs(struct cpu_state *cpu); void fpu_chs(struct cpu_state *cpu); diff --git a/emu/interp/fpu.h b/emu/interp/fpu.h index 51de9bcb34..530e6b0129 100644 --- a/emu/interp/fpu.h +++ b/emu/interp/fpu.h @@ -78,6 +78,7 @@ ST(0) = f80_mod(ST(0), ST(1)) #define FRNDINT() UNDEFINED +#define FYL2X() UNDEFINED #define FUCOMI() \ cpu->zf = f80_eq(ST(0), ST_i); \ diff --git a/jit/gen.c b/jit/gen.c index 9437db128e..70473f1c5b 100644 --- a/jit/gen.c +++ b/jit/gen.c @@ -358,6 +358,7 @@ static inline bool gen_op(struct gen_state *state, gadget_t *gadgets, enum arg a #define FLDC(what) hh(fpu_ldc, fconst_##what) #define FPREM() h(fpu_prem) #define FRNDINT() h(fpu_rndint) +#define FYL2X() h(fpu_yl2x) #define FSTSW(dst) if (arg_##dst == arg_reg_a) g(fstsw_ax); else UNDEFINED #define FSTCW(dst) if (arg_##dst == arg_reg_a) UNDEFINED; else h_write(fpu_stcw, 16) #define FLDCW(dst) if (arg_##dst == arg_reg_a) UNDEFINED; else h_read(fpu_ldcw, 16)