about summary refs log tree commit diff stats
path: root/src/emu
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-05-24 15:01:35 +0200
committerptitSeb <sebastien.chev@gmail.com>2024-05-24 15:01:46 +0200
commitfcf0cf00d0a82649ba0cf9f6a8c0450bb6ed5f47 (patch)
tree7c3ba3519cf1a9ebdbca47fe3310dbc531212707 /src/emu
parent2ee846f48e7fa9b103f0949f63f91712ca7b03ca (diff)
downloadbox64-fcf0cf00d0a82649ba0cf9f6a8c0450bb6ed5f47.tar.gz
box64-fcf0cf00d0a82649ba0cf9f6a8c0450bb6ed5f47.zip
Added support for XSAVE/XRSTOR ([ARM64_DYNAREC] too)
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/x64run0f.c27
-rw-r--r--src/emu/x87emu_private.c83
-rw-r--r--src/emu/x87emu_private.h2
3 files changed, 107 insertions, 5 deletions
diff --git a/src/emu/x64run0f.c b/src/emu/x64run0f.c
index f2666e5e..95b8cc12 100644
--- a/src/emu/x64run0f.c
+++ b/src/emu/x64run0f.c
@@ -91,11 +91,16 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
             if(MODREG)

             switch(nextop) {

                 case 0xD0:

-                    #ifndef TEST_INTERPRETER

-                    emit_signal(emu, SIGILL, (void*)R_RIP, 0);

-                    #else

-                    test->notest = 1;

-                    #endif

+                    if(R_RCX) {

+                        #ifndef TEST_INTERPRETER

+                        emit_signal(emu, SIGILL, (void*)R_RIP, 0);

+                        #else

+                        test->notest = 1;

+                        #endif

+                    } else {

+                        R_RAX = 0b11;   // x87 & SSE for now

+                        R_RDX = 0;

+                    }

                     break;

                 case 0xE0:

                 case 0xE1:

@@ -1286,6 +1291,18 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
                     GETED(0);

                     ED->dword[0] = emu->mxcsr.x32;

                     break;

+                case 4:                 /* XSAVE Ed */

+                    _GETED(0);

+                    #ifdef TEST_INTERPRETER

+                    emu->sw.f.F87_TOP = emu->top&7;

+                    #else

+                    fpu_xsave(emu, ED, rex.is32bits);

+                    #endif

+                    break;

+                case 5:                 /* XRSTOR Ed */

+                    _GETED(0);

+                    fpu_xrstor(emu, ED, rex.is32bits);

+                    break;

                 case 7:                 /* CLFLUSH Ed */

                     _GETED(0);

                     #if defined(DYNAREC) && !defined(TEST_INTERPRETER)

diff --git a/src/emu/x87emu_private.c b/src/emu/x87emu_private.c
index f6fda3b6..79306a76 100644
--- a/src/emu/x87emu_private.c
+++ b/src/emu/x87emu_private.c
@@ -430,3 +430,86 @@ void fpu_fxrstor64(x64emu_t* emu, void* ed)
     // copy SSE regs
     memcpy(&emu->xmm[0], &p->XmmRegisters[0], sizeof(emu->xmm));
 }
+
+typedef struct xsaveheader_s {
+    uint64_t xstate_bv;
+    uint64_t xcomp_bv;
+    uint8_t  reserved[64-16];
+} xsaveheader_t;
+
+void fpu_xsave(x64emu_t* emu, void* ed, int is32bits)
+{
+    xsave64_t *p = (xsave64_t*)ed;
+    xsaveheader_t *h = (xsaveheader_t*)(p+1);
+    uint32_t rfbm = (0b11&R_EAX);
+    h->xstate_bv =(h->xstate_bv&~0b11)|rfbm;
+    h->xcomp_bv = 0;
+    if(h->xstate_bv&0b01) {
+        int top = emu->top&7;
+        int stack = 8-top;
+        if(emu->fpu_tags == TAGS_EMPTY)
+            stack = 0;
+        emu->sw.f.F87_TOP = top;
+        p->ControlWord = emu->cw.x16;
+        p->StatusWord = emu->sw.x16;
+        p->MxCsr = emu->mxcsr.x32;
+        uint8_t tags = 0;
+        for (int i=0; i<8; ++i)
+            tags |= (((emu->fpu_tags>>(i*2))&0b11)?0:1)<<i;
+        p->TagWord = emu->fpu_tags;
+        p->ErrorOpcode = 0;
+        p->ErrorOffset = 0;
+        p->DataOffset = 0;
+        // copy FPU/MMX regs...
+        for(int i=0; i<8; ++i)
+            memcpy(&p->FloatRegisters[i].q[0], (i<stack)?&ST(i):&emu->mmx[i], sizeof(mmx87_regs_t));
+    }
+    if(((h->xstate_bv&0b10)||(h->xstate_bv&0b100))&&!(h->xstate_bv&0b01)) {
+        p->MxCsr = emu->mxcsr.x32;
+    }
+    // copy SSE regs
+    if(h->xstate_bv&0b10) {
+        for(int i=0; i<is32bits?8:16; ++i)
+            memcpy(&p->XmmRegisters[i], &emu->xmm[i], 16);
+    }
+}
+
+void fpu_xrstor(x64emu_t* emu, void* ed, int is32bits)
+{
+    xsave64_t *p = (xsave64_t*)ed;
+    xsaveheader_t *h = (xsaveheader_t*)(p+1);
+    int compressed = (h->xcomp_bv>>63);
+    uint32_t rfbm = (0b11&R_EAX);
+    uint32_t to_restore = rfbm & h->xstate_bv;
+    uint32_t to_init = rfbm & ~h->xstate_bv;
+    // check componant to restore
+    if(to_restore&0b01) {
+        emu->cw.x16 = p->ControlWord;
+        emu->sw.x16 = p->StatusWord;
+        emu->mxcsr.x32 = p->MxCsr;
+        if(box64_sse_flushto0)
+            applyFlushTo0(emu);
+        emu->top = emu->sw.f.F87_TOP;
+        uint8_t tags = p->TagWord;
+        emu->fpu_tags = 0;
+        for(int i=0; i<8; ++i)
+            emu->fpu_tags |= (((tags>>i)&1)?0:0b11)<<(i*2);
+        int top = emu->top&7;
+        int stack = 8-top;
+        if(emu->fpu_tags == TAGS_EMPTY)
+            stack = 0;
+        // copy back MMX regs...
+        for(int i=0; i<8; ++i)
+            memcpy((i<stack)?&ST(i):&emu->mmx[i], &p->FloatRegisters[i].q[0], sizeof(mmx87_regs_t));
+    } else if(to_init&0b01) {
+        reset_fpu(emu);
+    }
+    if(((to_restore&0b10)||(to_restore&0b100))&&!(to_restore&0b01)) {
+        emu->mxcsr.x32 = p->MxCsr;
+    }
+    if(to_restore&0b10) {
+        // copy SSE regs
+        for(int i=0; i<is32bits?8:16; ++i)
+            memcpy(&emu->xmm[i], &p->XmmRegisters[i], 16);
+    }
+}
\ No newline at end of file
diff --git a/src/emu/x87emu_private.h b/src/emu/x87emu_private.h
index a3c589df..db5553a2 100644
--- a/src/emu/x87emu_private.h
+++ b/src/emu/x87emu_private.h
@@ -216,5 +216,7 @@ void fpu_fxsave32(x64emu_t* emu, void* ed);
 void fpu_fxrstor32(x64emu_t* emu, void* ed);
 void fpu_fxsave64(x64emu_t* emu, void* ed);
 void fpu_fxrstor64(x64emu_t* emu, void* ed);
+void fpu_xsave(x64emu_t* emu, void* ed, int is32bits);
+void fpu_xrstor(x64emu_t* emu, void* ed, int is32bits);
 
 #endif //__X87RUN_PRIVATE_H_