summaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-02-25 23:15:55 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-02-25 23:15:55 +0000
commit9588b95a0849cb4c9e344b3791a76af7df0aaf80 (patch)
treeff27bc2270a6af6ab2e5f08b230630d49e71b19b /target-i386
parent2edcdce334e8bf6143a498550a39e4a363c69bfc (diff)
downloadqemu-9588b95a0849cb4c9e344b3791a76af7df0aaf80.tar.gz
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')
-rw-r--r--target-i386/helper2.c73
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