From dca76175020111f9474843ad78601be26f30fa5a Mon Sep 17 00:00:00 2001 From: Theodore Dubois Date: Sun, 17 Nov 2019 23:33:36 -0800 Subject: [PATCH] Implement fnstenv/fldenv --- emu/decode.h | 6 ++++++ emu/fpu.c | 41 +++++++++++++++++++++++++++++++++-------- emu/fpu.h | 8 ++++++-- jit/gen.c | 2 ++ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/emu/decode.h b/emu/decode.h index ba36f2ff8b..9ea4d81f95 100644 --- a/emu/decode.h +++ b/emu/decode.h @@ -603,7 +603,13 @@ __no_instrument DECODER_RET glue(DECODER_NAME, OP_SIZE)(DECODER_ARGS) { case 0xd90: TRACE("fld mem32"); FLDM(mem_addr_real,32); break; case 0xd92: TRACE("fst mem32"); FSTM(mem_addr_real,32); break; case 0xd93: TRACE("fstp mem32"); FSTM(mem_addr_real,32); FPOP; break; +#if OP_SIZE == 32 + case 0xd94: TRACE("fldenv mem32"); FLDENV(mem_addr,32); break; +#endif case 0xd95: TRACE("fldcw mem16"); FLDCW(mem_addr); break; +#if OP_SIZE == 32 + case 0xd96: TRACE("fnstenv mem32"); FSTENV(mem_addr,32); break; +#endif case 0xd97: TRACE("fnstcw mem16"); FSTCW(mem_addr); break; case 0xda0: TRACE("fiadd mem32"); FIADD(mem_addr,32); break; case 0xda1: TRACE("fimul mem32"); FIMUL(mem_addr,32); break; diff --git a/emu/fpu.c b/emu/fpu.c index c3f09bd0f1..74aaffdfab 100644 --- a/emu/fpu.c +++ b/emu/fpu.c @@ -254,14 +254,6 @@ void fpu_divrm64(struct cpu_state *cpu, float64 *f) { ST(0) = f80_div(f80_from_double(*f), ST(0)); } -void fpu_stcw16(struct cpu_state *cpu, uint16_t *i) { - *i = cpu->fcw; -} -void fpu_ldcw16(struct cpu_state *cpu, uint16_t *i) { - cpu->fcw = *i; - f80_rounding_mode = cpu->rc; -} - void fpu_patan(struct cpu_state *cpu) { // there's no native atan2 for 80-bit float yet. ST(1) = f80_from_double(atan2(f80_to_double(ST(1)), f80_to_double(ST(0)))); @@ -291,3 +283,36 @@ void fpu_xam(struct cpu_state *cpu) { cpu->c2 = (outflags >> 1) & 1; cpu->c3 = (outflags >> 2) & 1; } + +// meta + +void fpu_stcw16(struct cpu_state *cpu, uint16_t *i) { + *i = cpu->fcw; +} +void fpu_ldcw16(struct cpu_state *cpu, uint16_t *i) { + cpu->fcw = *i; + f80_rounding_mode = cpu->rc; +} + +struct fpu_env32 { + uint32_t control; + uint32_t status; + uint32_t tag; + uint32_t ip; + uint32_t ip_selector; + uint32_t operand; + uint32_t operand_selector; +}; + +void fpu_stenv32(struct cpu_state *cpu, struct fpu_env32 *env) { + env->control = cpu->fcw; + env->status = cpu->fsw; + // hope nobody looks at these + env->tag = 0; + env->ip = env->ip_selector = 0; + env->operand = env->operand_selector = 0; +} +void fpu_ldenv32(struct cpu_state *cpu, struct fpu_env32 *env) { + cpu->fcw = env->control; + cpu->fsw = env->status; +} diff --git a/emu/fpu.h b/emu/fpu.h index 868ec80a13..eaac387cc0 100644 --- a/emu/fpu.h +++ b/emu/fpu.h @@ -2,6 +2,7 @@ #define EMU_FPU_H #include "emu/float80.h" struct cpu_state; +struct fpu_env32; typedef float float32; typedef double float64; @@ -95,9 +96,12 @@ void fpu_mulm64(struct cpu_state *cpu, double *f); void fpu_divm64(struct cpu_state *cpu, double *f); void fpu_divrm64(struct cpu_state *cpu, double *f); -void fpu_stcw16(struct cpu_state *cpu, uint16_t *i); -void fpu_ldcw16(struct cpu_state *cpu, uint16_t *i); void fpu_patan(struct cpu_state *cpu); void fpu_xam(struct cpu_state *cpu); +void fpu_stcw16(struct cpu_state *cpu, uint16_t *i); +void fpu_ldcw16(struct cpu_state *cpu, uint16_t *i); +void fpu_stenv32(struct cpu_state *cpu, struct fpu_env32 *env); +void fpu_ldenv32(struct cpu_state *cpu, struct fpu_env32 *env); + #endif diff --git a/jit/gen.c b/jit/gen.c index a3f619f67d..2ea3d24e3a 100644 --- a/jit/gen.c +++ b/jit/gen.c @@ -393,6 +393,8 @@ void helper_rdtsc(struct cpu_state *cpu); #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) +#define FSTENV(val,z) h_write(fpu_stenv, z) +#define FLDENV(val,z) h_write(fpu_ldenv, z) #define FPOP h(fpu_pop) #define FADD(src, dst) hhh(fpu_add, src, dst) #define FIADD(val,z) h_read(fpu_iadd, z)