about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-03-27 23:21:36 +0200
committerptitSeb <sebastien.chev@gmail.com>2023-03-27 23:21:36 +0200
commit9f75f28e7a464734bab8e719c1a60178280b224d (patch)
tree6c7d9c2d1e1c4d307e7acfbcbf92b04c7e83dea1 /src
parentfeb4a394577ea152b60393875860c551a7573adf (diff)
downloadbox64-9f75f28e7a464734bab8e719c1a60178280b224d.tar.gz
box64-9f75f28e7a464734bab8e719c1a60178280b224d.zip
[DYNAREC] Added BOX64_DYNAREC_TEST to run interpeter and dynarec at the same time and compare states
Diffstat (limited to 'src')
-rwxr-xr-xsrc/box64context.c5
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_00.c14
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_private.h9
-rwxr-xr-xsrc/dynarec/dynarec_native_pass.c18
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00.c2
-rw-r--r--src/dynarec/rv64/dynarec_rv64_private.h7
-rw-r--r--src/emu/modrm.h24
-rwxr-xr-xsrc/emu/x64emu.c47
-rwxr-xr-xsrc/emu/x64emu_private.h11
-rwxr-xr-xsrc/emu/x64run.c143
-rw-r--r--src/emu/x64run0f.c69
-rw-r--r--src/emu/x64run64.c7
-rw-r--r--src/emu/x64run66.c41
-rw-r--r--src/emu/x64run660f.c17
-rw-r--r--src/emu/x64run6664.c7
-rw-r--r--src/emu/x64run66d9.c9
-rw-r--r--src/emu/x64run66dd.c9
-rw-r--r--src/emu/x64run66f0.c20
-rw-r--r--src/emu/x64run67.c12
-rw-r--r--src/emu/x64run670f.c11
-rw-r--r--src/emu/x64run6766.c12
-rw-r--r--src/emu/x64run67660f.c8
-rwxr-xr-xsrc/emu/x64run_private.c250
-rwxr-xr-xsrc/emu/x64run_private.h46
-rw-r--r--src/emu/x64rund8.c7
-rw-r--r--src/emu/x64rund9.c12
-rw-r--r--src/emu/x64runda.c10
-rw-r--r--src/emu/x64rundb.c17
-rw-r--r--src/emu/x64rundc.c10
-rw-r--r--src/emu/x64rundd.c15
-rw-r--r--src/emu/x64runde.c10
-rw-r--r--src/emu/x64rundf.c20
-rw-r--r--src/emu/x64runf0.c73
-rw-r--r--src/emu/x64runf20f.c7
-rw-r--r--src/emu/x64runf30f.c7
-rw-r--r--src/emu/x64test.c142
-rwxr-xr-xsrc/include/box64context.h1
-rwxr-xr-xsrc/include/debug.h1
-rwxr-xr-xsrc/include/dynarec.h3
-rwxr-xr-xsrc/include/x64emu.h1
-rwxr-xr-xsrc/include/x64run.h2
-rwxr-xr-xsrc/main.c13
-rw-r--r--src/tools/rcfile.c2
43 files changed, 1089 insertions, 62 deletions
diff --git a/src/box64context.c b/src/box64context.c
index 589493ec..bae00f9c 100755
--- a/src/box64context.c
+++ b/src/box64context.c
@@ -143,6 +143,7 @@ static void init_mutexes(box64context_t* context)
     native_lock_store(&context->mutex_thread, 0);
     native_lock_store(&context->mutex_bridge, 0);
     native_lock_store(&context->mutex_dyndump, 0);
+    pthread_mutex_init(&context->mutex_lock, NULL);
 #endif
 }
 
@@ -325,7 +326,9 @@ void FreeBox64Context(box64context_t** context)
 
     finiAllHelpers(ctx);
 
-#ifndef DYNAREC
+#ifdef DYNAREC
+    pthread_mutex_destroy(&ctx->mutex_lock);
+#else
     pthread_mutex_destroy(&ctx->mutex_trace);
     pthread_mutex_destroy(&ctx->mutex_lock);
     pthread_mutex_destroy(&ctx->mutex_tls);
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index 2118580a..7a91dcf1 100755
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -499,9 +499,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
         case 0x56:
         case 0x57:
             INST_NAME("PUSH reg");
-            if(dyn->doublepush)
+            if(dyn->doublepush) {
+                dyn->test = 0;
                 dyn->doublepush = 0;
-            else {
+            } else {
                 gd = xRAX+(opcode&0x07)+(rex.b<<3);
                 if(gd==xRSP) {
                     MOVx_REG(x1, gd);
@@ -524,6 +525,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     }
                     PUSH2(gd, u32);
                     dyn->doublepush = 1;
+                    dyn->test = 0;  // disable test for this OP
                 } else {
                     PUSH1(gd);
                 }   
@@ -538,9 +540,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
         case 0x5E:
         case 0x5F:
             INST_NAME("POP reg");
-            if(dyn->doublepop)
+            if(dyn->doublepop) {
+                dyn->test = 0;
                 dyn->doublepop = 0;
-            else {
+            } else {
                 gd = xRAX+(opcode&0x07)+(rex.b<<3);
                 u32 = 0;
                 i32 = 0;
@@ -563,6 +566,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                         }
                     }
                     dyn->doublepop = 1;
+                    dyn->test = 0;  // disable test for this OP
                 } else {
                     if(gd == xRSP) {
                         POP1(x1);
@@ -1745,6 +1749,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
 
         case 0xCC:
             SETFLAGS(X_ALL, SF_SET);    // Hack, set all flags (to an unknown state...)
+            dyn->test = 0;
             if(PK(0)=='S' && PK(1)=='C') {
                 addr+=2;
                 BARRIER(BARRIER_FLOAT);
@@ -2211,6 +2216,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     }
                     PUSH1(x2);
                     MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall-1)), dyn->insts[ninst].retn);
+                    dyn->test=0;    // disable test as this hack dos 2 instructions for 1
                     // calling a native function
                     sse_purge07cache(dyn, ninst, x3);
                     if((box64_log<2 && !cycle_log) && dyn->insts[ninst].natcall)
diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h
index c966f9b3..b9b91483 100755
--- a/src/dynarec/arm64/dynarec_arm64_private.h
+++ b/src/dynarec/arm64/dynarec_arm64_private.h
@@ -106,6 +106,7 @@ typedef struct dynarec_arm_s {
     size_t              insts_size; // size of the instruction size array (calculated)
     uint8_t             smread;    // for strongmem model emulation
     uint8_t             smwrite;    // for strongmem model emulation
+    int8_t              test;       // test the opcode?
     uintptr_t           forward;    // address of the last end of code while testing forward
     uintptr_t           forward_to; // address of the next jump to (to check if everything is ok)
     int32_t             forward_size;   // size at the forward point
@@ -123,12 +124,12 @@ int Table64(dynarec_arm_t *dyn, uint64_t val);  // add a value to etable64 (if n
 
 void CreateJmpNext(void* addr, void* next);
 
-#define GO_TRACE() \
-    GETIP_(ip);             \
+#define GO_TRACE(A, B)      \
+    GETIP_(addr);           \
     MOVx_REG(x1, xRIP);     \
     STORE_XEMU_CALL(xRIP);  \
-    MOV32w(x2, 1);          \
-    CALL(PrintTrace, -1);   \
+    MOV32w(x2, B);          \
+    CALL(A, -1);            \
     LOAD_XEMU_CALL(xRIP)
 
 #endif //__DYNAREC_ARM_PRIVATE_H_
diff --git a/src/dynarec/dynarec_native_pass.c b/src/dynarec/dynarec_native_pass.c
index 4b1c976d..80da9436 100755
--- a/src/dynarec/dynarec_native_pass.c
+++ b/src/dynarec/dynarec_native_pass.c
@@ -83,13 +83,20 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
         if((dyn->insts[ninst].x64.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
             READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
         }
+        if(box64_dynarec_test) {
+            MESSAGE(LOG_DUMP, "TEST INIT ----\n");
+            fpu_reflectcache(dyn, ninst, x1, x2, x3);
+            GO_TRACE(x64test_init, dyn->test);
+            MESSAGE(LOG_DUMP, "----------\n");
+            dyn->test = 1;
+        }
 #ifdef HAVE_TRACE
-        if(my_context->dec && box64_dynarec_trace) {
+        else if(my_context->dec && box64_dynarec_trace) {
         if((trace_end == 0) 
             || ((ip >= trace_start) && (ip < trace_end)))  {
                 MESSAGE(LOG_DUMP, "TRACE ----\n");
                 fpu_reflectcache(dyn, ninst, x1, x2, x3);
-                GO_TRACE();
+                GO_TRACE(PrintTrace, 1);
                 MESSAGE(LOG_DUMP, "----------\n");
             }
         }
@@ -115,6 +122,13 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
 
         addr = dynarec64_00(dyn, addr, ip, ninst, rex, rep, &ok, &need_epilog);
 
+        if(dyn->test) {
+            MESSAGE(LOG_DUMP, "TEST CHECK ----\n");
+            fpu_reflectcache(dyn, ninst, x1, x2, x3);
+            GO_TRACE(x64test_check, 1);
+            MESSAGE(LOG_DUMP, "----------\n");
+        }
+
         INST_EPILOG;
 
         int next = ninst+1;
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c
index e6bfe91f..2b62f097 100644
--- a/src/dynarec/rv64/dynarec_rv64_00.c
+++ b/src/dynarec/rv64/dynarec_rv64_00.c
@@ -1270,6 +1270,7 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
 
         case 0xCC:
             SETFLAGS(X_ALL, SF_SET);    // Hack, set all flags (to an unknown state...)
+            dyn->test=0;
             if(PK(0)=='S' && PK(1)=='C') {
                 addr+=2;
                 BARRIER(BARRIER_FLOAT);
@@ -1463,6 +1464,7 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             switch(tmp) {
                 case 3:
                     SETFLAGS(X_ALL, SF_SET);    // Hack to set flags to "dont'care" state
+                    dyn->test = 0;
                     BARRIER(BARRIER_FULL);
                     //BARRIER_NEXT(BARRIER_FULL);
                     if(dyn->last_ip && (addr-dyn->last_ip<0x1000)) {
diff --git a/src/dynarec/rv64/dynarec_rv64_private.h b/src/dynarec/rv64/dynarec_rv64_private.h
index bf510c0b..4f9bdd63 100644
--- a/src/dynarec/rv64/dynarec_rv64_private.h
+++ b/src/dynarec/rv64/dynarec_rv64_private.h
@@ -107,6 +107,7 @@ typedef struct dynarec_rv64_s {
     size_t              insts_size; // size of the instruction size array (calculated)
     uint8_t             smread;    // for strongmem model emulation
     uint8_t             smwrite;    // for strongmem model emulation
+    int8_t              test;       // test the opcode?
     uintptr_t           forward;    // address of the last end of code while testing forward
     uintptr_t           forward_to; // address of the next jump to (to check if everything is ok)
     int32_t             forward_size;   // size at the forward point
@@ -127,12 +128,12 @@ int Table64(dynarec_rv64_t *dyn, uint64_t val);  // add a value to etable64 (if
 
 void CreateJmpNext(void* addr, void* next);
 
-#define GO_TRACE()          \
+#define GO_TRACE(A, B)      \
     GETIP_(ip);             \
     MV(A1, xRIP);           \
     STORE_XEMU_CALL();      \
-    MOV64x(A2, 1);          \
-    CALL(PrintTrace, -1);   \
+    MOV64x(A2, B);          \
+    CALL(A, -1);            \
     LOAD_XEMU_CALL()
 
 #endif //__DYNAREC_RV64_PRIVATE_H_
\ No newline at end of file
diff --git a/src/emu/modrm.h b/src/emu/modrm.h
index c01343b0..e3fc1e98 100644
--- a/src/emu/modrm.h
+++ b/src/emu/modrm.h
@@ -18,6 +18,27 @@
 #define STEP3

 #endif

 

+#ifdef TEST_INTERPRETER

+#define GETED(D)            oped=TestEd(test, &addr, rex, nextop, D)

+#define GETED32(D)          oped=TestEd32O(test, &addr, rex, nextop, D, 0)

+#define GETED_OFFS(D, O)    oped=TestEdO(test, &addr, rex, nextop, D, O)

+#define GETGD               opgd=GetGd(test->emu, &addr, rex, nextop)

+#define GETEB(D)            oped=TestEb(test, &addr, rex, nextop, D)

+#define GETEB32(D)          oped=TestEb32O(test, &addr, rex, nextop, D, 0)

+#define GETEB_OFFS(D, O)    oped=TestEbO(test, &addr, rex, nextop, D, O)

+#define GETGB               opgd=GetGb(test->emu, &addr, rex, nextop)

+#define GETEW(D)            oped=TestEw(test, &addr, rex, nextop, D)

+#define GETEW32(D)          oped=TestEw32O(test, &addr, rex, nextop, D, 0)

+#define GETEW_OFFS(D, O)    oped=TestEdO(test, &addr, rex, nextop, D, O)

+#define GETGW               opgd=GetGw(test->emu, &addr, rex, nextop)

+#define GETEX(D)            opex=TestEx(test, &addr, rex, nextop, D)

+#define GETEX32(D)          opex=TestEx32O(test, &addr, rex, nextop, D, 0)

+#define GETEX_OFFS(D, O)    opex=TestExO(test, &addr, rex, nextop, D, O)

+#define GETGX               opgx=GetGx(test->emu, &addr, rex, nextop)

+#define GETEM(D)            opem=TestEm(test, &addr, rex, nextop, D)

+#define GETEM32(D)          opem=TestEm32O(test, &addr, rex, nextop, D, 0)

+#define GETGM               opgm=GetGm(test->emu, &addr, rex, nextop)

+#else

 #define GETED(D)            oped=GetEd(emu, &addr, rex, nextop, D)

 #define GETED32(D)          oped=GetEd32O(emu, &addr, rex, nextop, D, 0)

 #define GETED_OFFS(D, O)    oped=GetEdO(emu, &addr, rex, nextop, D, O)

@@ -37,6 +58,7 @@
 #define GETEM(D)            opem=GetEm(emu, &addr, rex, nextop, D)

 #define GETEM32(D)          opem=GetEm32O(emu, &addr, rex, nextop, D, 0)

 #define GETGM               opgm=GetGm(emu, &addr, rex, nextop)

+#endif

 #define ED  oped

 #define GD  opgd

 #define EB  oped

@@ -47,6 +69,8 @@
 #define GX  opgx

 #define EM  opem

 #define GM  opgm

+#define FAKEED(D)           GetEd(emu, &addr, rex, nextop, D)

+#define FAKEED32(D)         GetEd32O(emu, &addr, rex, nextop, D, 0)

 

 #define MODREG  ((nextop&0xC0)==0xC0)

 

diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c
index 9a328bb0..eca8ee1d 100755
--- a/src/emu/x64emu.c
+++ b/src/emu/x64emu.c
@@ -205,6 +205,11 @@ void FreeX64Emu(x64emu_t **emu)
         return;
     printf_log(LOG_DEBUG, "%04d|Free a X86_64 Emu (%p)\n", GetTID(), *emu);
 
+    if((*emu)->test.emu) {
+        internalFreeX64((*emu)->test.emu);
+        box_free((*emu)->test.emu);
+        (*emu)->test.emu = NULL;
+    }
     internalFreeX64(*emu);
 
     box_free(*emu);
@@ -238,6 +243,13 @@ void CloneEmu(x64emu_t *newemu, const x64emu_t* emu)
 	newemu->top = emu->top;
     newemu->fpu_stack = emu->fpu_stack;
     memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
+    newemu->df = emu->df;
+    newemu->df_sav = emu->df_sav;
+    newemu->op1 = emu->op1;
+    newemu->op2 = emu->op2;
+    newemu->res = emu->res;
+    newemu->op1_sav = emu->op1_sav;
+    newemu->res_sav = emu->res_sav;
     newemu->mxcsr = emu->mxcsr;
     newemu->quit = emu->quit;
     newemu->error = emu->error;
@@ -247,6 +259,37 @@ void CloneEmu(x64emu_t *newemu, const x64emu_t* emu)
     newemu->regs[_SP].q[0] = emu->regs[_SP].q[0] + (intptr_t)(newst - oldst);
 }
 
+void CopyEmu(x64emu_t *newemu, const x64emu_t* emu)
+{
+	memcpy(newemu->regs, emu->regs, sizeof(emu->regs));
+    memcpy(&newemu->ip, &emu->ip, sizeof(emu->ip));
+	memcpy(&newemu->eflags, &emu->eflags, sizeof(emu->eflags));
+    newemu->old_ip = emu->old_ip;
+    memcpy(newemu->segs, emu->segs, sizeof(emu->segs));
+    memcpy(newemu->segs_serial, emu->segs_serial, sizeof(emu->segs_serial));
+    memcpy(newemu->segs_offs, emu->segs_offs, sizeof(emu->segs_offs));
+	memcpy(newemu->x87, emu->x87, sizeof(emu->x87));
+	memcpy(newemu->mmx, emu->mmx, sizeof(emu->mmx));
+    memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
+    memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
+    memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
+	memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
+	newemu->cw = emu->cw;
+	newemu->sw = emu->sw;
+	newemu->top = emu->top;
+    newemu->fpu_stack = emu->fpu_stack;
+    newemu->df = emu->df;
+    newemu->df_sav = emu->df_sav;
+    newemu->op1 = emu->op1;
+    newemu->op2 = emu->op2;
+    newemu->res = emu->res;
+    newemu->op1_sav = emu->op1_sav;
+    newemu->res_sav = emu->res_sav;
+    newemu->mxcsr = emu->mxcsr;
+    newemu->quit = emu->quit;
+    newemu->error = emu->error;
+}
+
 box64context_t* GetEmuContext(x64emu_t* emu)
 {
     return emu->context;
@@ -355,8 +398,8 @@ void ResetFlags(x64emu_t *emu)
 const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip)
 {
     static char buff[1000];
-    char* regname[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
-                       " R8", " R9", "R10", "R11", "R12", "R13", "R14", "R15"};
+    static const char* regname[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
+                                    " R8", " R9", "R10", "R11", "R12", "R13", "R14", "R15"};
     char tmp[160];
     buff[0] = '\0';
 #ifdef HAVE_TRACE
diff --git a/src/emu/x64emu_private.h b/src/emu/x64emu_private.h
index fb86531a..3393986c 100755
--- a/src/emu/x64emu_private.h
+++ b/src/emu/x64emu_private.h
@@ -25,6 +25,15 @@ typedef union multiuint_s {
     uint64_t    u64;
 } multiuint_t;
 
+typedef struct x64emu_s x64emu_t;
+
+typedef struct x64test_s {
+    x64emu_t*   emu;
+    uintptr_t   memaddr;
+    int         memsize;
+    uint8_t     mem[16];
+} x64test_t;
+
 typedef struct x64emu_s {
     // cpu
 	reg64_t     regs[16];
@@ -87,7 +96,7 @@ typedef struct x64emu_s {
     x64_ucontext_t *uc_link; // to handle setcontext
 
     int         type;       // EMUTYPE_xxx define
-
+    x64test_t   test;
 } x64emu_t;
 
 #define EMUTYPE_NONE    0
diff --git a/src/emu/x64run.c b/src/emu/x64run.c
index df1d341e..3eeec71f 100755
--- a/src/emu/x64run.c
+++ b/src/emu/x64run.c
@@ -28,7 +28,11 @@
 
 int my_setcontext(x64emu_t* emu, void* ucp);
 
+#ifdef TEST_INTERPRETER
+int RunTest(x64test_t *test)
+#else
 int Run(x64emu_t *emu, int step)
+#endif
 {
     uint8_t opcode;
     uint8_t nextop;
@@ -40,6 +44,10 @@ int Run(x64emu_t *emu, int step)
     uint32_t tmp32u, tmp32u2;
     int64_t tmp64s;
     uint64_t tmp64u, tmp64u2, tmp64u3;
+    #ifdef TEST_INTERPRETER
+    x64emu_t* emu = test->emu;
+    int step = 0;
+    #endif
     uintptr_t addr = R_RIP;
     rex_t rex;
     int rep;    // 0 none, 1=F2 prefix, 2=F3 prefix
@@ -57,9 +65,11 @@ int Run(x64emu_t *emu, int step)
     printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)addr, (void*)R_RSP);
 
 x64emurun:
-
-    while(1) {
-#ifdef HAVE_TRACE
+#ifndef TEST_INTERPRETER
+    while(1) 
+#endif
+    {
+#if defined(HAVE_TRACE)
         __builtin_prefetch((void*)addr, 0, 0); 
         emu->prev2_ip = emu->old_ip;
         if(my_context->dec && (
@@ -136,24 +146,39 @@ x64emurun:
         case 0x0F:                      /* More instructions */
             switch(rep) {
                 case 1:
+                    #ifdef TEST_INTERPRETER 
+                    if(!(addr = TestF20F(test, rex, addr, &step)))
+                        unimp = 1;
+                    #else
                     if(!(addr = RunF20F(emu, rex, addr, &step))) {
                         unimp = 1;
                         goto fini;
                     }
                     if(step==2) STEP2;
+                    #endif
                     break;
                 case 2:
+                    #ifdef TEST_INTERPRETER 
+                    if(!(addr = TestF30F(test, rex, addr)))
+                        unimp = 1;
+                    #else
                     if(!(addr = RunF30F(emu, rex, addr))) {
                         unimp = 1;
                         goto fini;
                     }
+                    #endif
                     break;
                 default:
+                    #ifdef TEST_INTERPRETER 
+                    if(!(addr = Test0F(test, rex, addr, &step)))
+                        unimp = 1;
+                    #else
                     if(!(addr = Run0F(emu, rex, addr, &step))) {
                         unimp = 1;
                         goto fini;
                     }
                     if(step==2) STEP2;
+                    #endif
                     break;
             }
             if(emu->quit) {
@@ -255,6 +280,10 @@ x64emurun:
                     GD->sdword[0] = ED->sdword[0];  // meh?
             break;
         case 0x64:                      /* FS: prefix */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = Test64(test, rex, _FS, addr)))
+                unimp = 1;
+            #else
             if(!(addr = Run64(emu, rex, _FS, addr))) {
                 unimp = 1;
                 goto fini;
@@ -263,8 +292,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0x65:                      /* GS: prefix */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = Test64(test, rex, _GS, addr)))
+                unimp = 1;
+            #else
             if(!(addr = Run64(emu, rex, _GS, addr))) {
                 unimp = 1;
                 goto fini;
@@ -273,8 +307,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0x66:                      /* 16bits prefix */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = Test66(test, rex, rep, addr)))
+                unimp = 1;
+            #else
             if(!(addr = Run66(emu, rex, rep, addr))) {
                 unimp = 1;
                 goto fini;
@@ -283,8 +322,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0x67:                      /* reduce EASize prefix */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = Test67(test, rex, rep, addr)))
+                unimp = 1;
+            #else
             if(!(addr = Run67(emu, rex, rep, addr))) {
                 unimp = 1;
                 goto fini;
@@ -293,6 +337,7 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0x68:                      /* Push Id */
             Push(emu, F32S64);
@@ -326,8 +371,10 @@ x64emurun:
         case 0x6E:                      /* OUTSB DX */
         case 0x6F:                      /* OUTSL DX */
             // this is a privilege opcode...
+            #ifndef TEST_INTERPRETOR
             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
             STEP;
+            #endif
             break;
 
         GOCOND(0x70
@@ -416,7 +463,7 @@ x64emurun:
             break;
         case 0x86:                      /* XCHG Eb,Gb */
             nextop = F8;
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
             GETEB(0);
             GETGB;
             if(MODREG) { // reg / reg: no lock
@@ -441,7 +488,7 @@ x64emurun:
             break;
         case 0x87:                      /* XCHG Ed,Gd */
             nextop = F8;
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
             GETED(0);
             GETGD;
             if(MODREG) {
@@ -527,8 +574,12 @@ x64emurun:
             break;
         case 0x8D:                      /* LEA Gd,M */
             nextop = F8;
-            GETED(0);
             GETGD;
+            #ifdef TEST_INTERPRETER
+            oped=GetEd(emu, &addr, rex, nextop, 0);
+            #else
+            GETED(0);
+            #endif
             if(rex.w)
                 GD->q[0] = (uint64_t)ED;
             else
@@ -630,7 +681,9 @@ x64emurun:
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
             tmp64u = (rep)?R_RCX:1L;
             while(tmp64u) {
+                #ifndef TEST_INTERPRETER
                 *(uint8_t*)R_RDI = *(uint8_t*)R_RSI;
+                #endif
                 R_RDI += tmp8s;
                 R_RSI += tmp8s;
                 --tmp64u;
@@ -645,7 +698,9 @@ x64emurun:
                 tmp8s *= 8;
                 while(tmp64u) {
                     --tmp64u;
+                    #ifndef TEST_INTERPRETER
                     *(uint64_t*)R_RDI = *(uint64_t*)R_RSI;
+                    #endif
                     R_RDI += tmp8s;
                     R_RSI += tmp8s;
                 }
@@ -653,7 +708,9 @@ x64emurun:
                 tmp8s *= 4;
                 while(tmp64u) {
                     --tmp64u;
+                    #ifndef TEST_INTERPRETER
                     *(uint32_t*)R_RDI = *(uint32_t*)R_RSI;
+                    #endif
                     R_RDI += tmp8s;
                     R_RSI += tmp8s;
                 }
@@ -793,7 +850,9 @@ x64emurun:
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
             tmp64u = (rep)?R_RCX:1L;
             while(tmp64u) {
+                #ifndef TEST_INTERPRETER
                 *(uint8_t*)R_RDI = R_AL;
+                #endif
                 R_RDI += tmp8s;
                 --tmp64u;
             }
@@ -808,7 +867,9 @@ x64emurun:
             tmp64u = (rep)?R_RCX:1L;
             if((rex.w))
                 while(tmp64u) {
+                    #ifndef TEST_INTERPRETER
                     *(uint64_t*)R_RDI = R_RAX;
+                    #endif
                     R_RDI += tmp8s;
                     --tmp64u;
                 }
@@ -1079,14 +1140,18 @@ x64emurun:
             break;
 
         case 0xCC:                      /* INT 3 */
+            #ifndef TEST_INTERPRETER
             x64Int3(emu, &addr);
             if(emu->quit) goto fini;    // R_RIP is up to date when returning from x64Int3
             addr = R_RIP;
+            #endif
             break;
         case 0xCD:                      /* INT n */
             // this is a privilege opcode...
+            #ifndef TEST_INTERPRETER
             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
             STEP;
+            #endif
             break;
 
 
@@ -1165,6 +1230,10 @@ x64emurun:
             R_AL = *(uint8_t*)(R_RBX + R_AL);
             break;
         case 0xD8:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestD8(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunD8(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1173,8 +1242,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xD9:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestD9(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunD9(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1183,8 +1257,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xDA:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestDA(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunDA(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1193,8 +1272,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xDB:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestDB(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunDB(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1203,8 +1287,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xDC:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestDC(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunDC(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1213,8 +1302,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xDD:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestDD(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunDD(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1223,8 +1317,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xDE:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestDE(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunDE(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1233,8 +1332,13 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xDF:                      /* x87 opcodes */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestDF(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunDF(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1243,6 +1347,7 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
         case 0xE0:                      /* LOOPNZ */
             CHECK_FLAGS(emu);
@@ -1278,8 +1383,10 @@ x64emurun:
         case 0xE6:                      /* OUT XX, AL */
         case 0xE7:                      /* OUT XX, EAX */
             // this is a privilege opcode...
+            #ifndef TEST_INTERPRETER
             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
             STEP;
+            #endif
             break;
         case 0xE8:                      /* CALL Id */
             tmp32s = F32S; // call is relative
@@ -1303,10 +1410,16 @@ x64emurun:
         case 0xEE:                      /* OUT DX, AL */
         case 0xEF:                      /* OUT DX, EAX */
             // this is a privilege opcode...
+            #ifndef TEST_INTERPRETER
             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
             STEP;
+            #endif
             break;
         case 0xF0:                      /* LOCK prefix */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = TestF0(test, rex, addr)))
+                unimp = 1;
+            #else
             if(!(addr = RunF0(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
@@ -1315,12 +1428,15 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            #endif
             break;
 
         case 0xF4:                      /* HLT */
             // this is a privilege opcode...
+            #ifndef TEST_INTERPRETER
             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
             STEP;
+            #endif
             break;
         case 0xF5:                      /* CMC */
             CHECK_FLAGS(emu);
@@ -1529,7 +1645,15 @@ x64emurun:
                     break;
                 case 6:                 /* Push Ed */
                     tmp64u = ED->q[0];  // rex.w ignored
+                    #ifdef TEST_INTERPRETER
+                    R_RSP -=8;
+                    if(test->memsize!=8)
+                        *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;
+                    test->memsize = 8;
+                    test->memaddr = R_RSP;
+                    #else
                     Push(emu, tmp64u);  // avoid potential issue with push [esp+...]
+                    #endif
                     break;
                 default:
                     printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5));
@@ -1547,6 +1671,7 @@ x64emurun:
 
 
 fini:
+#ifndef TEST_INTERPRETER
     printf_log(LOG_DEBUG, "End of X86 run (%p), RIP=%p, Stack=%p, unimp=%d, emu->fork=%d, emu->uc_link=%p, emu->quit=%d\n", emu, (void*)R_RIP, (void*)R_RSP, unimp, emu->fork, emu->uc_link, emu->quit);
     if(unimp) {
         emu->quit = 1;
@@ -1570,5 +1695,11 @@ fini:
         addr = R_RIP;
         goto x64emurun;
     }
+#else
+    if(unimp) {
+        printf_log(LOG_INFO, "Warning, inimplemented opcode in Test Interpreter\n");
+    } else
+        addr = R_RIP;
+#endif
     return 0;
 }
diff --git a/src/emu/x64run0f.c b/src/emu/x64run0f.c
index 05c9aab6..745f57f4 100644
--- a/src/emu/x64run0f.c
+++ b/src/emu/x64run0f.c
@@ -28,7 +28,11 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test0F(x64test_t *test, rex_t rex, uintptr_t addr, int *step)

+#else

 uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -42,27 +46,38 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
     sse_regs_t *opex, *opgx, eax1;

     mmx87_regs_t *opem, *opgm, eam1;

 

+#ifdef TEST_INTERPRETER

+    x64emu_t *emu = test->emu;

+#endif

     opcode = F8;

 

     switch(opcode) {

 

         case 0x05:                      /* SYSCALL */

+            #ifndef TEST_INTERPRETER

             R_RIP = addr;

             x64Syscall(emu);

+            #endif

             break;

         case 0x06:                      /* CLTS */

             // this is a privilege opcode...

+            #ifndef TEST_INTERPRETER

             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);

+            #endif

             break;

 

         case 0x08:                      /* INVD */

         case 0x09:                      /* WBINVD */

             // this is a privilege opcode...

+            #ifndef TEST_INTERPRETER

             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);

+            #endif

             break;

 

         case 0x0B:                      /* UD2 */

+            #ifndef TEST_INTERPRETER

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

+            #endif

             break;

 

         case 0x0D:

@@ -152,14 +167,16 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
 

         case 0x1F:                      /* NOP (multi-byte) */

             nextop = F8;

-            GETED(0);

+            FAKEED(0);

             break;

         case 0x20:                      /* MOV REG, crX */

         case 0x21:                      /* MOV REG, drX */

         case 0x22:                      /* MOV cxR, REG */

         case 0x23:                      /* MOV drX, REG */

             // this is a privilege opcode...

+            #ifndef TEST_INTERPRETER

             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);

+            #endif

             break;

 

         case 0x28:                      /* MOVAPS Gx,Ex */

@@ -800,7 +817,15 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
             tmp32s >>= (rex.w?6:5);

             if(!MODREG)

             {

+                #ifdef TEST_INTERPRETER

+                test->memaddr=((test->memaddr)+(tmp32s<<(rex.w?3:2)));

+                if(rex.w)

+                    *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;

+                else

+                    *(uint32_t*)test->mem = *(uint32_t*)test->memaddr;

+                #else

                 ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));

+                #endif

             }

             if(rex.w) {

                 if(ED->q[0] & (1LL<<tmp8u))

@@ -843,7 +868,15 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
             tmp64s >>= (rex.w?6:5);

             if(!MODREG)

             {

-                ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));

+                #ifdef TEST_INTERPRETER

+                test->memaddr=((test->memaddr)+(tmp32s<<(rex.w?3:2)));

+                if(rex.w)

+                    *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;

+                else

+                    *(uint32_t*)test->mem = *(uint32_t*)test->memaddr;

+                #else

+                ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));

+                #endif

             }

             if(rex.w) {

                 if(ED->q[0] & (1LL<<tmp8u))

@@ -892,27 +925,33 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
             GETED(0);

             switch((nextop>>3)&7) {

                 case 0:                 /* FXSAVE Ed */

+                    #ifndef TEST_INTERPRETER

                     if(rex.w)

                         fpu_fxsave64(emu, ED);

                     else

                         fpu_fxsave32(emu, ED);

+                    #endif

                     break;

                 case 1:                 /* FXRSTOR Ed */

+                    #ifndef TEST_INTERPRETER

                     if(rex.w)

                         fpu_fxrstor64(emu, ED);

                     else

                         fpu_fxrstor32(emu, ED);

+                    #endif

                     break;

                 case 2:                 /* LDMXCSR Md */

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

+                    #ifndef TEST_INTERPRETER

                     if(box64_sse_flushto0)

                         applyFlushTo0(emu);

+                    #endif

                     break;

                 case 3:                 /* STMXCSR Md */

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

                     break;

                 case 7:                 /* CLFLUSH Ed */

-                    #ifdef DYNAREC

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

                     if(box64_dynarec)

                         cleanDBFromAddressRange((uintptr_t)ED, 8, 0);

                     #endif

@@ -975,7 +1014,15 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
             tmp64s >>= (rex.w?6:5);

             if(!MODREG)

             {

-                ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));

+                #ifdef TEST_INTERPRETER

+                test->memaddr=((test->memaddr)+(tmp32s<<(rex.w?3:2)));

+                if(rex.w)

+                    *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;

+                else

+                    *(uint32_t*)test->mem = *(uint32_t*)test->memaddr;

+                #else

+                ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));

+                #endif

             }

             if(rex.w) {

                 if(ED->q[0] & (1LL<<tmp8u)) {

@@ -1105,7 +1152,15 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
             tmp64s >>= (rex.w?6:5);

             if(!MODREG)

             {

-                ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));

+                #ifdef TEST_INTERPRETER

+                test->memaddr=((test->memaddr)+(tmp32s<<(rex.w?3:2)));

+                if(rex.w)

+                    *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;

+                else

+                    *(uint32_t*)test->mem = *(uint32_t*)test->memaddr;

+                #else

+                ED=(reg64_t*)(((uintptr_t)(ED))+(tmp32s<<(rex.w?3:2)));

+                #endif

             }

             if(rex.w) {

                 if(ED->q[0] & (1LL<<tmp8u))

@@ -1289,6 +1344,10 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
             CHECK_FLAGS(emu);

             nextop = F8;

             GETED(0);

+            #ifdef TEST_INTERPRETER

+            test->memsize = 16;

+            ((uint64_t*)test->mem)[1] = ((uint64_t*)test->memaddr)[1];

+            #endif

             switch((nextop>>3)&7) {

                 case 1:

                     if(rex.w) {

diff --git a/src/emu/x64run64.c b/src/emu/x64run64.c
index fa1ea281..a8d100a3 100644
--- a/src/emu/x64run64.c
+++ b/src/emu/x64run64.c
@@ -22,7 +22,11 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test64(x64test_t *test, rex_t rex, int seg, uintptr_t addr)

+#else

 uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -35,6 +39,9 @@ uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr)
     reg64_t *oped, *opgd;

     sse_regs_t *opex, *opgx;

     int rep;

+    #ifdef TEST_INTERPRETER

+    x64emu_t* emu = test->emu;

+    #endif

     uintptr_t tlsdata = GetSegmentBaseEmu(emu, seg);

 

     opcode = F8;

diff --git a/src/emu/x64run66.c b/src/emu/x64run66.c
index f7696ee1..4a73cf60 100644
--- a/src/emu/x64run66.c
+++ b/src/emu/x64run66.c
@@ -25,7 +25,11 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test66(x64test_t *test, rex_t rex, int rep, uintptr_t addr)

+#else

 uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -37,6 +41,9 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
     int64_t tmp64s;

     uint64_t tmp64u, tmp64u2, tmp64u3;

     reg64_t *oped, *opgd;

+    #ifdef TEST_INTERPRETER

+    x64emu_t* emu = test->emu;

+    #endif

 

     opcode = F8;

 

@@ -105,7 +112,11 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
     GO(0x30, xor)                   /* XOR 0x31 ~> 0x35 */

 

     case 0x0F:                              /* more opcdes */

+        #ifdef TEST_INTERPRETER

+        return Test660F(test, rex, addr);

+        #else

         return Run660F(emu, rex, addr);

+        #endif

 

     case 0x39:

         nextop = F8;

@@ -133,9 +144,17 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
         break;

 

     case 0x64:                              /* FS: */

+        #ifdef TEST_INTERPRETER

+        return Test6664(test, rex, _FS, addr);

+        #else

         return Run6664(emu, rex, _FS, addr);

+        #endif

     case 0x65:                              /* GS: */

+        #ifdef TEST_INTERPRETER

+        return Test6664(test, rex, _GS, addr);

+        #else

         return Run6664(emu, rex, _GS, addr);

+        #endif

 

     case 0x69:                      /* IMUL Gw,Ew,Iw */

         nextop = F8;

@@ -257,8 +276,12 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
         break;

     case 0x8D:                              /* LEA Gw,M */

         nextop = F8;

-        GETED(0);

         GETGD;

+        #ifdef TEST_INTERPRETER

+        oped=GetEd(emu, &addr, rex, nextop, 0);

+        #else

+        GETED(0);

+        #endif

         if(rex.w)

             GD->q[0] = (uint64_t)ED;

         else

@@ -427,13 +450,17 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
         tmp64u = (rep)?R_RCX:1L;

         if((rex.w))

             while(tmp64u) {

+                #ifndef TEST_INTERPRETER

                 *(uint64_t*)R_RDI = R_RAX;

+                #endif

                 R_RDI += tmp8s;

                 --tmp64u;

             }

         else

             while(tmp64u) {

+                #ifndef TEST_INTERPRETER

                 *(uint16_t*)R_RDI = R_AX;

+                #endif

                 R_RDI += tmp8s;

                 --tmp64u;

             }

@@ -609,10 +636,18 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
         break;

 

     case 0xD9:                              /* x87 opcdes */

+        #ifdef TEST_INTERPRETER

+        return Test66D9(test, rex, addr);

+        #else

         return Run66D9(emu, rex, addr);

+        #endif

 

     case 0xDD:                              /* x87 opcdes */

+        #ifdef TEST_INTERPRETER

+        return Test66DD(test, rex, addr);

+        #else

         return Run66DD(emu, rex, addr);

+        #endif

 

     case 0xE8:                              /* CALL Id */

         tmp32s = F32S; // call is relative

@@ -621,7 +656,11 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
         break;

 

     case 0xF0:                              /* LOCK: */

+        #ifdef TEST_INTERPRETER

+        return Test66F0(test, rex, addr);

+        #else

         return Run66F0(emu, rex, addr);

+        #endif

 

     case 0xF7:                      /* GRP3 Ew(,Iw) */

         nextop = F8;

diff --git a/src/emu/x64run660f.c b/src/emu/x64run660f.c
index 0b868a27..019aaea7 100644
--- a/src/emu/x64run660f.c
+++ b/src/emu/x64run660f.c
@@ -43,7 +43,11 @@ static uint8_t ff_mult(uint8_t a, uint8_t b)
 	return retval;

 }

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test660F(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -106,6 +110,9 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
         0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,

     };

 

+    #ifdef TEST_INTERPRETER

+    x64emu_t* emu = test->emu;

+    #endif

     opcode = F8;

 

     switch(opcode) {

@@ -162,7 +169,7 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
 

     case 0x1F:                      /* NOP (multi-byte) */

         nextop = F8;

-        GETED(0);

+        FAKEED(0);

         break;

 

     case 0x28:                      /* MOVAPD Gx, Ex */

@@ -1564,7 +1571,15 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
         tmp32s >>= (rex.w?6:4);

         if(!MODREG)

         {

+            #ifdef TEST_INTERPRETER

+            test->memaddr=((test->memaddr)+(tmp32s<<(rex.w?3:1)));

+            if(rex.w)

+                *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;

+            else

+                *(uint16_t*)test->mem = *(uint16_t*)test->memaddr;

+            #else

             EW=(reg64_t*)(((uintptr_t)(EW))+(tmp32s<<(rex.w?3:1)));

+            #endif

         }

         if(rex.w) {

             if(EW->q[0] & (1LL<<tmp8u)) {

diff --git a/src/emu/x64run6664.c b/src/emu/x64run6664.c
index 9753dfce..668507a4 100644
--- a/src/emu/x64run6664.c
+++ b/src/emu/x64run6664.c
@@ -22,12 +22,19 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test6664(x64test_t *test, rex_t rex, int seg, uintptr_t addr)

+#else

 uintptr_t Run6664(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

     reg64_t *oped, *opgd;

     sse_regs_t *opex, *opgx;

+    #ifdef TEST_INTERPRETER

+    x64emu_t* emu = test->emu;

+    #endif

     uintptr_t tlsdata = GetSegmentBaseEmu(emu, seg);

 

     opcode = F8;

diff --git a/src/emu/x64run66d9.c b/src/emu/x64run66d9.c
index 198c3a88..84b554df 100644
--- a/src/emu/x64run66d9.c
+++ b/src/emu/x64run66d9.c
@@ -22,10 +22,17 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test66D9(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t Run66D9(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t* emu = test->emu;

+    #endif

 

     nextop = F8;

     switch (nextop) {

@@ -84,7 +91,9 @@ uintptr_t Run66D9(x64emu_t *emu, rex_t rex, uintptr_t addr)
             case 6:     /* FNSTENV m */

                 // warning, incomplete

                 GETEW(0);

+                #ifndef TEST_INTERPRETER

                 fpu_savenv(emu, (char*)ED, 1);

+                #endif

                 break;

             default:

                 return 0;

diff --git a/src/emu/x64run66dd.c b/src/emu/x64run66dd.c
index d0fc703c..e8465dd2 100644
--- a/src/emu/x64run66dd.c
+++ b/src/emu/x64run66dd.c
@@ -22,10 +22,17 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test66DD(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t Run66DD(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t* emu = test->emu;

+    #endif

 

     nextop = F8;

     switch (nextop) {

@@ -92,6 +99,7 @@ uintptr_t Run66DD(x64emu_t *emu, rex_t rex, uintptr_t addr)
             case 6: /* FNSAVE m94byte */

                 GETEW(0);

                 // ENV first...

+                #ifndef TEST_INTERPRETER

                 fpu_savenv(emu, (char*)ED, 1);

                 // save the STx

                 {

@@ -102,6 +110,7 @@ uintptr_t Run66DD(x64emu_t *emu, rex_t rex, uintptr_t addr)
                         p+=10;

                     }

                 }

+                #endif

                 reset_fpu(emu);

                 break;

             default:

diff --git a/src/emu/x64run66f0.c b/src/emu/x64run66f0.c
index 7b76fe32..a880593c 100644
--- a/src/emu/x64run66f0.c
+++ b/src/emu/x64run66f0.c
@@ -25,7 +25,11 @@
 
 #include "modrm.h"
 
+#ifdef TEST_INTERPRETER
+uintptr_t Test66F0(x64test_t *test, rex_t rex, uintptr_t addr)
+#else
 uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
+#endif
 {
     uint8_t opcode;
     uint8_t nextop;
@@ -37,7 +41,9 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
     #ifdef USE_CAS
     uint64_t tmpcas;
     #endif
-
+    #ifdef TEST_INTERPRETER
+    x64emu_t* emu = test->emu;
+    #endif
     opcode = F8;
     // REX prefix before the F0 are ignored
     rex.rex = 0;
@@ -58,7 +64,7 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                     nextop = F8;
                     GETEW(0);
                     GETGW;
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
                     do {
                         tmp16u = native_lock_read_h(EW);
                         cmp16(emu, R_AX, tmp16u);
@@ -85,7 +91,7 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                     nextop = F8;
                     GETEW(0);
                     GETGW;
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
                     if(rex.w) {
                         do {
                             tmp64u = native_lock_read_dd(ED);
@@ -128,7 +134,7 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             }
             break;
 
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
         #define GO(B, OP)                                           \
         case B+1:                                                   \
             nextop = F8;                                            \
@@ -209,7 +215,7 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             GETED((opcode==0x83)?1:2);
             tmp64s = (opcode==0x83)?(F8S):(F16S);
             tmp64u = (uint64_t)tmp64s;
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
             if(MODREG)
                 switch((nextop>>3)&7) {
                     case 0: ED->word[0] = add16(emu, ED->word[0], tmp64u); break;
@@ -253,7 +259,7 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             GETED(0);
             switch((nextop>>3)&7) {
                 case 0:                 /* INC Ed */
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
                     if(rex.w)
                         if(((uintptr_t)ED)&7) {
                             // unaligned
@@ -295,7 +301,7 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
 #endif
                     break;
                 case 1:                 /* DEC Ed */
-#ifdef DYNAREC
+#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
                     if(rex.w)
                         if(((uintptr_t)ED)&7) {
                             // unaligned
diff --git a/src/emu/x64run67.c b/src/emu/x64run67.c
index 034fd640..8b058f6b 100644
--- a/src/emu/x64run67.c
+++ b/src/emu/x64run67.c
@@ -22,7 +22,11 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t Test67(x64test_t *test, rex_t rex, int rep, uintptr_t addr)

+#else

 uintptr_t Run67(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -32,7 +36,9 @@ uintptr_t Run67(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
     int32_t tmp32s;

     uint64_t tmp64u;

     reg64_t *oped, *opgd;

-

+    #ifdef TEST_INTERPRETER

+    x64emu_t* emu = test->emu;

+    #endif

     opcode = F8;

 

     while(opcode==0x67)

@@ -146,7 +152,11 @@ uintptr_t Run67(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
         break;

 

     case 0x66:

+        #ifdef TEST_INTERPRETER

+        return Test6766(test, rex, rep, addr);

+        #else

         return Run6766(emu, rex, rep, addr);

+        #endif

 

     case 0x80:                      /* GRP Eb,Ib */

         nextop = F8;

diff --git a/src/emu/x64run670f.c b/src/emu/x64run670f.c
index d122d0e0..589e5181 100644
--- a/src/emu/x64run670f.c
+++ b/src/emu/x64run670f.c
@@ -26,7 +26,11 @@
 
 #include "modrm.h"
 
+#ifdef TEST_INTERPRETER
+uintptr_t Test670F(x64test_t *test, rex_t rex, int rep, uintptr_t addr)
+#else
 uintptr_t Run670F(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
+#endif
 {
     (void)rep;
     uint8_t opcode;
@@ -40,6 +44,9 @@ uintptr_t Run670F(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
     sse_regs_t *opex, *opgx, eax1;      (void)eax1;
     mmx87_regs_t *opem, *opgm, eam1;    (void)opem;   (void)opgm;    (void)eam1;
 
+    #ifdef TEST_INTERPRETER
+    x64emu_t* emu = test->emu;
+    #endif
     opcode = F8;
 
     switch(opcode) {
@@ -99,8 +106,10 @@ uintptr_t Run670F(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
             switch(rep) {
                 case 0: /* UD1 Ed */
                     nextop = F8;
-                    GETED32(0);
+                    FAKEED32(0);
+                    #ifndef TEST_INTERPRETER
                     emit_signal(emu, SIGILL, (void*)R_RIP, 0);
+                    #endif
                     break;
                 default:
                     return 0;
diff --git a/src/emu/x64run6766.c b/src/emu/x64run6766.c
index c12e9032..ad44f8c4 100644
--- a/src/emu/x64run6766.c
+++ b/src/emu/x64run6766.c
@@ -25,7 +25,11 @@
 
 #include "modrm.h"
 
+#ifdef TEST_INTERPRETER
+uintptr_t Test6766(x64test_t *test, rex_t rex, int rep, uintptr_t addr)
+#else
 uintptr_t Run6766(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
+#endif
 {
     // Hmmmm....
     (void)rep;
@@ -39,7 +43,9 @@ uintptr_t Run6766(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
     int64_t tmp64s;                     (void)tmp64s;
     uint64_t tmp64u, tmp64u2, tmp64u3;  (void)tmp64u; (void)tmp64u2; (void)tmp64u3;
     reg64_t *oped, *opgd;               (void)oped;   (void)opgd;
-
+    #ifdef TEST_INTERPRETER
+    x64emu_t* emu = test->emu;
+    #endif
     opcode = F8;
 
     while((opcode==0x2E) || (opcode==0x66))   // ignoring CS: or multiple 0x66
@@ -59,7 +65,11 @@ uintptr_t Run6766(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
     switch(opcode) {
 
     case 0x0F:                              /* more opcodes */
+        #ifdef TEST_INTERPRETER
+        return Test67660F(test, rex, addr);
+        #else
         return Run67660F(emu, rex, addr);
+        #endif
 
     default:
         return 0;
diff --git a/src/emu/x64run67660f.c b/src/emu/x64run67660f.c
index 75506426..ba031c8a 100644
--- a/src/emu/x64run67660f.c
+++ b/src/emu/x64run67660f.c
@@ -22,7 +22,11 @@
 
 #include "modrm.h"
 
+#ifdef TEST_INTERPRETER
+uintptr_t Test67660F(x64test_t *test, rex_t rex, uintptr_t addr)
+#else
 uintptr_t Run67660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
+#endif
 {
     uint8_t opcode;
     uint8_t nextop;
@@ -36,7 +40,9 @@ uintptr_t Run67660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
     uint64_t tmp64u;            (void)tmp64u;
     reg64_t *oped, *opgd;       (void)oped;   (void)opgd;
     sse_regs_t *opex, *opgx;
-
+    #ifdef TEST_INTERPRETER
+    x64emu_t* emu = test->emu;
+    #endif
     opcode = F8;
 
     switch(opcode) {
diff --git a/src/emu/x64run_private.c b/src/emu/x64run_private.c
index 082f0aae..3e519cd2 100755
--- a/src/emu/x64run_private.c
+++ b/src/emu/x64run_private.c
@@ -1225,6 +1225,26 @@ reg64_t* GetEb(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t del
     } else return GetECommon(emu, addr, rex, m, delta);
 }
 
+reg64_t* TestEb(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
+{
+    // rex ignored here
+    uint8_t m = v&0xC7;    // filter Eb
+    if(m>=0xC0) {
+        if(rex.rex) {
+            return &test->emu->regs[(m&0x07)+(rex.b<<3)];
+        } else {
+            int lowhigh = (m&4)>>2;
+            return (reg64_t *)(((char*)(&test->emu->regs[(m&0x03)]))+lowhigh);  //?
+        }
+    } else {
+        reg64_t* ret = GetECommon(test->emu, addr, rex, m, delta);
+        test->memsize = 1;
+        test->memaddr = (uintptr_t)ret;
+        test->mem[0] = ret->byte[0];
+        return (reg64_t*)test->mem;
+    }
+}
+
 reg64_t* GetEbO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
 {
     // rex ignored here
@@ -1239,6 +1259,26 @@ reg64_t* GetEbO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t de
     } else return GetECommonO(emu, addr, rex, m, delta, offset);
 }
 
+reg64_t* TestEbO(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
+{
+    // rex ignored here
+    uint8_t m = v&0xC7;    // filter Eb
+    if(m>=0xC0) {
+        if(rex.rex) {
+            return &test->emu->regs[(m&0x07)+(rex.b<<3)];
+        } else {
+            int lowhigh = (m&4)>>2;
+            return (reg64_t *)(((char*)(&test->emu->regs[(m&0x03)]))+lowhigh);  //?
+        }
+    } else {
+        reg64_t* ret =  GetECommonO(test->emu, addr, rex, m, delta, offset);
+        test->memsize = 1;
+        test->memaddr = (uintptr_t)ret;
+        test->mem[0] = ret->byte[0];
+        return (reg64_t*)test->mem;
+    }
+}
+
 reg64_t* GetEd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1247,6 +1287,23 @@ reg64_t* GetEd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t del
     } else return GetECommon(emu, addr, rex, m, delta);
 }
 
+reg64_t* TestEd(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &test->emu->regs[(m&0x07)+(rex.b<<3)];
+    } else {
+        reg64_t* ret =  GetECommon(test->emu, addr, rex, m, delta);
+        test->memsize = 4<<rex.w;
+        test->memaddr = (uintptr_t)ret;
+        if(rex.w)
+            *(uint64_t*)test->mem = ret->q[0];
+        else
+            *(uint32_t*)test->mem = ret->dword[0];
+        return (reg64_t*)test->mem;
+    }
+}
+
 reg64_t* GetEdO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1255,6 +1312,23 @@ reg64_t* GetEdO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t de
     } else return GetECommonO(emu, addr, rex, m, delta, offset);
 }
 
+reg64_t* TestEdO(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &test->emu->regs[(m&0x07)+(rex.b<<3)];
+    } else {
+        reg64_t* ret =  GetECommonO(test->emu, addr, rex, m, delta, offset);
+        test->memsize = 4<<rex.w;
+        test->memaddr = (uintptr_t)ret;
+        if(rex.w)
+            *(uint64_t*)test->mem = ret->q[0];
+        else
+            *(uint32_t*)test->mem = ret->dword[0];
+        return (reg64_t*)test->mem;
+    }
+}
+
 reg64_t* GetEd32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1263,6 +1337,23 @@ reg64_t* GetEd32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t
     } else return GetECommon32O(emu, addr, rex, m, delta, offset);
 }
 
+reg64_t* TestEd32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &test->emu->regs[(m&0x07)+(rex.b<<3)];
+    } else {
+        reg64_t* ret =  GetECommon32O(test->emu, addr, rex, m, delta, offset);
+        test->memsize = 4<<rex.w;
+        test->memaddr = (uintptr_t)ret;
+        if(rex.w)
+            *(uint64_t*)test->mem = ret->q[0];
+        else
+            *(uint32_t*)test->mem = ret->dword[0];
+        return (reg64_t*)test->mem;
+    }
+}
+
 reg64_t* GetEb32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
 {
     uint8_t m = v&0xC7;    // filter Eb
@@ -1276,7 +1367,27 @@ reg64_t* GetEb32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t
     } else return GetECommon32O(emu, addr, rex, m, delta, offset);
 }
 
+reg64_t* TestEb32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
+{
+    uint8_t m = v&0xC7;    // filter Eb
+    if(m>=0xC0) {
+        if(rex.rex) {
+            return &test->emu->regs[(m&0x07)+(rex.b<<3)];
+        } else {
+            int lowhigh = (m&4)>>2;
+            return (reg64_t *)(((char*)(&test->emu->regs[(m&0x03)]))+lowhigh);  //?
+        }
+    } else {
+        reg64_t* ret =  GetECommon32O(test->emu, addr, rex, m, delta, offset);
+        test->memsize = 1;
+        test->memaddr = (uintptr_t)ret;
+        test->mem[0] = ret->byte[0];
+        return (reg64_t*)test->mem;
+    }
+}
+
 #define GetEw GetEd
+#define TestEw TestEd
 
 reg64_t* GetEw16(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
 {
@@ -1307,6 +1418,39 @@ reg64_t* GetEw16(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
     }
 }
 
+reg64_t* TestEw16(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v)
+{
+    (void)rex;
+    x64emu_t* emu = test->emu;
+
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &emu->regs[(m&0x07)];
+    } else {
+        uintptr_t base = 0;
+        switch(m&7) {
+            case 0: base = R_BX+R_SI; break;
+            case 1: base = R_BX+R_DI; break;
+            case 2: base = R_BP+R_SI; break;
+            case 3: base = R_BP+R_DI; break;
+            case 4: base =      R_SI; break;
+            case 5: base =      R_DI; break;
+            case 6: base =      R_BP; break;
+            case 7: base =      R_BX; break;
+        }
+        switch((m>>6)&3) {
+            case 0: if(m==6) base = F16(addr); break;
+            case 1: base += F8S(addr); break;
+            case 2: base += F16S(addr); break;
+            // case 3 is C0..C7, already dealt with
+        }
+        test->memsize = 2;
+        *(uint16_t*)test->mem = *(uint16_t*)base;
+        test->memaddr = (uintptr_t)base;
+        return (reg64_t*)test->mem;
+    }
+}
+
 reg64_t* GetEw16off(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uintptr_t offset)
 {
     (void)rex;
@@ -1336,6 +1480,39 @@ reg64_t* GetEw16off(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uintpt
     }
 }
 
+reg64_t* TestEw16off(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uintptr_t offset)
+{
+    (void)rex;
+    x64emu_t* emu = test->emu;
+
+    uint32_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &emu->regs[(m&0x07)];
+    } else {
+        uint32_t base = 0;
+        switch(m&7) {
+            case 0: base = R_BX+R_SI; break;
+            case 1: base = R_BX+R_DI; break;
+            case 2: base = R_BP+R_SI; break;
+            case 3: base = R_BP+R_DI; break;
+            case 4: base =      R_SI; break;
+            case 5: base =      R_DI; break;
+            case 6: base =      R_BP; break;
+            case 7: base =      R_BX; break;
+        }
+        switch((m>>6)&3) {
+            case 0: if(m==6) base = F16(addr); break;
+            case 1: base += F8S(addr); break;
+            case 2: base += F16S(addr); break;
+            // case 3 is C0..C7, already dealt with
+        }
+        test->memsize = 2;
+        *(uint16_t*)test->mem = *(uint16_t*)(base+offset);
+        test->memaddr = (uintptr_t)(base+offset);
+        return (reg64_t*)test->mem;
+    }
+}
+
 mmx87_regs_t* GetEm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1344,6 +1521,20 @@ mmx87_regs_t* GetEm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_
     } else return (mmx87_regs_t*)GetECommon(emu, addr, rex, m, delta);
 }
 
+mmx87_regs_t* TestEm(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &test->emu->mmx[m&0x07];
+    } else {
+        mmx87_regs_t* ret = (mmx87_regs_t*)GetECommon(test->emu, addr, rex, m, delta);
+        test->memsize = 8;
+        *(uint64_t*)test->mem = ret->q;
+        test->memaddr = (uintptr_t)ret;
+        return (mmx87_regs_t*)test->mem;
+    }
+}
+
 sse_regs_t* GetEx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1352,6 +1543,22 @@ sse_regs_t* GetEx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t
     } else return (sse_regs_t*)GetECommon(emu, addr, rex, m, delta);
 }
 
+sse_regs_t* TestEx(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+        test->memsize=0;
+         return &test->emu->xmm[(m&0x07)+(rex.b<<3)];
+    } else {
+        sse_regs_t* ret = (sse_regs_t*)GetECommon(test->emu, addr, rex, m, delta);
+        test->memsize = 16;
+        ((uint64_t*)test->mem)[0] = ret->q[0];
+        ((uint64_t*)test->mem)[1] = ret->q[1];
+        test->memaddr = (uintptr_t)ret;
+        return (sse_regs_t*)test->mem;
+    }
+}
+
 sse_regs_t* GetExO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1360,6 +1567,21 @@ sse_regs_t* GetExO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t
     } else return (sse_regs_t*)GetECommonO(emu, addr, rex, m, delta, offset);
 }
 
+sse_regs_t* TestExO(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &test->emu->xmm[(m&0x07)+(rex.b<<3)];
+    } else {
+        sse_regs_t* ret = (sse_regs_t*)GetECommonO(test->emu, addr, rex, m, delta, offset);
+        test->memsize = 16;
+        ((uint64_t*)test->mem)[0] = ret->q[0];
+        ((uint64_t*)test->mem)[1] = ret->q[1];
+        test->memaddr = (uintptr_t)ret;
+        return (sse_regs_t*)test->mem;
+    }
+}
+
 sse_regs_t* GetEx32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1368,6 +1590,21 @@ sse_regs_t* GetEx32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8
     } else return (sse_regs_t*)GetECommon32O(emu, addr, rex, m, delta, offset);
 }
 
+sse_regs_t* TestEx32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &test->emu->xmm[(m&0x07)+(rex.b<<3)];
+    } else {
+        sse_regs_t* ret = (sse_regs_t*)GetECommon32O(test->emu, addr, rex, m, delta, offset);
+        test->memsize = 16;
+        ((uint64_t*)test->mem)[0] = ret->q[0];
+        ((uint64_t*)test->mem)[1] = ret->q[1];
+        test->memaddr = (uintptr_t)ret;
+        return (sse_regs_t*)test->mem;
+    }
+}
+
 mmx87_regs_t* GetEm32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
 {
     uint8_t m = v&0xC7;    // filter Ed
@@ -1376,6 +1613,19 @@ mmx87_regs_t* GetEm32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uin
     } else return (mmx87_regs_t*)GetECommon32O(emu, addr, rex, m, delta, offset);
 }
 
+mmx87_regs_t* TestEm32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset)
+{
+    uint8_t m = v&0xC7;    // filter Ed
+    if(m>=0xC0) {
+         return &test->emu->mmx[(m&0x07)];
+    } else {
+        mmx87_regs_t* ret = (mmx87_regs_t*)GetECommon32O(test->emu, addr, rex, m, delta, offset);
+        test->memsize = 8;
+        *(uint64_t*)test->mem = ret->q;
+        test->memaddr = (uintptr_t)ret;
+        return (mmx87_regs_t*)test->mem;
+    }
+}
 
 reg64_t* GetGd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v)
 {
diff --git a/src/emu/x64run_private.h b/src/emu/x64run_private.h
index c4704a77..df0f177c 100755
--- a/src/emu/x64run_private.h
+++ b/src/emu/x64run_private.h
@@ -26,12 +26,16 @@ static inline uint64_t Pop(x64emu_t *emu)
     return *st;
 }
 
+#ifdef TEST_INTERPRETER
+#define Push(E, V)  do{R_RSP -=8; test->memsize = 8; *(uint64_t*)test->mem = (V); test->memaddr = R_RSP;}while(0)
+#define Push16(E, V)  do{R_RSP -=2; test->memsize = 2; *(uint16_t*)test->mem = (V); test->memaddr = R_RSP;}while(0)
+#else
 static inline void Push(x64emu_t *emu, uint64_t v)
 {
     R_RSP -= 8;
     *((uint64_t*)R_RSP) = v;
 }
-
+#endif
 
 // the op code definition can be found here: http://ref.x86asm.net/geek32.html
 
@@ -39,24 +43,39 @@ reg64_t* GetECommon(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_
 reg64_t* GetECommonO(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t offset);
 reg64_t* GetECommon32O(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t offset);
 reg64_t* GetEb(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
+reg64_t* TestEb(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
 reg64_t* GetEbO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
+reg64_t* TestEbO(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
 reg64_t* GetEd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
+reg64_t* TestEd(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
 reg64_t* GetEdO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
+reg64_t* TestEdO(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
 reg64_t* GetEd32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
+reg64_t* TestEd32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
 reg64_t* GetEb32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
+reg64_t* TestEb32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
 #define GetEw GetEd
+#define TestEw TestEd
 #define GetEw32O GetEd32O
+#define TestEw32O TestEd32O
 reg64_t* GetEw16(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
+reg64_t* TestEw16(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v);
 reg64_t* GetEw16off(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uintptr_t offset);
+reg64_t* TestEw16off(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uintptr_t offset);
 mmx87_regs_t* GetEm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
+mmx87_regs_t* TestEm(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
 sse_regs_t* GetEx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
+sse_regs_t* TestEx(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta);
 sse_regs_t* GetExO(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
+sse_regs_t* TestExO(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
 sse_regs_t* GetEx32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
+sse_regs_t* TestEx32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
 reg64_t* GetGd(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
 #define GetGw GetGd
 reg64_t* GetGb(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
 mmx87_regs_t* GetGm(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
 mmx87_regs_t* GetEm32O(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
+mmx87_regs_t* TestEm32O(x64test_t *test, uintptr_t* addr, rex_t rex, uint8_t v, uint8_t delta, uintptr_t offset);
 sse_regs_t* GetGx(x64emu_t *emu, uintptr_t* addr, rex_t rex, uint8_t v);
 
 void UpdateFlags(x64emu_t *emu);
@@ -88,6 +107,31 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr);
 uintptr_t RunF20F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step);
 uintptr_t RunF30F(x64emu_t *emu, rex_t rex, uintptr_t addr);
 
+uintptr_t Test0F(x64test_t *test, rex_t rex, uintptr_t addr, int *step);
+uintptr_t Test64(x64test_t *test, rex_t rex, int seg, uintptr_t addr);
+uintptr_t Test66(x64test_t *test, rex_t rex, int rep, uintptr_t addr);
+uintptr_t Test660F(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t Test6664(x64test_t *test, rex_t rex, int seg, uintptr_t addr);
+uintptr_t Test66D9(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t Test66DD(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t Test66F0(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t Test67(x64test_t *test, rex_t rex, int rep, uintptr_t addr);
+uintptr_t Test670F(x64test_t *test, rex_t rex, int rep, uintptr_t addr);
+uintptr_t Test6766(x64test_t *test, rex_t rex, int rep, uintptr_t addr);
+uintptr_t Test67660F(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestD8(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestD9(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestDA(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestDB(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestDC(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestDD(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestDE(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestDF(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestF0(x64test_t *test, rex_t rex, uintptr_t addr);
+uintptr_t TestF20F(x64test_t *test, rex_t rex, uintptr_t addr, int *step);
+uintptr_t TestF30F(x64test_t *test, rex_t rex, uintptr_t addr);
+
+
 void x64Syscall(x64emu_t *emu);
 void x64Int3(x64emu_t* emu, uintptr_t* addr);
 x64emu_t* x64emu_fork(x64emu_t* e, int forktype);
diff --git a/src/emu/x64rund8.c b/src/emu/x64rund8.c
index 1f851bb5..374658b2 100644
--- a/src/emu/x64rund8.c
+++ b/src/emu/x64rund8.c
@@ -22,11 +22,18 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestD8(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunD8(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     float f;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     nextop = F8;

     switch (nextop) {

diff --git a/src/emu/x64rund9.c b/src/emu/x64rund9.c
index e50f5bf5..6c1ad490 100644
--- a/src/emu/x64rund9.c
+++ b/src/emu/x64rund9.c
@@ -22,13 +22,20 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestD9(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunD9(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     int32_t tmp32s;

     uint64_t ll;

     float f;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     nextop = F8;

     switch (nextop) {

@@ -228,6 +235,9 @@ uintptr_t RunD9(x64emu_t *emu, rex_t rex, uintptr_t addr)
         case 0xEF:

             return 0;

         default:

+        #ifdef TEST_INTERPRETER

+        rex.w = 0;  // hack, 32bit access only here

+        #endif

         switch((nextop>>3)&7) {

             case 0:     /* FLD ST0, Ed float */

                 GETED(0);

@@ -256,7 +266,9 @@ uintptr_t RunD9(x64emu_t *emu, rex_t rex, uintptr_t addr)
             case 6:     /* FNSTENV m */

                 // warning, incomplete

                 GETED(0);

+                #ifndef TEST_INTERPRETER

                 fpu_savenv(emu, (char*)ED, 0);

+                #endif

                 // intruction pointer: 48bits

                 // data (operand) pointer: 48bits

                 // last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)

diff --git a/src/emu/x64runda.c b/src/emu/x64runda.c
index 8a0f793c..a2f07cca 100644
--- a/src/emu/x64runda.c
+++ b/src/emu/x64runda.c
@@ -22,10 +22,17 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestDA(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunDA(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     nextop = F8;

     switch (nextop) {

@@ -96,6 +103,9 @@ uintptr_t RunDA(x64emu_t *emu, rex_t rex, uintptr_t addr)
     case 0xFD:

         return 0;

     default:

+        #ifdef TEST_INTERPRETER

+        rex.w = 0;  // hack, 32bit access only here

+        #endif

         switch((nextop>>3)&7) {

             case 0:     /* FIADD ST0, Ed int */

                 GETED(0);

diff --git a/src/emu/x64rundb.c b/src/emu/x64rundb.c
index 5791b58d..e3c05216 100644
--- a/src/emu/x64rundb.c
+++ b/src/emu/x64rundb.c
@@ -22,11 +22,18 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestDB(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunDB(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     int32_t tmp32s;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     nextop = F8;

     switch(nextop) {

@@ -125,6 +132,9 @@ uintptr_t RunDB(x64emu_t *emu, rex_t rex, uintptr_t addr)
     case 0xE7:

         return 0;

     default:

+        #ifdef TEST_INTERPRETER

+        rex.w = 0;  // hack, 32bit access only here

+        #endif

         switch((nextop>>3)&7) {

             case 0: /* FILD ST0, Ed */

                 GETED(0);

@@ -160,6 +170,10 @@ uintptr_t RunDB(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 break;

             case 5: /* FLD ST0, Et */

                 GETED(0);

+                #ifdef TEST_INTERPRETER

+                test->memsize = 10;

+                memcpy(ED, (void*)test->memaddr, 10);

+                #endif

                 fpu_do_push(emu);

                 memcpy(&STld(0).ld, ED, 10);

                 LD2D(&STld(0), &ST(0).d);

@@ -167,6 +181,9 @@ uintptr_t RunDB(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 break;

             case 7: /* FSTP tbyte */

                 GETED(0);

+                #ifdef TEST_INTERPRETER

+                test->memsize = 10;

+                #endif

                 if(ST0.q!=STld(0).uref)

                     D2LD(&ST0.d, ED);

                 else

diff --git a/src/emu/x64rundc.c b/src/emu/x64rundc.c
index dbe4d45f..3b54f94c 100644
--- a/src/emu/x64rundc.c
+++ b/src/emu/x64rundc.c
@@ -22,10 +22,17 @@
 
 #include "modrm.h"
 
+#ifdef TEST_INTERPRETER
+uintptr_t TestDC(x64test_t *test, rex_t rex, uintptr_t addr)
+#else
 uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
+#endif
 {
     uint8_t nextop;
     reg64_t *oped;
+    #ifdef TEST_INTERPRETER
+    x64emu_t*emu = test->emu;
+    #endif
 
     nextop = F8;
     switch(nextop) {
@@ -111,6 +118,9 @@ uintptr_t RunDC(x64emu_t *emu, rex_t rex, uintptr_t addr)
             ST(nextop&7).d /=  ST0.d;
             break;
         default:
+            #ifdef TEST_INTERPRETER
+            rex.w = 1;  // hack, 64bit access only here
+            #endif
             GETED(0);
             switch((nextop>>3)&7) {
             case 0:         /* FADD ST0, double */
diff --git a/src/emu/x64rundd.c b/src/emu/x64rundd.c
index abb18f77..651d04c9 100644
--- a/src/emu/x64rundd.c
+++ b/src/emu/x64rundd.c
@@ -22,10 +22,17 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestDD(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunDD(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     nextop = F8;

     switch (nextop) {

@@ -110,6 +117,9 @@ uintptr_t RunDD(x64emu_t *emu, rex_t rex, uintptr_t addr)
         return 0;

 

     default:

+        #ifdef TEST_INTERPRETER

+        rex.w = 1;  // hack, mostly 64bit access only here

+        #endif

         switch((nextop>>3)&7) {

             case 0: /* FLD double */

                 GETED(0);

@@ -147,6 +157,7 @@ uintptr_t RunDD(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 GETED(0);

                 // ENV first...

                 // warning, incomplete

+                #ifndef TEST_INTERPRETER

                 fpu_savenv(emu, (char*)ED, 0);

                 // save the STx

                 {

@@ -157,10 +168,14 @@ uintptr_t RunDD(x64emu_t *emu, rex_t rex, uintptr_t addr)
                         p+=10;

                     }

                 }

+                #endif

                 reset_fpu(emu);

                 break;

             case 7: /* FNSTSW m2byte */

                 GETED(0);

+                #ifdef TEST_INTERPRETER

+                test->memsize = 2;

+                #endif

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

                 *(uint16_t*)ED = emu->sw.x16;

                 break;

diff --git a/src/emu/x64runde.c b/src/emu/x64runde.c
index 4911be32..317c0d95 100644
--- a/src/emu/x64runde.c
+++ b/src/emu/x64runde.c
@@ -22,10 +22,17 @@
 
 #include "modrm.h"
 
+#ifdef TEST_INTERPRETER
+uintptr_t TestDE(x64test_t *test, rex_t rex, uintptr_t addr)
+#else
 uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
+#endif
 {
     uint8_t nextop;
     reg64_t *oped;
+    #ifdef TEST_INTERPRETER
+    x64emu_t*emu = test->emu;
+    #endif
 
     nextop = F8;
     switch(nextop) {
@@ -127,6 +134,9 @@ uintptr_t RunDE(x64emu_t *emu, rex_t rex, uintptr_t addr)
         return 0;
     
     default:
+        #ifdef TEST_INTERPRETER
+        rex.w = 0;  // hack, 32bit access only here
+        #endif
         switch((nextop>>3)&7) {
             case 0:     /* FIADD ST0, Ew int */
                 GETEW(0);
diff --git a/src/emu/x64rundf.c b/src/emu/x64rundf.c
index 657c1a48..beec70db 100644
--- a/src/emu/x64rundf.c
+++ b/src/emu/x64rundf.c
@@ -22,12 +22,19 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestDF(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunDF(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t nextop;

     int16_t tmp16s;

     int64_t tmp64s;

     reg64_t *oped;

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     nextop = F8;

     switch(nextop) {

@@ -144,10 +151,17 @@ uintptr_t RunDF(x64emu_t *emu, rex_t rex, uintptr_t addr)
             break;

         case 4: /* FBLD ST0, tbytes */

             GETED(0);

+            #ifdef TEST_INTERPRETER

+            test->memsize = 10;

+            memcpy(ED, (void*)test->memaddr, 10);

+            #endif

             fpu_do_push(emu);

             fpu_fbld(emu, (uint8_t*)ED);

             break;

         case 5: /* FILD ST0, Gq */

+            #ifdef TEST_INTERPRETER

+            rex.w = 1;  // hack, 64bit access

+            #endif

             GETED(0);

             tmp64s = ED->sq[0];

             fpu_do_push(emu);

@@ -157,10 +171,16 @@ uintptr_t RunDF(x64emu_t *emu, rex_t rex, uintptr_t addr)
             break;

         case 6: /* FBSTP tbytes, ST0 */

             GETED(0);

+            #ifdef TEST_INTERPRETER

+            test->memsize = 10;

+            #endif

             fpu_fbst(emu, (uint8_t*)ED);

             fpu_do_pop(emu);

             break;

         case 7: /* FISTP i64 */

+            #ifdef TEST_INTERPRETER

+            rex.w = 1;  // hack, 64bits access

+            #endif

             GETED(0);

             if(STll(0).sref==ST(0).sq)

                 ED->sq[0] = STll(0).sq;

diff --git a/src/emu/x64runf0.c b/src/emu/x64runf0.c
index 6a9276be..03f5125e 100644
--- a/src/emu/x64runf0.c
+++ b/src/emu/x64runf0.c
@@ -26,7 +26,11 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestF0(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -39,6 +43,9 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
     #ifdef USE_CAS

     uint64_t tmpcas;

     #endif

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     opcode = F8;

     // REX prefix before the F0 are ignored

@@ -49,7 +56,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
     }

 

     switch(opcode) {

-#ifdef DYNAREC

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

         #define GO(B, OP)                                           \

         case B+0:                                                   \

             nextop = F8;                                            \

@@ -181,9 +188,17 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 tmp64s >>= (rex.w?6:5);

                 if(!MODREG)

                 {

+                    #ifdef TEST_INTERPRETER

+                    test->memaddr=((test->memaddr)+(tmp32s<<(rex.w?3:2)));

+                    if(rex.w)

+                        *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;

+                    else

+                        *(uint32_t*)test->mem = *(uint32_t*)test->memaddr;

+                    #else

                     ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));

+                    #endif

                 }

-#ifdef DYNAREC

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

                 if(rex.w) {

                     tmp8u&=63;

                     if(MODREG) {

@@ -258,7 +273,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                     nextop = F8;

                     GETGB;

                     GETEB(0);

-#ifdef DYNAREC

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

                     do {

                         tmp8u = native_lock_read_b(EB);

                         cmp8(emu, R_AL, tmp8u);

@@ -284,7 +299,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                     nextop = F8;

                     GETED(0);

                     GETGD;

-#ifdef DYNAREC

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

                     if(rex.w)

                         if(((uintptr_t)ED)&7) {

                             do {

@@ -360,10 +375,18 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                     tmp64s >>= (rex.w?6:5);

                     if(!MODREG)

                     {

+                        #ifdef TEST_INTERPRETER

+                        test->memaddr=((test->memaddr)+(tmp32s<<(rex.w?3:2)));

+                        if(rex.w)

+                            *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;

+                        else

+                            *(uint32_t*)test->mem = *(uint32_t*)test->memaddr;

+                        #else

                         ED=(reg64_t*)(((uintptr_t)(ED))+(tmp64s<<(rex.w?3:2)));

+                        #endif

                     }

                     tmp8u&=rex.w?63:31;

-#ifdef DYNAREC

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

                     if(rex.w)

                         do {

                             tmp64u = native_lock_read_dd(ED);

@@ -437,7 +460,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                                 CHECK_FLAGS(emu);

                                 GETED(1);

                                 tmp8u = F8;

-#ifdef DYNAREC

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

                                 if(rex.w) {

                                     tmp8u&=63;

                                     do {

@@ -491,7 +514,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                                 CHECK_FLAGS(emu);

                                 GETED(1);

                                 tmp8u = F8;

-#ifdef DYNAREC

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

                                 if(rex.w) {

                                     do {

                                         tmp8u&=63;

@@ -543,7 +566,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                                 CHECK_FLAGS(emu);

                                 GETED(1);

                                 tmp8u = F8;

-#ifdef DYNAREC

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

                                 if(rex.w) {

                                     tmp8u&=63;

                                     do {

@@ -597,7 +620,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                     nextop = F8;

                     GETEB(0);

                     GETGB;

-#ifdef DYNAREC

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

                     do {

                         tmp8u = native_lock_read_b(EB);

                         tmp8u2 = add8(emu, tmp8u, GB);

@@ -615,7 +638,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                     nextop = F8;

                     GETED(0);

                     GETGD;

-#ifdef DYNAREC

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

                     if(rex.w) {

                         do {

                             tmp64u = native_lock_read_dd(ED);

@@ -665,7 +688,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                         case 1:

                             CHECK_FLAGS(emu);

                             GETGD;

-#ifdef DYNAREC

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

                             if(rex.w)

                                 do {

                                     native_lock_read_dq(&tmp64u, &tmp64u2, ED);

@@ -695,6 +718,9 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
 #else

                             pthread_mutex_lock(&emu->context->mutex_lock);

                             if(rex.w) {

+                                #ifdef TEST_INTERPRETER

+                                test->memsize = 16;

+                                #endif

                                 tmp64u = ED->q[0];

                                 tmp64u2= ED->q[1];

                                 if(R_RAX == tmp64u && R_RDX == tmp64u2) {

@@ -707,6 +733,9 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                                     R_RDX = tmp64u2;

                                 }

                             } else {

+                                #ifdef TEST_INTERPRETER

+                                test->memsize = 8;

+                                #endif

                                 tmp32u = ED->dword[0];

                                 tmp32u2= ED->dword[1];

                                 if(R_EAX == tmp32u && R_EDX == tmp32u2) {

@@ -733,13 +762,17 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             break;

 

         case 0x66:

+            #ifdef TEST_INTERPRETER

+            return Test66F0(test, rex, addr);

+            #else

             return Run66F0(emu, rex, addr);   // more opcode F0 66 and 66 F0 is the same

+            #endif

 

         case 0x80:                      /* GRP Eb,Ib */

             nextop = F8;

             GETEB(1);

             tmp8u = F8;

-#ifdef DYNAREC

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

             switch((nextop>>3)&7) {

                 case 0: do { tmp8u2 = native_lock_read_b(EB); tmp8u2 = add8(emu, tmp8u2, tmp8u);} while(native_lock_write_b(EB, tmp8u2)); break;

                 case 1: do { tmp8u2 = native_lock_read_b(EB); tmp8u2 =  or8(emu, tmp8u2, tmp8u);} while(native_lock_write_b(EB, tmp8u2)); break;

@@ -774,7 +807,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 tmp64u = (uint64_t)tmp64s;

             } else

                 tmp64u = F32S64;

-#ifdef DYNAREC

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

             if(rex.w) {

                 switch((nextop>>3)&7) {

                     case 0: do { tmp64u2 = native_lock_read_dd(ED); tmp64u2 = add64(emu, tmp64u2, tmp64u);} while(native_lock_write_dd(ED, tmp64u2)); break;

@@ -853,7 +886,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
 

         case 0x86:                      /* XCHG Eb,Gb */

             nextop = F8;

-#ifdef DYNAREC

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

             GETEB(0);

             GETGB;

             if(MODREG) { // reg / reg: no lock

@@ -880,7 +913,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             break;

         case 0x87:                      /* XCHG Ed,Gd */

             nextop = F8;

-#ifdef DYNAREC

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

             GETED(0);

             GETGD;

             if(MODREG) {

@@ -926,7 +959,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             GETEB((tmp8u<2)?1:0);

             switch(tmp8u) {

                 case 2:                 /* NOT Eb */

-#ifdef DYNAREC

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

                     do {

                         tmp8u2 = native_lock_read_b(EB); 

                         tmp8u2 = not8(emu, tmp8u2);

@@ -947,7 +980,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             GETED(0);

             switch((nextop>>3)&7) {

                 case 0:                 /* INC Eb */

-#ifdef DYNAREC

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

                     do {

                         tmp8u = native_lock_read_b(ED);

                     } while(native_lock_write_b(ED, inc8(emu, tmp8u)));

@@ -958,7 +991,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
 #endif

                     break;

                 case 1:                 /* DEC Ed */

-#ifdef DYNAREC

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

                     do {

                         tmp8u = native_lock_read_b(ED);

                     } while(native_lock_write_b(ED, dec8(emu, tmp8u)));

@@ -980,7 +1013,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
             GETED(0);

             switch((nextop>>3)&7) {

                 case 0:                 /* INC Ed */

-#ifdef DYNAREC

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

                     if(rex.w)

                         if(((uintptr_t)ED)&7) {

                             // unaligned

@@ -1026,7 +1059,7 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
 #endif

                     break;

                 case 1:                 /* DEC Ed */

-#ifdef DYNAREC

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

                     if(rex.w)

                         if(((uintptr_t)ED)&7) {

                             // unaligned

diff --git a/src/emu/x64runf20f.c b/src/emu/x64runf20f.c
index a2c0e8e0..d7ce1eee 100644
--- a/src/emu/x64runf20f.c
+++ b/src/emu/x64runf20f.c
@@ -22,7 +22,11 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestF20F(x64test_t *test, rex_t rex, uintptr_t addr, int *step)

+#else

 uintptr_t RunF20F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -35,6 +39,9 @@ uintptr_t RunF20F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
     #ifndef NOALIGN

     int is_nan;

     #endif

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     opcode = F8;

 

diff --git a/src/emu/x64runf30f.c b/src/emu/x64runf30f.c
index acfd7895..4149c94e 100644
--- a/src/emu/x64runf30f.c
+++ b/src/emu/x64runf30f.c
@@ -22,7 +22,11 @@
 

 #include "modrm.h"

 

+#ifdef TEST_INTERPRETER

+uintptr_t TestF30F(x64test_t *test, rex_t rex, uintptr_t addr)

+#else

 uintptr_t RunF30F(x64emu_t *emu, rex_t rex, uintptr_t addr)

+#endif

 {

     uint8_t opcode;

     uint8_t nextop;

@@ -33,6 +37,9 @@ uintptr_t RunF30F(x64emu_t *emu, rex_t rex, uintptr_t addr)
     reg64_t *oped, *opgd;

     sse_regs_t *opex, *opgx, eax1;

     mmx87_regs_t *opem;

+    #ifdef TEST_INTERPRETER

+    x64emu_t*emu = test->emu;

+    #endif

 

     opcode = F8;

 

diff --git a/src/emu/x64test.c b/src/emu/x64test.c
new file mode 100644
index 00000000..f58e68c4
--- /dev/null
+++ b/src/emu/x64test.c
@@ -0,0 +1,142 @@
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "debug.h"
+#include "box64stack.h"
+#include "x64emu.h"
+#include "x64run.h"
+#include "x64emu_private.h"
+#include "x64run_private.h"
+#include "x64primop.h"
+#include "x64trace.h"
+#include "x87emu_private.h"
+#include "box64context.h"
+#include "bridge.h"
+#include "signals.h"
+
+void x64test_init(x64emu_t* ref, uintptr_t ip, int ok)
+{
+    x64test_t* test = &ref->test;
+    // check if test as a valid emu struct
+    if(!test->emu) {
+        test->emu = NewX64Emu(my_context, ip, (uintptr_t)ref->init_stack, ref->size_stack, 0);
+        CopyEmu(test->emu, ref);
+    }
+    // check if IP is same, else, sync
+    if(ip != test->emu->ip.q[0] || !ok) {
+        CopyEmu(test->emu, ref);
+    }
+    // Do a Dry single Step
+    test->memsize = 0;
+    RunTest(test);
+}
+
+void print_banner(x64emu_t* ref)
+{
+    printf_log(LOG_NONE, "Warning, difference between Interpreter and Dynarec in %p\n=======================================\n", (void*)ref->ip.q[0]);
+    printf_log(LOG_NONE, "DIF: Dynarec |  Intepreter\n----------------------\n");
+}
+#define BANNER if(!banner) {banner=1; print_banner(ref);}
+void x64test_check(x64emu_t* ref, uintptr_t ip)
+{
+    int banner = 0;
+    x64test_t* test = &ref->test;
+    x64emu_t* emu = test->emu;
+    if(memcmp(ref->regs, emu->regs, sizeof(emu->regs))) {
+        static const char* regname[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
+                                        " R8", " R9", "R10", "R11", "R12", "R13", "R14", "R15"};
+        BANNER;
+        for(int i=0; i<16; ++i) {
+            if(ref->regs[i].q[0]!=emu->regs[i].q[0]) {
+                printf_log(LOG_NONE, "%s: %016zx | %016zx\n", regname[i], ref->regs[i].q[0], emu->regs[i].q[0]);
+            }
+        }
+    }
+    if(ip!=emu->ip.q[0]) {
+        BANNER;
+        printf_log(LOG_NONE, "RIP: %016zx | %016zx\n", ip, emu->ip.q[0]);
+    }
+    // flags are volatile, so don't test them
+	//memcpy(&ref->eflags, &emu->eflags, sizeof(emu->eflags));
+    if(memcmp(ref->segs, emu->segs, sizeof(emu->segs))) {
+        static const char* segname[] = {"CS", "DS", "ES", "SS", "FS", "GS"};
+        BANNER;
+        for(int i=0; i<6; ++i) {
+            if(ref->segs[i]!=emu->segs[i]) {
+                printf_log(LOG_NONE, "%s: %04x | %04x\n", segname[i], ref->segs[i], emu->segs[i]);
+            }
+        }
+    }
+    if(ref->top != emu->top) {
+        BANNER;
+        printf_log(LOG_NONE, "X87 TOP: %d | %d\n", ref->top, emu->top);
+    }
+    if(ref->fpu_stack != emu->fpu_stack) {
+        BANNER;
+        printf_log(LOG_NONE, "X87 STACK: %d | %d\n", ref->fpu_stack, emu->fpu_stack);
+    }
+	if(ref->fpu_stack && memcmp(ref->x87, emu->x87, sizeof(emu->x87))) {
+        // need to check each regs, unused one might have different left over value
+        for(int i=0; i<ref->fpu_stack; ++i) {
+            if(ref->x87[(ref->top+i)&7].d != emu->x87[(emu->top+i)&7].d) {
+                BANNER;
+                printf_log(LOG_NONE, "ST%d: %g | %g\n", i, ref->x87[(ref->top+i)&7].d, emu->x87[(emu->top+i)&7].d);
+            }
+        }
+    }
+    //memcpy(ref->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
+    //memcpy(ref->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
+	/*if(ref->p_regs != emu->p_regs) {
+        BANNER;
+        printf_log(LOG_NONE, "X87 PREG: %x | %x\n", ref->p_regs, emu->p_regs);
+    }*/
+	if(ref->cw.x16 != emu->cw.x16) {
+        BANNER;
+        printf_log(LOG_NONE, "X87 CW: %x | %x\n", ref->cw.x16, emu->cw.x16);
+    }
+	if(ref->sw.x16 != emu->sw.x16) {
+        BANNER;
+        printf_log(LOG_NONE, "X87 SW: %x | %x\n", ref->sw.x16, emu->sw.x16);
+    }
+	if(memcmp(ref->mmx, emu->mmx, sizeof(emu->mmx))) {
+        BANNER;
+        for(int i=0; i<8; ++i) {
+            if(ref->mmx[i].q!=emu->mmx[i].q) {
+                printf_log(LOG_NONE, "EMM[%d]: %016x | %016x\n", i, ref->mmx[i].q, emu->mmx[i].q);
+            }
+        }
+    }
+    if(ref->mxcsr.x32 != emu->mxcsr.x32) {
+        BANNER;
+        printf_log(LOG_NONE, "MXCSR: %x | %x\n", ref->mxcsr.x32, emu->mxcsr.x32);
+    }
+    if(memcmp(ref->xmm, emu->xmm, sizeof(emu->xmm))) {
+        BANNER;
+        for(int i=0; i<16; ++i) {
+            if(ref->xmm[i].q[0]!=emu->xmm[i].q[0] || ref->xmm[i].q[1]!=emu->xmm[i].q[1] ) {
+                printf_log(LOG_NONE, "XMM[%02d]: %016zx-%016zx | %016zx-%016zx\n", i, ref->xmm[i].q[0], ref->xmm[i].q[1], emu->xmm[i].q[0], emu->xmm[i].q[1]);
+            }
+        }
+    }
+    if(test->memsize) {
+        if(memcmp(test->mem, (void*)test->memaddr, test->memsize)) {
+            BANNER;
+            printf_log(LOG_NONE, "MEM: @%p :", (void*)test->memaddr);
+            for(int i=0; i<test->memsize; ++i)
+                printf_log(LOG_NONE, " %02x", test->mem[i]);
+            printf_log(LOG_NONE, " |");
+            for(int i=0; i<test->memsize; ++i)
+                printf_log(LOG_NONE, " %02x", ((uint8_t*)test->memaddr)[i]);
+        }
+    }
+    if(banner)  // there was an error, re-sync!
+        CopyEmu(emu, ref);
+}
+#undef BANNER
\ No newline at end of file
diff --git a/src/include/box64context.h b/src/include/box64context.h
index 1920bb8a..62e4bad5 100755
--- a/src/include/box64context.h
+++ b/src/include/box64context.h
@@ -136,6 +136,7 @@ typedef struct box64context_s {
     uint32_t            mutex_bridge;
     uintptr_t           max_db_size;    // the biggest (in x86_64 instructions bytes) built dynablock
     int                 trace_dynarec;
+    pthread_mutex_t     mutex_lock;     // this is for the Test interpreter
     #endif
 
     library_t           *libclib;       // shortcut to libc library (if loaded, so probably yes)
diff --git a/src/include/debug.h b/src/include/debug.h
index e13de642..37146e02 100755
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -26,6 +26,7 @@ extern int box64_dynarec_bleeding_edge;
 extern int box64_dynarec_hotpage;
 extern int box64_dynarec_fastpage;
 extern int box64_dynarec_wait;
+extern int box64_dynarec_test;
 #ifdef ARM64
 extern int arm64_asimd;
 extern int arm64_aes;
diff --git a/src/include/dynarec.h b/src/include/dynarec.h
index a68c6d6a..c304cf1e 100755
--- a/src/include/dynarec.h
+++ b/src/include/dynarec.h
@@ -5,4 +5,7 @@ typedef struct x64emu_s x64emu_t;
 
 void DynaCall(x64emu_t* emu, uintptr_t addr); // try to use DynaRec... Fallback to EmuCall if no dynarec available
 
+void x64test_init(x64emu_t* ref);
+void x64test_check(x64emu_t* ref);
+
 #endif // __DYNAREC_H_
\ No newline at end of file
diff --git a/src/include/x64emu.h b/src/include/x64emu.h
index e7efbb07..17252b68 100755
--- a/src/include/x64emu.h
+++ b/src/include/x64emu.h
@@ -10,6 +10,7 @@ void SetupX64Emu(x64emu_t *emu);
 void FreeX64Emu(x64emu_t **x64emu);
 void FreeX64EmuFromStack(x64emu_t **emu);
 void CloneEmu(x64emu_t *newemu, const x64emu_t* emu);
+void CopyEmu(x64emu_t *newemu, const x64emu_t* emu);
 void SetTraceEmu(uintptr_t trace_start, uintptr_t trace_end);
 
 box64context_t* GetEmuContext(x64emu_t* emu);
diff --git a/src/include/x64run.h b/src/include/x64run.h
index 78903bbc..0e156341 100755
--- a/src/include/x64run.h
+++ b/src/include/x64run.h
@@ -3,7 +3,9 @@
 #include <stdint.h>
 
 typedef struct x64emu_s x64emu_t;
+typedef struct x64test_s x64test_t;
 int Run(x64emu_t *emu, int step); // 0 if run was successfull, 1 if error in x86 world
+int RunTest(x64test_t *test);
 int DynaRun(x64emu_t *emu);
 
 uint32_t LibSyscall(x64emu_t *emu);
diff --git a/src/main.c b/src/main.c
index 67c004eb..9d4fc873 100755
--- a/src/main.c
+++ b/src/main.c
@@ -62,6 +62,7 @@ int box64_dynarec_hotpage = 4;
 int box64_dynarec_fastpage = 0;
 int box64_dynarec_bleeding_edge = 1;
 int box64_dynarec_wait = 1;
+int box64_dynarec_test = 0;
 uintptr_t box64_nodynarec_start = 0;
 uintptr_t box64_nodynarec_end = 0;
 #ifdef ARM64
@@ -600,6 +601,18 @@ void LoadLogEnv()
             printf_log(LOG_INFO, "No dynablock creation that start in the range %p - %p\n", (void*)box64_nodynarec_start, (void*)box64_nodynarec_end);
         }
     }
+    p = getenv("BOX64_DYNAREC_TEST");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[0]<='1')
+                box64_dynarec_test = p[0]-'0';
+        }
+        if(box64_dynarec_test) {
+            box64_dynarec_fastnan = 0;
+            box64_dynarec_fastround = 0;
+            printf_log(LOG_INFO, "Dynarec will compare it's execution with the interpreter (super slow, only for testing)\n");
+        }
+    }
 
 #endif
 #ifdef HAVE_TRACE
diff --git a/src/tools/rcfile.c b/src/tools/rcfile.c
index 884f60eb..4687ec50 100644
--- a/src/tools/rcfile.c
+++ b/src/tools/rcfile.c
@@ -127,6 +127,7 @@ ENTRYINT(BOX64_DYNAREC_HOTPAGE, box64_dynarec_hotpage, 0, 255, 8)   \
 ENTRYBOOL(BOX64_DYNAREC_FASTPAGE, box64_dynarec_fastpage)           \
 ENTRYBOOL(BOX64_DYNAREC_WAIT, box64_dynarec_wait)                   \
 ENTRYSTRING_(BOX64_NODYNAREC, box64_nodynarec)                      \
+ENTRYBOOL(BOX64_DYNAREC_TEST, box64_dynarec_test)                   \
 
 #else
 #define SUPER3()                                                    \
@@ -146,6 +147,7 @@ IGNORE(BOX64_DYNAREC_HOTPAGE)                                       \
 IGNORE(BOX64_DYNAREC_FASTPAGE)                                      \
 IGNORE(BOX64_DYNAREC_WAIT)                                          \
 IGNORE(BOX64_NODYNAREC)                                             \
+IGNORE(BOX64_DYNAREC_TEST)                                          \
 
 #endif