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.c101
-rw-r--r--src/dynarec/la64/dynarec_la64_0f.c82
-rw-r--r--src/dynarec/la64/dynarec_la64_66.c72
-rw-r--r--src/dynarec/la64/dynarec_la64_660f.c62
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_shift.c175
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h47
-rw-r--r--src/dynarec/la64/la64_emitter.h27
-rw-r--r--src/dynarec/la64/la64_printer.c20
8 files changed, 571 insertions, 15 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 9616a1e1..351ec85c 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -105,6 +105,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             break;
         case 0x0F:
             switch (rep) {
+                case 0:
+                    addr = dynarec64_0F(dyn, addr, ip, ninst, rex, ok, need_epilog);
+                    break;
                 case 2:
                     addr = dynarec64_F30F(dyn, addr, ip, ninst, rex, ok, need_epilog);
                     break;
@@ -186,6 +189,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             gd = TO_LA64((opcode & 0x07) + (rex.b << 3));
             POP1z(gd);
             break;
+            break;
+        case 0x66:
+            addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
+            break;
         case 0x81:
         case 0x83:
             nextop = F8;
@@ -312,6 +319,47 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 }
             }
             break;
+        case 0xB8:
+        case 0xB9:
+        case 0xBA:
+        case 0xBB:
+        case 0xBC:
+        case 0xBD:
+        case 0xBE:
+        case 0xBF:
+            INST_NAME("MOV Reg, Id");
+            gd = TO_LA64((opcode & 7) + (rex.b << 3));
+            if (rex.w) {
+                u64 = F64;
+                MOV64x(gd, u64);
+            } else {
+                u32 = F32;
+                MOV32w(gd, u32);
+            }
+            break;
+        case 0xC1:
+            nextop = F8;
+            switch ((nextop >> 3) & 7) {
+                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; }
+                    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; }
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
         case 0xC3:
             INST_NAME("RET");
             // SETFLAGS(X_ALL, SF_SET);    // Hack, set all flags (to an unknown state...)
@@ -323,6 +371,25 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             *need_epilog = 0;
             *ok = 0;
             break;
+        case 0xC7:
+            INST_NAME("MOV Ed, Id");
+            nextop = F8;
+            if (MODREG) { // reg <= i32
+                i64 = F32S;
+                ed = TO_LA64((nextop & 7) + (rex.b << 3));
+                MOV64xw(ed, i64);
+            } else { // mem <= i32
+                addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, &lock, 0, 4);
+                i64 = F32S;
+                if (i64) {
+                    MOV64xw(x3, i64);
+                    ed = x3;
+                } else
+                    ed = xZR;
+                SDxw(ed, wback, fixedaddress);
+                SMWRITELOCK(lock);
+            }
+            break;
         case 0xCC:
             SETFLAGS(X_ALL, SF_SET);
             SKIPTEST(x1);
@@ -345,7 +412,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     // FIXME: Even the basic support of isSimpleWrapper is disabled for now.
 
                     GETIP(ip + 1); // read the 0xCC
-                    STORE_XEMU_CALL(x3);
+                    STORE_XEMU_CALL();
                     ADDI_D(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
                     CALL_S(x64Int3, -1);
                     LOAD_XEMU_CALL();
@@ -367,12 +434,33 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     LD_D(x3, x2, 0);
                     CBZ_NEXT(x3);
                     GETIP(ip);
-                    STORE_XEMU_CALL(x3);
+                    STORE_XEMU_CALL();
                     CALL(native_int3, -1);
                     LOAD_XEMU_CALL();
                 }
             }
             break;
+        case 0xD1:
+            nextop = F8;
+            switch ((nextop >> 3) & 7) {
+                case 5:
+                    INST_NAME("SHR Ed, 1");
+                    SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
+                    GETED(0);
+                    emit_shr32c(dyn, ninst, rex, ed, 1, x3, x4);
+                    WBACK;
+                    break;
+                case 7:
+                    INST_NAME("SAR Ed, 1");
+                    SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
+                    GETED(0);
+                    emit_sar32c(dyn, ninst, rex, ed, 1, x3, x4);
+                    WBACK;
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
         case 0xE9:
         case 0xEB:
             BARRIER(BARRIER_MAYBE);
@@ -446,6 +534,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     PUSH1z(xRIP);
                     jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
                     break;
+                case 4: // JMP Ed
+                    INST_NAME("JMP Ed");
+                    READFLAGS(X_PEND);
+                    BARRIER(BARRIER_FLOAT);
+                    GETEDz(0);
+                    jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
+                    *need_epilog = 0;
+                    *ok = 0;
+                    break;
                 default:
                     DEFAULT;
             }
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c
new file mode 100644
index 00000000..4c1a2aba
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_0f.c
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "emu/x64emu_private.h"
+#include "emu/x64run_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+#include "my_cpuid.h"
+#include "emu/x87emu_private.h"
+#include "emu/x64shaext.h"
+#include "bitutils.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_functions.h"
+#include "dynarec_la64_helper.h"
+
+uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
+{
+    (void)ip;
+    (void)need_epilog;
+
+    uint8_t opcode = F8;
+    uint8_t nextop, u8;
+    uint8_t gd, ed;
+    uint8_t wb1, wback, wb2, gback;
+    uint8_t eb1, eb2;
+    uint8_t gb1, gb2;
+    int32_t i32, i32_;
+    int cacheupd = 0;
+    int v0, v1;
+    int q0, q1;
+    int d0, d1;
+    int s0, s1;
+    uint64_t tmp64u;
+    int64_t j64;
+    int64_t fixedaddress, gdoffset;
+    int unscaled;
+    MAYUSE(wb2);
+    MAYUSE(gback);
+    MAYUSE(eb1);
+    MAYUSE(eb2);
+    MAYUSE(q0);
+    MAYUSE(q1);
+    MAYUSE(d0);
+    MAYUSE(d1);
+    MAYUSE(s0);
+    MAYUSE(j64);
+    MAYUSE(cacheupd);
+
+    switch (opcode) {
+        case 0x05:
+            INST_NAME("SYSCALL");
+            NOTEST(x1);
+            SMEND();
+            GETIP(addr);
+            STORE_XEMU_CALL();
+            CALL_S(x64Syscall, -1);
+            LOAD_XEMU_CALL();
+            TABLE64(x3, addr); // expected return address
+            BNE_MARK(xRIP, x3);
+            LD_W(w1, xEmu, offsetof(x64emu_t, quit));
+            CBZ_NEXT(w1);
+            MARK;
+            LOAD_XEMU_REM();
+            jump_to_epilog(dyn, 0, xRIP, ninst);
+            break;
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c
new file mode 100644
index 00000000..7626102c
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_66.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "emu/x64emu_private.h"
+#include "emu/x64run_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+#include "custommem.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_helper.h"
+#include "dynarec_la64_functions.h"
+
+
+uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
+{
+    uint8_t opcode = F8;
+    uint8_t nextop, u8;
+    int16_t i16;
+    uint16_t u16;
+    uint64_t u64;
+    int32_t i32;
+    int64_t j64;
+    uint8_t gd, ed;
+    uint8_t wback, wb1;
+    int64_t fixedaddress;
+    int unscaled;
+    int lock;
+    MAYUSE(u8);
+    MAYUSE(u16);
+    MAYUSE(u64);
+    MAYUSE(j64);
+    MAYUSE(lock);
+
+    while ((opcode == 0x2E) || (opcode == 0x36) || (opcode == 0x66)) // ignoring CS:, SS: or multiple 0x66
+        opcode = F8;
+
+    while ((opcode == 0xF2) || (opcode == 0xF3)) {
+        rep = opcode - 0xF1;
+        opcode = F8;
+    }
+
+    GETREX();
+
+    if (rex.w && !(opcode == 0x0f || opcode == 0xf0 || opcode == 0x64 || opcode == 0x65)) // rex.w cancels "66", but not for 66 0f type of prefix
+        return dynarec64_00(dyn, addr - 1, ip, ninst, rex, rep, ok, need_epilog);         // addr-1, to "put back" opcode
+
+    switch (opcode) {
+
+        case 0x0F:
+            switch (rep) {
+                case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
+                default:
+                    DEFAULT;
+            }
+            break;
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/la64/dynarec_la64_660f.c b/src/dynarec/la64/dynarec_la64_660f.c
new file mode 100644
index 00000000..5f7192ca
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_660f.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "emu/x64emu_private.h"
+#include "emu/x64run_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+#include "bitutils.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_functions.h"
+#include "dynarec_la64_helper.h"
+
+uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
+{
+    (void)ip;
+    (void)need_epilog;
+
+    uint8_t opcode = F8;
+    uint8_t nextop, u8, s8;
+    int32_t i32;
+    uint8_t gd, ed;
+    uint8_t wback, wb1, wb2, gback;
+    uint8_t eb1, eb2;
+    int64_t j64;
+    uint64_t tmp64u, tmp64u2;
+    int v0, v1;
+    int q0, q1;
+    int d0, d1, d2;
+    int64_t fixedaddress, gdoffset;
+    int unscaled;
+
+    MAYUSE(d0);
+    MAYUSE(d1);
+    MAYUSE(q0);
+    MAYUSE(q1);
+    MAYUSE(eb1);
+    MAYUSE(eb2);
+    MAYUSE(j64);
+
+    switch (opcode) {
+        case 0x1F:
+            INST_NAME("NOP (multibyte)");
+            nextop = F8;
+            FAKEED;
+            break;
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c
new file mode 100644
index 00000000..24d7f102
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_emit_shift.c
@@ -0,0 +1,175 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "emu/x64emu_private.h"
+#include "emu/x64run_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_functions.h"
+#include "dynarec_la64_helper.h"
+
+// 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)
+{
+    CLEAR_FLAGS(s3);
+
+    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_shr64 : d_shr32);
+    } 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_SRL_D(s1, s3); else X64_SRL_W(s1, s3);
+            X64_GET_EFLAGS(s3, X_ALL);
+            OR(xFlags, xFlags, s3);
+        }
+
+        SRLIxw(s1, s1, c);
+
+        IFX(X_PEND) {
+            SDxw(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    IFX(X_CF) {
+        if (c > 1) {
+            SRAI_D(s3, s1, c - 1);
+            ANDI(s3, s3, 1); // LSB == F_CF
+        } else {
+            // no need to shift
+            ANDI(s3, s1, 1); // LSB == F_CF
+        }
+        OR(xFlags, xFlags, s3);
+    }
+    IFX(X_OF) {
+        // OF flag is affected only on 1-bit shifts
+        // OF flag is set to the most-significant bit of the original operand
+        if (c == 1) {
+            SRLIxw(s3, s1, rex.w ? 63 : 31);
+            SLLI_D(s3, s3, F_OF);
+            OR(xFlags, xFlags, s3);
+        }
+    }
+
+    SRLIxw(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_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
+
+// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
+void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
+{
+    CLEAR_FLAGS(s3);
+
+    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_sar64 : d_sar32);
+    } 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_SRA_D(s1, s3); else X64_SRA_W(s1, s3);
+            X64_GET_EFLAGS(s3, X_ALL);
+            OR(xFlags, xFlags, s3);
+        }
+
+        SRAIxw(s1, s1, c);
+
+        IFX(X_PEND) {
+            SDxw(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    IFX(X_CF) {
+        if (c > 1) {
+            SRAI_D(s3, s1, c - 1);
+            ANDI(s3, s3, 1); // LSB == F_CF
+        } else {
+            // no need to shift
+            ANDI(s3, s1, 1); // LSB == F_CF
+        }
+        OR(xFlags, xFlags, s3);
+    }
+
+    SRAIxw(s1, s1, c);
+
+    // SRAIW sign-extends, so test sign bit before clearing upper bits
+    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_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
\ No newline at end of file
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index e1088ec9..67d562b2 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -255,20 +255,27 @@
 #define LOAD_REG(A)  LD_D(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
 
 // Need to also store current value of some register, as they may be used by functions like setjmp
-#define STORE_XEMU_CALL(s0) \
-    STORE_REG(RBX);         \
-    STORE_REG(RDX);         \
-    STORE_REG(RSP);         \
-    STORE_REG(RBP);         \
-    STORE_REG(RDI);         \
-    STORE_REG(RSI);         \
-    STORE_REG(R8);          \
-    STORE_REG(R9);          \
-    STORE_REG(R10);         \
-    STORE_REG(R11);
+#define STORE_XEMU_CALL() \
+    STORE_REG(R8);        \
+    STORE_REG(R9);        \
+    STORE_REG(R10);       \
+    STORE_REG(R11);       \
+    STORE_REG(R12);       \
+    STORE_REG(R13);       \
+    STORE_REG(R14);       \
+    STORE_REG(R15);
 
 #define LOAD_XEMU_CALL()
 
+#define LOAD_XEMU_REM() \
+    LOAD_REG(R8);       \
+    LOAD_REG(R9);       \
+    LOAD_REG(R10);      \
+    LOAD_REG(R11);      \
+    LOAD_REG(R12);      \
+    LOAD_REG(R13);      \
+    LOAD_REG(R14);      \
+    LOAD_REG(R15);
 
 #define SET_DFNONE()                             \
     if (!dyn->f.dfnone) {                        \
@@ -440,7 +447,10 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define native_pass STEPNAME(native_pass)
 
 #define dynarec64_00   STEPNAME(dynarec64_00)
+#define dynarec64_0F   STEPNAME(dynarec64_0F)
+#define dynarec64_66   STEPNAME(dynarec64_66)
 #define dynarec64_F30F STEPNAME(dynarec64_F30F)
+#define dynarec64_660F STEPNAME(dynarec64_660F)
 
 #define geted               STEPNAME(geted)
 #define geted32             STEPNAME(geted32)
@@ -458,6 +468,8 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_sub32c         STEPNAME(emit_sub32c)
 #define emit_sub8           STEPNAME(emit_sub8)
 #define emit_sub8c          STEPNAME(emit_sub8c)
+#define emit_shr32c         STEPNAME(emit_shr32c)
+#define emit_sar32c         STEPNAME(emit_sar32c)
 
 #define emit_pf STEPNAME(emit_pf)
 
@@ -496,6 +508,8 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5);
 void emit_sub8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_sub8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s2, 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);
 
 void emit_pf(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);
 
@@ -527,7 +541,10 @@ void CacheTransform(dynarec_la64_t* dyn, int ninst, int cacheupd, int s1, int s2
 #endif
 
 uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
+uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
 uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
+uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
+uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
 
 #if STEP < 3
 #define PASS3(A)
@@ -638,4 +655,12 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
         ST_W(s2, xEmu, offsetof(x64emu_t, test.test)); \
     }
 
+#define GETREX()                                   \
+    rex.rex = 0;                                   \
+    if (!rex.is32bits)                             \
+        while (opcode >= 0x40 && opcode <= 0x4f) { \
+            rex.rex = opcode;                      \
+            opcode = F8;                           \
+        }
+
 #endif //__DYNAREC_LA64_HELPER_H__
\ No newline at end of file
diff --git a/src/dynarec/la64/la64_emitter.h b/src/dynarec/la64/la64_emitter.h
index f8d8a20e..e3235633 100644
--- a/src/dynarec/la64/la64_emitter.h
+++ b/src/dynarec/la64/la64_emitter.h
@@ -112,8 +112,6 @@ f24-f31  fs0-fs7   Static registers                Callee
 #define type_3R(opc, rk, rj, rd)         ((opc) << 15 | (rk) << 10 | (rj) << 5 | (rd))
 #define type_3RI2(opc, imm2, rk, rj, rd) ((opc) << 17 | ((imm2) & 0x3) << 15 | (rk) << 10 | (rj) << 5 | (rd))
 #define type_2R(opc, rj, rd)             ((opc) << 10 | (rj) << 5 | (rd))
-#define type_2RI5(opc, imm5, rj, rd)     ((opc) << 15 | ((imm5) & 0x1F) << 10 | (rj) << 5 | (rd))
-#define type_2RI6(opc, imm6, rj, rd)     ((opc) << 16 | ((imm6) & 0x3F) << 10 | (rj) << 5 | (rd))
 #define type_2RI8(opc, imm8, rj, rd)     ((opc) << 18 | ((imm8) & 0xFF) << 10 | (rj) << 5 | (rd))
 #define type_2RI12(opc, imm12, rj, rd)   ((opc) << 22 | ((imm12) & 0xFFF) << 10 | (rj) << 5 | (rd))
 #define type_2RI14(opc, imm14, rj, rd)   ((opc) << 24 | ((imm14) & 0x3FFF) << 10 | (rj) << 5 | (rd))
@@ -223,6 +221,31 @@ f24-f31  fs0-fs7   Static registers                Callee
 // GR[rd] = ROTR(GR[rj][63:0], imm6) (Rotate To Right)
 #define ROTRI_D(rd, rj, imm6) EMIT(type_2RI6(0b0000000001001101, imm6, rj, rd))
 
+// GR[rd] = SLL(GR[rj][31:0], imm5) (Shift Left Logical)
+#define SLLI_W(rd, rj, imm5) EMIT(type_2RI5(0b00000000010000001, imm5, rj, rd))
+// GR[rd] = SRL(GR[rj][31:0], imm5) (Shift Right Logical)
+#define SRLI_W(rd, rj, imm5) EMIT(type_2RI5(0b00000000010001001, imm5, rj, rd))
+// GR[rd] = SRA(GR[rj][31:0], imm5) (Shift Right Arithmetic)
+#define SRAI_W(rd, rj, imm5) EMIT(type_2RI5(0b00000000010010001, imm5, rj, rd))
+// 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 Right Logical Immediate
+#define SRLIxw(rd, rs1, imm)  \
+    if (rex.w) {              \
+        SRLI_D(rd, rs1, imm); \
+    } else {                  \
+        SRLI_W(rd, rs1, imm); \
+    }
+
+// Shift Right Arithmetic Immediate
+#define SRAIxw(rd, rs1, imm)  \
+    if (rex.w) {              \
+        SRAI_D(rd, rs1, imm); \
+    } else {                  \
+        SRAI_W(rd, rs1, imm); \
+    }
+
 // rd = rj + (rk << imm6)
 #define ADDSL(rd, rs1, rs2, imm6, scratch) \
     if (!(imm6)) {                         \
diff --git a/src/dynarec/la64/la64_printer.c b/src/dynarec/la64/la64_printer.c
index 62718191..72ada67d 100644
--- a/src/dynarec/la64/la64_printer.c
+++ b/src/dynarec/la64/la64_printer.c
@@ -235,6 +235,26 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
         snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "ROTRI.D", Xt[Rd], Xt[Rj], imm);
         return buff;
     }
+    // SLLI.W
+    if(isMask(opcode, "00000000010000001iiiiijjjjjddddd", &a)) {
+        snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SLLI.W", Xt[Rd], Xt[Rj], imm);
+        return buff;
+    }
+    // SRLI.W
+    if(isMask(opcode, "00000000010001001iiiiijjjjjddddd", &a)) {
+        snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SRLI.W", Xt[Rd], Xt[Rj], imm);
+        return buff;
+    }
+    // SRAI.W
+    if(isMask(opcode, "00000000010010001iiiiijjjjjddddd", &a)) {
+        snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SRAI.W", Xt[Rd], Xt[Rj], imm);
+        return buff;
+    }
+    // ROTRI.W
+    if(isMask(opcode, "00000000010011001iiiiijjjjjddddd", &a)) {
+        snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "ROTRI.W", Xt[Rd], Xt[Rj], imm);
+        return buff;
+    }
     // BEQ
     if(isMask(opcode, "010110iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
         snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "BEQ", Xt[Rd], Xt[Rj], imm << 2);