diff --git a/asbestos/gen.c b/asbestos/gen.c index b917ab852d..d1f2e0f8c9 100644 --- a/asbestos/gen.c +++ b/asbestos/gen.c @@ -412,6 +412,7 @@ void helper_rdtsc(struct cpu_state *cpu); #define FLDENV(val,z) h_write(fpu_ldenv, z) #define FSAVE(val,z) h_write(fpu_save, z) #define FRESTORE(val,z) h_write(fpu_restore, z) +#define FINIT() h(fpu_init) #define FCLEX() h(fpu_clex) #define FPOP h(fpu_pop) #define FINCSTP() h(fpu_incstp) diff --git a/emu/decode.h b/emu/decode.h index 00a075fc86..856d9e5c5d 100644 --- a/emu/decode.h +++ b/emu/decode.h @@ -1084,6 +1084,7 @@ __no_instrument DECODER_RET glue(DECODER_NAME, OP_SIZE)(DECODER_ARGS) { case 0xd976: TRACE("fsin"); FSIN(); break; case 0xd977: TRACE("fcos"); FCOS(); break; case 0xdb42: TRACE("fnclex"); FCLEX(); break; + case 0xdb43: TRACE("fninit"); FINIT(); break; case 0xde31: TRACE("fcompp"); FCOM(); FPOP; FPOP; break; case 0xdf40: TRACE("fnstsw ax"); FSTSW(reg_a); break; default: TRACE("undefined"); UNDEFINED; diff --git a/emu/fpu.c b/emu/fpu.c index d523e30fd0..78c14fad0e 100644 --- a/emu/fpu.c +++ b/emu/fpu.c @@ -377,6 +377,18 @@ void fpu_restore32(struct cpu_state *cpu, struct fpu_state32 *state) { memcpy(&ST(i), state->regs[i], 10); } +// FNINIT: control word back to 0x037f (all exceptions masked, round to +// nearest, extended precision) and the status word cleared. Clearing fsw also +// resets TOP, since TOP is a field of it, which is what empties the register +// stack; there is no tag word to write because we do not model one. The +// control word changing means the live rounding mode has to follow it, the +// same way fldcw does. +void fpu_init(struct cpu_state *cpu) { + cpu->fcw = 0x037f; + cpu->fsw = 0; + f80_rounding_mode = cpu->rc; +} + void fpu_clex(struct cpu_state *cpu) { cpu->pe = cpu->ue = cpu->oe = cpu->ze = cpu->de = cpu->ie = cpu->es = cpu->sf = cpu->b = 0; } diff --git a/emu/fpu.h b/emu/fpu.h index 7cdf6349e4..06c5890291 100644 --- a/emu/fpu.h +++ b/emu/fpu.h @@ -119,6 +119,7 @@ void fpu_stenv32(struct cpu_state *cpu, struct fpu_env32 *env); void fpu_ldenv32(struct cpu_state *cpu, struct fpu_env32 *env); void fpu_save32(struct cpu_state *cpu, struct fpu_state32 *state); void fpu_restore32(struct cpu_state *cpu, struct fpu_state32 *state); +void fpu_init(struct cpu_state *cpu); void fpu_clex(struct cpu_state *cpu); #endif