early-access version 2615
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 2614. | ||||
| This is the source code for early-access 2615. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								externals/dynarmic/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								externals/dynarmic/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -160,7 +160,7 @@ if (DYNARMIC_USE_LLVM) | ||||
|     llvm_map_components_to_libnames(llvm_libs armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler) | ||||
| endif() | ||||
|  | ||||
| if (DYNARMIC_TESTS_USE_UNICORN) | ||||
| if (DYNARMIC_TESTS_USE_UNICORN AND DYNARMIC_TESTS) | ||||
|     find_package(Unicorn REQUIRED) | ||||
| endif() | ||||
|  | ||||
|   | ||||
| @@ -75,6 +75,7 @@ add_library(dynarmic | ||||
|     frontend/imm.h | ||||
|     interface/exclusive_monitor.h | ||||
|     interface/optimization_flags.h | ||||
|     ir/acc_type.h | ||||
|     ir/basic_block.cpp | ||||
|     ir/basic_block.h | ||||
|     ir/cond.h | ||||
| @@ -99,7 +100,7 @@ add_library(dynarmic | ||||
|     ir/type.h | ||||
|     ir/value.cpp | ||||
|     ir/value.h | ||||
|         ir/access_type.h) | ||||
| ) | ||||
|  | ||||
| if ("A32" IN_LIST DYNARMIC_FRONTENDS) | ||||
|     target_sources(dynarmic PRIVATE | ||||
| @@ -390,7 +391,7 @@ target_link_libraries(dynarmic | ||||
|         tsl::robin_map | ||||
|         $<BUILD_INTERFACE:xbyak> | ||||
|         $<BUILD_INTERFACE:Zydis> | ||||
|         $<$<BOOL:DYNARMIC_USE_LLVM>:${llvm_libs}> | ||||
|         "$<$<BOOL:DYNARMIC_USE_LLVM>:${llvm_libs}>" | ||||
| ) | ||||
| if (DYNARMIC_ENABLE_CPU_FEATURE_DETECTION) | ||||
|     target_compile_definitions(dynarmic PRIVATE DYNARMIC_ENABLE_CPU_FEATURE_DETECTION=1) | ||||
|   | ||||
| @@ -158,120 +158,6 @@ FakeCall A32EmitX64::FastmemCallback(u64 rip_) { | ||||
|     }; | ||||
| } | ||||
|  | ||||
| namespace { | ||||
|  | ||||
| constexpr size_t page_bits = 12; | ||||
| constexpr size_t page_size = 1 << page_bits; | ||||
| constexpr size_t page_mask = (1 << page_bits) - 1; | ||||
|  | ||||
| void EmitDetectMisaignedVAddr(BlockOfCode& code, A32EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg32 vaddr, Xbyak::Reg32 tmp) { | ||||
|     if (bitsize == 8 || (ctx.conf.detect_misaligned_access_via_page_table & bitsize) == 0) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const u32 align_mask = [bitsize]() -> u32 { | ||||
|         switch (bitsize) { | ||||
|         case 16: | ||||
|             return 0b1; | ||||
|         case 32: | ||||
|             return 0b11; | ||||
|         case 64: | ||||
|             return 0b111; | ||||
|         } | ||||
|         UNREACHABLE(); | ||||
|     }(); | ||||
|  | ||||
|     code.test(vaddr, align_mask); | ||||
|  | ||||
|     if (!ctx.conf.only_detect_misalignment_via_page_table_on_page_boundary) { | ||||
|         code.jnz(abort, code.T_NEAR); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const u32 page_align_mask = static_cast<u32>(page_size - 1) & ~align_mask; | ||||
|  | ||||
|     Xbyak::Label detect_boundary, resume; | ||||
|  | ||||
|     code.jnz(detect_boundary, code.T_NEAR); | ||||
|     code.L(resume); | ||||
|  | ||||
|     code.SwitchToFarCode(); | ||||
|     code.L(detect_boundary); | ||||
|     code.mov(tmp, vaddr); | ||||
|     code.and_(tmp, page_align_mask); | ||||
|     code.cmp(tmp, page_align_mask); | ||||
|     code.jne(resume, code.T_NEAR); | ||||
|     // NOTE: We expect to fallthrough into abort code here. | ||||
|     code.SwitchToNearCode(); | ||||
| } | ||||
|  | ||||
| Xbyak::RegExp EmitVAddrLookup(BlockOfCode& code, A32EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr) { | ||||
|     const Xbyak::Reg64 page = ctx.reg_alloc.ScratchGpr(); | ||||
|     const Xbyak::Reg32 tmp = ctx.conf.absolute_offset_page_table ? page.cvt32() : ctx.reg_alloc.ScratchGpr().cvt32(); | ||||
|  | ||||
|     EmitDetectMisaignedVAddr(code, ctx, bitsize, abort, vaddr.cvt32(), tmp); | ||||
|  | ||||
|     // TODO: This code assumes vaddr has been zext from 32-bits to 64-bits. | ||||
|  | ||||
|     code.mov(tmp, vaddr.cvt32()); | ||||
|     code.shr(tmp, static_cast<int>(page_bits)); | ||||
|     code.mov(page, qword[r14 + tmp.cvt64() * sizeof(void*)]); | ||||
|     if (ctx.conf.page_table_pointer_mask_bits == 0) { | ||||
|         code.test(page, page); | ||||
|     } else { | ||||
|         code.and_(page, ~u32(0) << ctx.conf.page_table_pointer_mask_bits); | ||||
|     } | ||||
|     code.jz(abort, code.T_NEAR); | ||||
|     if (ctx.conf.absolute_offset_page_table) { | ||||
|         return page + vaddr; | ||||
|     } | ||||
|     code.mov(tmp, vaddr.cvt32()); | ||||
|     code.and_(tmp, static_cast<u32>(page_mask)); | ||||
|     return page + tmp.cvt64(); | ||||
| } | ||||
|  | ||||
| template<std::size_t bitsize> | ||||
| void EmitReadMemoryMov(BlockOfCode& code, const Xbyak::Reg64& value, const Xbyak::RegExp& addr) { | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         code.movzx(value.cvt32(), code.byte[addr]); | ||||
|         return; | ||||
|     case 16: | ||||
|         code.movzx(value.cvt32(), word[addr]); | ||||
|         return; | ||||
|     case 32: | ||||
|         code.mov(value.cvt32(), dword[addr]); | ||||
|         return; | ||||
|     case 64: | ||||
|         code.mov(value, qword[addr]); | ||||
|         return; | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bitsize"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<std::size_t bitsize> | ||||
| void EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, const Xbyak::Reg64& value) { | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         code.mov(code.byte[addr], value.cvt8()); | ||||
|         return; | ||||
|     case 16: | ||||
|         code.mov(word[addr], value.cvt16()); | ||||
|         return; | ||||
|     case 32: | ||||
|         code.mov(dword[addr], value.cvt32()); | ||||
|         return; | ||||
|     case 64: | ||||
|         code.mov(qword[addr], value); | ||||
|         return; | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bitsize"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| }  // anonymous namespace | ||||
|  | ||||
| template<std::size_t bitsize, auto callback> | ||||
| void A32EmitX64::EmitMemoryRead(A32EmitContext& ctx, IR::Inst* inst) { | ||||
|     auto args = ctx.reg_alloc.GetArgumentInfo(inst); | ||||
| @@ -295,7 +181,7 @@ void A32EmitX64::EmitMemoryRead(A32EmitContext& ctx, IR::Inst* inst) { | ||||
|         const auto src_ptr = r13 + vaddr; | ||||
|  | ||||
|         const auto location = code.getCurr(); | ||||
|         EmitReadMemoryMov<bitsize>(code, value, src_ptr); | ||||
|         EmitReadMemoryMov<bitsize>(code, value.getIdx(), src_ptr); | ||||
|  | ||||
|         fastmem_patch_info.emplace( | ||||
|             Common::BitCast<u64>(location), | ||||
| @@ -315,7 +201,7 @@ void A32EmitX64::EmitMemoryRead(A32EmitContext& ctx, IR::Inst* inst) { | ||||
|     Xbyak::Label abort, end; | ||||
|  | ||||
|     const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr); | ||||
|     EmitReadMemoryMov<bitsize>(code, value, src_ptr); | ||||
|     EmitReadMemoryMov<bitsize>(code, value.getIdx(), src_ptr); | ||||
|     code.L(end); | ||||
|  | ||||
|     code.SwitchToFarCode(); | ||||
| @@ -349,7 +235,7 @@ void A32EmitX64::EmitMemoryWrite(A32EmitContext& ctx, IR::Inst* inst) { | ||||
|         const auto dest_ptr = r13 + vaddr; | ||||
|  | ||||
|         const auto location = code.getCurr(); | ||||
|         EmitWriteMemoryMov<bitsize>(code, dest_ptr, value); | ||||
|         EmitWriteMemoryMov<bitsize>(code, dest_ptr, value.getIdx()); | ||||
|  | ||||
|         fastmem_patch_info.emplace( | ||||
|             Common::BitCast<u64>(location), | ||||
| @@ -368,7 +254,7 @@ void A32EmitX64::EmitMemoryWrite(A32EmitContext& ctx, IR::Inst* inst) { | ||||
|     Xbyak::Label abort, end; | ||||
|  | ||||
|     const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr); | ||||
|     EmitWriteMemoryMov<bitsize>(code, dest_ptr, value); | ||||
|     EmitWriteMemoryMov<bitsize>(code, dest_ptr, value.getIdx()); | ||||
|     code.L(end); | ||||
|  | ||||
|     code.SwitchToFarCode(); | ||||
| @@ -488,7 +374,7 @@ void A32EmitX64::ExclusiveReadMemoryInline(A32EmitContext& ctx, IR::Inst* inst) | ||||
|         const auto src_ptr = r13 + vaddr; | ||||
|  | ||||
|         const auto location = code.getCurr(); | ||||
|         EmitReadMemoryMov<bitsize>(code, value, src_ptr); | ||||
|         EmitReadMemoryMov<bitsize>(code, value.getIdx(), src_ptr); | ||||
|  | ||||
|         fastmem_patch_info.emplace( | ||||
|             Common::BitCast<u64>(location), | ||||
| @@ -505,7 +391,7 @@ void A32EmitX64::ExclusiveReadMemoryInline(A32EmitContext& ctx, IR::Inst* inst) | ||||
|     } | ||||
|  | ||||
|     code.mov(tmp, Common::BitCast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id))); | ||||
|     EmitWriteMemoryMov<bitsize>(code, tmp, value); | ||||
|     EmitWriteMemoryMov<bitsize>(code, tmp, value.getIdx()); | ||||
|  | ||||
|     EmitExclusiveUnlock(code, conf, tmp, tmp2.cvt32()); | ||||
|  | ||||
| @@ -546,7 +432,7 @@ void A32EmitX64::ExclusiveWriteMemoryInline(A32EmitContext& ctx, IR::Inst* inst) | ||||
|     code.mov(code.byte[r15 + offsetof(A32JitState, exclusive_state)], u8(0)); | ||||
|     code.mov(tmp, Common::BitCast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id))); | ||||
|  | ||||
|     EmitReadMemoryMov<bitsize>(code, rax, tmp); | ||||
|     EmitReadMemoryMov<bitsize>(code, rax.getIdx(), tmp); | ||||
|  | ||||
|     const auto fastmem_marker = ShouldFastmem(ctx, inst); | ||||
|     if (fastmem_marker) { | ||||
|   | ||||
| @@ -22,7 +22,6 @@ | ||||
| #include "dynarmic/common/spin_lock_x64.h" | ||||
| #include "dynarmic/common/x64_disassemble.h" | ||||
| #include "dynarmic/interface/exclusive_monitor.h" | ||||
| #include "dynarmic/ir/access_type.h" | ||||
|  | ||||
| namespace Dynarmic::Backend::X64 { | ||||
|  | ||||
| @@ -301,272 +300,19 @@ FakeCall A64EmitX64::FastmemCallback(u64 rip_) { | ||||
|     }; | ||||
| } | ||||
|  | ||||
| namespace { | ||||
|  | ||||
| constexpr size_t page_bits = 12; | ||||
| constexpr size_t page_size = 1 << page_bits; | ||||
| constexpr size_t page_mask = (1 << page_bits) - 1; | ||||
|  | ||||
| void EmitDetectMisaignedVAddr(BlockOfCode& code, A64EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr, Xbyak::Reg64 tmp) { | ||||
|     if (bitsize == 8 || (ctx.conf.detect_misaligned_access_via_page_table & bitsize) == 0) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const u32 align_mask = [bitsize]() -> u32 { | ||||
|         switch (bitsize) { | ||||
|         case 16: | ||||
|             return 0b1; | ||||
|         case 32: | ||||
|             return 0b11; | ||||
|         case 64: | ||||
|             return 0b111; | ||||
|         case 128: | ||||
|             return 0b1111; | ||||
|         } | ||||
|         UNREACHABLE(); | ||||
|     }(); | ||||
|  | ||||
|     code.test(vaddr, align_mask); | ||||
|  | ||||
|     if (!ctx.conf.only_detect_misalignment_via_page_table_on_page_boundary) { | ||||
|         code.jnz(abort, code.T_NEAR); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const u32 page_align_mask = static_cast<u32>(page_size - 1) & ~align_mask; | ||||
|  | ||||
|     Xbyak::Label detect_boundary, resume; | ||||
|  | ||||
|     code.jnz(detect_boundary, code.T_NEAR); | ||||
|     code.L(resume); | ||||
|  | ||||
|     code.SwitchToFarCode(); | ||||
|     code.L(detect_boundary); | ||||
|     code.mov(tmp, vaddr); | ||||
|     code.and_(tmp, page_align_mask); | ||||
|     code.cmp(tmp, page_align_mask); | ||||
|     code.jne(resume, code.T_NEAR); | ||||
|     // NOTE: We expect to fallthrough into abort code here. | ||||
|     code.SwitchToNearCode(); | ||||
| } | ||||
|  | ||||
| Xbyak::RegExp EmitVAddrLookup(BlockOfCode& code, A64EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr) { | ||||
|     const size_t valid_page_index_bits = ctx.conf.page_table_address_space_bits - page_bits; | ||||
|     const size_t unused_top_bits = 64 - ctx.conf.page_table_address_space_bits; | ||||
|  | ||||
|     const Xbyak::Reg64 page = ctx.reg_alloc.ScratchGpr(); | ||||
|     const Xbyak::Reg64 tmp = ctx.conf.absolute_offset_page_table ? page : ctx.reg_alloc.ScratchGpr(); | ||||
|  | ||||
|     EmitDetectMisaignedVAddr(code, ctx, bitsize, abort, vaddr, tmp); | ||||
|  | ||||
|     if (unused_top_bits == 0) { | ||||
|         code.mov(tmp, vaddr); | ||||
|         code.shr(tmp, int(page_bits)); | ||||
|     } else if (ctx.conf.silently_mirror_page_table) { | ||||
|         if (valid_page_index_bits >= 32) { | ||||
|             if (code.HasHostFeature(HostFeature::BMI2)) { | ||||
|                 const Xbyak::Reg64 bit_count = ctx.reg_alloc.ScratchGpr(); | ||||
|                 code.mov(bit_count, unused_top_bits); | ||||
|                 code.bzhi(tmp, vaddr, bit_count); | ||||
|                 code.shr(tmp, int(page_bits)); | ||||
|                 ctx.reg_alloc.Release(bit_count); | ||||
|             } else { | ||||
|                 code.mov(tmp, vaddr); | ||||
|                 code.shl(tmp, int(unused_top_bits)); | ||||
|                 code.shr(tmp, int(unused_top_bits + page_bits)); | ||||
|             } | ||||
|         } else { | ||||
|             code.mov(tmp, vaddr); | ||||
|             code.shr(tmp, int(page_bits)); | ||||
|             code.and_(tmp, u32((1 << valid_page_index_bits) - 1)); | ||||
|         } | ||||
|     } else { | ||||
|         ASSERT(valid_page_index_bits < 32); | ||||
|         code.mov(tmp, vaddr); | ||||
|         code.shr(tmp, int(page_bits)); | ||||
|         code.test(tmp, u32(-(1 << valid_page_index_bits))); | ||||
|         code.jnz(abort, code.T_NEAR); | ||||
|     } | ||||
|     code.mov(page, qword[r14 + tmp * sizeof(void*)]); | ||||
|     if (ctx.conf.page_table_pointer_mask_bits == 0) { | ||||
|         code.test(page, page); | ||||
|     } else { | ||||
|         code.and_(page, ~u32(0) << ctx.conf.page_table_pointer_mask_bits); | ||||
|     } | ||||
|     code.jz(abort, code.T_NEAR); | ||||
|     if (ctx.conf.absolute_offset_page_table) { | ||||
|         return page + vaddr; | ||||
|     } | ||||
|     code.mov(tmp, vaddr); | ||||
|     code.and_(tmp, static_cast<u32>(page_mask)); | ||||
|     return page + tmp; | ||||
| } | ||||
|  | ||||
| Xbyak::RegExp EmitFastmemVAddr(BlockOfCode& code, A64EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr, bool& require_abort_handling, std::optional<Xbyak::Reg64> tmp = std::nullopt) { | ||||
|     const size_t unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits; | ||||
|  | ||||
|     if (unused_top_bits == 0) { | ||||
|         return r13 + vaddr; | ||||
|     } else if (ctx.conf.silently_mirror_fastmem) { | ||||
|         if (!tmp) { | ||||
|             tmp = ctx.reg_alloc.ScratchGpr(); | ||||
|         } | ||||
|         if (unused_top_bits < 32) { | ||||
|             code.mov(*tmp, vaddr); | ||||
|             code.shl(*tmp, int(unused_top_bits)); | ||||
|             code.shr(*tmp, int(unused_top_bits)); | ||||
|         } else if (unused_top_bits == 32) { | ||||
|             code.mov(tmp->cvt32(), vaddr.cvt32()); | ||||
|         } else { | ||||
|             code.mov(tmp->cvt32(), vaddr.cvt32()); | ||||
|             code.and_(*tmp, u32((1 << ctx.conf.fastmem_address_space_bits) - 1)); | ||||
|         } | ||||
|         return r13 + *tmp; | ||||
|     } else { | ||||
|         if (ctx.conf.fastmem_address_space_bits < 32) { | ||||
|             code.test(vaddr, u32(-(1 << ctx.conf.fastmem_address_space_bits))); | ||||
|             code.jnz(abort, code.T_NEAR); | ||||
|             require_abort_handling = true; | ||||
|         } else { | ||||
|             // TODO: Consider having TEST as above but coalesce 64-bit constant in register allocator | ||||
|             if (!tmp) { | ||||
|                 tmp = ctx.reg_alloc.ScratchGpr(); | ||||
|             } | ||||
|             code.mov(*tmp, vaddr); | ||||
|             code.shr(*tmp, int(ctx.conf.fastmem_address_space_bits)); | ||||
|             code.jnz(abort, code.T_NEAR); | ||||
|             require_abort_handling = true; | ||||
|         } | ||||
|         return r13 + vaddr; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<std::size_t bitsize> | ||||
| const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::RegExp& addr, bool ordered) { | ||||
|     if (ordered) { | ||||
|         if constexpr (bitsize == 128) { | ||||
|             code.mfence(); | ||||
|         } else { | ||||
|             code.xor_(Xbyak::Reg32{value_idx}, Xbyak::Reg32{value_idx}); | ||||
|         } | ||||
|  | ||||
|         const void* fastmem_location = code.getCurr(); | ||||
|  | ||||
|         switch (bitsize) { | ||||
|         case 8: | ||||
|             code.lock(); | ||||
|             code.xadd(code.byte[addr], Xbyak::Reg32{value_idx}.cvt8()); | ||||
|             return fastmem_location; | ||||
|         case 16: | ||||
|             code.lock(); | ||||
|             code.xadd(word[addr], Xbyak::Reg32{value_idx}); | ||||
|             return fastmem_location; | ||||
|         case 32: | ||||
|             code.lock(); | ||||
|             code.xadd(dword[addr], Xbyak::Reg32{value_idx}); | ||||
|             return fastmem_location; | ||||
|         case 64: | ||||
|             code.lock(); | ||||
|             code.xadd(qword[addr], Xbyak::Reg64{value_idx}); | ||||
|             return fastmem_location; | ||||
|         case 128: | ||||
|             code.movaps(Xbyak::Xmm{value_idx}, xword[addr]); | ||||
|             return fastmem_location; | ||||
|         default: | ||||
|             ASSERT_FALSE("Invalid bitsize"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     const void* fastmem_location = code.getCurr(); | ||||
|  | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         code.movzx(Xbyak::Reg32{value_idx}, code.byte[addr]); | ||||
|         return fastmem_location; | ||||
|     case 16: | ||||
|         code.movzx(Xbyak::Reg32{value_idx}, word[addr]); | ||||
|         return fastmem_location; | ||||
|     case 32: | ||||
|         code.mov(Xbyak::Reg32{value_idx}, dword[addr]); | ||||
|         return fastmem_location; | ||||
|     case 64: | ||||
|         code.mov(Xbyak::Reg64{value_idx}, qword[addr]); | ||||
|         return fastmem_location; | ||||
|     case 128: | ||||
|         code.movups(Xbyak::Xmm{value_idx}, xword[addr]); | ||||
|         return fastmem_location; | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bitsize"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<std::size_t bitsize> | ||||
| void EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int value_idx, bool ordered) { | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         if (ordered) { | ||||
|             code.xchg(code.byte[addr], Xbyak::Reg64{value_idx}.cvt8()); | ||||
|         } else { | ||||
|             code.mov(code.byte[addr], Xbyak::Reg64{value_idx}.cvt8()); | ||||
|         } | ||||
|         return; | ||||
|     case 16: | ||||
|         if (ordered) { | ||||
|             code.xchg(word[addr], Xbyak::Reg16{value_idx}); | ||||
|         } else { | ||||
|             code.mov(word[addr], Xbyak::Reg16{value_idx}); | ||||
|         } | ||||
|         return; | ||||
|     case 32: | ||||
|         if (ordered) { | ||||
|             code.xchg(dword[addr], Xbyak::Reg32{value_idx}); | ||||
|         } else { | ||||
|             code.mov(dword[addr], Xbyak::Reg32{value_idx}); | ||||
|         } | ||||
|         return; | ||||
|     case 64: | ||||
|         if (ordered) { | ||||
|             code.xchg(qword[addr], Xbyak::Reg64{value_idx}); | ||||
|         } else { | ||||
|             code.mov(qword[addr], Xbyak::Reg64{value_idx}); | ||||
|         } | ||||
|         return; | ||||
|     case 128: | ||||
|         if (ordered) { | ||||
|             code.movaps(xword[addr], Xbyak::Xmm{value_idx}); | ||||
|             code.mfence(); | ||||
|         } else { | ||||
|             code.movups(xword[addr], Xbyak::Xmm{value_idx}); | ||||
|         } | ||||
|         return; | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bitsize"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| }  // namespace | ||||
|  | ||||
| template<std::size_t bitsize, auto callback> | ||||
| void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|     auto args = ctx.reg_alloc.GetArgumentInfo(inst); | ||||
|     const IR::AccessType acctype = args[2].GetImmediateAccType(); | ||||
|     const bool ordered = acctype == IR::AccessType::ORDERED || acctype == IR::AccessType::ORDEREDRW || acctype == IR::AccessType::LIMITEDORDERED; | ||||
|     const auto fastmem_marker = ShouldFastmem(ctx, inst); | ||||
|  | ||||
|     if (!conf.page_table && !fastmem_marker) { | ||||
|         // Neither fastmem nor page table: Use callbacks | ||||
|         if constexpr (bitsize == 128) { | ||||
|             ctx.reg_alloc.HostCall(nullptr, {}, args[0]); | ||||
|             if (ordered) { | ||||
|                 code.mfence(); | ||||
|             } | ||||
|             code.CallFunction(memory_read_128); | ||||
|             ctx.reg_alloc.DefineValue(inst, xmm1); | ||||
|         } else { | ||||
|             ctx.reg_alloc.HostCall(inst, {}, args[0]); | ||||
|             if (ordered) { | ||||
|                 code.mfence(); | ||||
|             } | ||||
|             Devirtualize<callback>(conf.callbacks).EmitCall(code); | ||||
|             code.ZeroExtendFrom(bitsize, code.ABI_RETURN); | ||||
|         } | ||||
| @@ -585,7 +331,8 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|         // Use fastmem | ||||
|         const auto src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling); | ||||
|  | ||||
|         const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered); | ||||
|         const auto location = code.getCurr(); | ||||
|         EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr); | ||||
|  | ||||
|         fastmem_patch_info.emplace( | ||||
|             Common::BitCast<u64>(location), | ||||
| @@ -600,16 +347,13 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|         ASSERT(conf.page_table); | ||||
|         const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr); | ||||
|         require_abort_handling = true; | ||||
|         EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered); | ||||
|         EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr); | ||||
|     } | ||||
|     code.L(end); | ||||
|  | ||||
|     if (require_abort_handling) { | ||||
|         code.SwitchToFarCode(); | ||||
|         code.L(abort); | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|         code.call(wrapped_fn); | ||||
|         code.jmp(end, code.T_NEAR); | ||||
|         code.SwitchToNearCode(); | ||||
| @@ -625,8 +369,6 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) { | ||||
| template<std::size_t bitsize, auto callback> | ||||
| void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|     auto args = ctx.reg_alloc.GetArgumentInfo(inst); | ||||
|     const IR::AccessType acctype = args[2].GetImmediateAccType(); | ||||
|     const bool ordered = acctype == IR::AccessType::ORDERED || acctype == IR::AccessType::ORDEREDRW || acctype == IR::AccessType::LIMITEDORDERED; | ||||
|     const auto fastmem_marker = ShouldFastmem(ctx, inst); | ||||
|  | ||||
|     if (!conf.page_table && !fastmem_marker) { | ||||
| @@ -641,16 +383,11 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|             ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]); | ||||
|             Devirtualize<callback>(conf.callbacks).EmitCall(code); | ||||
|         } | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]); | ||||
|     const int value_idx = bitsize == 128 | ||||
|                             ? ctx.reg_alloc.UseXmm(args[1]).getIdx() | ||||
|                             : (ordered ? ctx.reg_alloc.UseScratchGpr(args[1]).getIdx() : ctx.reg_alloc.UseGpr(args[1]).getIdx()); | ||||
|     const int value_idx = bitsize == 128 ? ctx.reg_alloc.UseXmm(args[1]).getIdx() : ctx.reg_alloc.UseGpr(args[1]).getIdx(); | ||||
|  | ||||
|     const auto wrapped_fn = write_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value_idx)]; | ||||
|  | ||||
| @@ -662,7 +399,7 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|         const auto dest_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling); | ||||
|  | ||||
|         const auto location = code.getCurr(); | ||||
|         EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered); | ||||
|         EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx); | ||||
|  | ||||
|         fastmem_patch_info.emplace( | ||||
|             Common::BitCast<u64>(location), | ||||
| @@ -677,7 +414,7 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|         ASSERT(conf.page_table); | ||||
|         const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr); | ||||
|         require_abort_handling = true; | ||||
|         EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered); | ||||
|         EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx); | ||||
|     } | ||||
|     code.L(end); | ||||
|  | ||||
| @@ -685,9 +422,6 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|         code.SwitchToFarCode(); | ||||
|         code.L(abort); | ||||
|         code.call(wrapped_fn); | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|         code.jmp(end, code.T_NEAR); | ||||
|         code.SwitchToNearCode(); | ||||
|     } | ||||
| @@ -737,8 +471,6 @@ template<std::size_t bitsize, auto callback> | ||||
| void A64EmitX64::EmitExclusiveReadMemory(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|     ASSERT(conf.global_monitor != nullptr); | ||||
|     auto args = ctx.reg_alloc.GetArgumentInfo(inst); | ||||
|     const IR::AccessType acctype = args[2].GetImmediateAccType(); | ||||
|     const bool ordered = acctype == IR::AccessType::ORDERED || acctype == IR::AccessType::ORDEREDRW || acctype == IR::AccessType::LIMITEDORDERED; | ||||
|  | ||||
|     if constexpr (bitsize != 128) { | ||||
|         using T = mp::unsigned_integer_of_size<bitsize>; | ||||
| @@ -747,9 +479,6 @@ void A64EmitX64::EmitExclusiveReadMemory(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|  | ||||
|         code.mov(code.byte[r15 + offsetof(A64JitState, exclusive_state)], u8(1)); | ||||
|         code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(&conf)); | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|         code.CallLambda( | ||||
|             [](A64::UserConfig& conf, u64 vaddr) -> T { | ||||
|                 return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T { | ||||
| @@ -767,9 +496,6 @@ void A64EmitX64::EmitExclusiveReadMemory(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|         code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(&conf)); | ||||
|         ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE); | ||||
|         code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]); | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|         code.CallLambda( | ||||
|             [](A64::UserConfig& conf, u64 vaddr, A64::Vector& ret) { | ||||
|                 ret = conf.global_monitor->ReadAndMark<A64::Vector>(conf.processor_id, vaddr, [&]() -> A64::Vector { | ||||
| @@ -787,8 +513,6 @@ template<std::size_t bitsize, auto callback> | ||||
| void A64EmitX64::EmitExclusiveWriteMemory(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|     ASSERT(conf.global_monitor != nullptr); | ||||
|     auto args = ctx.reg_alloc.GetArgumentInfo(inst); | ||||
|     const IR::AccessType acctype = args[3].GetImmediateAccType(); | ||||
|     const bool ordered = acctype == IR::AccessType::ORDERED || acctype == IR::AccessType::ORDEREDRW || acctype == IR::AccessType::LIMITEDORDERED; | ||||
|  | ||||
|     if constexpr (bitsize != 128) { | ||||
|         ctx.reg_alloc.HostCall(inst, {}, args[0], args[1]); | ||||
| @@ -818,9 +542,6 @@ void A64EmitX64::EmitExclusiveWriteMemory(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|                          ? 0 | ||||
|                          : 1; | ||||
|             }); | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|     } else { | ||||
|         ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE); | ||||
|         code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]); | ||||
| @@ -834,9 +555,6 @@ void A64EmitX64::EmitExclusiveWriteMemory(A64EmitContext& ctx, IR::Inst* inst) { | ||||
|                          ? 0 | ||||
|                          : 1; | ||||
|             }); | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|         ctx.reg_alloc.ReleaseStackSpace(16 + ABI_SHADOW_SPACE); | ||||
|     } | ||||
|     code.L(end); | ||||
| @@ -851,8 +569,6 @@ void A64EmitX64::EmitExclusiveReadMemoryInline(A64EmitContext& ctx, IR::Inst* in | ||||
|     } | ||||
|  | ||||
|     auto args = ctx.reg_alloc.GetArgumentInfo(inst); | ||||
|     const IR::AccessType acctype = args[2].GetImmediateAccType(); | ||||
|     const bool ordered = acctype == IR::AccessType::ORDERED || acctype == IR::AccessType::ORDEREDRW || acctype == IR::AccessType::LIMITEDORDERED; | ||||
|  | ||||
|     const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]); | ||||
|     const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm().getIdx() : ctx.reg_alloc.ScratchGpr().getIdx(); | ||||
| @@ -875,7 +591,7 @@ void A64EmitX64::EmitExclusiveReadMemoryInline(A64EmitContext& ctx, IR::Inst* in | ||||
|         const auto src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling); | ||||
|  | ||||
|         const auto location = code.getCurr(); | ||||
|         EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered); | ||||
|         EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr); | ||||
|  | ||||
|         fastmem_patch_info.emplace( | ||||
|             Common::BitCast<u64>(location), | ||||
| @@ -900,7 +616,7 @@ void A64EmitX64::EmitExclusiveReadMemoryInline(A64EmitContext& ctx, IR::Inst* in | ||||
|     } | ||||
|  | ||||
|     code.mov(tmp, Common::BitCast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id))); | ||||
|     EmitWriteMemoryMov<bitsize>(code, tmp, value_idx, false); | ||||
|     EmitWriteMemoryMov<bitsize>(code, tmp, value_idx); | ||||
|  | ||||
|     EmitExclusiveUnlock(code, conf, tmp, tmp2.cvt32()); | ||||
|  | ||||
| @@ -920,8 +636,6 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i | ||||
|     } | ||||
|  | ||||
|     auto args = ctx.reg_alloc.GetArgumentInfo(inst); | ||||
|     const IR::AccessType acctype = args[3].GetImmediateAccType(); | ||||
|     const bool ordered = acctype == IR::AccessType::ORDERED || acctype == IR::AccessType::ORDEREDRW || acctype == IR::AccessType::LIMITEDORDERED; | ||||
|  | ||||
|     const auto value = [&] { | ||||
|         if constexpr (bitsize == 128) { | ||||
| @@ -970,7 +684,7 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i | ||||
|             code.movq(rcx, xmm0); | ||||
|         } | ||||
|     } else { | ||||
|         EmitReadMemoryMov<bitsize>(code, rax.getIdx(), tmp, false); | ||||
|         EmitReadMemoryMov<bitsize>(code, rax.getIdx(), tmp); | ||||
|     } | ||||
|  | ||||
|     const auto fastmem_marker = ShouldFastmem(ctx, inst); | ||||
| @@ -1008,10 +722,6 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|  | ||||
|         code.setnz(status.cvt8()); | ||||
|  | ||||
|         code.SwitchToFarCode(); | ||||
| @@ -1027,10 +737,6 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i | ||||
|                 conf.recompile_on_exclusive_fastmem_failure, | ||||
|             }); | ||||
|  | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|  | ||||
|         code.cmp(al, 0); | ||||
|         code.setz(status.cvt8()); | ||||
|         code.movzx(status.cvt32(), status.cvt8()); | ||||
| @@ -1038,9 +744,6 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i | ||||
|         code.SwitchToNearCode(); | ||||
|     } else { | ||||
|         code.call(fallback_fn); | ||||
|         if (ordered) { | ||||
|             code.mfence(); | ||||
|         } | ||||
|         code.cmp(al, 0); | ||||
|         code.setz(status.cvt8()); | ||||
|         code.movzx(status.cvt32(), status.cvt8()); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  | ||||
| #include <xbyak/xbyak.h> | ||||
|  | ||||
| #include "dynarmic/backend/x64/a32_emit_x64.h" | ||||
| #include "dynarmic/backend/x64/a64_emit_x64.h" | ||||
| #include "dynarmic/backend/x64/exclusive_monitor_friend.h" | ||||
| #include "dynarmic/common/spin_lock_x64.h" | ||||
| @@ -16,6 +17,232 @@ namespace { | ||||
|  | ||||
| using namespace Xbyak::util; | ||||
|  | ||||
| constexpr size_t page_bits = 12; | ||||
| constexpr size_t page_size = 1 << page_bits; | ||||
| constexpr size_t page_mask = (1 << page_bits) - 1; | ||||
|  | ||||
| template<typename EmitContext> | ||||
| void EmitDetectMisalignedVAddr(BlockOfCode& code, EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr, Xbyak::Reg64 tmp) { | ||||
|     if (bitsize == 8 || (ctx.conf.detect_misaligned_access_via_page_table & bitsize) == 0) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const u32 align_mask = [bitsize]() -> u32 { | ||||
|         switch (bitsize) { | ||||
|         case 16: | ||||
|             return 0b1; | ||||
|         case 32: | ||||
|             return 0b11; | ||||
|         case 64: | ||||
|             return 0b111; | ||||
|         case 128: | ||||
|             return 0b1111; | ||||
|         default: | ||||
|             UNREACHABLE(); | ||||
|         } | ||||
|     }(); | ||||
|  | ||||
|     code.test(vaddr, align_mask); | ||||
|  | ||||
|     if (!ctx.conf.only_detect_misalignment_via_page_table_on_page_boundary) { | ||||
|         code.jnz(abort, code.T_NEAR); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const u32 page_align_mask = static_cast<u32>(page_size - 1) & ~align_mask; | ||||
|  | ||||
|     Xbyak::Label detect_boundary, resume; | ||||
|  | ||||
|     code.jnz(detect_boundary, code.T_NEAR); | ||||
|     code.L(resume); | ||||
|  | ||||
|     code.SwitchToFarCode(); | ||||
|     code.L(detect_boundary); | ||||
|     code.mov(tmp, vaddr); | ||||
|     code.and_(tmp, page_align_mask); | ||||
|     code.cmp(tmp, page_align_mask); | ||||
|     code.jne(resume, code.T_NEAR); | ||||
|     // NOTE: We expect to fallthrough into abort code here. | ||||
|     code.SwitchToNearCode(); | ||||
| } | ||||
|  | ||||
| template<typename EmitContext> | ||||
| Xbyak::RegExp EmitVAddrLookup(BlockOfCode& code, EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr); | ||||
|  | ||||
| template<> | ||||
| [[maybe_unused]] Xbyak::RegExp EmitVAddrLookup<A32EmitContext>(BlockOfCode& code, A32EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr) { | ||||
|     const Xbyak::Reg64 page = ctx.reg_alloc.ScratchGpr(); | ||||
|     const Xbyak::Reg32 tmp = ctx.conf.absolute_offset_page_table ? page.cvt32() : ctx.reg_alloc.ScratchGpr().cvt32(); | ||||
|  | ||||
|     EmitDetectMisalignedVAddr(code, ctx, bitsize, abort, vaddr, tmp.cvt64()); | ||||
|  | ||||
|     // TODO: This code assumes vaddr has been zext from 32-bits to 64-bits. | ||||
|  | ||||
|     code.mov(tmp, vaddr.cvt32()); | ||||
|     code.shr(tmp, static_cast<int>(page_bits)); | ||||
|  | ||||
|     code.mov(page, qword[r14 + tmp.cvt64() * sizeof(void*)]); | ||||
|     if (ctx.conf.page_table_pointer_mask_bits == 0) { | ||||
|         code.test(page, page); | ||||
|     } else { | ||||
|         code.and_(page, ~u32(0) << ctx.conf.page_table_pointer_mask_bits); | ||||
|     } | ||||
|     code.jz(abort, code.T_NEAR); | ||||
|     if (ctx.conf.absolute_offset_page_table) { | ||||
|         return page + vaddr; | ||||
|     } | ||||
|     code.mov(tmp, vaddr.cvt32()); | ||||
|     code.and_(tmp, static_cast<u32>(page_mask)); | ||||
|     return page + tmp.cvt64(); | ||||
| } | ||||
|  | ||||
| template<> | ||||
| [[maybe_unused]] Xbyak::RegExp EmitVAddrLookup<A64EmitContext>(BlockOfCode& code, A64EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr) { | ||||
|     const size_t valid_page_index_bits = ctx.conf.page_table_address_space_bits - page_bits; | ||||
|     const size_t unused_top_bits = 64 - ctx.conf.page_table_address_space_bits; | ||||
|  | ||||
|     const Xbyak::Reg64 page = ctx.reg_alloc.ScratchGpr(); | ||||
|     const Xbyak::Reg64 tmp = ctx.conf.absolute_offset_page_table ? page : ctx.reg_alloc.ScratchGpr(); | ||||
|  | ||||
|     EmitDetectMisalignedVAddr(code, ctx, bitsize, abort, vaddr, tmp); | ||||
|  | ||||
|     if (unused_top_bits == 0) { | ||||
|         code.mov(tmp, vaddr); | ||||
|         code.shr(tmp, int(page_bits)); | ||||
|     } else if (ctx.conf.silently_mirror_page_table) { | ||||
|         if (valid_page_index_bits >= 32) { | ||||
|             if (code.HasHostFeature(HostFeature::BMI2)) { | ||||
|                 const Xbyak::Reg64 bit_count = ctx.reg_alloc.ScratchGpr(); | ||||
|                 code.mov(bit_count, unused_top_bits); | ||||
|                 code.bzhi(tmp, vaddr, bit_count); | ||||
|                 code.shr(tmp, int(page_bits)); | ||||
|                 ctx.reg_alloc.Release(bit_count); | ||||
|             } else { | ||||
|                 code.mov(tmp, vaddr); | ||||
|                 code.shl(tmp, int(unused_top_bits)); | ||||
|                 code.shr(tmp, int(unused_top_bits + page_bits)); | ||||
|             } | ||||
|         } else { | ||||
|             code.mov(tmp, vaddr); | ||||
|             code.shr(tmp, int(page_bits)); | ||||
|             code.and_(tmp, u32((1 << valid_page_index_bits) - 1)); | ||||
|         } | ||||
|     } else { | ||||
|         ASSERT(valid_page_index_bits < 32); | ||||
|         code.mov(tmp, vaddr); | ||||
|         code.shr(tmp, int(page_bits)); | ||||
|         code.test(tmp, u32(-(1 << valid_page_index_bits))); | ||||
|         code.jnz(abort, code.T_NEAR); | ||||
|     } | ||||
|     code.mov(page, qword[r14 + tmp * sizeof(void*)]); | ||||
|     if (ctx.conf.page_table_pointer_mask_bits == 0) { | ||||
|         code.test(page, page); | ||||
|     } else { | ||||
|         code.and_(page, ~u32(0) << ctx.conf.page_table_pointer_mask_bits); | ||||
|     } | ||||
|     code.jz(abort, code.T_NEAR); | ||||
|     if (ctx.conf.absolute_offset_page_table) { | ||||
|         return page + vaddr; | ||||
|     } | ||||
|     code.mov(tmp, vaddr); | ||||
|     code.and_(tmp, static_cast<u32>(page_mask)); | ||||
|     return page + tmp; | ||||
| } | ||||
|  | ||||
| template<typename EmitContext> | ||||
| Xbyak::RegExp EmitFastmemVAddr(BlockOfCode& code, EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr, bool& require_abort_handling, std::optional<Xbyak::Reg64> tmp = std::nullopt); | ||||
|  | ||||
| template<> | ||||
| [[maybe_unused]] Xbyak::RegExp EmitFastmemVAddr<A32EmitContext>(BlockOfCode&, A32EmitContext&, Xbyak::Label&, Xbyak::Reg64 vaddr, bool&, std::optional<Xbyak::Reg64>) { | ||||
|     return r13 + vaddr; | ||||
| } | ||||
|  | ||||
| template<> | ||||
| [[maybe_unused]] Xbyak::RegExp EmitFastmemVAddr<A64EmitContext>(BlockOfCode& code, A64EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr, bool& require_abort_handling, std::optional<Xbyak::Reg64> tmp) { | ||||
|     const size_t unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits; | ||||
|  | ||||
|     if (unused_top_bits == 0) { | ||||
|         return r13 + vaddr; | ||||
|     } else if (ctx.conf.silently_mirror_fastmem) { | ||||
|         if (!tmp) { | ||||
|             tmp = ctx.reg_alloc.ScratchGpr(); | ||||
|         } | ||||
|         if (unused_top_bits < 32) { | ||||
|             code.mov(*tmp, vaddr); | ||||
|             code.shl(*tmp, int(unused_top_bits)); | ||||
|             code.shr(*tmp, int(unused_top_bits)); | ||||
|         } else if (unused_top_bits == 32) { | ||||
|             code.mov(tmp->cvt32(), vaddr.cvt32()); | ||||
|         } else { | ||||
|             code.mov(tmp->cvt32(), vaddr.cvt32()); | ||||
|             code.and_(*tmp, u32((1 << ctx.conf.fastmem_address_space_bits) - 1)); | ||||
|         } | ||||
|         return r13 + *tmp; | ||||
|     } else { | ||||
|         if (ctx.conf.fastmem_address_space_bits < 32) { | ||||
|             code.test(vaddr, u32(-(1 << ctx.conf.fastmem_address_space_bits))); | ||||
|             code.jnz(abort, code.T_NEAR); | ||||
|             require_abort_handling = true; | ||||
|         } else { | ||||
|             // TODO: Consider having TEST as above but coalesce 64-bit constant in register allocator | ||||
|             if (!tmp) { | ||||
|                 tmp = ctx.reg_alloc.ScratchGpr(); | ||||
|             } | ||||
|             code.mov(*tmp, vaddr); | ||||
|             code.shr(*tmp, int(ctx.conf.fastmem_address_space_bits)); | ||||
|             code.jnz(abort, code.T_NEAR); | ||||
|             require_abort_handling = true; | ||||
|         } | ||||
|         return r13 + vaddr; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<std::size_t bitsize> | ||||
| void EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::RegExp& addr) { | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         code.movzx(Xbyak::Reg32{value_idx}, code.byte[addr]); | ||||
|         return; | ||||
|     case 16: | ||||
|         code.movzx(Xbyak::Reg32{value_idx}, word[addr]); | ||||
|         return; | ||||
|     case 32: | ||||
|         code.mov(Xbyak::Reg32{value_idx}, dword[addr]); | ||||
|         return; | ||||
|     case 64: | ||||
|         code.mov(Xbyak::Reg64{value_idx}, qword[addr]); | ||||
|         return; | ||||
|     case 128: | ||||
|         code.movups(Xbyak::Xmm{value_idx}, xword[addr]); | ||||
|         return; | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bitsize"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<std::size_t bitsize> | ||||
| void EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int value_idx) { | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         code.mov(code.byte[addr], Xbyak::Reg64{value_idx}.cvt8()); | ||||
|         return; | ||||
|     case 16: | ||||
|         code.mov(word[addr], Xbyak::Reg16{value_idx}); | ||||
|         return; | ||||
|     case 32: | ||||
|         code.mov(dword[addr], Xbyak::Reg32{value_idx}); | ||||
|         return; | ||||
|     case 64: | ||||
|         code.mov(qword[addr], Xbyak::Reg64{value_idx}); | ||||
|         return; | ||||
|     case 128: | ||||
|         code.movups(xword[addr], Xbyak::Xmm{value_idx}); | ||||
|         return; | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bitsize"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<typename UserConfig> | ||||
| void EmitExclusiveLock(BlockOfCode& code, const UserConfig& conf, Xbyak::Reg64 pointer, Xbyak::Reg32 tmp) { | ||||
|     if (conf.HasOptimization(OptimizationFlag::Unsafe_IgnoreGlobalMonitor)) { | ||||
|   | ||||
| @@ -42,6 +42,7 @@ static size_t GetBitWidth(IR::Type type) { | ||||
|     case IR::Type::Cond: | ||||
|     case IR::Type::Void: | ||||
|     case IR::Type::Table: | ||||
|     case IR::Type::AccType: | ||||
|         ASSERT_FALSE("Type {} cannot be represented at runtime", type); | ||||
|     case IR::Type::Opaque: | ||||
|         ASSERT_FALSE("Not a concrete type"); | ||||
| @@ -207,11 +208,6 @@ IR::Cond Argument::GetImmediateCond() const { | ||||
|     return value.GetCond(); | ||||
| } | ||||
|  | ||||
| IR::AccessType Argument::GetImmediateAccType() const { | ||||
|     ASSERT(IsImmediate() && GetType() == IR::Type::AccessType); | ||||
|     return value.GetAccType(); | ||||
| } | ||||
|  | ||||
| bool Argument::IsInGpr() const { | ||||
|     if (IsImmediate()) | ||||
|         return false; | ||||
|   | ||||
| @@ -75,7 +75,6 @@ public: | ||||
|     u64 GetImmediateS32() const; | ||||
|     u64 GetImmediateU64() const; | ||||
|     IR::Cond GetImmediateCond() const; | ||||
|     IR::AccessType GetImmediateAccType() const; | ||||
|  | ||||
|     /// Is this value currently in a GPR? | ||||
|     bool IsInGpr() const; | ||||
|   | ||||
| @@ -229,55 +229,55 @@ void IREmitter::ClearExclusive() { | ||||
|     Inst(Opcode::A32ClearExclusive); | ||||
| } | ||||
|  | ||||
| IR::UAny IREmitter::ReadMemory(size_t bitsize, const IR::U32& vaddr) { | ||||
| IR::UAny IREmitter::ReadMemory(size_t bitsize, const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         return ReadMemory8(vaddr); | ||||
|         return ReadMemory8(vaddr, acc_type); | ||||
|     case 16: | ||||
|         return ReadMemory16(vaddr); | ||||
|         return ReadMemory16(vaddr, acc_type); | ||||
|     case 32: | ||||
|         return ReadMemory32(vaddr); | ||||
|         return ReadMemory32(vaddr, acc_type); | ||||
|     case 64: | ||||
|         return ReadMemory64(vaddr); | ||||
|         return ReadMemory64(vaddr, acc_type); | ||||
|     } | ||||
|     ASSERT_FALSE("Invalid bitsize"); | ||||
| } | ||||
|  | ||||
| IR::U8 IREmitter::ReadMemory8(const IR::U32& vaddr) { | ||||
|     return Inst<IR::U8>(Opcode::A32ReadMemory8, vaddr); | ||||
| IR::U8 IREmitter::ReadMemory8(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U8>(Opcode::A32ReadMemory8, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U16 IREmitter::ReadMemory16(const IR::U32& vaddr) { | ||||
|     const auto value = Inst<IR::U16>(Opcode::A32ReadMemory16, vaddr); | ||||
| IR::U16 IREmitter::ReadMemory16(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     const auto value = Inst<IR::U16>(Opcode::A32ReadMemory16, vaddr, IR::Value{acc_type}); | ||||
|     return current_location.EFlag() ? ByteReverseHalf(value) : value; | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ReadMemory32(const IR::U32& vaddr) { | ||||
|     const auto value = Inst<IR::U32>(Opcode::A32ReadMemory32, vaddr); | ||||
| IR::U32 IREmitter::ReadMemory32(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     const auto value = Inst<IR::U32>(Opcode::A32ReadMemory32, vaddr, IR::Value{acc_type}); | ||||
|     return current_location.EFlag() ? ByteReverseWord(value) : value; | ||||
| } | ||||
|  | ||||
| IR::U64 IREmitter::ReadMemory64(const IR::U32& vaddr) { | ||||
|     const auto value = Inst<IR::U64>(Opcode::A32ReadMemory64, vaddr); | ||||
| IR::U64 IREmitter::ReadMemory64(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     const auto value = Inst<IR::U64>(Opcode::A32ReadMemory64, vaddr, IR::Value{acc_type}); | ||||
|     return current_location.EFlag() ? ByteReverseDual(value) : value; | ||||
| } | ||||
|  | ||||
| IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U32& vaddr) { | ||||
|     return Inst<IR::U8>(Opcode::A32ExclusiveReadMemory8, vaddr); | ||||
| IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U8>(Opcode::A32ExclusiveReadMemory8, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U32& vaddr) { | ||||
|     const auto value = Inst<IR::U16>(Opcode::A32ExclusiveReadMemory16, vaddr); | ||||
| IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     const auto value = Inst<IR::U16>(Opcode::A32ExclusiveReadMemory16, vaddr, IR::Value{acc_type}); | ||||
|     return current_location.EFlag() ? ByteReverseHalf(value) : value; | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U32& vaddr) { | ||||
|     const auto value = Inst<IR::U32>(Opcode::A32ExclusiveReadMemory32, vaddr); | ||||
| IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     const auto value = Inst<IR::U32>(Opcode::A32ExclusiveReadMemory32, vaddr, IR::Value{acc_type}); | ||||
|     return current_location.EFlag() ? ByteReverseWord(value) : value; | ||||
| } | ||||
|  | ||||
| std::pair<IR::U32, IR::U32> IREmitter::ExclusiveReadMemory64(const IR::U32& vaddr) { | ||||
|     const auto value = Inst<IR::U64>(Opcode::A32ExclusiveReadMemory64, vaddr); | ||||
| std::pair<IR::U32, IR::U32> IREmitter::ExclusiveReadMemory64(const IR::U32& vaddr, IR::AccType acc_type) { | ||||
|     const auto value = Inst<IR::U64>(Opcode::A32ExclusiveReadMemory64, vaddr, IR::Value{acc_type}); | ||||
|     const auto lo = LeastSignificantWord(value); | ||||
|     const auto hi = MostSignificantWord(value).result; | ||||
|     if (current_location.EFlag()) { | ||||
| @@ -287,80 +287,80 @@ std::pair<IR::U32, IR::U32> IREmitter::ExclusiveReadMemory64(const IR::U32& vadd | ||||
|     return std::make_pair(lo, hi); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny& value) { | ||||
| void IREmitter::WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny& value, IR::AccType acc_type) { | ||||
|     switch (bitsize) { | ||||
|     case 8: | ||||
|         return WriteMemory8(vaddr, value); | ||||
|         return WriteMemory8(vaddr, value, acc_type); | ||||
|     case 16: | ||||
|         return WriteMemory16(vaddr, value); | ||||
|         return WriteMemory16(vaddr, value, acc_type); | ||||
|     case 32: | ||||
|         return WriteMemory32(vaddr, value); | ||||
|         return WriteMemory32(vaddr, value, acc_type); | ||||
|     case 64: | ||||
|         return WriteMemory64(vaddr, value); | ||||
|         return WriteMemory64(vaddr, value, acc_type); | ||||
|     } | ||||
|     ASSERT_FALSE("Invalid bitsize"); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory8(const IR::U32& vaddr, const IR::U8& value) { | ||||
|     Inst(Opcode::A32WriteMemory8, vaddr, value); | ||||
| void IREmitter::WriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type) { | ||||
|     Inst(Opcode::A32WriteMemory8, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory16(const IR::U32& vaddr, const IR::U16& value) { | ||||
| void IREmitter::WriteMemory16(const IR::U32& vaddr, const IR::U16& value, IR::AccType acc_type) { | ||||
|     if (current_location.EFlag()) { | ||||
|         const auto v = ByteReverseHalf(value); | ||||
|         Inst(Opcode::A32WriteMemory16, vaddr, v); | ||||
|         Inst(Opcode::A32WriteMemory16, vaddr, v, IR::Value{acc_type}); | ||||
|     } else { | ||||
|         Inst(Opcode::A32WriteMemory16, vaddr, value); | ||||
|         Inst(Opcode::A32WriteMemory16, vaddr, value, IR::Value{acc_type}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory32(const IR::U32& vaddr, const IR::U32& value) { | ||||
| void IREmitter::WriteMemory32(const IR::U32& vaddr, const IR::U32& value, IR::AccType acc_type) { | ||||
|     if (current_location.EFlag()) { | ||||
|         const auto v = ByteReverseWord(value); | ||||
|         Inst(Opcode::A32WriteMemory32, vaddr, v); | ||||
|         Inst(Opcode::A32WriteMemory32, vaddr, v, IR::Value{acc_type}); | ||||
|     } else { | ||||
|         Inst(Opcode::A32WriteMemory32, vaddr, value); | ||||
|         Inst(Opcode::A32WriteMemory32, vaddr, value, IR::Value{acc_type}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory64(const IR::U32& vaddr, const IR::U64& value) { | ||||
| void IREmitter::WriteMemory64(const IR::U32& vaddr, const IR::U64& value, IR::AccType acc_type) { | ||||
|     if (current_location.EFlag()) { | ||||
|         const auto v = ByteReverseDual(value); | ||||
|         Inst(Opcode::A32WriteMemory64, vaddr, v); | ||||
|         Inst(Opcode::A32WriteMemory64, vaddr, v, IR::Value{acc_type}); | ||||
|     } else { | ||||
|         Inst(Opcode::A32WriteMemory64, vaddr, value); | ||||
|         Inst(Opcode::A32WriteMemory64, vaddr, value, IR::Value{acc_type}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value) { | ||||
|     return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory8, vaddr, value); | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory8, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U32& vaddr, const IR::U16& value) { | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U32& vaddr, const IR::U16& value, IR::AccType acc_type) { | ||||
|     if (current_location.EFlag()) { | ||||
|         const auto v = ByteReverseHalf(value); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, v); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, v, IR::Value{acc_type}); | ||||
|     } else { | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, value); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory16, vaddr, value, IR::Value{acc_type}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U32& vaddr, const IR::U32& value) { | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U32& vaddr, const IR::U32& value, IR::AccType acc_type) { | ||||
|     if (current_location.EFlag()) { | ||||
|         const auto v = ByteReverseWord(value); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, v); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, v, IR::Value{acc_type}); | ||||
|     } else { | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, value); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory32, vaddr, value, IR::Value{acc_type}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U32& vaddr, const IR::U32& value_lo, const IR::U32& value_hi) { | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U32& vaddr, const IR::U32& value_lo, const IR::U32& value_hi, IR::AccType acc_type) { | ||||
|     if (current_location.EFlag()) { | ||||
|         const auto vlo = ByteReverseWord(value_lo); | ||||
|         const auto vhi = ByteReverseWord(value_hi); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(vlo, vhi)); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(vlo, vhi), IR::Value{acc_type}); | ||||
|     } else { | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(value_lo, value_hi)); | ||||
|         return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(value_lo, value_hi), IR::Value{acc_type}); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -80,24 +80,24 @@ public: | ||||
|     void SetFpscrNZCV(const IR::NZCV& new_fpscr_nzcv); | ||||
|  | ||||
|     void ClearExclusive(); | ||||
|     IR::UAny ReadMemory(size_t bitsize, const IR::U32& vaddr); | ||||
|     IR::U8 ReadMemory8(const IR::U32& vaddr); | ||||
|     IR::U16 ReadMemory16(const IR::U32& vaddr); | ||||
|     IR::U32 ReadMemory32(const IR::U32& vaddr); | ||||
|     IR::U64 ReadMemory64(const IR::U32& vaddr); | ||||
|     IR::U8 ExclusiveReadMemory8(const IR::U32& vaddr); | ||||
|     IR::U16 ExclusiveReadMemory16(const IR::U32& vaddr); | ||||
|     IR::U32 ExclusiveReadMemory32(const IR::U32& vaddr); | ||||
|     std::pair<IR::U32, IR::U32> ExclusiveReadMemory64(const IR::U32& vaddr); | ||||
|     void WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny& value); | ||||
|     void WriteMemory8(const IR::U32& vaddr, const IR::U8& value); | ||||
|     void WriteMemory16(const IR::U32& vaddr, const IR::U16& value); | ||||
|     void WriteMemory32(const IR::U32& vaddr, const IR::U32& value); | ||||
|     void WriteMemory64(const IR::U32& vaddr, const IR::U64& value); | ||||
|     IR::U32 ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value); | ||||
|     IR::U32 ExclusiveWriteMemory16(const IR::U32& vaddr, const IR::U16& value); | ||||
|     IR::U32 ExclusiveWriteMemory32(const IR::U32& vaddr, const IR::U32& value); | ||||
|     IR::U32 ExclusiveWriteMemory64(const IR::U32& vaddr, const IR::U32& value_lo, const IR::U32& value_hi); | ||||
|     IR::UAny ReadMemory(size_t bitsize, const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     IR::U8 ReadMemory8(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     IR::U16 ReadMemory16(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     IR::U32 ReadMemory32(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     IR::U64 ReadMemory64(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     IR::U8 ExclusiveReadMemory8(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     IR::U16 ExclusiveReadMemory16(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveReadMemory32(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     std::pair<IR::U32, IR::U32> ExclusiveReadMemory64(const IR::U32& vaddr, IR::AccType acc_type); | ||||
|     void WriteMemory(size_t bitsize, const IR::U32& vaddr, const IR::UAny& value, IR::AccType acc_type); | ||||
|     void WriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type); | ||||
|     void WriteMemory16(const IR::U32& vaddr, const IR::U16& value, IR::AccType acc_type); | ||||
|     void WriteMemory32(const IR::U32& vaddr, const IR::U32& value, IR::AccType acc_type); | ||||
|     void WriteMemory64(const IR::U32& vaddr, const IR::U64& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory16(const IR::U32& vaddr, const IR::U16& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory32(const IR::U32& vaddr, const IR::U32& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory64(const IR::U32& vaddr, const IR::U32& value_lo, const IR::U32& value_hi, IR::AccType acc_type); | ||||
|  | ||||
|     void CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, size_t opc2); | ||||
|     void CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, CoprocReg CRn, CoprocReg CRm, size_t opc2, const IR::U32& word); | ||||
|   | ||||
| @@ -103,7 +103,7 @@ bool TranslatorVisitor::v8_VST_multiple(bool D, Reg n, size_t Vd, Imm<4> type, s | ||||
|                 const ExtReg ext_reg = d + i * inc + r; | ||||
|                 const IR::U64 shifted_element = ir.LogicalShiftRight(ir.GetExtendedRegister(ext_reg), ir.Imm8(static_cast<u8>(e * ebytes * 8))); | ||||
|                 const IR::UAny element = ir.LeastSignificant(8 * ebytes, shifted_element); | ||||
|                 ir.WriteMemory(8 * ebytes, address, element); | ||||
|                 ir.WriteMemory(8 * ebytes, address, element, IR::AccType::NORMAL); | ||||
|  | ||||
|                 address = ir.Add(address, ir.Imm32(static_cast<u32>(ebytes))); | ||||
|             } | ||||
| @@ -156,7 +156,7 @@ bool TranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, s | ||||
|     for (size_t r = 0; r < regs; r++) { | ||||
|         for (size_t e = 0; e < elements; e++) { | ||||
|             for (size_t i = 0; i < nelem; i++) { | ||||
|                 const IR::U64 element = ir.ZeroExtendToLong(ir.ReadMemory(ebytes * 8, address)); | ||||
|                 const IR::U64 element = ir.ZeroExtendToLong(ir.ReadMemory(ebytes * 8, address, IR::AccType::NORMAL)); | ||||
|                 const IR::U64 shifted_element = ir.LogicalShiftLeft(element, ir.Imm8(static_cast<u8>(e * ebytes * 8))); | ||||
|  | ||||
|                 const ExtReg ext_reg = d + i * inc + r; | ||||
| @@ -221,7 +221,7 @@ bool TranslatorVisitor::v8_VLD_all_lanes(bool D, Reg n, size_t Vd, size_t nn, si | ||||
|  | ||||
|     auto address = ir.GetRegister(n); | ||||
|     for (size_t i = 0; i < nelem; i++) { | ||||
|         const auto element = ir.ReadMemory(ebytes * 8, address); | ||||
|         const auto element = ir.ReadMemory(ebytes * 8, address, IR::AccType::NORMAL); | ||||
|         const auto replicated_element = ir.VectorBroadcast(ebytes * 8, element); | ||||
|  | ||||
|         for (size_t r = 0; r < regs; r++) { | ||||
| @@ -291,7 +291,7 @@ bool TranslatorVisitor::v8_VST_single(bool D, Reg n, size_t Vd, size_t sz, size_ | ||||
|         const ExtReg ext_reg = d + i * inc; | ||||
|         const auto element = ir.VectorGetElement(ebytes * 8, ir.GetVector(ext_reg), index); | ||||
|  | ||||
|         ir.WriteMemory(ebytes * 8, address, element); | ||||
|         ir.WriteMemory(ebytes * 8, address, element, IR::AccType::NORMAL); | ||||
|  | ||||
|         address = ir.Add(address, ir.Imm32(static_cast<u32>(ebytes))); | ||||
|     } | ||||
| @@ -352,7 +352,7 @@ bool TranslatorVisitor::v8_VLD_single(bool D, Reg n, size_t Vd, size_t sz, size_ | ||||
|  | ||||
|     auto address = ir.GetRegister(n); | ||||
|     for (size_t i = 0; i < nelem; i++) { | ||||
|         const auto element = ir.ReadMemory(ebytes * 8, address); | ||||
|         const auto element = ir.ReadMemory(ebytes * 8, address, IR::AccType::NORMAL); | ||||
|  | ||||
|         const ExtReg ext_reg = d + i * inc; | ||||
|         const auto new_reg = ir.VectorSetElement(ebytes * 8, ir.GetVector(ext_reg), index, element); | ||||
|   | ||||
| @@ -71,7 +71,7 @@ bool TranslatorVisitor::arm_LDR_lit(Cond cond, bool U, Reg t, Imm<12> imm12) { | ||||
|     const bool add = U; | ||||
|     const u32 base = ir.AlignPC(4); | ||||
|     const u32 address = add ? (base + imm12.ZeroExtend()) : (base - imm12.ZeroExtend()); | ||||
|     const auto data = ir.ReadMemory32(ir.Imm32(address)); | ||||
|     const auto data = ir.ReadMemory32(ir.Imm32(address), IR::AccType::NORMAL); | ||||
|  | ||||
|     if (t == Reg::PC) { | ||||
|         ir.LoadWritePC(data); | ||||
| @@ -102,7 +102,7 @@ bool TranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re | ||||
|     const u32 imm32 = imm12.ZeroExtend(); | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.ReadMemory32(address); | ||||
|     const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     if (t == Reg::PC) { | ||||
|         ir.LoadWritePC(data); | ||||
| @@ -138,7 +138,7 @@ bool TranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Re | ||||
|  | ||||
|     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result; | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.ReadMemory32(address); | ||||
|     const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     if (t == Reg::PC) { | ||||
|         ir.LoadWritePC(data); | ||||
| @@ -164,7 +164,7 @@ bool TranslatorVisitor::arm_LDRB_lit(Cond cond, bool U, Reg t, Imm<12> imm12) { | ||||
|     const bool add = U; | ||||
|     const u32 base = ir.AlignPC(4); | ||||
|     const u32 address = add ? (base + imm32) : (base - imm32); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(ir.Imm32(address))); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -193,7 +193,7 @@ bool TranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|     const u32 imm32 = imm12.ZeroExtend(); | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address)); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -217,7 +217,7 @@ bool TranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|  | ||||
|     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result; | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address)); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -243,11 +243,17 @@ bool TranslatorVisitor::arm_LDRD_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm | ||||
|  | ||||
|     const u32 base = ir.AlignPC(4); | ||||
|     const u32 address = add ? (base + imm32) : (base - imm32); | ||||
|     const auto data_a = ir.ReadMemory32(ir.Imm32(address)); | ||||
|     const auto data_b = ir.ReadMemory32(ir.Imm32(address + 4)); | ||||
|  | ||||
|     ir.SetRegister(t, data_a); | ||||
|     ir.SetRegister(t2, data_b); | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     const IR::U64 data = ir.ReadMemory64(ir.Imm32(address), IR::AccType::ATOMIC); | ||||
|  | ||||
|     if (ir.current_location.EFlag()) { | ||||
|         ir.SetRegister(t, ir.MostSignificantWord(data).result); | ||||
|         ir.SetRegister(t2, ir.LeastSignificantWord(data)); | ||||
|     } else { | ||||
|         ir.SetRegister(t, ir.LeastSignificantWord(data)); | ||||
|         ir.SetRegister(t2, ir.MostSignificantWord(data).result); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -282,13 +288,18 @@ bool TranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend(); | ||||
|  | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address_a = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto address_b = ir.Add(address_a, ir.Imm32(4)); | ||||
|     const auto data_a = ir.ReadMemory32(address_a); | ||||
|     const auto data_b = ir.ReadMemory32(address_b); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|  | ||||
|     ir.SetRegister(t, data_a); | ||||
|     ir.SetRegister(t2, data_b); | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     const IR::U64 data = ir.ReadMemory64(address, IR::AccType::ATOMIC); | ||||
|  | ||||
|     if (ir.current_location.EFlag()) { | ||||
|         ir.SetRegister(t, ir.MostSignificantWord(data).result); | ||||
|         ir.SetRegister(t2, ir.LeastSignificantWord(data)); | ||||
|     } else { | ||||
|         ir.SetRegister(t, ir.LeastSignificantWord(data)); | ||||
|         ir.SetRegister(t2, ir.MostSignificantWord(data).result); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -317,13 +328,18 @@ bool TranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|  | ||||
|     const Reg t2 = t + 1; | ||||
|     const auto offset = ir.GetRegister(m); | ||||
|     const auto address_a = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto address_b = ir.Add(address_a, ir.Imm32(4)); | ||||
|     const auto data_a = ir.ReadMemory32(address_a); | ||||
|     const auto data_b = ir.ReadMemory32(address_b); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|  | ||||
|     ir.SetRegister(t, data_a); | ||||
|     ir.SetRegister(t2, data_b); | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     const IR::U64 data = ir.ReadMemory64(address, IR::AccType::ATOMIC); | ||||
|  | ||||
|     if (ir.current_location.EFlag()) { | ||||
|         ir.SetRegister(t, ir.MostSignificantWord(data).result); | ||||
|         ir.SetRegister(t2, ir.LeastSignificantWord(data)); | ||||
|     } else { | ||||
|         ir.SetRegister(t, ir.LeastSignificantWord(data)); | ||||
|         ir.SetRegister(t2, ir.MostSignificantWord(data).result); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -346,7 +362,7 @@ bool TranslatorVisitor::arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, I | ||||
|     const bool add = U; | ||||
|     const u32 base = ir.AlignPC(4); | ||||
|     const u32 address = add ? (base + imm32) : (base - imm32); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address))); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -375,7 +391,7 @@ bool TranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend(); | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -399,7 +415,7 @@ bool TranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|  | ||||
|     const auto offset = ir.GetRegister(m); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -420,7 +436,7 @@ bool TranslatorVisitor::arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Im | ||||
|  | ||||
|     const u32 base = ir.AlignPC(4); | ||||
|     const u32 address = add ? (base + imm32) : (base - imm32); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(ir.Imm32(address))); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -449,7 +465,7 @@ bool TranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, | ||||
|     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend(); | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address)); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -473,7 +489,7 @@ bool TranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, | ||||
|  | ||||
|     const auto offset = ir.GetRegister(m); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address)); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -493,7 +509,7 @@ bool TranslatorVisitor::arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Im | ||||
|     const bool add = U; | ||||
|     const u32 base = ir.AlignPC(4); | ||||
|     const u32 address = add ? (base + imm32) : (base - imm32); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address))); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -522,7 +538,7 @@ bool TranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, | ||||
|     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend(); | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address)); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -546,7 +562,7 @@ bool TranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, | ||||
|  | ||||
|     const auto offset = ir.GetRegister(m); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address)); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -565,7 +581,7 @@ bool TranslatorVisitor::arm_STR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re | ||||
|  | ||||
|     const auto offset = ir.Imm32(imm12.ZeroExtend()); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t)); | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -586,7 +602,7 @@ bool TranslatorVisitor::arm_STR_reg(Cond cond, bool P, bool U, bool W, Reg n, Re | ||||
|  | ||||
|     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result; | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t)); | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -607,7 +623,7 @@ bool TranslatorVisitor::arm_STRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|  | ||||
|     const auto offset = ir.Imm32(imm12.ZeroExtend()); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t))); | ||||
|     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -628,7 +644,7 @@ bool TranslatorVisitor::arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|  | ||||
|     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result; | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t))); | ||||
|     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -658,13 +674,15 @@ bool TranslatorVisitor::arm_STRD_imm(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|  | ||||
|     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend(); | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address_a = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto address_b = ir.Add(address_a, ir.Imm32(4)); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto value_a = ir.GetRegister(t); | ||||
|     const auto value_b = ir.GetRegister(t2); | ||||
|  | ||||
|     ir.WriteMemory32(address_a, value_a); | ||||
|     ir.WriteMemory32(address_b, value_b); | ||||
|     const IR::U64 data = ir.current_location.EFlag() ? ir.Pack2x32To1x64(value_b, value_a) | ||||
|                                                      : ir.Pack2x32To1x64(value_a, value_b); | ||||
|  | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     ir.WriteMemory64(address, data, IR::AccType::ATOMIC); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -693,13 +711,15 @@ bool TranslatorVisitor::arm_STRD_reg(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|     } | ||||
|  | ||||
|     const auto offset = ir.GetRegister(m); | ||||
|     const auto address_a = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto address_b = ir.Add(address_a, ir.Imm32(4)); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|     const auto value_a = ir.GetRegister(t); | ||||
|     const auto value_b = ir.GetRegister(t2); | ||||
|  | ||||
|     ir.WriteMemory32(address_a, value_a); | ||||
|     ir.WriteMemory32(address_b, value_b); | ||||
|     const IR::U64 data = ir.current_location.EFlag() ? ir.Pack2x32To1x64(value_b, value_a) | ||||
|                                                      : ir.Pack2x32To1x64(value_a, value_b); | ||||
|  | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     ir.WriteMemory64(address, data, IR::AccType::ATOMIC); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -722,7 +742,7 @@ bool TranslatorVisitor::arm_STRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|     const auto offset = ir.Imm32(imm32); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|  | ||||
|     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t))); | ||||
|     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -744,7 +764,7 @@ bool TranslatorVisitor::arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n, R | ||||
|     const auto offset = ir.GetRegister(m); | ||||
|     const auto address = GetAddress(ir, P, U, W, n, offset); | ||||
|  | ||||
|     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t))); | ||||
|     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -752,7 +772,7 @@ static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s | ||||
|     auto address = start_address; | ||||
|     for (size_t i = 0; i <= 14; i++) { | ||||
|         if (Common::Bit(i, list)) { | ||||
|             ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address)); | ||||
|             ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC)); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|     } | ||||
| @@ -760,7 +780,7 @@ static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s | ||||
|         ir.SetRegister(n, writeback_address); | ||||
|     } | ||||
|     if (Common::Bit<15>(list)) { | ||||
|         ir.LoadWritePC(ir.ReadMemory32(address)); | ||||
|         ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC)); | ||||
|         if (n == Reg::R13) | ||||
|             ir.SetTerm(IR::Term::PopRSBHint{}); | ||||
|         else | ||||
| @@ -854,7 +874,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s | ||||
|     auto address = start_address; | ||||
|     for (size_t i = 0; i <= 14; i++) { | ||||
|         if (Common::Bit(i, list)) { | ||||
|             ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i))); | ||||
|             ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|     } | ||||
| @@ -862,7 +882,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s | ||||
|         ir.SetRegister(n, writeback_address); | ||||
|     } | ||||
|     if (Common::Bit<15>(list)) { | ||||
|         ir.WriteMemory32(address, ir.Imm32(ir.PC())); | ||||
|         ir.WriteMemory32(address, ir.Imm32(ir.PC()), IR::AccType::ATOMIC); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|   | ||||
| @@ -24,8 +24,9 @@ bool TranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     const auto data = ir.ReadMemory32(ir.GetRegister(n)); | ||||
|     ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2)); | ||||
|     // TODO (HACK): Implement bus locking here | ||||
|     const auto data = ir.ReadMemory32(ir.GetRegister(n), IR::AccType::SWAP); | ||||
|     ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2), IR::AccType::SWAP); | ||||
|     // TODO: Alignment check | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -42,8 +43,9 @@ bool TranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     const auto data = ir.ReadMemory8(ir.GetRegister(n)); | ||||
|     ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2))); | ||||
|     // TODO (HACK): Implement bus locking here | ||||
|     const auto data = ir.ReadMemory8(ir.GetRegister(n), IR::AccType::SWAP); | ||||
|     ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2)), IR::AccType::SWAP); | ||||
|     // TODO: Alignment check | ||||
|     ir.SetRegister(t, ir.ZeroExtendByteToWord(data)); | ||||
|     return true; | ||||
| @@ -60,7 +62,7 @@ bool TranslatorVisitor::arm_LDA(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ReadMemory32(address));  // AccessType::Ordered | ||||
|     ir.SetRegister(t, ir.ReadMemory32(address, IR::AccType::ORDERED)); | ||||
|     return true; | ||||
| } | ||||
| // LDAB<c> <Rt>, [<Rn>] | ||||
| @@ -74,7 +76,7 @@ bool TranslatorVisitor::arm_LDAB(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory8(address)));  // AccessType::Ordered | ||||
|     ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory8(address, IR::AccType::ORDERED))); | ||||
|     return true; | ||||
| } | ||||
| // LDAH<c> <Rt>, [<Rn>] | ||||
| @@ -88,7 +90,7 @@ bool TranslatorVisitor::arm_LDAH(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory16(address)));  // AccessType::Ordered | ||||
|     ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory16(address, IR::AccType::ORDERED))); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -103,7 +105,7 @@ bool TranslatorVisitor::arm_LDAEX(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ExclusiveReadMemory32(address));  // AccessType::Ordered | ||||
|     ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ORDERED)); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -118,7 +120,7 @@ bool TranslatorVisitor::arm_LDAEXB(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address)));  // AccessType::Ordered | ||||
|     ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ORDERED))); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -133,7 +135,7 @@ bool TranslatorVisitor::arm_LDAEXD(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto [lo, hi] = ir.ExclusiveReadMemory64(address);  // AccessType::Ordered | ||||
|     const auto [lo, hi] = ir.ExclusiveReadMemory64(address, IR::AccType::ORDERED); | ||||
|     // DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR | ||||
|     ir.SetRegister(t, lo); | ||||
|     ir.SetRegister(t + 1, hi); | ||||
| @@ -151,7 +153,7 @@ bool TranslatorVisitor::arm_LDAEXH(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address)));  // AccessType::Ordered | ||||
|     ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ORDERED))); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -166,7 +168,7 @@ bool TranslatorVisitor::arm_STL(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t));  // AccessType::Ordered | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -181,7 +183,7 @@ bool TranslatorVisitor::arm_STLB(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)));  // AccessType::Ordered | ||||
|     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::ORDERED); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -196,7 +198,7 @@ bool TranslatorVisitor::arm_STLH(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)));  // AccessType::Ordered | ||||
|     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::ORDERED); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -216,7 +218,7 @@ bool TranslatorVisitor::arm_STLEXB(Cond cond, Reg n, Reg d, Reg t) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.LeastSignificantByte(ir.GetRegister(t)); | ||||
|     const auto passed = ir.ExclusiveWriteMemory8(address, value);  // AccessType::Ordered | ||||
|     const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ORDERED); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -238,7 +240,7 @@ bool TranslatorVisitor::arm_STLEXD(Cond cond, Reg n, Reg d, Reg t) { | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value_lo = ir.GetRegister(t); | ||||
|     const auto value_hi = ir.GetRegister(t2); | ||||
|     const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi);  // AccessType::Ordered | ||||
|     const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ORDERED); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -259,7 +261,7 @@ bool TranslatorVisitor::arm_STLEXH(Cond cond, Reg n, Reg d, Reg t) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.LeastSignificantHalf(ir.GetRegister(t)); | ||||
|     const auto passed = ir.ExclusiveWriteMemory16(address, value);  // AccessType::Ordered | ||||
|     const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ORDERED); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -280,7 +282,7 @@ bool TranslatorVisitor::arm_STLEX(Cond cond, Reg n, Reg d, Reg t) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.GetRegister(t); | ||||
|     const auto passed = ir.ExclusiveWriteMemory32(address, value); | ||||
|     const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ORDERED); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -296,7 +298,7 @@ bool TranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ExclusiveReadMemory32(address)); | ||||
|     ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC)); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -311,7 +313,7 @@ bool TranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address))); | ||||
|     ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC))); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -326,7 +328,7 @@ bool TranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto [lo, hi] = ir.ExclusiveReadMemory64(address); | ||||
|     const auto [lo, hi] = ir.ExclusiveReadMemory64(address, IR::AccType::ATOMIC); | ||||
|     // DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR | ||||
|     ir.SetRegister(t, lo); | ||||
|     ir.SetRegister(t + 1, hi); | ||||
| @@ -344,7 +346,7 @@ bool TranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address))); | ||||
|     ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC))); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -364,7 +366,7 @@ bool TranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg t) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.GetRegister(t); | ||||
|     const auto passed = ir.ExclusiveWriteMemory32(address, value); | ||||
|     const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -385,7 +387,7 @@ bool TranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg t) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.LeastSignificantByte(ir.GetRegister(t)); | ||||
|     const auto passed = ir.ExclusiveWriteMemory8(address, value); | ||||
|     const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -408,7 +410,7 @@ bool TranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg t) { | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value_lo = ir.GetRegister(t); | ||||
|     const auto value_hi = ir.GetRegister(t2); | ||||
|     const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi); | ||||
|     const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -429,7 +431,7 @@ bool TranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg t) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.LeastSignificantHalf(ir.GetRegister(t)); | ||||
|     const auto passed = ir.ExclusiveWriteMemory16(address, value); | ||||
|     const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
|   | ||||
| @@ -444,7 +444,7 @@ bool TranslatorVisitor::thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) { | ||||
| bool TranslatorVisitor::thumb16_LDR_literal(Reg t, Imm<8> imm8) { | ||||
|     const u32 imm32 = imm8.ZeroExtend() << 2; | ||||
|     const u32 address = ir.AlignPC(4) + imm32; | ||||
|     const auto data = ir.ReadMemory32(ir.Imm32(address)); | ||||
|     const auto data = ir.ReadMemory32(ir.Imm32(address), IR::AccType::NORMAL); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -456,7 +456,7 @@ bool TranslatorVisitor::thumb16_STR_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.GetRegister(t); | ||||
|  | ||||
|     ir.WriteMemory32(address, data); | ||||
|     ir.WriteMemory32(address, data, IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -466,7 +466,7 @@ bool TranslatorVisitor::thumb16_STRH_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.LeastSignificantHalf(ir.GetRegister(t)); | ||||
|  | ||||
|     ir.WriteMemory16(address, data); | ||||
|     ir.WriteMemory16(address, data, IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -476,7 +476,7 @@ bool TranslatorVisitor::thumb16_STRB_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.LeastSignificantByte(ir.GetRegister(t)); | ||||
|  | ||||
|     ir.WriteMemory8(address, data); | ||||
|     ir.WriteMemory8(address, data, IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -484,7 +484,7 @@ bool TranslatorVisitor::thumb16_STRB_reg(Reg m, Reg n, Reg t) { | ||||
| // Rt cannot encode R15. | ||||
| bool TranslatorVisitor::thumb16_LDRSB_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address)); | ||||
|     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -494,7 +494,7 @@ bool TranslatorVisitor::thumb16_LDRSB_reg(Reg m, Reg n, Reg t) { | ||||
| // Rt cannot encode R15. | ||||
| bool TranslatorVisitor::thumb16_LDR_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.ReadMemory32(address); | ||||
|     const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -504,7 +504,7 @@ bool TranslatorVisitor::thumb16_LDR_reg(Reg m, Reg n, Reg t) { | ||||
| // Rt cannot encode R15. | ||||
| bool TranslatorVisitor::thumb16_LDRH_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -514,7 +514,7 @@ bool TranslatorVisitor::thumb16_LDRH_reg(Reg m, Reg n, Reg t) { | ||||
| // Rt cannot encode R15. | ||||
| bool TranslatorVisitor::thumb16_LDRB_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address)); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -524,7 +524,7 @@ bool TranslatorVisitor::thumb16_LDRB_reg(Reg m, Reg n, Reg t) { | ||||
| // Rt cannot encode R15. | ||||
| bool TranslatorVisitor::thumb16_LDRSH_reg(Reg m, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m)); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address)); | ||||
|     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -537,7 +537,7 @@ bool TranslatorVisitor::thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.GetRegister(t); | ||||
|  | ||||
|     ir.WriteMemory32(address, data); | ||||
|     ir.WriteMemory32(address, data, IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -546,7 +546,7 @@ bool TranslatorVisitor::thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) { | ||||
| bool TranslatorVisitor::thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) { | ||||
|     const u32 imm32 = imm5.ZeroExtend() << 2; | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.ReadMemory32(address); | ||||
|     const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -559,7 +559,7 @@ bool TranslatorVisitor::thumb16_STRB_imm(Imm<5> imm5, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.LeastSignificantByte(ir.GetRegister(t)); | ||||
|  | ||||
|     ir.WriteMemory8(address, data); | ||||
|     ir.WriteMemory8(address, data, IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -568,7 +568,7 @@ bool TranslatorVisitor::thumb16_STRB_imm(Imm<5> imm5, Reg n, Reg t) { | ||||
| bool TranslatorVisitor::thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) { | ||||
|     const u32 imm32 = imm5.ZeroExtend(); | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address)); | ||||
|     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -580,7 +580,7 @@ bool TranslatorVisitor::thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.LeastSignificantHalf(ir.GetRegister(t)); | ||||
|  | ||||
|     ir.WriteMemory16(address, data); | ||||
|     ir.WriteMemory16(address, data, IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -588,7 +588,7 @@ bool TranslatorVisitor::thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) { | ||||
| bool TranslatorVisitor::thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) { | ||||
|     const u32 imm32 = imm5.ZeroExtend() << 1; | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); | ||||
|     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -602,7 +602,7 @@ bool TranslatorVisitor::thumb16_STR_imm_t2(Reg t, Imm<8> imm8) { | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.GetRegister(t); | ||||
|  | ||||
|     ir.WriteMemory32(address, data); | ||||
|     ir.WriteMemory32(address, data, IR::AccType::NORMAL); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -612,7 +612,7 @@ bool TranslatorVisitor::thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) { | ||||
|     const u32 imm32 = imm8.ZeroExtend() << 2; | ||||
|     const Reg n = Reg::SP; | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32)); | ||||
|     const auto data = ir.ReadMemory32(address); | ||||
|     const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -766,7 +766,7 @@ bool TranslatorVisitor::thumb16_PUSH(bool M, RegList reg_list) { | ||||
|         if (Common::Bit(i, reg_list)) { | ||||
|             // TODO: Deal with alignment | ||||
|             const auto Ri = ir.GetRegister(static_cast<Reg>(i)); | ||||
|             ir.WriteMemory32(address, Ri); | ||||
|             ir.WriteMemory32(address, Ri, IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|     } | ||||
| @@ -789,7 +789,7 @@ bool TranslatorVisitor::thumb16_POP(bool P, RegList reg_list) { | ||||
|     for (size_t i = 0; i < 15; i++) { | ||||
|         if (Common::Bit(i, reg_list)) { | ||||
|             // TODO: Deal with alignment | ||||
|             const auto data = ir.ReadMemory32(address); | ||||
|             const auto data = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|             ir.SetRegister(static_cast<Reg>(i), data); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
| @@ -797,7 +797,7 @@ bool TranslatorVisitor::thumb16_POP(bool P, RegList reg_list) { | ||||
|  | ||||
|     if (Common::Bit<15>(reg_list)) { | ||||
|         // TODO(optimization): Possible location for an RSB pop. | ||||
|         const auto data = ir.ReadMemory32(address); | ||||
|         const auto data = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|         ir.UpdateUpperLocationDescriptor(); | ||||
|         ir.LoadWritePC(data); | ||||
|         address = ir.Add(address, ir.Imm32(4)); | ||||
| @@ -879,7 +879,7 @@ bool TranslatorVisitor::thumb16_STMIA(Reg n, RegList reg_list) { | ||||
|     for (size_t i = 0; i < 8; i++) { | ||||
|         if (Common::Bit(i, reg_list)) { | ||||
|             const auto Ri = ir.GetRegister(static_cast<Reg>(i)); | ||||
|             ir.WriteMemory32(address, Ri); | ||||
|             ir.WriteMemory32(address, Ri, IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|     } | ||||
| @@ -899,7 +899,7 @@ bool TranslatorVisitor::thumb16_LDMIA(Reg n, RegList reg_list) { | ||||
|  | ||||
|     for (size_t i = 0; i < 8; i++) { | ||||
|         if (Common::Bit(i, reg_list)) { | ||||
|             const auto data = ir.ReadMemory32(address); | ||||
|             const auto data = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|             ir.SetRegister(static_cast<Reg>(i), data); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|   | ||||
| @@ -31,7 +31,7 @@ static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, | ||||
|     const u32 imm32 = imm12.ZeroExtend(); | ||||
|     const u32 base = v.ir.AlignPC(4); | ||||
|     const u32 address = U ? (base + imm32) : (base - imm32); | ||||
|     const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(v.ir.Imm32(address))); | ||||
|     const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(v.ir.Imm32(address), IR::AccType::NORMAL)); | ||||
|  | ||||
|     v.ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -46,7 +46,7 @@ static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re | ||||
|     const auto reg_m = v.ir.GetRegister(m); | ||||
|     const auto offset = v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(imm2.ZeroExtend<u8>())); | ||||
|     const auto address = v.ir.Add(reg_n, offset); | ||||
|     const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address)); | ||||
|     const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     v.ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -58,7 +58,7 @@ static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U | ||||
|     const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32)) | ||||
|                                      : v.ir.Sub(reg_n, v.ir.Imm32(imm32)); | ||||
|     const IR::U32 address = P ? offset_address : reg_n; | ||||
|     const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address)); | ||||
|     const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     v.ir.SetRegister(t, data); | ||||
|     if (W) { | ||||
|   | ||||
| @@ -13,7 +13,7 @@ static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, | ||||
|     const auto imm32 = imm12.ZeroExtend(); | ||||
|     const auto base = v.ir.AlignPC(4); | ||||
|     const auto address = U ? (base + imm32) : (base - imm32); | ||||
|     const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory16(v.ir.Imm32(address))); | ||||
|     const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory16(v.ir.Imm32(address), IR::AccType::NORMAL)); | ||||
|  | ||||
|     v.ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -28,7 +28,7 @@ static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re | ||||
|     const IR::U32 reg_n = v.ir.GetRegister(n); | ||||
|     const IR::U32 offset = v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(imm2.ZeroExtend<u8>())); | ||||
|     const IR::U32 address = v.ir.Add(reg_n, offset); | ||||
|     const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address)); | ||||
|     const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     v.ir.SetRegister(t, data); | ||||
|     return true; | ||||
| @@ -41,7 +41,7 @@ static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U | ||||
|                                      : v.ir.Sub(reg_n, v.ir.Imm32(imm32)); | ||||
|     const IR::U32 address = P ? offset_address | ||||
|                               : reg_n; | ||||
|     const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address)); | ||||
|     const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address, IR::AccType::NORMAL)); | ||||
|  | ||||
|     if (W) { | ||||
|         v.ir.SetRegister(n, offset_address); | ||||
|   | ||||
| @@ -24,10 +24,10 @@ static bool TableBranch(TranslatorVisitor& v, Reg n, Reg m, bool half) { | ||||
|  | ||||
|     IR::U32 halfwords; | ||||
|     if (half) { | ||||
|         const auto data = v.ir.ReadMemory16(v.ir.Add(reg_n, v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(1)))); | ||||
|         const auto data = v.ir.ReadMemory16(v.ir.Add(reg_n, v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(1))), IR::AccType::NORMAL); | ||||
|         halfwords = v.ir.ZeroExtendToWord(data); | ||||
|     } else { | ||||
|         halfwords = v.ir.ZeroExtendToWord(v.ir.ReadMemory8(v.ir.Add(reg_n, reg_m))); | ||||
|         halfwords = v.ir.ZeroExtendToWord(v.ir.ReadMemory8(v.ir.Add(reg_n, reg_m), IR::AccType::NORMAL)); | ||||
|     } | ||||
|  | ||||
|     const auto current_pc = v.ir.Imm32(v.ir.PC()); | ||||
| @@ -51,12 +51,18 @@ static bool LoadDualImmediate(TranslatorVisitor& v, bool P, bool U, bool W, Reg | ||||
|     const IR::U32 reg_n = v.ir.GetRegister(n); | ||||
|     const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm)) | ||||
|                                      : v.ir.Sub(reg_n, v.ir.Imm32(imm)); | ||||
|     const IR::U32 address_1 = P ? offset_address | ||||
|                                 : reg_n; | ||||
|     const IR::U32 address_2 = v.ir.Add(address_1, v.ir.Imm32(4)); | ||||
|     const IR::U32 address = P ? offset_address : reg_n; | ||||
|  | ||||
|     v.ir.SetRegister(t, v.ir.ReadMemory32(address_1)); | ||||
|     v.ir.SetRegister(t2, v.ir.ReadMemory32(address_2)); | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     const IR::U64 data = v.ir.ReadMemory64(address, IR::AccType::ATOMIC); | ||||
|  | ||||
|     if (v.ir.current_location.EFlag()) { | ||||
|         v.ir.SetRegister(t, v.ir.MostSignificantWord(data).result); | ||||
|         v.ir.SetRegister(t2, v.ir.LeastSignificantWord(data)); | ||||
|     } else { | ||||
|         v.ir.SetRegister(t, v.ir.LeastSignificantWord(data)); | ||||
|         v.ir.SetRegister(t2, v.ir.MostSignificantWord(data).result); | ||||
|     } | ||||
|  | ||||
|     if (W) { | ||||
|         v.ir.SetRegister(n, offset_address); | ||||
| @@ -73,12 +79,20 @@ static bool LoadDualLiteral(TranslatorVisitor& v, bool U, bool W, Reg t, Reg t2, | ||||
|     } | ||||
|  | ||||
|     const auto imm = imm8.ZeroExtend() << 2; | ||||
|     const auto address_1 = U ? v.ir.Add(v.ir.Imm32(v.ir.AlignPC(4)), v.ir.Imm32(imm)) | ||||
|                              : v.ir.Sub(v.ir.Imm32(v.ir.AlignPC(4)), v.ir.Imm32(imm)); | ||||
|     const auto address_2 = v.ir.Add(address_1, v.ir.Imm32(4)); | ||||
|     const auto address = U ? v.ir.Add(v.ir.Imm32(v.ir.AlignPC(4)), v.ir.Imm32(imm)) | ||||
|                            : v.ir.Sub(v.ir.Imm32(v.ir.AlignPC(4)), v.ir.Imm32(imm)); | ||||
|  | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     const IR::U64 data = v.ir.ReadMemory64(address, IR::AccType::ATOMIC); | ||||
|  | ||||
|     if (v.ir.current_location.EFlag()) { | ||||
|         v.ir.SetRegister(t, v.ir.MostSignificantWord(data).result); | ||||
|         v.ir.SetRegister(t2, v.ir.LeastSignificantWord(data)); | ||||
|     } else { | ||||
|         v.ir.SetRegister(t, v.ir.LeastSignificantWord(data)); | ||||
|         v.ir.SetRegister(t2, v.ir.MostSignificantWord(data).result); | ||||
|     } | ||||
|  | ||||
|     v.ir.SetRegister(t, v.ir.ReadMemory32(address_1)); | ||||
|     v.ir.SetRegister(t2, v.ir.ReadMemory32(address_2)); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -97,12 +111,13 @@ static bool StoreDual(TranslatorVisitor& v, bool P, bool U, bool W, Reg n, Reg t | ||||
|  | ||||
|     const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm)) | ||||
|                                      : v.ir.Sub(reg_n, v.ir.Imm32(imm)); | ||||
|     const IR::U32 address_1 = P ? offset_address | ||||
|                                 : reg_n; | ||||
|     const IR::U32 address_2 = v.ir.Add(address_1, v.ir.Imm32(4)); | ||||
|     const IR::U32 address = P ? offset_address : reg_n; | ||||
|  | ||||
|     v.ir.WriteMemory32(address_1, reg_t); | ||||
|     v.ir.WriteMemory32(address_2, reg_t2); | ||||
|     const IR::U64 data = v.ir.current_location.EFlag() ? v.ir.Pack2x32To1x64(reg_t2, reg_t) | ||||
|                                                        : v.ir.Pack2x32To1x64(reg_t, reg_t2); | ||||
|  | ||||
|     // NOTE: If alignment is exactly off by 4, each word is an atomic access. | ||||
|     v.ir.WriteMemory64(address, data, IR::AccType::ATOMIC); | ||||
|  | ||||
|     if (W) { | ||||
|         v.ir.SetRegister(n, offset_address); | ||||
| @@ -116,7 +131,7 @@ bool TranslatorVisitor::thumb32_LDA(Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.SetRegister(t, ir.ReadMemory32(address));  // AccType::Ordered | ||||
|     ir.SetRegister(t, ir.ReadMemory32(address, IR::AccType::ORDERED)); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -150,7 +165,7 @@ bool TranslatorVisitor::thumb32_LDREX(Reg n, Reg t, Imm<8> imm8) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm8.ZeroExtend() << 2)); | ||||
|     const auto value = ir.ExclusiveReadMemory32(address); | ||||
|     const auto value = ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC); | ||||
|  | ||||
|     ir.SetRegister(t, value); | ||||
|     return true; | ||||
| @@ -162,7 +177,7 @@ bool TranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory8(address)); | ||||
|     const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC)); | ||||
|  | ||||
|     ir.SetRegister(t, value); | ||||
|     return true; | ||||
| @@ -174,7 +189,7 @@ bool TranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto [lo, hi] = ir.ExclusiveReadMemory64(address); | ||||
|     const auto [lo, hi] = ir.ExclusiveReadMemory64(address, IR::AccType::ATOMIC); | ||||
|  | ||||
|     // DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR | ||||
|     ir.SetRegister(t, lo); | ||||
| @@ -188,7 +203,7 @@ bool TranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory16(address)); | ||||
|     const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC)); | ||||
|  | ||||
|     ir.SetRegister(t, value); | ||||
|     return true; | ||||
| @@ -200,7 +215,7 @@ bool TranslatorVisitor::thumb32_STL(Reg n, Reg t) { | ||||
|     } | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t));  // AccType::Ordered | ||||
|     ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -214,7 +229,7 @@ bool TranslatorVisitor::thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8) { | ||||
|  | ||||
|     const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm8.ZeroExtend() << 2)); | ||||
|     const auto value = ir.GetRegister(t); | ||||
|     const auto passed = ir.ExclusiveWriteMemory32(address, value); | ||||
|     const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -229,7 +244,7 @@ bool TranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.LeastSignificantByte(ir.GetRegister(t)); | ||||
|     const auto passed = ir.ExclusiveWriteMemory8(address, value); | ||||
|     const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -245,7 +260,7 @@ bool TranslatorVisitor::thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d) { | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value_lo = ir.GetRegister(t); | ||||
|     const auto value_hi = ir.GetRegister(t2); | ||||
|     const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi); | ||||
|     const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
| @@ -260,7 +275,7 @@ bool TranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) { | ||||
|  | ||||
|     const auto address = ir.GetRegister(n); | ||||
|     const auto value = ir.LeastSignificantHalf(ir.GetRegister(t)); | ||||
|     const auto passed = ir.ExclusiveWriteMemory16(address, value); | ||||
|     const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC); | ||||
|     ir.SetRegister(d, passed); | ||||
|     return true; | ||||
| } | ||||
|   | ||||
| @@ -15,7 +15,7 @@ static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32 | ||||
|     auto address = start_address; | ||||
|     for (size_t i = 0; i <= 14; i++) { | ||||
|         if (Common::Bit(i, list)) { | ||||
|             ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address)); | ||||
|             ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC)); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|     } | ||||
| @@ -24,7 +24,7 @@ static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32 | ||||
|     } | ||||
|     if (Common::Bit<15>(list)) { | ||||
|         ir.UpdateUpperLocationDescriptor(); | ||||
|         ir.LoadWritePC(ir.ReadMemory32(address)); | ||||
|         ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC)); | ||||
|         if (n == Reg::R13) { | ||||
|             ir.SetTerm(IR::Term::PopRSBHint{}); | ||||
|         } else { | ||||
| @@ -39,7 +39,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32 | ||||
|     auto address = start_address; | ||||
|     for (size_t i = 0; i <= 14; i++) { | ||||
|         if (Common::Bit(i, list)) { | ||||
|             ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i))); | ||||
|             ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ bool TranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) { | ||||
|     const u32 imm32 = imm12.ZeroExtend(); | ||||
|     const u32 base = ir.AlignPC(4); | ||||
|     const u32 address = U ? base + imm32 : base - imm32; | ||||
|     const auto data = ir.ReadMemory32(ir.Imm32(address)); | ||||
|     const auto data = ir.ReadMemory32(ir.Imm32(address), IR::AccType::NORMAL); | ||||
|  | ||||
|     if (t == Reg::PC) { | ||||
|         ir.UpdateUpperLocationDescriptor(); | ||||
| @@ -48,7 +48,7 @@ bool TranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, I | ||||
|                                      : ir.Sub(reg_n, ir.Imm32(imm32)); | ||||
|     const IR::U32 address = P ? offset_address | ||||
|                               : reg_n; | ||||
|     const IR::U32 data = ir.ReadMemory32(address); | ||||
|     const IR::U32 data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     if (W) { | ||||
|         ir.SetRegister(n, offset_address); | ||||
| @@ -79,7 +79,7 @@ bool TranslatorVisitor::thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12) { | ||||
|     const auto imm32 = imm12.ZeroExtend(); | ||||
|     const auto reg_n = ir.GetRegister(n); | ||||
|     const auto address = ir.Add(reg_n, ir.Imm32(imm32)); | ||||
|     const auto data = ir.ReadMemory32(address); | ||||
|     const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     if (t == Reg::PC) { | ||||
|         ir.UpdateUpperLocationDescriptor(); | ||||
| @@ -104,7 +104,7 @@ bool TranslatorVisitor::thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) { | ||||
|     const auto reg_n = ir.GetRegister(n); | ||||
|     const auto offset = ir.LogicalShiftLeft(reg_m, ir.Imm8(imm2.ZeroExtend<u8>())); | ||||
|     const auto address = ir.Add(reg_n, offset); | ||||
|     const auto data = ir.ReadMemory32(address); | ||||
|     const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL); | ||||
|  | ||||
|     if (t == Reg::PC) { | ||||
|         ir.UpdateUpperLocationDescriptor(); | ||||
|   | ||||
| @@ -32,15 +32,15 @@ static bool StoreRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m | ||||
| using StoreImmFn = void (*)(TranslatorVisitor&, const IR::U32&, const IR::U32&); | ||||
|  | ||||
| static void StoreImmByteFn(TranslatorVisitor& v, const IR::U32& address, const IR::U32& data) { | ||||
|     v.ir.WriteMemory8(address, v.ir.LeastSignificantByte(data)); | ||||
|     v.ir.WriteMemory8(address, v.ir.LeastSignificantByte(data), IR::AccType::NORMAL); | ||||
| } | ||||
|  | ||||
| static void StoreImmHalfFn(TranslatorVisitor& v, const IR::U32& address, const IR::U32& data) { | ||||
|     v.ir.WriteMemory16(address, v.ir.LeastSignificantHalf(data)); | ||||
|     v.ir.WriteMemory16(address, v.ir.LeastSignificantHalf(data), IR::AccType::NORMAL); | ||||
| } | ||||
|  | ||||
| static void StoreImmWordFn(TranslatorVisitor& v, const IR::U32& address, const IR::U32& data) { | ||||
|     v.ir.WriteMemory32(address, data); | ||||
|     v.ir.WriteMemory32(address, data, IR::AccType::NORMAL); | ||||
| } | ||||
|  | ||||
| static bool StoreImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, StoreImmFn store_fn) { | ||||
| @@ -110,7 +110,7 @@ bool TranslatorVisitor::thumb32_STRBT(Reg n, Reg t, Imm<8> imm8) { | ||||
|  | ||||
| bool TranslatorVisitor::thumb32_STRB(Reg n, Reg t, Imm<2> imm2, Reg m) { | ||||
|     return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) { | ||||
|         ir.WriteMemory8(offset_address, ir.LeastSignificantByte(data)); | ||||
|         ir.WriteMemory8(offset_address, ir.LeastSignificantByte(data), IR::AccType::NORMAL); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| @@ -163,7 +163,7 @@ bool TranslatorVisitor::thumb32_STRHT(Reg n, Reg t, Imm<8> imm8) { | ||||
|  | ||||
| bool TranslatorVisitor::thumb32_STRH(Reg n, Reg t, Imm<2> imm2, Reg m) { | ||||
|     return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) { | ||||
|         ir.WriteMemory16(offset_address, ir.LeastSignificantHalf(data)); | ||||
|         ir.WriteMemory16(offset_address, ir.LeastSignificantHalf(data), IR::AccType::NORMAL); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| @@ -216,7 +216,7 @@ bool TranslatorVisitor::thumb32_STRT(Reg n, Reg t, Imm<8> imm8) { | ||||
|  | ||||
| bool TranslatorVisitor::thumb32_STR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) { | ||||
|     return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) { | ||||
|         ir.WriteMemory32(offset_address, data); | ||||
|         ir.WriteMemory32(offset_address, data, IR::AccType::NORMAL); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1186,16 +1186,16 @@ bool TranslatorVisitor::vfp_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm<8> i | ||||
|  | ||||
|     for (size_t i = 0; i < regs; ++i) { | ||||
|         if (sz) { | ||||
|             auto lo = ir.ReadMemory32(address); | ||||
|             auto lo = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|             auto hi = ir.ReadMemory32(address); | ||||
|             auto hi = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|             if (ir.current_location.EFlag()) { | ||||
|                 std::swap(lo, hi); | ||||
|             } | ||||
|             ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(lo, hi)); | ||||
|         } else { | ||||
|             const auto res = ir.ReadMemory32(address); | ||||
|             const auto res = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|             ir.SetExtendedRegister(d + i, res); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
| @@ -1232,12 +1232,12 @@ bool TranslatorVisitor::vfp_VPUSH(Cond cond, bool D, size_t Vd, bool sz, Imm<8> | ||||
|             auto hi = ir.MostSignificantWord(reg_d).result; | ||||
|             if (ir.current_location.EFlag()) | ||||
|                 std::swap(lo, hi); | ||||
|             ir.WriteMemory32(address, lo); | ||||
|             ir.WriteMemory32(address, lo, IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|             ir.WriteMemory32(address, hi); | ||||
|             ir.WriteMemory32(address, hi, IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } else { | ||||
|             ir.WriteMemory32(address, ir.GetExtendedRegister(d + i)); | ||||
|             ir.WriteMemory32(address, ir.GetExtendedRegister(d + i), IR::AccType::ATOMIC); | ||||
|             address = ir.Add(address, ir.Imm32(4)); | ||||
|         } | ||||
|     } | ||||
| @@ -1258,14 +1258,14 @@ bool TranslatorVisitor::vfp_VLDR(Cond cond, bool U, bool D, Reg n, size_t Vd, bo | ||||
|     const auto address = U ? ir.Add(base, ir.Imm32(imm32)) : ir.Sub(base, ir.Imm32(imm32)); | ||||
|  | ||||
|     if (sz) { | ||||
|         auto lo = ir.ReadMemory32(address); | ||||
|         auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4))); | ||||
|         auto lo = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|         auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4)), IR::AccType::ATOMIC); | ||||
|         if (ir.current_location.EFlag()) { | ||||
|             std::swap(lo, hi); | ||||
|         } | ||||
|         ir.SetExtendedRegister(d, ir.Pack2x32To1x64(lo, hi)); | ||||
|     } else { | ||||
|         ir.SetExtendedRegister(d, ir.ReadMemory32(address)); | ||||
|         ir.SetExtendedRegister(d, ir.ReadMemory32(address, IR::AccType::ATOMIC)); | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| @@ -1289,10 +1289,10 @@ bool TranslatorVisitor::vfp_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd, bo | ||||
|         if (ir.current_location.EFlag()) { | ||||
|             std::swap(lo, hi); | ||||
|         } | ||||
|         ir.WriteMemory32(address, lo); | ||||
|         ir.WriteMemory32(ir.Add(address, ir.Imm32(4)), hi); | ||||
|         ir.WriteMemory32(address, lo, IR::AccType::ATOMIC); | ||||
|         ir.WriteMemory32(ir.Add(address, ir.Imm32(4)), hi, IR::AccType::ATOMIC); | ||||
|     } else { | ||||
|         ir.WriteMemory32(address, ir.GetExtendedRegister(d)); | ||||
|         ir.WriteMemory32(address, ir.GetExtendedRegister(d), IR::AccType::ATOMIC); | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| @@ -1341,9 +1341,9 @@ bool TranslatorVisitor::vfp_VSTM_a1(Cond cond, bool p, bool u, bool D, bool w, R | ||||
|             std::swap(word1, word2); | ||||
|         } | ||||
|  | ||||
|         ir.WriteMemory32(address, word1); | ||||
|         ir.WriteMemory32(address, word1, IR::AccType::ATOMIC); | ||||
|         address = ir.Add(address, ir.Imm32(4)); | ||||
|         ir.WriteMemory32(address, word2); | ||||
|         ir.WriteMemory32(address, word2, IR::AccType::ATOMIC); | ||||
|         address = ir.Add(address, ir.Imm32(4)); | ||||
|     } | ||||
|  | ||||
| @@ -1386,7 +1386,7 @@ bool TranslatorVisitor::vfp_VSTM_a2(Cond cond, bool p, bool u, bool D, bool w, R | ||||
|     } | ||||
|     for (size_t i = 0; i < regs; i++) { | ||||
|         const auto word = ir.GetExtendedRegister(d + i); | ||||
|         ir.WriteMemory32(address, word); | ||||
|         ir.WriteMemory32(address, word, IR::AccType::ATOMIC); | ||||
|         address = ir.Add(address, ir.Imm32(4)); | ||||
|     } | ||||
|  | ||||
| @@ -1428,9 +1428,9 @@ bool TranslatorVisitor::vfp_VLDM_a1(Cond cond, bool p, bool u, bool D, bool w, R | ||||
|         ir.SetRegister(n, u ? IR::U32(ir.Add(address, ir.Imm32(imm32))) : address); | ||||
|     } | ||||
|     for (size_t i = 0; i < regs; i++) { | ||||
|         auto word1 = ir.ReadMemory32(address); | ||||
|         auto word1 = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|         address = ir.Add(address, ir.Imm32(4)); | ||||
|         auto word2 = ir.ReadMemory32(address); | ||||
|         auto word2 = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|         address = ir.Add(address, ir.Imm32(4)); | ||||
|  | ||||
|         if (ir.current_location.EFlag()) { | ||||
| @@ -1478,7 +1478,7 @@ bool TranslatorVisitor::vfp_VLDM_a2(Cond cond, bool p, bool u, bool D, bool w, R | ||||
|         ir.SetRegister(n, u ? IR::U32(ir.Add(address, ir.Imm32(imm32))) : address); | ||||
|     } | ||||
|     for (size_t i = 0; i < regs; i++) { | ||||
|         const auto word = ir.ReadMemory32(address); | ||||
|         const auto word = ir.ReadMemory32(address, IR::AccType::ATOMIC); | ||||
|         address = ir.Add(address, ir.Imm32(4)); | ||||
|         ir.SetExtendedRegister(d + i, word); | ||||
|     } | ||||
|   | ||||
| @@ -105,84 +105,84 @@ void IREmitter::ClearExclusive() { | ||||
|     Inst(Opcode::A64ClearExclusive); | ||||
| } | ||||
|  | ||||
| IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U8>(Opcode::A64ReadMemory8, vaddr, IR::Value(acctype)); | ||||
| IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U8>(Opcode::A64ReadMemory8, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U16>(Opcode::A64ReadMemory16, vaddr, IR::Value(acctype)); | ||||
| IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U16>(Opcode::A64ReadMemory16, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U32>(Opcode::A64ReadMemory32, vaddr, IR::Value(acctype)); | ||||
| IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A64ReadMemory32, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U64>(Opcode::A64ReadMemory64, vaddr, IR::Value(acctype)); | ||||
| IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U64>(Opcode::A64ReadMemory64, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U128>(Opcode::A64ReadMemory128, vaddr, IR::Value(acctype)); | ||||
| IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U128>(Opcode::A64ReadMemory128, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, vaddr, IR::Value(acctype)); | ||||
| IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, vaddr, IR::Value(acctype)); | ||||
| IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, vaddr, IR::Value(acctype)); | ||||
| IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, vaddr, IR::Value(acctype)); | ||||
| IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccessType acctype) { | ||||
|     return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, vaddr, IR::Value(acctype)); | ||||
| IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) { | ||||
|     return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, vaddr, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccessType acctype) { | ||||
|     Inst(Opcode::A64WriteMemory8, vaddr, value, IR::Value(acctype)); | ||||
| void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) { | ||||
|     Inst(Opcode::A64WriteMemory8, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccessType acctype) { | ||||
|     Inst(Opcode::A64WriteMemory16, vaddr, value, IR::Value(acctype)); | ||||
| void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) { | ||||
|     Inst(Opcode::A64WriteMemory16, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccessType acctype) { | ||||
|     Inst(Opcode::A64WriteMemory32, vaddr, value, IR::Value(acctype)); | ||||
| void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) { | ||||
|     Inst(Opcode::A64WriteMemory32, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccessType acctype) { | ||||
|     Inst(Opcode::A64WriteMemory64, vaddr, value, IR::Value(acctype)); | ||||
| void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) { | ||||
|     Inst(Opcode::A64WriteMemory64, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccessType acctype) { | ||||
|     Inst(Opcode::A64WriteMemory128, vaddr, value, IR::Value(acctype)); | ||||
| void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) { | ||||
|     Inst(Opcode::A64WriteMemory128, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccessType acctype) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory8, vaddr, value, IR::Value(acctype)); | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory8, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccessType acctype) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory16, vaddr, value, IR::Value(acctype)); | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory16, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccessType acctype) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory32, vaddr, value, IR::Value(acctype)); | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory32, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccessType acctype) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory64, vaddr, value, IR::Value(acctype)); | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory64, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccessType acctype) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, vaddr, value, IR::Value(acctype)); | ||||
| IR::U32 IREmitter::ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) { | ||||
|     return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, vaddr, value, IR::Value{acc_type}); | ||||
| } | ||||
|  | ||||
| IR::U32 IREmitter::GetW(Reg reg) { | ||||
|   | ||||
| @@ -56,26 +56,26 @@ public: | ||||
|     void SetTPIDR(const IR::U64& value); | ||||
|  | ||||
|     void ClearExclusive(); | ||||
|     IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccessType acctype); | ||||
|     void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccessType acctype); | ||||
|     void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccessType acctype); | ||||
|     void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccessType acctype); | ||||
|     void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccessType acctype); | ||||
|     void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccessType acctype); | ||||
|     IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccessType acctype); | ||||
|     IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccessType acctype); | ||||
|     IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccessType acctype); | ||||
|     IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccessType acctype); | ||||
|     IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccessType acctype); | ||||
|     IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type); | ||||
|     void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type); | ||||
|     void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type); | ||||
|     void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type); | ||||
|     void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type); | ||||
|     void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type); | ||||
|     IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type); | ||||
|  | ||||
|     IR::U32 GetW(Reg source_reg); | ||||
|     IR::U64 GetX(Reg source_reg); | ||||
|   | ||||
| @@ -217,74 +217,74 @@ void TranslatorVisitor::Vpart_scalar(size_t bitsize, Vec vec, size_t part, IR::U | ||||
|     } | ||||
| } | ||||
|  | ||||
| IR::UAnyU128 TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccessType acctype) { | ||||
| IR::UAnyU128 TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccType acc_type) { | ||||
|     switch (bytesize) { | ||||
|     case 1: | ||||
|         return ir.ReadMemory8(address, acctype); | ||||
|         return ir.ReadMemory8(address, acc_type); | ||||
|     case 2: | ||||
|         return ir.ReadMemory16(address, acctype); | ||||
|         return ir.ReadMemory16(address, acc_type); | ||||
|     case 4: | ||||
|         return ir.ReadMemory32(address, acctype); | ||||
|         return ir.ReadMemory32(address, acc_type); | ||||
|     case 8: | ||||
|         return ir.ReadMemory64(address, acctype); | ||||
|         return ir.ReadMemory64(address, acc_type); | ||||
|     case 16: | ||||
|         return ir.ReadMemory128(address, acctype); | ||||
|         return ir.ReadMemory128(address, acc_type); | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bytesize parameter {}", bytesize); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccessType acctype, IR::UAnyU128 value) { | ||||
| void TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccType acc_type, IR::UAnyU128 value) { | ||||
|     switch (bytesize) { | ||||
|     case 1: | ||||
|         ir.WriteMemory8(address, value, acctype); | ||||
|         ir.WriteMemory8(address, value, acc_type); | ||||
|         return; | ||||
|     case 2: | ||||
|         ir.WriteMemory16(address, value, acctype); | ||||
|         ir.WriteMemory16(address, value, acc_type); | ||||
|         return; | ||||
|     case 4: | ||||
|         ir.WriteMemory32(address, value, acctype); | ||||
|         ir.WriteMemory32(address, value, acc_type); | ||||
|         return; | ||||
|     case 8: | ||||
|         ir.WriteMemory64(address, value, acctype); | ||||
|         ir.WriteMemory64(address, value, acc_type); | ||||
|         return; | ||||
|     case 16: | ||||
|         ir.WriteMemory128(address, value, acctype); | ||||
|         ir.WriteMemory128(address, value, acc_type); | ||||
|         return; | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bytesize parameter {}", bytesize); | ||||
|     } | ||||
| } | ||||
|  | ||||
| IR::UAnyU128 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, IR::AccessType acctype) { | ||||
| IR::UAnyU128 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, IR::AccType acc_type) { | ||||
|     switch (bytesize) { | ||||
|     case 1: | ||||
|         return ir.ExclusiveReadMemory8(address, acctype); | ||||
|         return ir.ExclusiveReadMemory8(address, acc_type); | ||||
|     case 2: | ||||
|         return ir.ExclusiveReadMemory16(address, acctype); | ||||
|         return ir.ExclusiveReadMemory16(address, acc_type); | ||||
|     case 4: | ||||
|         return ir.ExclusiveReadMemory32(address, acctype); | ||||
|         return ir.ExclusiveReadMemory32(address, acc_type); | ||||
|     case 8: | ||||
|         return ir.ExclusiveReadMemory64(address, acctype); | ||||
|         return ir.ExclusiveReadMemory64(address, acc_type); | ||||
|     case 16: | ||||
|         return ir.ExclusiveReadMemory128(address, acctype); | ||||
|         return ir.ExclusiveReadMemory128(address, acc_type); | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bytesize parameter {}", bytesize); | ||||
|     } | ||||
| } | ||||
|  | ||||
| IR::U32 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, IR::AccessType acctype, IR::UAnyU128 value) { | ||||
| IR::U32 TranslatorVisitor::ExclusiveMem(IR::U64 address, size_t bytesize, IR::AccType acc_type, IR::UAnyU128 value) { | ||||
|     switch (bytesize) { | ||||
|     case 1: | ||||
|         return ir.ExclusiveWriteMemory8(address, value, acctype); | ||||
|         return ir.ExclusiveWriteMemory8(address, value, acc_type); | ||||
|     case 2: | ||||
|         return ir.ExclusiveWriteMemory16(address, value, acctype); | ||||
|         return ir.ExclusiveWriteMemory16(address, value, acc_type); | ||||
|     case 4: | ||||
|         return ir.ExclusiveWriteMemory32(address, value, acctype); | ||||
|         return ir.ExclusiveWriteMemory32(address, value, acc_type); | ||||
|     case 8: | ||||
|         return ir.ExclusiveWriteMemory64(address, value, acctype); | ||||
|         return ir.ExclusiveWriteMemory64(address, value, acc_type); | ||||
|     case 16: | ||||
|         return ir.ExclusiveWriteMemory128(address, value, acctype); | ||||
|         return ir.ExclusiveWriteMemory128(address, value, acc_type); | ||||
|     default: | ||||
|         ASSERT_FALSE("Invalid bytesize parameter {}", bytesize); | ||||
|     } | ||||
|   | ||||
| @@ -55,10 +55,10 @@ struct TranslatorVisitor final { | ||||
|     IR::UAny Vpart_scalar(size_t bitsize, Vec vec, size_t part); | ||||
|     void Vpart_scalar(size_t bitsize, Vec vec, size_t part, IR::UAny value); | ||||
|  | ||||
|     IR::UAnyU128 Mem(IR::U64 address, size_t size, IR::AccessType acctype); | ||||
|     void Mem(IR::U64 address, size_t size, IR::AccessType acctype, IR::UAnyU128 value); | ||||
|     IR::UAnyU128 ExclusiveMem(IR::U64 address, size_t size, IR::AccessType acctype); | ||||
|     IR::U32 ExclusiveMem(IR::U64 address, size_t size, IR::AccessType acctype, IR::UAnyU128 value); | ||||
|     IR::UAnyU128 Mem(IR::U64 address, size_t size, IR::AccType acctype); | ||||
|     void Mem(IR::U64 address, size_t size, IR::AccType acctype, IR::UAnyU128 value); | ||||
|     IR::UAnyU128 ExclusiveMem(IR::U64 address, size_t size, IR::AccType acctype); | ||||
|     IR::U32 ExclusiveMem(IR::U64 address, size_t size, IR::AccType acctype, IR::UAnyU128 value); | ||||
|  | ||||
|     IR::U32U64 SignExtend(IR::UAny value, size_t to_size); | ||||
|     IR::U32U64 ZeroExtend(IR::UAny value, size_t to_size); | ||||
|   | ||||
| @@ -12,7 +12,7 @@ namespace Dynarmic::A64 { | ||||
| static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, size_t size, bool L, bool o0, std::optional<Reg> Rs, std::optional<Reg> Rt2, Reg Rn, Reg Rt) { | ||||
|     // Shared Decode | ||||
|  | ||||
|     const auto acctype = o0 ? IR::AccessType::ORDERED : IR::AccessType::ATOMIC; | ||||
|     const auto acctype = o0 ? IR::AccType::ORDERED : IR::AccType::ATOMIC; | ||||
|     const auto memop = L ? IR::MemOp::LOAD : IR::MemOp::STORE; | ||||
|     const size_t elsize = 8 << size; | ||||
|     const size_t regsize = elsize == 64 ? 64 : 32; | ||||
| @@ -142,7 +142,7 @@ bool TranslatorVisitor::LDAXP(Imm<1> sz, Reg Rt2, Reg Rn, Reg Rt) { | ||||
| static bool OrderedSharedDecodeAndOperation(TranslatorVisitor& v, size_t size, bool L, bool o0, Reg Rn, Reg Rt) { | ||||
|     // Shared Decode | ||||
|  | ||||
|     const auto acctype = !o0 ? IR::AccessType::LIMITEDORDERED : IR::AccessType::ORDERED; | ||||
|     const auto acctype = !o0 ? IR::AccType::LIMITEDORDERED : IR::AccType::ORDERED; | ||||
|     const auto memop = L ? IR::MemOp::LOAD : IR::MemOp::STORE; | ||||
|     const size_t elsize = 8 << size; | ||||
|     const size_t regsize = elsize == 64 ? 64 : 32; | ||||
|   | ||||
| @@ -12,7 +12,7 @@ bool TranslatorVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) { | ||||
|     const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>(); | ||||
|  | ||||
|     const u64 address = ir.PC() + offset; | ||||
|     const auto data = Mem(ir.Imm64(address), size, IR::AccessType::NORMAL); | ||||
|     const auto data = Mem(ir.Imm64(address), size, IR::AccType::NORMAL); | ||||
|  | ||||
|     X(8 * size, Rt, data); | ||||
|     return true; | ||||
| @@ -26,7 +26,7 @@ bool TranslatorVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) { | ||||
|     const u64 size = 4 << opc.ZeroExtend(); | ||||
|     const u64 offset = imm19.SignExtend<u64>() << 2; | ||||
|     const IR::U64 address = ir.Imm64(ir.PC() + offset); | ||||
|     const IR::UAnyU128 data = Mem(address, size, IR::AccessType::VEC); | ||||
|     const IR::UAnyU128 data = Mem(address, size, IR::AccType::VEC); | ||||
|  | ||||
|     if (size == 16) { | ||||
|         V(128, Vt, data); | ||||
| @@ -39,7 +39,7 @@ bool TranslatorVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) { | ||||
| bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) { | ||||
|     const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>(); | ||||
|     const u64 address = ir.PC() + offset; | ||||
|     const auto data = Mem(ir.Imm64(address), 4, IR::AccessType::NORMAL); | ||||
|     const auto data = Mem(ir.Imm64(address), 4, IR::AccType::NORMAL); | ||||
|  | ||||
|     X(64, Rt, ir.SignExtendWordToLong(data)); | ||||
|     return true; | ||||
|   | ||||
| @@ -67,11 +67,11 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp | ||||
|         for (size_t r = 0; r < rpt; r++) { | ||||
|             const Vec tt = static_cast<Vec>((VecNumber(Vt) + r) % 32); | ||||
|             if (memop == IR::MemOp::LOAD) { | ||||
|                 const IR::UAnyU128 vec = v.Mem(v.ir.Add(address, offs), ebytes * elements, IR::AccessType::VEC); | ||||
|                 const IR::UAnyU128 vec = v.Mem(v.ir.Add(address, offs), ebytes * elements, IR::AccType::VEC); | ||||
|                 v.V_scalar(datasize, tt, vec); | ||||
|             } else { | ||||
|                 const IR::UAnyU128 vec = v.V_scalar(datasize, tt); | ||||
|                 v.Mem(v.ir.Add(address, offs), ebytes * elements, IR::AccessType::VEC, vec); | ||||
|                 v.Mem(v.ir.Add(address, offs), ebytes * elements, IR::AccType::VEC, vec); | ||||
|             } | ||||
|             offs = v.ir.Add(offs, v.ir.Imm64(ebytes * elements)); | ||||
|         } | ||||
| @@ -80,12 +80,12 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp | ||||
|             for (size_t s = 0; s < selem; s++) { | ||||
|                 const Vec tt = static_cast<Vec>((VecNumber(Vt) + s) % 32); | ||||
|                 if (memop == IR::MemOp::LOAD) { | ||||
|                     const IR::UAny elem = v.Mem(v.ir.Add(address, offs), ebytes, IR::AccessType::VEC); | ||||
|                     const IR::UAny elem = v.Mem(v.ir.Add(address, offs), ebytes, IR::AccType::VEC); | ||||
|                     const IR::U128 vec = v.ir.VectorSetElement(esize, v.V(datasize, tt), e, elem); | ||||
|                     v.V(datasize, tt, vec); | ||||
|                 } else { | ||||
|                     const IR::UAny elem = v.ir.VectorGetElement(esize, v.V(datasize, tt), e); | ||||
|                     v.Mem(v.ir.Add(address, offs), ebytes, IR::AccessType::VEC, elem); | ||||
|                     v.Mem(v.ir.Add(address, offs), ebytes, IR::AccType::VEC, elem); | ||||
|                 } | ||||
|                 offs = v.ir.Add(offs, v.ir.Imm64(ebytes)); | ||||
|             } | ||||
|   | ||||
| @@ -43,11 +43,11 @@ static bool LoadStoreRegisterImmediate(TranslatorVisitor& v, bool wback, bool po | ||||
|     switch (memop) { | ||||
|     case IR::MemOp::STORE: { | ||||
|         const auto data = v.X(datasize, Rt); | ||||
|         v.Mem(address, datasize / 8, IR::AccessType::NORMAL, data); | ||||
|         v.Mem(address, datasize / 8, IR::AccType::NORMAL, data); | ||||
|         break; | ||||
|     } | ||||
|     case IR::MemOp::LOAD: { | ||||
|         const auto data = v.Mem(address, datasize / 8, IR::AccessType::NORMAL); | ||||
|         const auto data = v.Mem(address, datasize / 8, IR::AccType::NORMAL); | ||||
|         if (signed_) { | ||||
|             v.X(regsize, Rt, v.SignExtend(data, regsize)); | ||||
|         } else { | ||||
| @@ -115,7 +115,7 @@ bool TranslatorVisitor::PRFM_unscaled_imm([[maybe_unused]] Imm<9> imm9, [[maybe_ | ||||
| } | ||||
|  | ||||
| static bool LoadStoreSIMD(TranslatorVisitor& v, bool wback, bool postindex, size_t scale, u64 offset, IR::MemOp memop, Reg Rn, Vec Vt) { | ||||
|     const auto acctype = IR::AccessType::VEC; | ||||
|     const auto acctype = IR::AccType::VEC; | ||||
|     const size_t datasize = 8 << scale; | ||||
|  | ||||
|     IR::U64 address; | ||||
|   | ||||
| @@ -46,13 +46,13 @@ bool TranslatorVisitor::STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, | ||||
|     case IR::MemOp::STORE: { | ||||
|         const IR::U32U64 data1 = X(datasize, Rt); | ||||
|         const IR::U32U64 data2 = X(datasize, Rt2); | ||||
|         Mem(address, dbytes, IR::AccessType::NORMAL, data1); | ||||
|         Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccessType::NORMAL, data2); | ||||
|         Mem(address, dbytes, IR::AccType::NORMAL, data1); | ||||
|         Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::NORMAL, data2); | ||||
|         break; | ||||
|     } | ||||
|     case IR::MemOp::LOAD: { | ||||
|         const IR::U32U64 data1 = Mem(address, dbytes, IR::AccessType::NORMAL); | ||||
|         const IR::U32U64 data2 = Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccessType::NORMAL); | ||||
|         const IR::U32U64 data1 = Mem(address, dbytes, IR::AccType::NORMAL); | ||||
|         const IR::U32U64 data2 = Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::NORMAL); | ||||
|         if (signed_) { | ||||
|             X(64, Rt, SignExtend(data1, 64)); | ||||
|             X(64, Rt2, SignExtend(data2, 64)); | ||||
| @@ -117,13 +117,13 @@ bool TranslatorVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wbac | ||||
|             data1 = ir.VectorGetElement(datasize, data1, 0); | ||||
|             data2 = ir.VectorGetElement(datasize, data2, 0); | ||||
|         } | ||||
|         Mem(address, dbytes, IR::AccessType::VEC, data1); | ||||
|         Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccessType::VEC, data2); | ||||
|         Mem(address, dbytes, IR::AccType::VEC, data1); | ||||
|         Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::VEC, data2); | ||||
|         break; | ||||
|     } | ||||
|     case IR::MemOp::LOAD: { | ||||
|         IR::UAnyU128 data1 = Mem(address, dbytes, IR::AccessType::VEC); | ||||
|         IR::UAnyU128 data2 = Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccessType::VEC); | ||||
|         IR::UAnyU128 data1 = Mem(address, dbytes, IR::AccType::VEC); | ||||
|         IR::UAnyU128 data2 = Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::VEC); | ||||
|         if (datasize != 128) { | ||||
|             data1 = ir.ZeroExtendToQuad(data1); | ||||
|             data2 = ir.ZeroExtendToQuad(data2); | ||||
|   | ||||
| @@ -10,7 +10,7 @@ namespace Dynarmic::A64 { | ||||
| static bool RegSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Reg Rt) { | ||||
|     // Shared Decode | ||||
|  | ||||
|     const auto acctype = IR::AccessType::NORMAL; | ||||
|     const auto acctype = IR::AccType::NORMAL; | ||||
|     IR::MemOp memop; | ||||
|     size_t regsize = 64; | ||||
|     bool signed_ = false; | ||||
| @@ -96,7 +96,7 @@ bool TranslatorVisitor::LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> optio | ||||
| static bool VecSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Vec Vt) { | ||||
|     // Shared Decode | ||||
|  | ||||
|     const auto acctype = IR::AccessType::VEC; | ||||
|     const auto acctype = IR::AccType::VEC; | ||||
|     const auto memop = opc_0 == 1 ? IR::MemOp::LOAD : IR::MemOp::STORE; | ||||
|     const size_t datasize = 8 << scale; | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,7 @@ namespace Dynarmic::A64 { | ||||
|  | ||||
| static bool StoreRegister(TranslatorVisitor& v, const size_t datasize, const Imm<9> imm9, const Reg Rn, const Reg Rt) { | ||||
|     const u64 offset = imm9.SignExtend<u64>(); | ||||
|     const auto acctype = IR::AccessType::UNPRIV; | ||||
|     const auto acctype = IR::AccType::UNPRIV; | ||||
|  | ||||
|     IR::U64 address; | ||||
|     if (Rn == Reg::SP) { | ||||
| @@ -27,7 +27,7 @@ static bool StoreRegister(TranslatorVisitor& v, const size_t datasize, const Imm | ||||
|  | ||||
| static bool LoadRegister(TranslatorVisitor& v, const size_t datasize, const Imm<9> imm9, const Reg Rn, const Reg Rt) { | ||||
|     const u64 offset = imm9.SignExtend<u64>(); | ||||
|     const auto acctype = IR::AccessType::UNPRIV; | ||||
|     const auto acctype = IR::AccType::UNPRIV; | ||||
|  | ||||
|     IR::U64 address; | ||||
|     if (Rn == Reg::SP) { | ||||
| @@ -47,7 +47,7 @@ static bool LoadRegister(TranslatorVisitor& v, const size_t datasize, const Imm< | ||||
|  | ||||
| static bool LoadRegisterSigned(TranslatorVisitor& v, const size_t datasize, const Imm<2> opc, const Imm<9> imm9, const Reg Rn, const Reg Rt) { | ||||
|     const u64 offset = imm9.SignExtend<u64>(); | ||||
|     const auto acctype = IR::AccessType::UNPRIV; | ||||
|     const auto acctype = IR::AccType::UNPRIV; | ||||
|  | ||||
|     IR::MemOp memop; | ||||
|     bool is_signed; | ||||
| @@ -131,7 +131,7 @@ bool TranslatorVisitor::LDTRSH(Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) { | ||||
|  | ||||
| bool TranslatorVisitor::LDTRSW(Imm<9> imm9, Reg Rn, Reg Rt) { | ||||
|     const u64 offset = imm9.SignExtend<u64>(); | ||||
|     const auto acctype = IR::AccessType::UNPRIV; | ||||
|     const auto acctype = IR::AccType::UNPRIV; | ||||
|  | ||||
|     IR::U64 address; | ||||
|     if (Rn == Reg::SP) { | ||||
|   | ||||
| @@ -62,7 +62,7 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp | ||||
|     if (replicate) { | ||||
|         for (size_t s = 0; s < selem; s++) { | ||||
|             const Vec tt = static_cast<Vec>((VecNumber(Vt) + s) % 32); | ||||
|             const IR::UAnyU128 element = v.Mem(v.ir.Add(address, offs), ebytes, IR::AccessType::VEC); | ||||
|             const IR::UAnyU128 element = v.Mem(v.ir.Add(address, offs), ebytes, IR::AccType::VEC); | ||||
|             const IR::U128 broadcasted_element = v.ir.VectorBroadcast(esize, element); | ||||
|  | ||||
|             v.V(datasize, tt, broadcasted_element); | ||||
| @@ -75,12 +75,12 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp | ||||
|             const IR::U128 rval = v.V(128, tt); | ||||
|  | ||||
|             if (memop == IR::MemOp::LOAD) { | ||||
|                 const IR::UAny elem = v.Mem(v.ir.Add(address, offs), ebytes, IR::AccessType::VEC); | ||||
|                 const IR::UAny elem = v.Mem(v.ir.Add(address, offs), ebytes, IR::AccType::VEC); | ||||
|                 const IR::U128 vec = v.ir.VectorSetElement(esize, rval, index, elem); | ||||
|                 v.V(128, tt, vec); | ||||
|             } else { | ||||
|                 const IR::UAny elem = v.ir.VectorGetElement(esize, rval, index); | ||||
|                 v.Mem(v.ir.Add(address, offs), ebytes, IR::AccessType::VEC, elem); | ||||
|                 v.Mem(v.ir.Add(address, offs), ebytes, IR::AccType::VEC, elem); | ||||
|             } | ||||
|             offs = v.ir.Add(offs, v.ir.Imm64(ebytes)); | ||||
|         } | ||||
|   | ||||
| @@ -9,17 +9,23 @@ namespace Dynarmic::A64 { | ||||
|  | ||||
| bool TranslatorVisitor::IC_IALLU() { | ||||
|     ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoU, ir.Imm64(0)); | ||||
|     return true; | ||||
|     ir.SetPC(ir.Imm64(ir.current_location->PC() + 4)); | ||||
|     ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}}); | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| bool TranslatorVisitor::IC_IALLUIS() { | ||||
|     ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoUInnerSharable, ir.Imm64(0)); | ||||
|     return true; | ||||
|     ir.SetPC(ir.Imm64(ir.current_location->PC() + 4)); | ||||
|     ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}}); | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| bool TranslatorVisitor::IC_IVAU(Reg Rt) { | ||||
|     ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateByVAToPoU, X(64, Rt)); | ||||
|     return true; | ||||
|     ir.SetPC(ir.Imm64(ir.current_location->PC() + 4)); | ||||
|     ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}}); | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| }  // namespace Dynarmic::A64 | ||||
|   | ||||
							
								
								
									
										29
									
								
								externals/dynarmic/src/dynarmic/ir/acc_type.h
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										29
									
								
								externals/dynarmic/src/dynarmic/ir/acc_type.h
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| /* This file is part of the dynarmic project. | ||||
|  * Copyright (c) 2022 MerryMage | ||||
|  * SPDX-License-Identifier: 0BSD | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace Dynarmic::IR { | ||||
|  | ||||
| enum class AccType { | ||||
|     NORMAL, | ||||
|     VEC, | ||||
|     STREAM, | ||||
|     VECSTREAM, | ||||
|     ATOMIC, | ||||
|     ORDERED, | ||||
|     ORDEREDRW, | ||||
|     LIMITEDORDERED, | ||||
|     UNPRIV, | ||||
|     IFETCH, | ||||
|     PTW, | ||||
|     DC, | ||||
|     IC, | ||||
|     DCZVA, | ||||
|     AT, | ||||
|     SWAP,  // TODO: Remove | ||||
| }; | ||||
|  | ||||
| }  // namespace Dynarmic::IR | ||||
| @@ -6,7 +6,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "dynarmic/common/common_types.h" | ||||
| #include "dynarmic/ir/access_type.h" | ||||
| #include "dynarmic/ir/acc_type.h" | ||||
| #include "dynarmic/ir/basic_block.h" | ||||
| #include "dynarmic/ir/location_descriptor.h" | ||||
| #include "dynarmic/ir/terminal.h" | ||||
|   | ||||
| @@ -43,7 +43,7 @@ constexpr Type CoprocInfo = Type::CoprocInfo; | ||||
| constexpr Type NZCV = Type::NZCVFlags; | ||||
| constexpr Type Cond = Type::Cond; | ||||
| constexpr Type Table = Type::Table; | ||||
| constexpr Type AccessType = Type::AccessType; | ||||
| constexpr Type AccType = Type::AccType; | ||||
|  | ||||
| static const std::array opcode_info{ | ||||
| #define OPCODE(name, type, ...) Meta{#name, type, {__VA_ARGS__}}, | ||||
|   | ||||
							
								
								
									
										72
									
								
								externals/dynarmic/src/dynarmic/ir/opcodes.inc
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								externals/dynarmic/src/dynarmic/ir/opcodes.inc
									
									
									
									
										vendored
									
									
								
							| @@ -688,45 +688,45 @@ OPCODE(FPVectorToUnsignedFixed64,                           U128,           U128 | ||||
|  | ||||
| // A32 Memory access | ||||
| A32OPC(ClearExclusive,                                      Void,                                                                           ) | ||||
| A32OPC(ReadMemory8,                                         U8,             U32                                                             ) | ||||
| A32OPC(ReadMemory16,                                        U16,            U32                                                             ) | ||||
| A32OPC(ReadMemory32,                                        U32,            U32                                                             ) | ||||
| A32OPC(ReadMemory64,                                        U64,            U32                                                             ) | ||||
| A32OPC(ExclusiveReadMemory8,                                U8,             U32                                                             ) | ||||
| A32OPC(ExclusiveReadMemory16,                               U16,            U32                                                             ) | ||||
| A32OPC(ExclusiveReadMemory32,                               U32,            U32                                                             ) | ||||
| A32OPC(ExclusiveReadMemory64,                               U64,            U32                                                             ) | ||||
| A32OPC(WriteMemory8,                                        Void,           U32,            U8                                              ) | ||||
| A32OPC(WriteMemory16,                                       Void,           U32,            U16                                             ) | ||||
| A32OPC(WriteMemory32,                                       Void,           U32,            U32                                             ) | ||||
| A32OPC(WriteMemory64,                                       Void,           U32,            U64                                             ) | ||||
| A32OPC(ExclusiveWriteMemory8,                               U32,            U32,            U8                                              ) | ||||
| A32OPC(ExclusiveWriteMemory16,                              U32,            U32,            U16                                             ) | ||||
| A32OPC(ExclusiveWriteMemory32,                              U32,            U32,            U32                                             ) | ||||
| A32OPC(ExclusiveWriteMemory64,                              U32,            U32,            U64                                             ) | ||||
| A32OPC(ReadMemory8,                                         U8,             U32,            AccType                                         ) | ||||
| A32OPC(ReadMemory16,                                        U16,            U32,            AccType                                         ) | ||||
| A32OPC(ReadMemory32,                                        U32,            U32,            AccType                                         ) | ||||
| A32OPC(ReadMemory64,                                        U64,            U32,            AccType                                         ) | ||||
| A32OPC(ExclusiveReadMemory8,                                U8,             U32,            AccType                                         ) | ||||
| A32OPC(ExclusiveReadMemory16,                               U16,            U32,            AccType                                         ) | ||||
| A32OPC(ExclusiveReadMemory32,                               U32,            U32,            AccType                                         ) | ||||
| A32OPC(ExclusiveReadMemory64,                               U64,            U32,            AccType                                         ) | ||||
| A32OPC(WriteMemory8,                                        Void,           U32,            U8,             AccType                         ) | ||||
| A32OPC(WriteMemory16,                                       Void,           U32,            U16,            AccType                         ) | ||||
| A32OPC(WriteMemory32,                                       Void,           U32,            U32,            AccType                         ) | ||||
| A32OPC(WriteMemory64,                                       Void,           U32,            U64,            AccType                         ) | ||||
| A32OPC(ExclusiveWriteMemory8,                               U32,            U32,            U8,             AccType                         ) | ||||
| A32OPC(ExclusiveWriteMemory16,                              U32,            U32,            U16,            AccType                         ) | ||||
| A32OPC(ExclusiveWriteMemory32,                              U32,            U32,            U32,            AccType                         ) | ||||
| A32OPC(ExclusiveWriteMemory64,                              U32,            U32,            U64,            AccType                         ) | ||||
|  | ||||
| // A64 Memory access | ||||
| A64OPC(ClearExclusive,                                      Void,                                                                           ) | ||||
| A64OPC(ReadMemory8,                                         U8,             U64,            AccessType                                      ) | ||||
| A64OPC(ReadMemory16,                                        U16,            U64,            AccessType                                      ) | ||||
| A64OPC(ReadMemory32,                                        U32,            U64,            AccessType                                      ) | ||||
| A64OPC(ReadMemory64,                                        U64,            U64,            AccessType                                      ) | ||||
| A64OPC(ReadMemory128,                                       U128,           U64,            AccessType                                      ) | ||||
| A64OPC(ExclusiveReadMemory8,                                U8,             U64,            AccessType                                      ) | ||||
| A64OPC(ExclusiveReadMemory16,                               U16,            U64,            AccessType                                      ) | ||||
| A64OPC(ExclusiveReadMemory32,                               U32,            U64,            AccessType                                      ) | ||||
| A64OPC(ExclusiveReadMemory64,                               U64,            U64,            AccessType                                      ) | ||||
| A64OPC(ExclusiveReadMemory128,                              U128,           U64,            AccessType                                      ) | ||||
| A64OPC(WriteMemory8,                                        Void,           U64,            U8,             AccessType                      ) | ||||
| A64OPC(WriteMemory16,                                       Void,           U64,            U16,            AccessType                      ) | ||||
| A64OPC(WriteMemory32,                                       Void,           U64,            U32,            AccessType                      ) | ||||
| A64OPC(WriteMemory64,                                       Void,           U64,            U64,            AccessType                      ) | ||||
| A64OPC(WriteMemory128,                                      Void,           U64,            U128,           AccessType                      ) | ||||
| A64OPC(ExclusiveWriteMemory8,                               U32,            U64,            U8,             AccessType                      ) | ||||
| A64OPC(ExclusiveWriteMemory16,                              U32,            U64,            U16,            AccessType                      ) | ||||
| A64OPC(ExclusiveWriteMemory32,                              U32,            U64,            U32,            AccessType                      ) | ||||
| A64OPC(ExclusiveWriteMemory64,                              U32,            U64,            U64,            AccessType                      ) | ||||
| A64OPC(ExclusiveWriteMemory128,                             U32,            U64,            U128,           AccessType                      ) | ||||
| A64OPC(ReadMemory8,                                         U8,             U64,            AccType                                         ) | ||||
| A64OPC(ReadMemory16,                                        U16,            U64,            AccType                                         ) | ||||
| A64OPC(ReadMemory32,                                        U32,            U64,            AccType                                         ) | ||||
| A64OPC(ReadMemory64,                                        U64,            U64,            AccType                                         ) | ||||
| A64OPC(ReadMemory128,                                       U128,           U64,            AccType                                         ) | ||||
| A64OPC(ExclusiveReadMemory8,                                U8,             U64,            AccType                                         ) | ||||
| A64OPC(ExclusiveReadMemory16,                               U16,            U64,            AccType                                         ) | ||||
| A64OPC(ExclusiveReadMemory32,                               U32,            U64,            AccType                                         ) | ||||
| A64OPC(ExclusiveReadMemory64,                               U64,            U64,            AccType                                         ) | ||||
| A64OPC(ExclusiveReadMemory128,                              U128,           U64,            AccType                                         ) | ||||
| A64OPC(WriteMemory8,                                        Void,           U64,            U8,             AccType                         ) | ||||
| A64OPC(WriteMemory16,                                       Void,           U64,            U16,            AccType                         ) | ||||
| A64OPC(WriteMemory32,                                       Void,           U64,            U32,            AccType                         ) | ||||
| A64OPC(WriteMemory64,                                       Void,           U64,            U64,            AccType                         ) | ||||
| A64OPC(WriteMemory128,                                      Void,           U64,            U128,           AccType                         ) | ||||
| A64OPC(ExclusiveWriteMemory8,                               U32,            U64,            U8,             AccType                         ) | ||||
| A64OPC(ExclusiveWriteMemory16,                              U32,            U64,            U16,            AccType                         ) | ||||
| A64OPC(ExclusiveWriteMemory32,                              U32,            U64,            U32,            AccType                         ) | ||||
| A64OPC(ExclusiveWriteMemory64,                              U32,            U64,            U64,            AccType                         ) | ||||
| A64OPC(ExclusiveWriteMemory128,                             U32,            U64,            U128,           AccType                         ) | ||||
|  | ||||
| // Coprocessor | ||||
| A32OPC(CoprocInternalOperation,                             Void,           CoprocInfo                                                      ) | ||||
|   | ||||
| @@ -32,19 +32,19 @@ void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf) { | ||||
|  | ||||
|             const IR::U128 zero_u128 = ir.ZeroExtendToQuad(ir.Imm64(0)); | ||||
|             while (bytes >= 16) { | ||||
|                 ir.WriteMemory128(addr, zero_u128, IR::AccessType::DCZVA); | ||||
|                 ir.WriteMemory128(addr, zero_u128, IR::AccType::DCZVA); | ||||
|                 addr = ir.Add(addr, ir.Imm64(16)); | ||||
|                 bytes -= 16; | ||||
|             } | ||||
|  | ||||
|             while (bytes >= 8) { | ||||
|                 ir.WriteMemory64(addr, ir.Imm64(0), IR::AccessType::DCZVA); | ||||
|                 ir.WriteMemory64(addr, ir.Imm64(0), IR::AccType::DCZVA); | ||||
|                 addr = ir.Add(addr, ir.Imm64(8)); | ||||
|                 bytes -= 8; | ||||
|             } | ||||
|  | ||||
|             while (bytes >= 4) { | ||||
|                 ir.WriteMemory32(addr, ir.Imm32(0), IR::AccessType::DCZVA); | ||||
|                 ir.WriteMemory32(addr, ir.Imm32(0), IR::AccType::DCZVA); | ||||
|                 addr = ir.Add(addr, ir.Imm64(4)); | ||||
|                 bytes -= 4; | ||||
|             } | ||||
|   | ||||
							
								
								
									
										2
									
								
								externals/dynarmic/src/dynarmic/ir/type.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								externals/dynarmic/src/dynarmic/ir/type.h
									
									
									
									
										vendored
									
									
								
							| @@ -32,7 +32,7 @@ enum class Type { | ||||
|     NZCVFlags = 1 << 12, | ||||
|     Cond = 1 << 13, | ||||
|     Table = 1 << 14, | ||||
|     AccessType = 1 << 15, | ||||
|     AccType = 1 << 15, | ||||
| }; | ||||
|  | ||||
| constexpr Type operator|(Type a, Type b) { | ||||
|   | ||||
							
								
								
									
										8
									
								
								externals/dynarmic/src/dynarmic/ir/value.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								externals/dynarmic/src/dynarmic/ir/value.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -73,8 +73,8 @@ Value::Value(Cond value) | ||||
|     inner.imm_cond = value; | ||||
| } | ||||
|  | ||||
| Value::Value(AccessType value) | ||||
|         : type(Type::AccessType) { | ||||
| Value::Value(AccType value) | ||||
|         : type(Type::AccType) { | ||||
|     inner.imm_acctype = value; | ||||
| } | ||||
|  | ||||
| @@ -183,10 +183,10 @@ Cond Value::GetCond() const { | ||||
|     return inner.imm_cond; | ||||
| } | ||||
|  | ||||
| AccessType Value::GetAccType() const { | ||||
| AccType Value::GetAccType() const { | ||||
|     if (IsIdentity()) | ||||
|         return inner.inst->GetArg(0).GetAccType(); | ||||
|     ASSERT(type == Type::AccessType); | ||||
|     ASSERT(type == Type::AccType); | ||||
|     return inner.imm_acctype; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										8
									
								
								externals/dynarmic/src/dynarmic/ir/value.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								externals/dynarmic/src/dynarmic/ir/value.h
									
									
									
									
										vendored
									
									
								
							| @@ -25,7 +25,7 @@ enum class Vec; | ||||
| namespace Dynarmic::IR { | ||||
|  | ||||
| class Inst; | ||||
| enum class AccessType; | ||||
| enum class AccType; | ||||
| enum class Cond; | ||||
|  | ||||
| /** | ||||
| @@ -50,7 +50,7 @@ public: | ||||
|     explicit Value(u64 value); | ||||
|     explicit Value(CoprocessorInfo value); | ||||
|     explicit Value(Cond value); | ||||
|     explicit Value(AccessType value); | ||||
|     explicit Value(AccType value); | ||||
|  | ||||
|     bool IsIdentity() const; | ||||
|     bool IsEmpty() const; | ||||
| @@ -70,7 +70,7 @@ public: | ||||
|     u64 GetU64() const; | ||||
|     CoprocessorInfo GetCoprocInfo() const; | ||||
|     Cond GetCond() const; | ||||
|     AccessType GetAccType() const; | ||||
|     AccType GetAccType() const; | ||||
|  | ||||
|     /** | ||||
|      * Retrieves the immediate of a Value instance as a signed 64-bit value. | ||||
| @@ -143,7 +143,7 @@ private: | ||||
|         u64 imm_u64; | ||||
|         CoprocessorInfo imm_coproc; | ||||
|         Cond imm_cond; | ||||
|         AccessType imm_acctype; | ||||
|         AccType imm_acctype; | ||||
|     } inner; | ||||
| }; | ||||
| static_assert(sizeof(Value) <= 2 * sizeof(u64), "IR::Value should be kept small in size"); | ||||
|   | ||||
| @@ -93,17 +93,19 @@ public: | ||||
|             static constexpr u64 ICACHE_LINE_SIZE = 64; | ||||
|  | ||||
|             const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); | ||||
|             parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE); | ||||
|             parent.system.InvalidateCpuInstructionCacheRange(cache_line_start, ICACHE_LINE_SIZE); | ||||
|             break; | ||||
|         } | ||||
|         case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: | ||||
|             parent.ClearInstructionCache(); | ||||
|             parent.system.InvalidateCpuInstructionCaches(); | ||||
|             break; | ||||
|         case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: | ||||
|         default: | ||||
|             LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         parent.jit->HaltExecution(); | ||||
|     } | ||||
|  | ||||
|     void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <bit> | ||||
|  | ||||
| #include "shader_recompiler/backend/spirv/emit_spirv.h" | ||||
| #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" | ||||
| #include "shader_recompiler/backend/spirv/spirv_emit_context.h" | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <bit> | ||||
| #include <tuple> | ||||
| #include <utility> | ||||
|  | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <array> | ||||
| #include <bit> | ||||
| #include <climits> | ||||
|  | ||||
| #include <boost/container/static_vector.hpp> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user