early-access version 2615

This commit is contained in:
pineappleEA 2022-03-27 19:27:28 +02:00
parent 22beaa2af1
commit 613446086b
46 changed files with 731 additions and 841 deletions

View file

@ -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

View file

@ -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()

View file

@ -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)

View file

@ -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) {

View file

@ -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());

View file

@ -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)) {

View file

@ -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;

View file

@ -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;

View file

@ -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});
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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));
}

View file

@ -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) {

View file

@ -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);

View file

@ -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;
}

View file

@ -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));
}
}

View file

@ -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();

View file

@ -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);
});
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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));
}

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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));
}

View file

@ -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
View 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

View file

@ -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"

View file

@ -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__}},

View file

@ -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 )

View file

@ -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;
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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");

View file

@ -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 {

View file

@ -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"

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <bit>
#include <tuple>
#include <utility>

View file

@ -4,6 +4,7 @@
#include <algorithm>
#include <array>
#include <bit>
#include <climits>
#include <boost/container/static_vector.hpp>