about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/dynarec/arm64/arm64_emitter.h2
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_00.c77
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_private.h2
3 files changed, 70 insertions, 11 deletions
diff --git a/src/dynarec/arm64/arm64_emitter.h b/src/dynarec/arm64/arm64_emitter.h
index 5a440520..ab397a2b 100755
--- a/src/dynarec/arm64/arm64_emitter.h
+++ b/src/dynarec/arm64/arm64_emitter.h
@@ -309,6 +309,8 @@
 // PUSH / POP helper
 #define POP1(reg)       LDRx_S9_postindex(reg, xRSP, 8)
 #define PUSH1(reg)      STRx_S9_preindex(reg, xRSP, -8)
+#define POP2(reg1, reg2)       LDPx_S7_postindex(reg1, reg2, xRSP, 16)
+#define PUSH2(reg1, reg2)      STPx_S7_preindex(reg2, reg1, xRSP, -16)
 
 // LOAD/STORE Acquire Exclusive
 #define MEMAX_gen(size, L, Rs, Rn, Rt)      ((size)<<30 | 0b001000<<24 | (L)<<22 | (Rs)<<16 | 1<<15 | 0b11111<<10 | (Rn)<<5 | (Rt))
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index b71f0bb8..3035514f 100755
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -498,12 +498,36 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
         case 0x56:
         case 0x57:
             INST_NAME("PUSH reg");
-            gd = xRAX+(opcode&0x07)+(rex.b<<3);
-            if(gd==xRSP) {
-                MOVx_REG(x1, gd);
-                gd = x1;
+            if(dyn->doublepush)
+                dyn->doublepush = 0;
+            else {
+                gd = xRAX+(opcode&0x07)+(rex.b<<3);
+                if(gd==xRSP) {
+                    MOVx_REG(x1, gd);
+                    gd = x1;
+                }
+                u32 = PK(0);
+                i32 = 1;
+                rex.rex = 0;
+                while(u32>=0x40 && u32<=0x4f) {
+                    rex.rex = u32;
+                    u32 = PK(i32);
+                    i32++;
+                }
+                if(u32>=0x50 && u32<=0x57 && (dyn->size && dyn->insts[ninst+1].pred_sz==1)) {
+                    // double push!
+                    u32= xRAX+(u32&0x07)+(rex.b<<3);
+                    MESSAGE(LOG_DUMP, "DOUBLE PUSH\n");
+                    if(u32==xRSP) {
+                        MOVx_REG(x1, u32);
+                        u32 = x1;
+                    }
+                    PUSH2(gd, u32);
+                    dyn->doublepush = 1;
+                } else {
+                    PUSH1(gd);
+                }   
             }
-            PUSH1(gd);
             break;
         case 0x58:
         case 0x59:
@@ -514,12 +538,43 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
         case 0x5E:
         case 0x5F:
             INST_NAME("POP reg");
-            gd = xRAX+(opcode&0x07)+(rex.b<<3);
-            if(gd == xRSP) {
-                POP1(x1);
-                MOVx_REG(gd, x1);
-            } else {
-                POP1(gd);
+            if(dyn->doublepop)
+                dyn->doublepop = 0;
+            else {
+                gd = xRAX+(opcode&0x07)+(rex.b<<3);
+                u32 = PK(0);
+                i32 = 1;
+                rex.rex = 0;
+                while(u32>=0x40 && u32<=0x4f) {
+                    rex.rex = u32;
+                    u32 = PK(i32);
+                    i32++;
+                }
+                if(u32>=0x58 && u32<=0x5f && (dyn->size && dyn->insts[ninst+1].pred_sz==1)) {
+                    // double pop!
+                    u32= xRAX+(u32&0x07)+(rex.b<<3);
+                    MESSAGE(LOG_DUMP, "DOUBLE POP\n");
+                    if(gd==u32) {
+                        ADDx_U12(xRSP, xRSP, 0x8);
+                        POP1((gd==xRSP)?x1:gd);
+                    } else {
+                        POP2((gd==xRSP)?x1:gd, (u32==xRSP)?x1:u32);
+                        if(u32==xRSP) {
+                            MOVx_REG(u32, x1);
+                        }
+                    }
+                    if(gd == xRSP) {
+                        MOVx_REG(gd, x1);
+                    }
+                    dyn->doublepop = 1;
+                } else {
+                    if(gd == xRSP) {
+                        POP1(x1);
+                        MOVx_REG(gd, x1);
+                    } else {
+                        POP1(gd);
+                    }
+                }
             }
             break;
 
diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h
index d0ca7c9c..dcf78084 100755
--- a/src/dynarec/arm64/dynarec_arm64_private.h
+++ b/src/dynarec/arm64/dynarec_arm64_private.h
@@ -110,6 +110,8 @@ typedef struct dynarec_arm_s {
     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
     int                 forward_ninst;  // ninst at the forward point
+    uint8_t             doublepush;
+    uint8_t             doublepop;
 } dynarec_arm_t;
 
 void add_next(dynarec_arm_t *dyn, uintptr_t addr);