about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-12-03 18:26:11 +0100
committerptitSeb <sebastien.chev@gmail.com>2023-12-03 18:26:11 +0100
commitb67975a820d481577f8ea7515858b2f35450b0d0 (patch)
tree4b9e322c9e2fa04267dbe2046539b12b2af7af6d
parentfa175e7d2405d0b521cfd98d549a94252b697bf6 (diff)
downloadbox64-b67975a820d481577f8ea7515858b2f35450b0d0.tar.gz
box64-b67975a820d481577f8ea7515858b2f35450b0d0.zip
[ARM64_DYNAREC] More work on LOCK prefixed opcodes (Atomic still disabled)
-rw-r--r--CMakeLists.txt5
-rw-r--r--src/dynarec/arm64/arm64_emitter.h12
-rw-r--r--src/dynarec/arm64/arm64_printer.c10
-rw-r--r--src/dynarec/arm64/dynarec_arm64_66.c42
-rw-r--r--src/dynarec/arm64/dynarec_arm64_f0.c11
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h4
-rw-r--r--tests/ref29.txt2
-rwxr-xr-xtests/test29bin0 -> 16024 bytes
-rw-r--r--tests/test29.c40
10 files changed, 106 insertions, 22 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1ea4e51f..bbad8677 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1097,6 +1097,11 @@ add_test(shaext ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
     -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref28.txt
     -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
 
+add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
+    -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29 -D TEST_OUTPUT=tmpfile29.txt
+    -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
+    -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
+
 
 file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
 foreach(file ${extension_tests})
diff --git a/src/dynarec/arm64/arm64_emitter.h b/src/dynarec/arm64/arm64_emitter.h
index 178c5b20..cbfa8371 100644
--- a/src/dynarec/arm64/arm64_emitter.h
+++ b/src/dynarec/arm64/arm64_emitter.h
@@ -200,6 +200,12 @@
 #define SBCSw_REG(Rd, Rn, Rm)       EMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
 #define SBCSxw_REG(Rd, Rn, Rm)      EMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
 
+// CCMP compare if cond is true, set nzcv if false
+#define CCMP_reg(sf, Rm, cond, Rn, nzcv)    ((sf)<<31 | 1<<30 | 1<<29 | 0b11010010<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (nzcv))
+#define CCMPw(Wn, Wm, nzcv, cond)   EMIT(CCMP_reg(0, Wm, cond, Wn, nzcv))
+#define CCMPx(Xn, Xm, nzcv, cond)   EMIT(CCMP_reg(1, Xm, cond, Xn, nzcv))
+#define CCMPxw(Xn, Xm, nzcv, cond)  EMIT(CCMP_reg(rex.w, Xm, cond, Xn, nzcv))
+
 // ADR
 #define ADR_gen(immlo, immhi, Rd)   ((immlo)<<29 | 0b10000<<24 | (immhi)<<5 | (Rd))
 #define ADR_S20(Rd, imm)            EMIT(ADR_gen((imm)&3, ((imm)>>2)&0x7ffff, (Rd)))
@@ -430,6 +436,12 @@
 #define DMB_ISH()                       EMIT(DMB_gen(0b1011))
 #define DMB_SY()                        EMIT(DMB_gen(0b1111))
 
+// Data Synchronization Barrier
+#define DSB_gen(CRm)                    (0b1101010100<<22 | 0b011<<16 | 0b0011<<12 | (CRm)<<8 | 1<<7 | 0b00<<5 | 0b11111)
+#define DSB_ISH()                       EMIT(DSB_gen(0b1011))
+#define DSB_ISHST()                     EMIT(DSB_gen(0b1010))
+#define DSB_SY()                        EMIT(DSB_gen(0b1111))
+
 // Break
 #define BRK_gen(imm16)                  (0b11010100<<24 | 0b001<<21 | (((imm16)&0xffff)<<5))
 #define BRK(imm16)                      EMIT(BRK_gen(imm16))
diff --git a/src/dynarec/arm64/arm64_printer.c b/src/dynarec/arm64/arm64_printer.c
index eca8c632..572d645f 100644
--- a/src/dynarec/arm64/arm64_printer.c
+++ b/src/dynarec/arm64/arm64_printer.c
@@ -797,6 +797,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
         snprintf(buff, sizeof(buff), "CSEL %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond]);    

         return buff;

     }

+    if(isMask(opcode, "f1111010010mmmmmcccc00nnnnn0iiii", &a)) {

+        snprintf(buff, sizeof(buff), "CCMP %s, %s, %s 0x%x", sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond], imm);

+        return buff;

+    }

+

     // MISC Bits

     if(isMask(opcode, "f10110101100000000010onnnnnddddd", &a)) {

         snprintf(buff, sizeof(buff), "CL%c %s, %s", option?'S':'Z', sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn]);

@@ -1621,6 +1626,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
         snprintf(buff, sizeof(buff), "DMB %s", (Rn==0b1011)?"ISH":"???");

         return buff;

     }

+    // DSB ISH/ISHST

+    if(isMask(opcode, "11010101000000110011nnnn10011111", &a)) {

+        snprintf(buff, sizeof(buff), "DSB %s", (Rn==0b1011)?"ISH":((Rn==0b1010)?"ISHST":"???"));

+        return buff;

+    }

 

     // CASxw

     if(isMask(opcode, "1f0010001L1ssssso11111nnnnnttttt", &a)) {

diff --git a/src/dynarec/arm64/dynarec_arm64_66.c b/src/dynarec/arm64/dynarec_arm64_66.c
index bb4a757e..e8540776 100644
--- a/src/dynarec/arm64/dynarec_arm64_66.c
+++ b/src/dynarec/arm64/dynarec_arm64_66.c
@@ -591,18 +591,36 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             } else {

                 GETGD;

                 addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);

-                TSTx_mask(ed, 1, 0, 0);    // mask=1

-                B_MARK(cNE);

-                MARKLOCK;

-                LDAXRH(x1, ed);

-                STLXRH(x3, gd, ed);

-                CBNZx_MARKLOCK(x3);

-                B_MARK2_nocond;

-                MARK;

-                LDRH_U12(x1, ed, 0);

-                STRH_U12(gd, ed, 0);

-                MARK2;

-                SMDMB();

+                if(!ALIGNED_ATOMICH) {

+                    TSTx_mask(ed, 1, 0, 0);    // mask=1

+                    B_MARK(cNE);

+                }

+                if(arm64_atomics) {

+                    SWPALH(gd, x1, ed);

+                    SMDMB();

+                    if(!ALIGNED_ATOMICH) {

+                        B_MARK2_nocond;

+                    }

+                } else {

+                    MARKLOCK;

+                    LDAXRH(x1, ed);

+                    STLXRH(x3, gd, ed);

+                    CBNZx_MARKLOCK(x3);

+                    SMDMB();

+                    if(!ALIGNED_ATOMICH) {

+                        B_MARK2_nocond;

+                    }

+                }

+                if(!ALIGNED_ATOMICH) {

+                    MARK;

+                    LDRH_U12(x1, ed, 0);

+                    LDAXRB(x3, ed);

+                    STLXRB(x3, gd, ed);

+                    CBNZx_MARK(x3);

+                    STRH_U12(gd, ed, 0);

+                    SMDMB();

+                    MARK2;

+                }

                 BFIx(gd, x1, 0, 16);

             }

             break;

diff --git a/src/dynarec/arm64/dynarec_arm64_f0.c b/src/dynarec/arm64/dynarec_arm64_f0.c
index 033b1f81..09d053cb 100644
--- a/src/dynarec/arm64/dynarec_arm64_f0.c
+++ b/src/dynarec/arm64/dynarec_arm64_f0.c
@@ -612,10 +612,8 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                                 CASPALxw(x2, x4, wback);
                                 UFLAG_IF {
                                     CMPSxw_REG(x2, xRAX);
-                                    CSETw(x4, cEQ);
-                                    CMPSxw_REG(x3, xRDX);
-                                    CSETw(x5, cEQ);
-                                    ANDw_REG(x1, x4, x5);
+                                    CCMPxw(x3, xRDX, 0, cEQ);
+                                    CSETw(x1, cEQ);
                                 }
                                 MOVx_REG(xRAX, x2);
                                 MOVx_REG(xRDX, x3);
@@ -623,9 +621,8 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                                 MARKLOCK;
                                 LDAXPxw(x2, x3, wback);
                                 CMPSxw_REG(xRAX, x2);
-                                B_MARK(cNE);    // EAX != Ed[0]
-                                CMPSxw_REG(xRDX, x3);
-                                B_MARK(cNE);    // EDX != Ed[1]
+                                CCMPxw(xRDX, x3, 0, cEQ);
+                                B_MARK(cNE);    // EAX!=ED[0] || EDX!=Ed[1]
                                 STLXPxw(x4, xRBX, xRCX, wback);
                                 CBNZx_MARKLOCK(x4);
                                 UFLAG_IF {
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index d404c6f3..ab49bc1e 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -32,7 +32,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
 {
     MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
 
-    if(l==LOCK_LOCK) { SMDMB(); }
+    if(l==LOCK_LOCK) { /*SMDMB();*/DMB_ISH(); }
 
     if(rex.is32bits)
         return geted_32(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, l, s);
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index b511457d..664ccaaf 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -55,9 +55,9 @@
 // Start of sequence
 #define SMSTART()   SMEND()
 // End of sequence
-#define SMEND()     if(dyn->smwrite && box64_dynarec_strongmem) {DMB_ISH();} dyn->smwrite=0; dyn->smread=0;
+#define SMEND()     if(dyn->smwrite && box64_dynarec_strongmem) {if(box64_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();}} dyn->smwrite=0; dyn->smread=0;
 // Force a Data memory barrier (for LOCK: prefix)
-#define SMDMB()     DMB_ISH(); dyn->smwrite=0; dyn->smread=1; dyn->smlastdmb = ninst
+#define SMDMB()     if(box64_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();} dyn->smwrite=0; dyn->smread=1; dyn->smlastdmb = ninst
 
 //LOCK_* define
 #define LOCK_LOCK   (int*)1
diff --git a/tests/ref29.txt b/tests/ref29.txt
new file mode 100644
index 00000000..6b25f7de
--- /dev/null
+++ b/tests/ref29.txt
@@ -0,0 +1,2 @@
+Lock XADD: Res = 0x456, Ed = 0x579
+Lock XCHG: Res = 0x579, Ed = 0x123
diff --git a/tests/test29 b/tests/test29
new file mode 100755
index 00000000..0c4a63da
--- /dev/null
+++ b/tests/test29
Binary files differdiff --git a/tests/test29.c b/tests/test29.c
new file mode 100644
index 00000000..96384251
--- /dev/null
+++ b/tests/test29.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdint.h>
+// Build with `gcc -march=core2 -O0 test29.c -o test29`
+
+uint64_t lock_xadd(uint64_t Gd, uint64_t volatile* Ed) {
+uint64_t Res;
+asm(
+"lock xadd %[_Gd], (%[_Ed])\n"
+"movq %[_Gd], %[_Res]\n"
+: [_Res] "+r"(Res)
+: [_Gd] "r"(Gd)
+, [_Ed] "r"(Ed)
+);
+return Res;
+}
+
+uint64_t lock_xchg(uint64_t Gd, uint64_t volatile* Ed) {
+uint64_t Res;
+asm(
+"lock xchg %[_Gd], (%[_Ed])\n"
+"movq %[_Gd], %[_Res]\n"
+: [_Res] "+r"(Res)
+: [_Gd] "r"(Gd)
+, [_Ed] "r"(Ed)
+);
+return Res;
+}
+
+int main() {
+uint64_t Gd = 0x123;
+uint64_t volatile Ed = 0x456;
+uint64_t Res = lock_xadd(Gd, &Ed);
+printf("Lock XADD: Res = 0x%lx, Ed = 0x%lx\n", Res, Ed);
+Gd = 0x123;
+Res = lock_xchg(Gd, &Ed);
+printf("Lock XCHG: Res = 0x%lx, Ed = 0x%lx\n", Res, Ed);
+return 0;
+}