diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2023-12-03 18:26:11 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2023-12-03 18:26:11 +0100 |
| commit | b67975a820d481577f8ea7515858b2f35450b0d0 (patch) | |
| tree | 4b9e322c9e2fa04267dbe2046539b12b2af7af6d | |
| parent | fa175e7d2405d0b521cfd98d549a94252b697bf6 (diff) | |
| download | box64-b67975a820d481577f8ea7515858b2f35450b0d0.tar.gz box64-b67975a820d481577f8ea7515858b2f35450b0d0.zip | |
[ARM64_DYNAREC] More work on LOCK prefixed opcodes (Atomic still disabled)
| -rw-r--r-- | CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/dynarec/arm64/arm64_emitter.h | 12 | ||||
| -rw-r--r-- | src/dynarec/arm64/arm64_printer.c | 10 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_66.c | 42 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_f0.c | 11 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_helper.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_helper.h | 4 | ||||
| -rw-r--r-- | tests/ref29.txt | 2 | ||||
| -rwxr-xr-x | tests/test29 | bin | 0 -> 16024 bytes | |||
| -rw-r--r-- | tests/test29.c | 40 |
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; +} |