about summary refs log tree commit diff stats
path: root/src/dynarec
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/dynarec
parent790022483b8079c4ad0e74cb7a292ba86f391984 (diff)
downloadbox64-e00d35f5bf90fec1f67c196d10bed40dc32211f3.tar.gz
box64-e00d35f5bf90fec1f67c196d10bed40dc32211f3.zip
Added 64 F7 opcode ([DYNAREC] too) (for #73)
Diffstat (limited to 'src/dynarec')
-rwxr-xr-xsrc/dynarec/arm64_emitter.h17
-rw-r--r--src/dynarec/dynarec_arm64_64.c144
-rwxr-xr-xsrc/dynarec/dynarec_arm64_helper.h12
3 files changed, 164 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); \