diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-02-25 23:15:55 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-02-25 23:15:55 +0000 |
commit | 9588b95a0849cb4c9e344b3791a76af7df0aaf80 (patch) | |
tree | ff27bc2270a6af6ab2e5f08b230630d49e71b19b /target-i386/helper2.c | |
parent | 2edcdce334e8bf6143a498550a39e4a363c69bfc (diff) |
CR0.MP/EM/TS support - native fpu support in code copy mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@640 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-i386/helper2.c')
-rw-r--r-- | target-i386/helper2.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/target-i386/helper2.c b/target-i386/helper2.c index e1dc4741d7..c98262c2d3 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -267,6 +267,9 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); /* ensure that ADDSEG is always set in real mode */ env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); + /* update FPU flags */ + env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) | + ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)); } void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3) @@ -476,3 +479,73 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return paddr; } #endif + +#if defined(USE_CODE_COPY) +struct fpstate { + uint16_t fpuc; + uint16_t dummy1; + uint16_t fpus; + uint16_t dummy2; + uint16_t fptag; + uint16_t dummy3; + + uint32_t fpip; + uint32_t fpcs; + uint32_t fpoo; + uint32_t fpos; + uint8_t fpregs1[8 * 10]; +}; + +void restore_native_fp_state(CPUState *env) +{ + int fptag, i, j; + struct fpstate fp1, *fp = &fp1; + + fp->fpuc = env->fpuc; + fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } else { + /* the FPU automatically computes it */ + } + } + fp->fptag = fptag; + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10); + j = (j + 1) & 7; + } + asm volatile ("frstor %0" : "=m" (*fp)); + env->native_fp_regs = 1; +} + +void save_native_fp_state(CPUState *env) +{ + int fptag, i, j; + uint16_t fpuc; + struct fpstate fp1, *fp = &fp1; + + asm volatile ("fsave %0" : : "m" (*fp)); + env->fpuc = fp->fpuc; + env->fpstt = (fp->fpus >> 11) & 7; + env->fpus = fp->fpus & ~0x3800; + fptag = fp->fptag; + for(i = 0;i < 8; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10); + j = (j + 1) & 7; + } + /* we must restore the default rounding state */ + /* XXX: we do not restore the exception state */ + fpuc = 0x037f | (env->fpuc & (3 << 10)); + asm volatile("fldcw %0" : : "m" (fpuc)); + env->native_fp_regs = 0; +} +#endif |