about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c62
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_shift.c79
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h2
-rw-r--r--src/dynarec/la64/la64_emitter.h7
4 files changed, 140 insertions, 10 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 8ad4a9d4..c0583e16 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -649,21 +649,63 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0xC1:
             nextop = F8;
             switch ((nextop >> 3) & 7) {
+                case 4:
+                case 6:
+                    INST_NAME("SHL Ed, Ib");
+                    u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
+                    if(u8) {
+                        SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
+                        GETED(1);
+                        u8 = (F8) & (rex.w ? 0x3f : 0x1f);
+                        emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4, x5);
+                        WBACK;
+                    } else {
+                        if(MODREG && ! rex.w && !rex.is32bits) {
+                            GETED(1);
+                            AND(ed, ed, xMASK);
+                        } else {
+                            FAKEED;
+                        }
+                        F8;
+                    }
+                    break;
                 case 5:
                     INST_NAME("SHR Ed, Ib");
-                    SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
-                    GETED(1);
-                    u8 = (F8) & (rex.w ? 0x3f : 0x1f);
-                    emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4);
-                    if (u8) { WBACK; }
+                    u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
+                        if(u8) {
+                        SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
+                        GETED(1);
+                        u8 = (F8) & (rex.w ? 0x3f : 0x1f);
+                        emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4);
+                        WBACK;
+                    } else {
+                        if(MODREG && ! rex.w && !rex.is32bits) {
+                            GETED(1);
+                            AND(ed, ed, xMASK);
+                        } else {
+                            FAKEED;
+                        }
+                        F8;
+                    }
                     break;
                 case 7:
                     INST_NAME("SAR Ed, Ib");
-                    SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
-                    GETED(1);
-                    u8 = (F8) & (rex.w ? 0x3f : 0x1f);
-                    emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4);
-                    if (u8) { WBACK; }
+                    u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
+                    if(u8) {
+                        SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
+                        GETED(1);
+                        u8 = (F8) & (rex.w ? 0x3f : 0x1f);
+                        emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4);
+                        WBACK; 
+                    } else {
+                        if(MODREG && ! rex.w && !rex.is32bits) {
+                            GETED(1);
+                            AND(ed, ed, xMASK);
+                        } else {
+                            FAKEED;
+                        }
+                        F8;
+                    }
                     break;
                 default:
                     DEFAULT;
diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c
index b2534c60..b4d7ccdd 100644
--- a/src/dynarec/la64/dynarec_la64_emit_shift.c
+++ b/src/dynarec/la64/dynarec_la64_emit_shift.c
@@ -88,6 +88,85 @@ void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
     }
 }
 
+// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
+void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5)
+{
+    IFX(X_PEND) {
+        if (c) {
+            MOV64x(s3, c);
+            SDxw(s3, xEmu, offsetof(x64emu_t, op2));
+        } else 
+            SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
+        SDxw(s1, xEmu, offsetof(x64emu_t, op1));
+        SET_DF(s4, rex.w?d_shl64:d_shl32);
+    } else IFX(X_ALL) {
+        SET_DFNONE();
+    }
+    if(!c) {
+        IFX(X_PEND) {
+            SDxw(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    if(la64_lbt) {
+        IFX(X_PEND) {} else { MOV64x(s3, c); }
+        IFX(X_ALL) {
+            if (rex.w)
+                X64_SLL_D(s1, s3);
+            else
+                X64_SLL_W(s1, s3);
+        }
+
+        SLLIxw(s1, s1, c);
+
+        IFX(X_PEND) {
+            SDxw(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    CLEAR_FLAGS(s3);
+    IFX(X_CF|X_OF) {
+        if (c > 0) {
+            SRLI_D(s3, s1, (rex.w?64:32)-c);
+            ANDI(s5, s3, 1); // LSB == F_CF
+            IFX(X_CF) {
+                OR(xFlags, xFlags, s5);
+            }
+        }
+    }
+
+    SLLIxw(s1, s1, c);
+
+    IFX(X_SF) {
+        BGE(s1, xZR, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    if (!rex.w) {
+        ZEROUP(s1);
+    }
+    IFX(X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX(X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX(X_OF) {
+        // OF flag is affected only on 1-bit shifts
+        if (c == 1) {
+            SRLIxw(s3, s1, rex.w?63:31);
+            XOR(s3, s3, s5);
+            SLLI_D(s3, s3, F_OF);
+            OR(xFlags, xFlags, s3);
+        }
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
 // emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
 void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
 {
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index fd07111b..a2503932 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -495,6 +495,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_and32          STEPNAME(emit_and32)
 #define emit_and32c         STEPNAME(emit_and32c)
 #define emit_shl32          STEPNAME(emit_shl32)
+#define emit_shl32c         STEPNAME(emit_shl32c)
 #define emit_shr32c         STEPNAME(emit_shr32c)
 #define emit_sar32c         STEPNAME(emit_sar32c)
 
@@ -549,6 +550,7 @@ void emit_and8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s
 void emit_and32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
 void emit_and32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
 void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
+void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5);
 void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 
diff --git a/src/dynarec/la64/la64_emitter.h b/src/dynarec/la64/la64_emitter.h
index b8c72ee7..51fbbf68 100644
--- a/src/dynarec/la64/la64_emitter.h
+++ b/src/dynarec/la64/la64_emitter.h
@@ -269,6 +269,13 @@ f24-f31  fs0-fs7   Static registers                Callee
 // GR[rd] = ROTR(GR[rj][31:0], imm5) (Rotate To Right)
 #define ROTRI_W(rd, rj, imm5) EMIT(type_2RI5(0b00000000010011001, imm5, rj, rd))
 
+// Shift Left Immediate
+#define SLLIxw(rd, rs1, imm)  \
+    if (rex.w) {              \
+        SLLI_D(rd, rs1, imm); \
+    } else {                  \
+        SLLI_W(rd, rs1, imm); \
+    }
 // Shift Right Logical Immediate
 #define SRLIxw(rd, rs1, imm)  \
     if (rex.w) {              \