about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-05-23 00:22:08 +0800
committerGitHub <noreply@github.com>2024-05-22 18:22:08 +0200
commit9edb89fc222e06e76e3299871bd7c34c9910879f (patch)
treebe87898e64aa5b0ebfeaa710eccd6b9dfa07fefb /src/dynarec
parent3faabb478d2f5ccaec250273750bd4b6d6adabea (diff)
downloadbox64-9edb89fc222e06e76e3299871bd7c34c9910879f.tar.gz
box64-9edb89fc222e06e76e3299871bd7c34c9910879f.zip
[LA64_DYNAREC] Fixed LOCK XCHG byte opcode fallback path (#1519)
* [LA64_DYNAREC] Fixed LOCK XCHG byte opcode fallback path

* fix
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c38
1 files changed, 34 insertions, 4 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 3eb172ab..21936bb9 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -772,7 +772,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             emit_test32(dyn, ninst, rex, ed, gd, x3, x4, x5);
             break;
         case 0x86:
-            INST_NAME("(LOCK)XCHG Eb, Gb");
+            INST_NAME("(LOCK) XCHG Eb, Gb");
             nextop = F8;
             if (MODREG) {
                 GETGB(x1);
@@ -786,9 +786,39 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     AMSWAP_DB_B(x1, gd, ed);
                 else {
                     SMDMB();
-                    LD_BU(x1, ed, 0);
-                    ST_B(gd, ed, 0);
-                    SMDMB();
+
+                    // calculate shift amount
+                    ANDI(x1, ed, 0x3);
+                    SLLI_D(x1, x1, 3);
+
+                    // align address to 4-bytes to use ll.w/sc.w
+                    ADDI_D(x4, xZR, 0xffc);
+                    AND(x6, ed, x4);
+
+                    // load aligned data
+                    LD_WU(x5, x6, 0);
+
+                    // insert gd byte into the aligned data
+                    ADDI_D(x4, xZR, 0xff);
+                    SLL_D(x4, x4, x1);
+                    NOR(x4, x4, xZR);
+                    AND(x4, x5, x4);
+                    SLL_D(x5, gd, x1);
+                    OR(x4, x4, x5);
+
+                    // do aligned ll/sc sequence
+                    MARKLOCK;
+                    LL_W(x1, x6, 0);
+                    MV(x5, x4);
+                    SC_W(x5, x6, 0);
+                    BEQZ_MARKLOCK(x5);
+
+                    // calculate shift amount again
+                    ANDI(x4, ed, 0x3);
+                    SLLI_D(x4, x4, 3);
+
+                    // extract loaded byte
+                    SRL_D(x1, x1, x4);
                 }
                 BSTRINS_D(gb1, x1, gb2 + 7, gb2);
             }