diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00_2.c | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00_2.c b/src/dynarec/rv64/dynarec_rv64_00_2.c index e62c73e9..fbabc49a 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_2.c +++ b/src/dynarec/rv64/dynarec_rv64_00_2.c @@ -226,7 +226,7 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int 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); @@ -240,9 +240,39 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int GETGB(x3); addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0); SMDMB(); - LBU(x1, ed, 0); - SB(gd, ed, 0); - SMDMB(); + + // calculate shift amount + ANDI(x1, ed, 0x3); + SLLI(x1, x1, 3); + + // align address to 4-bytes to use ll.w/sc.w + ADDI(x4, xZR, 0xffc); + AND(x6, ed, x4); + + // load aligned data + LWU(x5, x6, 0); + + // insert gd byte into the aligned data + ADDI(x4, xZR, 0xff); + SLL(x4, x4, x1); + NOT(x4, x4); + AND(x4, x5, x4); + SLL(x5, gd, x1); + OR(x4, x4, x5); + + // do aligned ll/sc sequence + MARKLOCK; + LR_W(x1, x6, 1, 1); + SC_W(x5, x4, x6, 1, 1); + BNEZ_MARKLOCK(x5); + + // calculate shift amount again + ANDI(x4, ed, 0x3); + SLLI(x4, x4, 3); + + // extract loaded byte + SRL(x1, x1, x4); + gd = x1; GBBACK(x3); } |