about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-07-27 13:28:46 +0200
committerptitSeb <sebastien.chev@gmail.com>2021-07-27 13:28:46 +0200
commite00d35f5bf90fec1f67c196d10bed40dc32211f3 (patch)
tree39bd37aa78d3f78fe8b440b24db916c935810c98 /src
parent790022483b8079c4ad0e74cb7a292ba86f391984 (diff)
downloadbox64-e00d35f5bf90fec1f67c196d10bed40dc32211f3.tar.gz
box64-e00d35f5bf90fec1f67c196d10bed40dc32211f3.zip
Added 64 F7 opcode ([DYNAREC] too) (for #73)
Diffstat (limited to 'src')
-rwxr-xr-xsrc/dynarec/arm64_emitter.h17
-rw-r--r--src/dynarec/dynarec_arm64_64.c144
-rwxr-xr-xsrc/dynarec/dynarec_arm64_helper.h12
-rw-r--r--src/emu/x64run64.c71
4 files changed, 235 insertions, 9 deletions
diff --git a/src/dynarec/arm64_emitter.h b/src/dynarec/arm64_emitter.h
index e6fe2fd6..13ad556b 100755
--- a/src/dynarec/arm64_emitter.h
+++ b/src/dynarec/arm64_emitter.h
@@ -230,13 +230,16 @@
 #define LDRB_REG(Rt, Rn, Rm)            EMIT(LDR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt))
 #define LDRH_REG(Rt, Rn, Rm)            EMIT(LDR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
 
-#define LDRSH_gen(size, op1, opc, imm12, Rn, Rt)    ((size)<<30 | 0b111<<27 | (op1)<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
-#define LDRSHx_U12(Rt, Rn, imm12)           EMIT(LDRSH_gen(0b01, 0b01, 0b10, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
-#define LDRSHw_U12(Rt, Rn, imm12)           EMIT(LDRSH_gen(0b01, 0b01, 0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
-#define LDRSHxw_U12(Rt, Rn, imm12)          EMIT(LDRSH_gen(0b01, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
-#define LDRSBx_U12(Rt, Rn, imm12)           EMIT(LDRSH_gen(0b00, 0b01, 0b10, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt))
-#define LDRSBw_U12(Rt, Rn, imm12)           EMIT(LDRSH_gen(0b00, 0b01, 0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt))
-#define LDRSBxw_U12(Rt, Rn, imm12)          EMIT(LDRSH_gen(0b00, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt))
+#define LDRS_U12_gen(size, op1, opc, imm12, Rn, Rt)    ((size)<<30 | 0b111<<27 | (op1)<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
+#define LDRSHx_U12(Rt, Rn, imm12)           EMIT(LDRS_U12_gen(0b01, 0b01, 0b10, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
+#define LDRSHw_U12(Rt, Rn, imm12)           EMIT(LDRS_U12_gen(0b01, 0b01, 0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
+#define LDRSHxw_U12(Rt, Rn, imm12)          EMIT(LDRS_U12_gen(0b01, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
+#define LDRSBx_U12(Rt, Rn, imm12)           EMIT(LDRS_U12_gen(0b00, 0b01, 0b10, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt))
+#define LDRSBw_U12(Rt, Rn, imm12)           EMIT(LDRS_U12_gen(0b00, 0b01, 0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt))
+#define LDRSBxw_U12(Rt, Rn, imm12)          EMIT(LDRS_U12_gen(0b00, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt))
+
+#define LDRS_REG_gen(size, Rm, option, S, Rn, Rt)    ((size)<<30 | 0b111<<27 | 0b10<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
+#define LDRSW_REG(Rt, Rn, Rm)           EMIT(LDRS_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
 
 #define LDR_PC_gen(opc, imm19, Rt)      ((opc)<<30 | 0b011<<27 | (imm19)<<5 | (Rt))
 #define LDRx_literal(Rt, imm19)         EMIT(LDR_PC_gen(0b01, ((imm19)>>2)&0x7FFFF, Rt))
diff --git a/src/dynarec/dynarec_arm64_64.c b/src/dynarec/dynarec_arm64_64.c
index 9ef1b272..18bb65de 100644
--- a/src/dynarec/dynarec_arm64_64.c
+++ b/src/dynarec/dynarec_arm64_64.c
@@ -32,7 +32,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
     uint8_t nextop;
     uint8_t u8;
     uint8_t gd, ed, eb1, eb2;
-    uint8_t wback, wb1, wb2;
+    uint8_t wback, wb1, wb2, wb;
     int64_t i64, j64;
     int v0;
     int q0;
@@ -625,6 +625,148 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             }
             break;
             
+        case 0xF7:
+            nextop = F8;
+            switch((nextop>>3)&7) {
+                case 0:
+                case 1:
+                    INST_NAME("TEST Ed, Id");
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, 4);
+                    i64 = F32S;
+                    MOV64xw(x2, i64);
+                    emit_test32(dyn, ninst, rex, ed, x2, x3, x4);
+                    break;
+                case 2:
+                    INST_NAME("NOT Ed");
+                    GETEDO(x6, 4);
+                    MVNxw_REG(ed, ed);
+                    WBACKO(x6);
+                    break;
+                case 3:
+                    INST_NAME("NEG Ed");
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, 0);
+                    emit_neg32(dyn, ninst, rex, ed, x3, x4);
+                    WBACKO(x6);
+                    break;
+                case 4:
+                    INST_NAME("MUL EAX, Ed");
+                    SETFLAGS(X_ALL, SF_PENDING);
+                    UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
+                    GETEDO(x6, 0);
+                    if(rex.w) {
+                        if(ed==xRDX) gd=x3; else gd=xRDX;
+                        UMULH(gd, xRAX, ed);
+                        MULx(xRAX, xRAX, ed);
+                        if(gd!=xRDX) {MOVx_REG(xRDX, gd);}
+                    } else {
+                        UMULL(xRDX, xRAX, ed);  //64 <- 32x32
+                        MOVw_REG(xRAX, xRDX);
+                        LSRx(xRDX, xRDX, 32);
+                    }
+                    UFLAG_RES(xRAX);
+                    UFLAG_OP1(xRDX);
+                    break;
+                case 5:
+                    INST_NAME("IMUL EAX, Ed");
+                    SETFLAGS(X_ALL, SF_PENDING);
+                    UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
+                    GETEDO(x6, 0);
+                    if(rex.w) {
+                        if(ed==xRDX) gd=x3; else gd=xRDX;
+                        SMULH(gd, xRAX, ed);
+                        MULx(xRAX, xRAX, ed);
+                        if(gd!=xRDX) {MOVx_REG(xRDX, gd);}
+                    } else {
+                        SMULL(xRDX, xRAX, ed);  //64 <- 32x32
+                        MOVw_REG(xRAX, xRDX);
+                        LSRx(xRDX, xRDX, 32);
+                    }
+                    UFLAG_RES(xRAX);
+                    UFLAG_OP1(xRDX);
+                    break;
+                case 6:
+                    INST_NAME("DIV Ed");
+                    SETFLAGS(X_ALL, SF_SET);
+                    if(!rex.w) {
+                        SET_DFNONE(x2);
+                        GETEDO(x6, 0);
+                        MOVw_REG(x3, xRAX);
+                        ORRx_REG_LSL(x3, x3, xRDX, 32);
+                        if(MODREG) {
+                            MOVw_REG(x4, ed);
+                            ed = x4;
+                        }
+                        UDIVx(x2, x3, ed);
+                        MSUBx(x4, x2, ed, xRAX);
+                        MOVw_REG(xRAX, x2);
+                        MOVw_REG(xRDX, x4);
+                    } else {
+                        if(ninst && dyn->insts 
+                           && dyn->insts[ninst-1].x64.addr 
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31 
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
+                            SET_DFNONE(x2);
+                            GETEDO(x6, 0);
+                            UDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVx_REG(xRAX, x2);
+                        } else {
+                            GETEDO(x6, 0);
+                            CBZxw_MARK(xRDX);
+                            if(ed!=x1) {MOVx_REG(x1, ed);}
+                            CALL(div64, -1);
+                            B_NEXT_nocond;
+                            MARK;
+                            UDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVx_REG(xRAX, x2);
+                            SET_DFNONE(x2);
+                        }
+                    }
+                    break;
+                case 7:
+                    INST_NAME("IDIV Ed");
+                    SETFLAGS(X_ALL, SF_SET);
+                    if(!rex.w) {
+                        SET_DFNONE(x2)
+                        GETSEDOw(x6, 0);
+                        MOVw_REG(x3, xRAX);
+                        ORRx_REG_LSL(x3, x3, xRDX, 32);
+                        SDIVx(x2, x3, wb);
+                        MSUBx(x4, x2, wb, x3);
+                        MOVw_REG(xRAX, x2);
+                        MOVw_REG(xRDX, x4);
+                    } else {
+                        if(ninst && dyn->insts
+                           &&  dyn->insts[ninst-1].x64.addr 
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) {
+                            SET_DFNONE(x2)
+                            GETEDO(x6, 0);
+                            SDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVx_REG(xRAX, x2);
+                        } else {
+                            GETEDO(x6, 0);
+                            CBZxw_MARK(xRDX);
+                            MVNx_REG(x2, xRDX);
+                            CBZxw_MARK(x2);
+                            if(ed!=x1) {MOVx_REG(x1, ed);}
+                            CALL((void*)idiv64, -1);
+                            B_NEXT_nocond;
+                            MARK;
+                            SDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVx_REG(xRAX, x2);
+                            SET_DFNONE(x2)
+                        }
+                    }
+                    break;
+            }
+            break;
+            
         case 0xFF:
             nextop = F8;
             grab_segdata(dyn, addr, ninst, x6, seg);
diff --git a/src/dynarec/dynarec_arm64_helper.h b/src/dynarec/dynarec_arm64_helper.h
index e2905874..27c1e9a7 100755
--- a/src/dynarec/dynarec_arm64_helper.h
+++ b/src/dynarec/dynarec_arm64_helper.h
@@ -66,7 +66,7 @@
                     wback = 0;                          \
                 } else {                                \
                     addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
-                    LDRw_U12(x1, wback, fixedaddress);  \
+                    LDRSW_U12(x1, wback, fixedaddress); \
                     wb = ed = x1;                       \
                 }
 //GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI
@@ -115,6 +115,16 @@
                     LDRx_REG(x1, wback, O);             \
                     ed = x1;                            \
                 }
+#define GETSEDOw(O, D)  if((nextop&0xC0)==0xC0) {       \
+                    ed = xRAX+(nextop&7)+(rex.b<<3);    \
+                    SXTWx(x1, ed);                      \
+                    wb = x1;                            \
+                    wback = 0;                          \
+                } else {                                \
+                    addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, D); \
+                    LDRSW_REG(x1, wback, O);            \
+                    wb = ed = x1;                       \
+                }
 //FAKEELike GETED, but doesn't get anything
 #define FAKEED  if(!MODREG) {   \
                     addr = fakeed(dyn, addr, ninst, nextop); \
diff --git a/src/emu/x64run64.c b/src/emu/x64run64.c
index e6039c2b..c7cbbc4b 100644
--- a/src/emu/x64run64.c
+++ b/src/emu/x64run64.c
@@ -413,6 +413,77 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
             }

             break;

 

+        case 0xF7:                      /* GRP3 Ed(,Id) */

+            nextop = F8;

+            tmp8u = (nextop>>3)&7;

+            GETED_OFFS((tmp8u<2)?4:0, tlsdata);

+            if(rex.w) {

+                switch(tmp8u) {

+                    case 0: 

+                    case 1:                 /* TEST Ed,Id */

+                        tmp64u = F32S64;

+                        test64(emu, ED->q[0], tmp64u);

+                        break;

+                    case 2:                 /* NOT Ed */

+                        ED->q[0] = not64(emu, ED->q[0]);

+                        break;

+                    case 3:                 /* NEG Ed */

+                        ED->q[0] = neg64(emu, ED->q[0]);

+                        break;

+                    case 4:                 /* MUL RAX,Ed */

+                        mul64_rax(emu, ED->q[0]);

+                        break;

+                    case 5:                 /* IMUL RAX,Ed */

+                        imul64_rax(emu, ED->q[0]);

+                        break;

+                    case 6:                 /* DIV Ed */

+                        div64(emu, ED->q[0]);

+                        break;

+                    case 7:                 /* IDIV Ed */

+                        idiv64(emu, ED->q[0]);

+                        break;

+                }

+            } else {

+                switch(tmp8u) {

+                    case 0: 

+                    case 1:                 /* TEST Ed,Id */

+                        tmp32u = F32;

+                        test32(emu, ED->dword[0], tmp32u);

+                        break;

+                    case 2:                 /* NOT Ed */

+                        if(MODREG)

+                            ED->q[0] = not32(emu, ED->dword[0]);

+                        else

+                            ED->dword[0] = not32(emu, ED->dword[0]);

+                        break;

+                    case 3:                 /* NEG Ed */

+                        if(MODREG)

+                            ED->q[0] = neg32(emu, ED->dword[0]);

+                        else

+                            ED->dword[0] = neg32(emu, ED->dword[0]);

+                        break;

+                    case 4:                 /* MUL EAX,Ed */

+                        mul32_eax(emu, ED->dword[0]);

+                        emu->regs[_AX].dword[1] = 0;

+                        break;

+                    case 5:                 /* IMUL EAX,Ed */

+                        imul32_eax(emu, ED->dword[0]);

+                        emu->regs[_AX].dword[1] = 0;

+                        break;

+                    case 6:                 /* DIV Ed */

+                        div32(emu, ED->dword[0]);

+                        //emu->regs[_AX].dword[1] = 0;  // already put high regs to 0

+                        //emu->regs[_DX].dword[1] = 0;

+                        break;

+                    case 7:                 /* IDIV Ed */

+                        idiv32(emu, ED->dword[0]);

+                        //emu->regs[_AX].dword[1] = 0;

+                        //emu->regs[_DX].dword[1] = 0;

+                        break;

+                }

+            }

+            break;

+            

         case 0xFF:                      /* GRP 5 Ed */

             nextop = F8;

             GETED_OFFS(0, tlsdata);