about summary refs log tree commit diff stats
path: root/src/emu/x64run.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/x64run.c')
-rw-r--r--src/emu/x64run.c271
1 files changed, 123 insertions, 148 deletions
diff --git a/src/emu/x64run.c b/src/emu/x64run.c
index a393e84c..9c536731 100644
--- a/src/emu/x64run.c
+++ b/src/emu/x64run.c
@@ -51,7 +51,6 @@ int Run(x64emu_t *emu, int step)
     #endif
     uintptr_t addr = R_RIP;
     rex_t rex = {0};
-    int rep;    // 0 none, 1=F2 prefix, 2=F3 prefix
     int unimp = 0;
     int is32bits = (emu->segs[_CS]==0x23);
     int tf_next = 0;
@@ -85,24 +84,53 @@ x64emurun:
 
         opcode = F8;
         
-        rep = 0;
-        while((opcode==0xF2) || (opcode==0xF3) || (opcode==0x3E) || (opcode==0x26)) {
+        rex.rex = 0;
+        rex.seg = 0;
+        rex.offset = 0;
+        rex.is32bits = is32bits;
+        rex.is66 = 0;
+        rex.is67 = 0;
+        rex.rep = 0;
+        while((opcode==0xF2) || (opcode==0xF3) 
+            || (opcode==0x3E) || (opcode==0x26) || (opcode==0x2e) || (opcode==0x36) 
+            || (opcode==0x64) || (opcode==0x65) || (opcode==0x66) || (opcode==0x67)
+            || (!is32bits && (opcode>=0x40 && opcode<=0x4f))) {
             switch (opcode) {
-                case 0xF2: rep = 1; break;
-                case 0xF3: rep = 2; break;
-                case 0x3E:
-                case 0x26: /* ignored*/ break;
+                case 0xF2: rex.rep = 1; rex.rex = 0; break;
+                case 0xF3: rex.rep = 2; rex.rex = 0; break;
+                case 0x26: /* ES: */
+                case 0x2E: /* CS: */
+                case 0x36: /* SS; */
+                case 0x3E: /* DS; */ 
+                           rex.seg =   0; rex.rex = 0; break;
+                case 0x64: rex.seg = _FS; rex.rex = 0; break;
+                case 0x65: rex.seg = _GS; rex.rex = 0; break;
+                case 0x66: rex.is66 = 1; rex.rex = 0; break;
+                case 0x67: rex.is67 = 1; rex.rex = 0; break;
+                case 0x40 ... 0x4F: rex.rex = opcode; break;
             }
             opcode = F8;
         }
-        rex.rex = 0;
-        rex.is32bits = is32bits;
-        if(!is32bits)
-            while(opcode>=0x40 && opcode<=0x4f) {
-                rex.rex = opcode;
-                opcode = F8;
-            }
 
+        if(rex.seg)
+            rex.offset = GetSegmentBaseEmu(emu, rex.seg);
+
+        if(rex.is66) {
+            /* 16bits prefix */
+            #ifdef TEST_INTERPRETER
+            if(!(addr = Test66(test, rex, addr-1)))
+                unimp = 1;
+            #else
+            if(!(addr = Run66(emu, rex, addr-1))) {
+                unimp = 1;
+                goto fini;
+            }
+            if(emu->quit) {
+                R_RIP = addr;
+                goto fini;
+            }
+            #endif
+        } else
         switch(opcode) {
 
         #define GO(B, OP)                                   \
@@ -175,7 +203,7 @@ x64emurun:
             Push32(emu, emu->segs[_CS]);  // even if a segment is a 16bits, a 32bits push/pop is done
             break;
         case 0x0F:                      /* More instructions */
-            switch(rep) {
+            switch(rex.rep) {
                 case 1:
                     #ifdef TEST_INTERPRETER 
                     if(!(addr = TestF20F(test, rex, addr, &step)))
@@ -458,98 +486,7 @@ 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;
-            }
-            if(emu->quit) {
-                R_RIP = addr;
-                goto fini;
-            }
-            if(is32bits!=(emu->segs[_CS]==0x23)) {
-                is32bits = (emu->segs[_CS]==0x23);
-                if(is32bits) {
-                    // Zero upper part of the 32bits regs
-                    R_RAX = R_EAX;
-                    R_RBX = R_EBX;
-                    R_RCX = R_ECX;
-                    R_RDX = R_EDX;
-                    R_RSP = R_ESP;
-                    R_RBP = R_EBP;
-                    R_RSI = R_ESI;
-                    R_RDI = R_EDI;
-                }
-                if(is32bits)
-                    running32bits = 1;
-            }
-            #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;
-            }
-            if(emu->quit) {
-                R_RIP = addr;
-                goto fini;
-            }
-            if(is32bits!=(emu->segs[_CS]==0x23)) {
-                is32bits = (emu->segs[_CS]==0x23);
-                if(is32bits) {
-                    // Zero upper part of the 32bits regs
-                    R_RAX = R_EAX;
-                    R_RBX = R_EBX;
-                    R_RCX = R_ECX;
-                    R_RDX = R_EDX;
-                    R_RSP = R_ESP;
-                    R_RBP = R_EBP;
-                    R_RSI = R_ESI;
-                    R_RDI = R_EDI;
-                }
-                if(is32bits)
-                    running32bits = 1;
-            }
-            #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;
-            }
-            if(emu->quit) {
-                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;
-            }
-            if(emu->quit) {
-                R_RIP = addr;
-                goto fini;
-            }
-            #endif
-            break;
+
         case 0x68:                      /* Push Id */
             if(rex.is32bits)
                 Push32(emu, F32);
@@ -919,39 +856,39 @@ x64emurun:
             break;
         case 0xA0:                      /* MOV AL,Ob */
             if(rex.is32bits)
-                R_AL = *(uint8_t*)(uintptr_t)F32;
+                R_AL = *(uint8_t*)(uintptr_t)(ptr_t)(F32+rex.offset);
             else
-                R_AL = *(uint8_t*)F64;
+                R_AL = *(uint8_t*)(F64+rex.offset);
             break;
         case 0xA1:                      /* MOV EAX,Od */
             if(rex.is32bits)
-                R_EAX = *(int32_t*)(uintptr_t)F32;
+                R_EAX = *(int32_t*)(uintptr_t)(ptr_t)(F32+rex.offset);
             else {
                 if(rex.w)
-                    R_RAX = *(uint64_t*)F64;
+                    R_RAX = *(uint64_t*)(F64+rex.offset);
                 else
-                    R_RAX = *(uint32_t*)F64;
+                    R_RAX = *(uint32_t*)(F64+rex.offset);
             }
             break;
         case 0xA2:                      /* MOV Ob,AL */
             if(rex.is32bits)
-                *(uint8_t*)(uintptr_t)F32 = R_AL;
+                *(uint8_t*)(uintptr_t)(ptr_t)(F32+rex.offset) = R_AL;
             else
-                *(uint8_t*)F64 = R_AL;
+                *(uint8_t*)(F64+rex.offset) = R_AL;
             break;
         case 0xA3:                      /* MOV Od,EAX */
             if(rex.is32bits)
-                *(uint32_t*)(uintptr_t)F32 = R_EAX;
+                *(uint32_t*)(uintptr_t)(ptr_t)(F32+rex.offset) = R_EAX;
             else {
                 if(rex.w)
-                    *(uint64_t*)F64 = R_RAX;
+                    *(uint64_t*)(F64+rex.offset) = R_RAX;
                 else
-                    *(uint32_t*)F64 = R_EAX;
+                    *(uint32_t*)(F64+rex.offset) = R_EAX;
             }
             break;
         case 0xA4:                      /* MOVSB */
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
-            tmp64u = (rep)?R_RCX:1L;
+            tmp64u = (rex.rep)?R_RCX:1L;
             while(tmp64u) {
                 #ifndef TEST_INTERPRETER
                 *(uint8_t*)R_RDI = *(uint8_t*)R_RSI;
@@ -960,12 +897,12 @@ x64emurun:
                 R_RSI += tmp8s;
                 --tmp64u;
             }
-            if(rep)
+            if(rex.rep)
                 R_RCX = tmp64u;
             break;
         case 0xA5:              /* (REP) MOVSD */
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
-            tmp64u = (rep)?R_RCX:1L;
+            tmp64u = (rex.rep)?R_RCX:1L;
             if(rex.w) {
                 tmp8s *= 8;
                 while(tmp64u) {
@@ -987,12 +924,12 @@ x64emurun:
                     R_RSI += tmp8s;
                 }
             }
-            if(rep)
+            if(rex.rep)
                 R_RCX = tmp64u;
             break;
         case 0xA6:                      /* (REPZ/REPNE) CMPSB */
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
-            switch(rep) {
+            switch(rex.rep) {
                 case 1:
                     if(R_RCX) {
                         while(R_RCX) {
@@ -1034,7 +971,7 @@ x64emurun:
                 tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
             else
                 tmp8s = ACCESS_FLAG(F_DF)?-4:+4;
-            switch(rep) {
+            switch(rex.rep) {
                 case 1:
                     if(R_RCX) {
                         if(rex.w) {
@@ -1117,7 +1054,7 @@ x64emurun:
 
         case 0xAA:                      /* (REP) STOSB */
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
-            tmp64u = (rep)?R_RCX:1L;
+            tmp64u = (rex.rep)?R_RCX:1L;
             while(tmp64u) {
                 #ifndef TEST_INTERPRETER
                 *(uint8_t*)R_RDI = R_AL;
@@ -1125,7 +1062,7 @@ x64emurun:
                 R_RDI += tmp8s;
                 --tmp64u;
             }
-            if(rep)
+            if(rex.rep)
                 R_RCX = tmp64u;
             break;
         case 0xAB:                      /* (REP) STOSD */
@@ -1133,7 +1070,7 @@ x64emurun:
                 tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
             else
                 tmp8s = ACCESS_FLAG(F_DF)?-4:+4;
-            tmp64u = (rep)?R_RCX:1L;
+            tmp64u = (rex.rep)?R_RCX:1L;
             if((rex.w))
                 while(tmp64u) {
                     #ifndef TEST_INTERPRETER
@@ -1148,18 +1085,18 @@ x64emurun:
                     R_RDI += tmp8s;
                     --tmp64u;
                 }
-            if(rep)
+            if(rex.rep)
                 R_RCX = tmp64u;
             break;
         case 0xAC:                      /* LODSB */
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
-            tmp64u = (rep)?R_RCX:1L;
+            tmp64u = (rex.rep)?R_RCX:1L;
             while(tmp64u) {
                 R_AL = *(uint8_t*)R_RSI;
                 R_RSI += tmp8s;
                 --tmp64u;
             }
-            if(rep)
+            if(rex.rep)
                 R_RCX = tmp64u;
             break;
         case 0xAD:                      /* (REP) LODSD */
@@ -1167,7 +1104,7 @@ x64emurun:
                 tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
             else
                 tmp8s = ACCESS_FLAG(F_DF)?-4:+4;
-            tmp64u = (rep)?R_RCX:1L;
+            tmp64u = (rex.rep)?R_RCX:1L;
             if((rex.w))
                 while(tmp64u) {
                     R_RAX = *(uint64_t*)R_RSI;
@@ -1180,12 +1117,12 @@ x64emurun:
                     R_RSI += tmp8s;
                     --tmp64u;
                 }
-            if(rep)
+            if(rex.rep)
                 R_RCX = tmp64u;
             break;
         case 0xAE:                      /* (REPZ/REPNE) SCASB */
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
-            switch(rep) {
+            switch(rex.rep) {
                 case 1:
                     if(R_RCX) {
                         while(R_RCX) {
@@ -1220,7 +1157,7 @@ x64emurun:
                 tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
             else
                 tmp8s = ACCESS_FLAG(F_DF)?-4:+4;
-            switch(rep) {
+            switch(rex.rep) {
                 case 1:
                     if(R_RCX) {
                         if(rex.w) {
@@ -1723,10 +1660,10 @@ x64emurun:
             break;
         case 0xD8:                      /* x87 opcodes */
             #ifdef TEST_INTERPRETER
-            if(!(addr = TestD8(test, rex, addr, 0)))
+            if(!(addr = TestD8(test, rex, addr)))
                 unimp = 1;
             #else
-            if(!(addr = RunD8(emu, rex, addr, 0))) {
+            if(!(addr = RunD8(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
             }
@@ -1738,10 +1675,10 @@ x64emurun:
             break;
         case 0xD9:                      /* x87 opcodes */
             #ifdef TEST_INTERPRETER
-            if(!(addr = TestD9(test, rex, addr, 0)))
+            if(!(addr = TestD9(test, rex, addr)))
                 unimp = 1;
             #else
-            if(!(addr = RunD9(emu, rex, addr, 0))) {
+            if(!(addr = RunD9(emu, rex, addr))) {
                 unimp = 1;
                 goto fini;
             }
@@ -1844,30 +1781,68 @@ x64emurun:
         case 0xE0:                      /* LOOPNZ */
             CHECK_FLAGS(emu);
             tmp8s = F8S;
-            --R_RCX; // don't update flags
-            if(R_RCX && !ACCESS_FLAG(F_ZF))
-                addr += tmp8s;
+            if(rex.is32bits && rex.is67) {
+                --R_CX; // don't update flags
+                if(R_CX && !ACCESS_FLAG(F_ZF))
+                    addr += tmp8s;
+            } else if(rex.is32bits || rex.is67) {
+                --R_ECX; // don't update flags
+                if(R_ECX && !ACCESS_FLAG(F_ZF))
+                    addr += tmp8s;
+            } else {
+                --R_RCX; // don't update flags
+                if(R_RCX && !ACCESS_FLAG(F_ZF))
+                    addr += tmp8s;
+            }
             STEP2
             break;
         case 0xE1:                      /* LOOPZ */
             CHECK_FLAGS(emu);
             tmp8s = F8S;
-            --R_RCX; // don't update flags
-            if(R_RCX && ACCESS_FLAG(F_ZF))
-                addr += tmp8s;
+            if(rex.is32bits && rex.is67) {
+                --R_CX; // don't update flags
+                if(R_CX && ACCESS_FLAG(F_ZF))
+                    addr += tmp8s;
+            } else if(rex.is32bits || rex.is67) {
+                --R_ECX; // don't update flags
+                if(R_ECX && ACCESS_FLAG(F_ZF))
+                    addr += tmp8s;
+            } else {
+                --R_RCX; // don't update flags
+                if(R_RCX && ACCESS_FLAG(F_ZF))
+                    addr += tmp8s;
+            }
             STEP2
             break;
         case 0xE2:                      /* LOOP */
             tmp8s = F8S;
-            --R_RCX; // don't update flags
-            if(R_RCX)
-                addr += tmp8s;
+            if(rex.is32bits && rex.is67) {
+                --R_CX; // don't update flags
+                if(R_CX)
+                    addr += tmp8s;
+            } else if(rex.is32bits || rex.is67) {
+                --R_ECX; // don't update flags
+                if(R_ECX)
+                    addr += tmp8s;
+            } else {
+                --R_RCX; // don't update flags
+                if(R_RCX)
+                    addr += tmp8s;
+            }
             STEP2
             break;
         case 0xE3:                      /* JRCXZ */
             tmp8s = F8S;
-            if(!R_RCX)
-                addr += tmp8s;
+            if(rex.is32bits && rex.is67) {
+                if(!R_CX)
+                    addr += tmp8s;
+            } else if(rex.is32bits || rex.is67) {
+                if(!R_ECX)
+                    addr += tmp8s;
+            } else {
+                if(!R_RCX)
+                    addr += tmp8s;
+            }
             STEP2
             break;
         case 0xE4:                      /* IN AL, XX */