early-access version 2615
This commit is contained in:
parent
22beaa2af1
commit
613446086b
@ -1,7 +1,7 @@
|
|||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 2614.
|
This is the source code for early-access 2615.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
2
externals/dynarmic/CMakeLists.txt
vendored
2
externals/dynarmic/CMakeLists.txt
vendored
@ -160,7 +160,7 @@ if (DYNARMIC_USE_LLVM)
|
|||||||
llvm_map_components_to_libnames(llvm_libs armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler)
|
llvm_map_components_to_libnames(llvm_libs armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (DYNARMIC_TESTS_USE_UNICORN)
|
if (DYNARMIC_TESTS_USE_UNICORN AND DYNARMIC_TESTS)
|
||||||
find_package(Unicorn REQUIRED)
|
find_package(Unicorn REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ add_library(dynarmic
|
|||||||
frontend/imm.h
|
frontend/imm.h
|
||||||
interface/exclusive_monitor.h
|
interface/exclusive_monitor.h
|
||||||
interface/optimization_flags.h
|
interface/optimization_flags.h
|
||||||
|
ir/acc_type.h
|
||||||
ir/basic_block.cpp
|
ir/basic_block.cpp
|
||||||
ir/basic_block.h
|
ir/basic_block.h
|
||||||
ir/cond.h
|
ir/cond.h
|
||||||
@ -99,7 +100,7 @@ add_library(dynarmic
|
|||||||
ir/type.h
|
ir/type.h
|
||||||
ir/value.cpp
|
ir/value.cpp
|
||||||
ir/value.h
|
ir/value.h
|
||||||
ir/access_type.h)
|
)
|
||||||
|
|
||||||
if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
||||||
target_sources(dynarmic PRIVATE
|
target_sources(dynarmic PRIVATE
|
||||||
@ -390,7 +391,7 @@ target_link_libraries(dynarmic
|
|||||||
tsl::robin_map
|
tsl::robin_map
|
||||||
$<BUILD_INTERFACE:xbyak>
|
$<BUILD_INTERFACE:xbyak>
|
||||||
$<BUILD_INTERFACE:Zydis>
|
$<BUILD_INTERFACE:Zydis>
|
||||||
$<$<BOOL:DYNARMIC_USE_LLVM>:${llvm_libs}>
|
"$<$<BOOL:DYNARMIC_USE_LLVM>:${llvm_libs}>"
|
||||||
)
|
)
|
||||||
if (DYNARMIC_ENABLE_CPU_FEATURE_DETECTION)
|
if (DYNARMIC_ENABLE_CPU_FEATURE_DETECTION)
|
||||||
target_compile_definitions(dynarmic PRIVATE DYNARMIC_ENABLE_CPU_FEATURE_DETECTION=1)
|
target_compile_definitions(dynarmic PRIVATE DYNARMIC_ENABLE_CPU_FEATURE_DETECTION=1)
|
||||||
|
@ -158,120 +158,6 @@ FakeCall A32EmitX64::FastmemCallback(u64 rip_) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr size_t page_bits = 12;
|
|
||||||
constexpr size_t page_size = 1 << page_bits;
|
|
||||||
constexpr size_t page_mask = (1 << page_bits) - 1;
|
|
||||||
|
|
||||||
void EmitDetectMisaignedVAddr(BlockOfCode& code, A32EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg32 vaddr, Xbyak::Reg32 tmp) {
|
|
||||||
if (bitsize == 8 || (ctx.conf.detect_misaligned_access_via_page_table & bitsize) == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 align_mask = [bitsize]() -> u32 {
|
|
||||||
switch (bitsize) {
|
|
||||||
case 16:
|
|
||||||
return 0b1;
|
|
||||||
case 32:
|
|
||||||
return 0b11;
|
|
||||||
case 64:
|
|
||||||
return 0b111;
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}();
|
|
||||||
|
|
||||||
code.test(vaddr, align_mask);
|
|
||||||
|
|
||||||
if (!ctx.conf.only_detect_misalignment_via_page_table_on_page_boundary) {
|
|
||||||
code.jnz(abort, code.T_NEAR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 page_align_mask = static_cast<u32>(page_size - 1) & ~align_mask;
|
|
||||||
|
|
||||||
Xbyak::Label detect_boundary, resume;
|
|
||||||
|
|
||||||
code.jnz(detect_boundary, code.T_NEAR);
|
|
||||||
code.L(resume);
|
|
||||||
|
|
||||||
code.SwitchToFarCode();
|
|
||||||
code.L(detect_boundary);
|
|
||||||
code.mov(tmp, vaddr);
|
|
||||||
code.and_(tmp, page_align_mask);
|
|
||||||
code.cmp(tmp, page_align_mask);
|
|
||||||
code.jne(resume, code.T_NEAR);
|
|
||||||
// NOTE: We expect to fallthrough into abort code here.
|
|
||||||
code.SwitchToNearCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
Xbyak::RegExp EmitVAddrLookup(BlockOfCode& code, A32EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr) {
|
|
||||||
const Xbyak::Reg64 page = ctx.reg_alloc.ScratchGpr();
|
|
||||||
const Xbyak::Reg32 tmp = ctx.conf.absolute_offset_page_table ? page.cvt32() : ctx.reg_alloc.ScratchGpr().cvt32();
|
|
||||||
|
|
||||||
EmitDetectMisaignedVAddr(code, ctx, bitsize, abort, vaddr.cvt32(), tmp);
|
|
||||||
|
|
||||||
// TODO: This code assumes vaddr has been zext from 32-bits to 64-bits.
|
|
||||||
|
|
||||||
code.mov(tmp, vaddr.cvt32());
|
|
||||||
code.shr(tmp, static_cast<int>(page_bits));
|
|
||||||
code.mov(page, qword[r14 + tmp.cvt64() * sizeof(void*)]);
|
|
||||||
if (ctx.conf.page_table_pointer_mask_bits == 0) {
|
|
||||||
code.test(page, page);
|
|
||||||
} else {
|
|
||||||
code.and_(page, ~u32(0) << ctx.conf.page_table_pointer_mask_bits);
|
|
||||||
}
|
|
||||||
code.jz(abort, code.T_NEAR);
|
|
||||||
if (ctx.conf.absolute_offset_page_table) {
|
|
||||||
return page + vaddr;
|
|
||||||
}
|
|
||||||
code.mov(tmp, vaddr.cvt32());
|
|
||||||
code.and_(tmp, static_cast<u32>(page_mask));
|
|
||||||
return page + tmp.cvt64();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t bitsize>
|
|
||||||
void EmitReadMemoryMov(BlockOfCode& code, const Xbyak::Reg64& value, const Xbyak::RegExp& addr) {
|
|
||||||
switch (bitsize) {
|
|
||||||
case 8:
|
|
||||||
code.movzx(value.cvt32(), code.byte[addr]);
|
|
||||||
return;
|
|
||||||
case 16:
|
|
||||||
code.movzx(value.cvt32(), word[addr]);
|
|
||||||
return;
|
|
||||||
case 32:
|
|
||||||
code.mov(value.cvt32(), dword[addr]);
|
|
||||||
return;
|
|
||||||
case 64:
|
|
||||||
code.mov(value, qword[addr]);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
ASSERT_FALSE("Invalid bitsize");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t bitsize>
|
|
||||||
void EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, const Xbyak::Reg64& value) {
|
|
||||||
switch (bitsize) {
|
|
||||||
case 8:
|
|
||||||
code.mov(code.byte[addr], value.cvt8());
|
|
||||||
return;
|
|
||||||
case 16:
|
|
||||||
code.mov(word[addr], value.cvt16());
|
|
||||||
return;
|
|
||||||
case 32:
|
|
||||||
code.mov(dword[addr], value.cvt32());
|
|
||||||
return;
|
|
||||||
case 64:
|
|
||||||
code.mov(qword[addr], value);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
ASSERT_FALSE("Invalid bitsize");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
template<std::size_t bitsize, auto callback>
|
template<std::size_t bitsize, auto callback>
|
||||||
void A32EmitX64::EmitMemoryRead(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitMemoryRead(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(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 src_ptr = r13 + vaddr;
|
||||||
|
|
||||||
const auto location = code.getCurr();
|
const auto location = code.getCurr();
|
||||||
EmitReadMemoryMov<bitsize>(code, value, src_ptr);
|
EmitReadMemoryMov<bitsize>(code, value.getIdx(), src_ptr);
|
||||||
|
|
||||||
fastmem_patch_info.emplace(
|
fastmem_patch_info.emplace(
|
||||||
Common::BitCast<u64>(location),
|
Common::BitCast<u64>(location),
|
||||||
@ -315,7 +201,7 @@ void A32EmitX64::EmitMemoryRead(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
Xbyak::Label abort, end;
|
Xbyak::Label abort, end;
|
||||||
|
|
||||||
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
|
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.L(end);
|
||||||
|
|
||||||
code.SwitchToFarCode();
|
code.SwitchToFarCode();
|
||||||
@ -349,7 +235,7 @@ void A32EmitX64::EmitMemoryWrite(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
const auto dest_ptr = r13 + vaddr;
|
const auto dest_ptr = r13 + vaddr;
|
||||||
|
|
||||||
const auto location = code.getCurr();
|
const auto location = code.getCurr();
|
||||||
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value);
|
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value.getIdx());
|
||||||
|
|
||||||
fastmem_patch_info.emplace(
|
fastmem_patch_info.emplace(
|
||||||
Common::BitCast<u64>(location),
|
Common::BitCast<u64>(location),
|
||||||
@ -368,7 +254,7 @@ void A32EmitX64::EmitMemoryWrite(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
Xbyak::Label abort, end;
|
Xbyak::Label abort, end;
|
||||||
|
|
||||||
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
|
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.L(end);
|
||||||
|
|
||||||
code.SwitchToFarCode();
|
code.SwitchToFarCode();
|
||||||
@ -488,7 +374,7 @@ void A32EmitX64::ExclusiveReadMemoryInline(A32EmitContext& ctx, IR::Inst* inst)
|
|||||||
const auto src_ptr = r13 + vaddr;
|
const auto src_ptr = r13 + vaddr;
|
||||||
|
|
||||||
const auto location = code.getCurr();
|
const auto location = code.getCurr();
|
||||||
EmitReadMemoryMov<bitsize>(code, value, src_ptr);
|
EmitReadMemoryMov<bitsize>(code, value.getIdx(), src_ptr);
|
||||||
|
|
||||||
fastmem_patch_info.emplace(
|
fastmem_patch_info.emplace(
|
||||||
Common::BitCast<u64>(location),
|
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)));
|
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());
|
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(code.byte[r15 + offsetof(A32JitState, exclusive_state)], u8(0));
|
||||||
code.mov(tmp, Common::BitCast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id)));
|
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);
|
const auto fastmem_marker = ShouldFastmem(ctx, inst);
|
||||||
if (fastmem_marker) {
|
if (fastmem_marker) {
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "dynarmic/common/spin_lock_x64.h"
|
#include "dynarmic/common/spin_lock_x64.h"
|
||||||
#include "dynarmic/common/x64_disassemble.h"
|
#include "dynarmic/common/x64_disassemble.h"
|
||||||
#include "dynarmic/interface/exclusive_monitor.h"
|
#include "dynarmic/interface/exclusive_monitor.h"
|
||||||
#include "dynarmic/ir/access_type.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::X64 {
|
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>
|
template<std::size_t bitsize, auto callback>
|
||||||
void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(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);
|
const auto fastmem_marker = ShouldFastmem(ctx, inst);
|
||||||
|
|
||||||
if (!conf.page_table && !fastmem_marker) {
|
if (!conf.page_table && !fastmem_marker) {
|
||||||
// Neither fastmem nor page table: Use callbacks
|
// Neither fastmem nor page table: Use callbacks
|
||||||
if constexpr (bitsize == 128) {
|
if constexpr (bitsize == 128) {
|
||||||
ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
|
ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
code.CallFunction(memory_read_128);
|
code.CallFunction(memory_read_128);
|
||||||
ctx.reg_alloc.DefineValue(inst, xmm1);
|
ctx.reg_alloc.DefineValue(inst, xmm1);
|
||||||
} else {
|
} else {
|
||||||
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
||||||
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
||||||
}
|
}
|
||||||
@ -585,7 +331,8 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) {
|
|||||||
// Use fastmem
|
// Use fastmem
|
||||||
const auto src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
|
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(
|
fastmem_patch_info.emplace(
|
||||||
Common::BitCast<u64>(location),
|
Common::BitCast<u64>(location),
|
||||||
@ -600,16 +347,13 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) {
|
|||||||
ASSERT(conf.page_table);
|
ASSERT(conf.page_table);
|
||||||
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
|
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
|
||||||
require_abort_handling = true;
|
require_abort_handling = true;
|
||||||
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
|
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr);
|
||||||
}
|
}
|
||||||
code.L(end);
|
code.L(end);
|
||||||
|
|
||||||
if (require_abort_handling) {
|
if (require_abort_handling) {
|
||||||
code.SwitchToFarCode();
|
code.SwitchToFarCode();
|
||||||
code.L(abort);
|
code.L(abort);
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
code.call(wrapped_fn);
|
code.call(wrapped_fn);
|
||||||
code.jmp(end, code.T_NEAR);
|
code.jmp(end, code.T_NEAR);
|
||||||
code.SwitchToNearCode();
|
code.SwitchToNearCode();
|
||||||
@ -625,8 +369,6 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) {
|
|||||||
template<std::size_t bitsize, auto callback>
|
template<std::size_t bitsize, auto callback>
|
||||||
void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(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);
|
const auto fastmem_marker = ShouldFastmem(ctx, inst);
|
||||||
|
|
||||||
if (!conf.page_table && !fastmem_marker) {
|
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]);
|
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||||
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
||||||
}
|
}
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
|
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
const int value_idx = bitsize == 128
|
const int value_idx = bitsize == 128 ? ctx.reg_alloc.UseXmm(args[1]).getIdx() : ctx.reg_alloc.UseGpr(args[1]).getIdx();
|
||||||
? ctx.reg_alloc.UseXmm(args[1]).getIdx()
|
|
||||||
: (ordered ? ctx.reg_alloc.UseScratchGpr(args[1]).getIdx() : ctx.reg_alloc.UseGpr(args[1]).getIdx());
|
|
||||||
|
|
||||||
const auto wrapped_fn = write_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value_idx)];
|
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 dest_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
|
||||||
|
|
||||||
const auto location = code.getCurr();
|
const auto location = code.getCurr();
|
||||||
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
|
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx);
|
||||||
|
|
||||||
fastmem_patch_info.emplace(
|
fastmem_patch_info.emplace(
|
||||||
Common::BitCast<u64>(location),
|
Common::BitCast<u64>(location),
|
||||||
@ -677,7 +414,7 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) {
|
|||||||
ASSERT(conf.page_table);
|
ASSERT(conf.page_table);
|
||||||
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
|
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
|
||||||
require_abort_handling = true;
|
require_abort_handling = true;
|
||||||
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
|
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx);
|
||||||
}
|
}
|
||||||
code.L(end);
|
code.L(end);
|
||||||
|
|
||||||
@ -685,9 +422,6 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) {
|
|||||||
code.SwitchToFarCode();
|
code.SwitchToFarCode();
|
||||||
code.L(abort);
|
code.L(abort);
|
||||||
code.call(wrapped_fn);
|
code.call(wrapped_fn);
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
code.jmp(end, code.T_NEAR);
|
code.jmp(end, code.T_NEAR);
|
||||||
code.SwitchToNearCode();
|
code.SwitchToNearCode();
|
||||||
}
|
}
|
||||||
@ -737,8 +471,6 @@ template<std::size_t bitsize, auto callback>
|
|||||||
void A64EmitX64::EmitExclusiveReadMemory(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitExclusiveReadMemory(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
ASSERT(conf.global_monitor != nullptr);
|
ASSERT(conf.global_monitor != nullptr);
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(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;
|
|
||||||
|
|
||||||
if constexpr (bitsize != 128) {
|
if constexpr (bitsize != 128) {
|
||||||
using T = mp::unsigned_integer_of_size<bitsize>;
|
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.byte[r15 + offsetof(A64JitState, exclusive_state)], u8(1));
|
||||||
code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(&conf));
|
code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(&conf));
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
code.CallLambda(
|
code.CallLambda(
|
||||||
[](A64::UserConfig& conf, u64 vaddr) -> T {
|
[](A64::UserConfig& conf, u64 vaddr) -> T {
|
||||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, 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));
|
code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(&conf));
|
||||||
ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE);
|
ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE);
|
||||||
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
|
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
code.CallLambda(
|
code.CallLambda(
|
||||||
[](A64::UserConfig& conf, u64 vaddr, A64::Vector& ret) {
|
[](A64::UserConfig& conf, u64 vaddr, A64::Vector& ret) {
|
||||||
ret = conf.global_monitor->ReadAndMark<A64::Vector>(conf.processor_id, vaddr, [&]() -> A64::Vector {
|
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) {
|
void A64EmitX64::EmitExclusiveWriteMemory(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
ASSERT(conf.global_monitor != nullptr);
|
ASSERT(conf.global_monitor != nullptr);
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
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) {
|
if constexpr (bitsize != 128) {
|
||||||
ctx.reg_alloc.HostCall(inst, {}, args[0], args[1]);
|
ctx.reg_alloc.HostCall(inst, {}, args[0], args[1]);
|
||||||
@ -818,9 +542,6 @@ void A64EmitX64::EmitExclusiveWriteMemory(A64EmitContext& ctx, IR::Inst* inst) {
|
|||||||
? 0
|
? 0
|
||||||
: 1;
|
: 1;
|
||||||
});
|
});
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE);
|
ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE);
|
||||||
code.lea(code.ABI_PARAM3, ptr[rsp + 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
|
? 0
|
||||||
: 1;
|
: 1;
|
||||||
});
|
});
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
ctx.reg_alloc.ReleaseStackSpace(16 + ABI_SHADOW_SPACE);
|
ctx.reg_alloc.ReleaseStackSpace(16 + ABI_SHADOW_SPACE);
|
||||||
}
|
}
|
||||||
code.L(end);
|
code.L(end);
|
||||||
@ -851,8 +569,6 @@ void A64EmitX64::EmitExclusiveReadMemoryInline(A64EmitContext& ctx, IR::Inst* in
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(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 Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
|
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();
|
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 src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
|
||||||
|
|
||||||
const auto location = code.getCurr();
|
const auto location = code.getCurr();
|
||||||
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
|
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr);
|
||||||
|
|
||||||
fastmem_patch_info.emplace(
|
fastmem_patch_info.emplace(
|
||||||
Common::BitCast<u64>(location),
|
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)));
|
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());
|
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);
|
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 = [&] {
|
const auto value = [&] {
|
||||||
if constexpr (bitsize == 128) {
|
if constexpr (bitsize == 128) {
|
||||||
@ -970,7 +684,7 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i
|
|||||||
code.movq(rcx, xmm0);
|
code.movq(rcx, xmm0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EmitReadMemoryMov<bitsize>(code, rax.getIdx(), tmp, false);
|
EmitReadMemoryMov<bitsize>(code, rax.getIdx(), tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto fastmem_marker = ShouldFastmem(ctx, inst);
|
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.setnz(status.cvt8());
|
||||||
|
|
||||||
code.SwitchToFarCode();
|
code.SwitchToFarCode();
|
||||||
@ -1027,10 +737,6 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i
|
|||||||
conf.recompile_on_exclusive_fastmem_failure,
|
conf.recompile_on_exclusive_fastmem_failure,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
|
|
||||||
code.cmp(al, 0);
|
code.cmp(al, 0);
|
||||||
code.setz(status.cvt8());
|
code.setz(status.cvt8());
|
||||||
code.movzx(status.cvt32(), status.cvt8());
|
code.movzx(status.cvt32(), status.cvt8());
|
||||||
@ -1038,9 +744,6 @@ void A64EmitX64::EmitExclusiveWriteMemoryInline(A64EmitContext& ctx, IR::Inst* i
|
|||||||
code.SwitchToNearCode();
|
code.SwitchToNearCode();
|
||||||
} else {
|
} else {
|
||||||
code.call(fallback_fn);
|
code.call(fallback_fn);
|
||||||
if (ordered) {
|
|
||||||
code.mfence();
|
|
||||||
}
|
|
||||||
code.cmp(al, 0);
|
code.cmp(al, 0);
|
||||||
code.setz(status.cvt8());
|
code.setz(status.cvt8());
|
||||||
code.movzx(status.cvt32(), status.cvt8());
|
code.movzx(status.cvt32(), status.cvt8());
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <xbyak/xbyak.h>
|
#include <xbyak/xbyak.h>
|
||||||
|
|
||||||
|
#include "dynarmic/backend/x64/a32_emit_x64.h"
|
||||||
#include "dynarmic/backend/x64/a64_emit_x64.h"
|
#include "dynarmic/backend/x64/a64_emit_x64.h"
|
||||||
#include "dynarmic/backend/x64/exclusive_monitor_friend.h"
|
#include "dynarmic/backend/x64/exclusive_monitor_friend.h"
|
||||||
#include "dynarmic/common/spin_lock_x64.h"
|
#include "dynarmic/common/spin_lock_x64.h"
|
||||||
@ -16,6 +17,232 @@ namespace {
|
|||||||
|
|
||||||
using namespace Xbyak::util;
|
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>
|
template<typename UserConfig>
|
||||||
void EmitExclusiveLock(BlockOfCode& code, const UserConfig& conf, Xbyak::Reg64 pointer, Xbyak::Reg32 tmp) {
|
void EmitExclusiveLock(BlockOfCode& code, const UserConfig& conf, Xbyak::Reg64 pointer, Xbyak::Reg32 tmp) {
|
||||||
if (conf.HasOptimization(OptimizationFlag::Unsafe_IgnoreGlobalMonitor)) {
|
if (conf.HasOptimization(OptimizationFlag::Unsafe_IgnoreGlobalMonitor)) {
|
||||||
|
@ -42,6 +42,7 @@ static size_t GetBitWidth(IR::Type type) {
|
|||||||
case IR::Type::Cond:
|
case IR::Type::Cond:
|
||||||
case IR::Type::Void:
|
case IR::Type::Void:
|
||||||
case IR::Type::Table:
|
case IR::Type::Table:
|
||||||
|
case IR::Type::AccType:
|
||||||
ASSERT_FALSE("Type {} cannot be represented at runtime", type);
|
ASSERT_FALSE("Type {} cannot be represented at runtime", type);
|
||||||
case IR::Type::Opaque:
|
case IR::Type::Opaque:
|
||||||
ASSERT_FALSE("Not a concrete type");
|
ASSERT_FALSE("Not a concrete type");
|
||||||
@ -207,11 +208,6 @@ IR::Cond Argument::GetImmediateCond() const {
|
|||||||
return value.GetCond();
|
return value.GetCond();
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::AccessType Argument::GetImmediateAccType() const {
|
|
||||||
ASSERT(IsImmediate() && GetType() == IR::Type::AccessType);
|
|
||||||
return value.GetAccType();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Argument::IsInGpr() const {
|
bool Argument::IsInGpr() const {
|
||||||
if (IsImmediate())
|
if (IsImmediate())
|
||||||
return false;
|
return false;
|
||||||
|
@ -75,7 +75,6 @@ public:
|
|||||||
u64 GetImmediateS32() const;
|
u64 GetImmediateS32() const;
|
||||||
u64 GetImmediateU64() const;
|
u64 GetImmediateU64() const;
|
||||||
IR::Cond GetImmediateCond() const;
|
IR::Cond GetImmediateCond() const;
|
||||||
IR::AccessType GetImmediateAccType() const;
|
|
||||||
|
|
||||||
/// Is this value currently in a GPR?
|
/// Is this value currently in a GPR?
|
||||||
bool IsInGpr() const;
|
bool IsInGpr() const;
|
||||||
|
@ -229,55 +229,55 @@ void IREmitter::ClearExclusive() {
|
|||||||
Inst(Opcode::A32ClearExclusive);
|
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) {
|
switch (bitsize) {
|
||||||
case 8:
|
case 8:
|
||||||
return ReadMemory8(vaddr);
|
return ReadMemory8(vaddr, acc_type);
|
||||||
case 16:
|
case 16:
|
||||||
return ReadMemory16(vaddr);
|
return ReadMemory16(vaddr, acc_type);
|
||||||
case 32:
|
case 32:
|
||||||
return ReadMemory32(vaddr);
|
return ReadMemory32(vaddr, acc_type);
|
||||||
case 64:
|
case 64:
|
||||||
return ReadMemory64(vaddr);
|
return ReadMemory64(vaddr, acc_type);
|
||||||
}
|
}
|
||||||
ASSERT_FALSE("Invalid bitsize");
|
ASSERT_FALSE("Invalid bitsize");
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U8 IREmitter::ReadMemory8(const IR::U32& vaddr) {
|
IR::U8 IREmitter::ReadMemory8(const IR::U32& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U8>(Opcode::A32ReadMemory8, vaddr);
|
return Inst<IR::U8>(Opcode::A32ReadMemory8, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U16 IREmitter::ReadMemory16(const IR::U32& vaddr) {
|
IR::U16 IREmitter::ReadMemory16(const IR::U32& vaddr, IR::AccType acc_type) {
|
||||||
const auto value = Inst<IR::U16>(Opcode::A32ReadMemory16, vaddr);
|
const auto value = Inst<IR::U16>(Opcode::A32ReadMemory16, vaddr, IR::Value{acc_type});
|
||||||
return current_location.EFlag() ? ByteReverseHalf(value) : value;
|
return current_location.EFlag() ? ByteReverseHalf(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::ReadMemory32(const IR::U32& vaddr) {
|
IR::U32 IREmitter::ReadMemory32(const IR::U32& vaddr, IR::AccType acc_type) {
|
||||||
const auto value = Inst<IR::U32>(Opcode::A32ReadMemory32, vaddr);
|
const auto value = Inst<IR::U32>(Opcode::A32ReadMemory32, vaddr, IR::Value{acc_type});
|
||||||
return current_location.EFlag() ? ByteReverseWord(value) : value;
|
return current_location.EFlag() ? ByteReverseWord(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U64 IREmitter::ReadMemory64(const IR::U32& vaddr) {
|
IR::U64 IREmitter::ReadMemory64(const IR::U32& vaddr, IR::AccType acc_type) {
|
||||||
const auto value = Inst<IR::U64>(Opcode::A32ReadMemory64, vaddr);
|
const auto value = Inst<IR::U64>(Opcode::A32ReadMemory64, vaddr, IR::Value{acc_type});
|
||||||
return current_location.EFlag() ? ByteReverseDual(value) : value;
|
return current_location.EFlag() ? ByteReverseDual(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U32& vaddr) {
|
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U32& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U8>(Opcode::A32ExclusiveReadMemory8, vaddr);
|
return Inst<IR::U8>(Opcode::A32ExclusiveReadMemory8, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U32& vaddr) {
|
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U32& vaddr, IR::AccType acc_type) {
|
||||||
const auto value = Inst<IR::U16>(Opcode::A32ExclusiveReadMemory16, vaddr);
|
const auto value = Inst<IR::U16>(Opcode::A32ExclusiveReadMemory16, vaddr, IR::Value{acc_type});
|
||||||
return current_location.EFlag() ? ByteReverseHalf(value) : value;
|
return current_location.EFlag() ? ByteReverseHalf(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U32& vaddr) {
|
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U32& vaddr, IR::AccType acc_type) {
|
||||||
const auto value = Inst<IR::U32>(Opcode::A32ExclusiveReadMemory32, vaddr);
|
const auto value = Inst<IR::U32>(Opcode::A32ExclusiveReadMemory32, vaddr, IR::Value{acc_type});
|
||||||
return current_location.EFlag() ? ByteReverseWord(value) : value;
|
return current_location.EFlag() ? ByteReverseWord(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<IR::U32, IR::U32> IREmitter::ExclusiveReadMemory64(const IR::U32& 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);
|
const auto value = Inst<IR::U64>(Opcode::A32ExclusiveReadMemory64, vaddr, IR::Value{acc_type});
|
||||||
const auto lo = LeastSignificantWord(value);
|
const auto lo = LeastSignificantWord(value);
|
||||||
const auto hi = MostSignificantWord(value).result;
|
const auto hi = MostSignificantWord(value).result;
|
||||||
if (current_location.EFlag()) {
|
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);
|
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) {
|
switch (bitsize) {
|
||||||
case 8:
|
case 8:
|
||||||
return WriteMemory8(vaddr, value);
|
return WriteMemory8(vaddr, value, acc_type);
|
||||||
case 16:
|
case 16:
|
||||||
return WriteMemory16(vaddr, value);
|
return WriteMemory16(vaddr, value, acc_type);
|
||||||
case 32:
|
case 32:
|
||||||
return WriteMemory32(vaddr, value);
|
return WriteMemory32(vaddr, value, acc_type);
|
||||||
case 64:
|
case 64:
|
||||||
return WriteMemory64(vaddr, value);
|
return WriteMemory64(vaddr, value, acc_type);
|
||||||
}
|
}
|
||||||
ASSERT_FALSE("Invalid bitsize");
|
ASSERT_FALSE("Invalid bitsize");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory8(const IR::U32& vaddr, const IR::U8& value) {
|
void IREmitter::WriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type) {
|
||||||
Inst(Opcode::A32WriteMemory8, vaddr, value);
|
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()) {
|
if (current_location.EFlag()) {
|
||||||
const auto v = ByteReverseHalf(value);
|
const auto v = ByteReverseHalf(value);
|
||||||
Inst(Opcode::A32WriteMemory16, vaddr, v);
|
Inst(Opcode::A32WriteMemory16, vaddr, v, IR::Value{acc_type});
|
||||||
} else {
|
} 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()) {
|
if (current_location.EFlag()) {
|
||||||
const auto v = ByteReverseWord(value);
|
const auto v = ByteReverseWord(value);
|
||||||
Inst(Opcode::A32WriteMemory32, vaddr, v);
|
Inst(Opcode::A32WriteMemory32, vaddr, v, IR::Value{acc_type});
|
||||||
} else {
|
} 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()) {
|
if (current_location.EFlag()) {
|
||||||
const auto v = ByteReverseDual(value);
|
const auto v = ByteReverseDual(value);
|
||||||
Inst(Opcode::A32WriteMemory64, vaddr, v);
|
Inst(Opcode::A32WriteMemory64, vaddr, v, IR::Value{acc_type});
|
||||||
} else {
|
} 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) {
|
IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type) {
|
||||||
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory8, vaddr, value);
|
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()) {
|
if (current_location.EFlag()) {
|
||||||
const auto v = ByteReverseHalf(value);
|
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 {
|
} 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()) {
|
if (current_location.EFlag()) {
|
||||||
const auto v = ByteReverseWord(value);
|
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 {
|
} 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()) {
|
if (current_location.EFlag()) {
|
||||||
const auto vlo = ByteReverseWord(value_lo);
|
const auto vlo = ByteReverseWord(value_lo);
|
||||||
const auto vhi = ByteReverseWord(value_hi);
|
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 {
|
} else {
|
||||||
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(value_lo, value_hi));
|
return Inst<IR::U32>(Opcode::A32ExclusiveWriteMemory64, vaddr, Pack2x32To1x64(value_lo, value_hi), IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,24 +80,24 @@ public:
|
|||||||
void SetFpscrNZCV(const IR::NZCV& new_fpscr_nzcv);
|
void SetFpscrNZCV(const IR::NZCV& new_fpscr_nzcv);
|
||||||
|
|
||||||
void ClearExclusive();
|
void ClearExclusive();
|
||||||
IR::UAny ReadMemory(size_t bitsize, const IR::U32& vaddr);
|
IR::UAny ReadMemory(size_t bitsize, const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
IR::U8 ReadMemory8(const IR::U32& vaddr);
|
IR::U8 ReadMemory8(const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
IR::U16 ReadMemory16(const IR::U32& vaddr);
|
IR::U16 ReadMemory16(const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
IR::U32 ReadMemory32(const IR::U32& vaddr);
|
IR::U32 ReadMemory32(const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
IR::U64 ReadMemory64(const IR::U32& vaddr);
|
IR::U64 ReadMemory64(const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
IR::U8 ExclusiveReadMemory8(const IR::U32& vaddr);
|
IR::U8 ExclusiveReadMemory8(const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
IR::U16 ExclusiveReadMemory16(const IR::U32& vaddr);
|
IR::U16 ExclusiveReadMemory16(const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
IR::U32 ExclusiveReadMemory32(const IR::U32& vaddr);
|
IR::U32 ExclusiveReadMemory32(const IR::U32& vaddr, IR::AccType acc_type);
|
||||||
std::pair<IR::U32, IR::U32> ExclusiveReadMemory64(const IR::U32& vaddr);
|
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);
|
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);
|
void WriteMemory8(const IR::U32& vaddr, const IR::U8& value, IR::AccType acc_type);
|
||||||
void WriteMemory16(const IR::U32& vaddr, const IR::U16& value);
|
void WriteMemory16(const IR::U32& vaddr, const IR::U16& value, IR::AccType acc_type);
|
||||||
void WriteMemory32(const IR::U32& vaddr, const IR::U32& value);
|
void WriteMemory32(const IR::U32& vaddr, const IR::U32& value, IR::AccType acc_type);
|
||||||
void WriteMemory64(const IR::U32& vaddr, const IR::U64& value);
|
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::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::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::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::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 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);
|
void CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, CoprocReg CRn, CoprocReg CRm, size_t opc2, const IR::U32& word);
|
||||||
|
@ -103,7 +103,7 @@ bool TranslatorVisitor::v8_VST_multiple(bool D, Reg n, size_t Vd, Imm<4> type, s
|
|||||||
const ExtReg ext_reg = d + i * inc + r;
|
const 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::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);
|
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)));
|
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 r = 0; r < regs; r++) {
|
||||||
for (size_t e = 0; e < elements; e++) {
|
for (size_t e = 0; e < elements; e++) {
|
||||||
for (size_t i = 0; i < nelem; i++) {
|
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 IR::U64 shifted_element = ir.LogicalShiftLeft(element, ir.Imm8(static_cast<u8>(e * ebytes * 8)));
|
||||||
|
|
||||||
const ExtReg ext_reg = d + i * inc + r;
|
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);
|
auto address = ir.GetRegister(n);
|
||||||
for (size_t i = 0; i < nelem; i++) {
|
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);
|
const auto replicated_element = ir.VectorBroadcast(ebytes * 8, element);
|
||||||
|
|
||||||
for (size_t r = 0; r < regs; r++) {
|
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 ExtReg ext_reg = d + i * inc;
|
||||||
const auto element = ir.VectorGetElement(ebytes * 8, ir.GetVector(ext_reg), index);
|
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)));
|
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);
|
auto address = ir.GetRegister(n);
|
||||||
for (size_t i = 0; i < nelem; i++) {
|
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 ExtReg ext_reg = d + i * inc;
|
||||||
const auto new_reg = ir.VectorSetElement(ebytes * 8, ir.GetVector(ext_reg), index, element);
|
const auto new_reg = ir.VectorSetElement(ebytes * 8, ir.GetVector(ext_reg), index, element);
|
||||||
|
@ -71,7 +71,7 @@ bool TranslatorVisitor::arm_LDR_lit(Cond cond, bool U, Reg t, Imm<12> imm12) {
|
|||||||
const bool add = U;
|
const bool add = U;
|
||||||
const u32 base = ir.AlignPC(4);
|
const u32 base = ir.AlignPC(4);
|
||||||
const u32 address = add ? (base + imm12.ZeroExtend()) : (base - imm12.ZeroExtend());
|
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) {
|
if (t == Reg::PC) {
|
||||||
ir.LoadWritePC(data);
|
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 u32 imm32 = imm12.ZeroExtend();
|
||||||
const auto offset = ir.Imm32(imm32);
|
const auto offset = ir.Imm32(imm32);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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) {
|
if (t == Reg::PC) {
|
||||||
ir.LoadWritePC(data);
|
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 offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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) {
|
if (t == Reg::PC) {
|
||||||
ir.LoadWritePC(data);
|
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 bool add = U;
|
||||||
const u32 base = ir.AlignPC(4);
|
const u32 base = ir.AlignPC(4);
|
||||||
const u32 address = add ? (base + imm32) : (base - imm32);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 u32 imm32 = imm12.ZeroExtend();
|
||||||
const auto offset = ir.Imm32(imm32);
|
const auto offset = ir.Imm32(imm32);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 base = ir.AlignPC(4);
|
||||||
const u32 address = add ? (base + imm32) : (base - imm32);
|
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);
|
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
|
||||||
ir.SetRegister(t2, data_b);
|
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;
|
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 u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
|
||||||
|
|
||||||
const auto offset = ir.Imm32(imm32);
|
const auto offset = ir.Imm32(imm32);
|
||||||
const auto address_a = GetAddress(ir, P, U, W, n, offset);
|
const auto address = 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);
|
|
||||||
|
|
||||||
ir.SetRegister(t, data_a);
|
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
|
||||||
ir.SetRegister(t2, data_b);
|
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;
|
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 Reg t2 = t + 1;
|
||||||
const auto offset = ir.GetRegister(m);
|
const auto offset = ir.GetRegister(m);
|
||||||
const auto address_a = GetAddress(ir, P, U, W, n, offset);
|
const auto address = 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);
|
|
||||||
|
|
||||||
ir.SetRegister(t, data_a);
|
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
|
||||||
ir.SetRegister(t2, data_b);
|
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;
|
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 bool add = U;
|
||||||
const u32 base = ir.AlignPC(4);
|
const u32 base = ir.AlignPC(4);
|
||||||
const u32 address = add ? (base + imm32) : (base - imm32);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
|
||||||
const auto offset = ir.Imm32(imm32);
|
const auto offset = ir.Imm32(imm32);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 offset = ir.GetRegister(m);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 base = ir.AlignPC(4);
|
||||||
const u32 address = add ? (base + imm32) : (base - imm32);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
|
||||||
const auto offset = ir.Imm32(imm32);
|
const auto offset = ir.Imm32(imm32);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 offset = ir.GetRegister(m);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 bool add = U;
|
||||||
const u32 base = ir.AlignPC(4);
|
const u32 base = ir.AlignPC(4);
|
||||||
const u32 address = add ? (base + imm32) : (base - imm32);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
|
||||||
const auto offset = ir.Imm32(imm32);
|
const auto offset = ir.Imm32(imm32);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 offset = ir.GetRegister(m);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 offset = ir.Imm32(imm12.ZeroExtend());
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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;
|
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 offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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;
|
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 offset = ir.Imm32(imm12.ZeroExtend());
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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;
|
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 offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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;
|
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 u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
|
||||||
const auto offset = ir.Imm32(imm32);
|
const auto offset = ir.Imm32(imm32);
|
||||||
const auto address_a = GetAddress(ir, P, U, W, n, offset);
|
const auto address = GetAddress(ir, P, U, W, n, offset);
|
||||||
const auto address_b = ir.Add(address_a, ir.Imm32(4));
|
|
||||||
const auto value_a = ir.GetRegister(t);
|
const auto value_a = ir.GetRegister(t);
|
||||||
const auto value_b = ir.GetRegister(t2);
|
const auto value_b = ir.GetRegister(t2);
|
||||||
|
|
||||||
ir.WriteMemory32(address_a, value_a);
|
const IR::U64 data = ir.current_location.EFlag() ? ir.Pack2x32To1x64(value_b, value_a)
|
||||||
ir.WriteMemory32(address_b, value_b);
|
: 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;
|
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 offset = ir.GetRegister(m);
|
||||||
const auto address_a = GetAddress(ir, P, U, W, n, offset);
|
const auto address = GetAddress(ir, P, U, W, n, offset);
|
||||||
const auto address_b = ir.Add(address_a, ir.Imm32(4));
|
|
||||||
const auto value_a = ir.GetRegister(t);
|
const auto value_a = ir.GetRegister(t);
|
||||||
const auto value_b = ir.GetRegister(t2);
|
const auto value_b = ir.GetRegister(t2);
|
||||||
|
|
||||||
ir.WriteMemory32(address_a, value_a);
|
const IR::U64 data = ir.current_location.EFlag() ? ir.Pack2x32To1x64(value_b, value_a)
|
||||||
ir.WriteMemory32(address_b, value_b);
|
: 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;
|
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 offset = ir.Imm32(imm32);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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;
|
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 offset = ir.GetRegister(m);
|
||||||
const auto address = GetAddress(ir, P, U, W, n, offset);
|
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;
|
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;
|
auto address = start_address;
|
||||||
for (size_t i = 0; i <= 14; i++) {
|
for (size_t i = 0; i <= 14; i++) {
|
||||||
if (Common::Bit(i, list)) {
|
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));
|
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);
|
ir.SetRegister(n, writeback_address);
|
||||||
}
|
}
|
||||||
if (Common::Bit<15>(list)) {
|
if (Common::Bit<15>(list)) {
|
||||||
ir.LoadWritePC(ir.ReadMemory32(address));
|
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC));
|
||||||
if (n == Reg::R13)
|
if (n == Reg::R13)
|
||||||
ir.SetTerm(IR::Term::PopRSBHint{});
|
ir.SetTerm(IR::Term::PopRSBHint{});
|
||||||
else
|
else
|
||||||
@ -854,7 +874,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 s
|
|||||||
auto address = start_address;
|
auto address = start_address;
|
||||||
for (size_t i = 0; i <= 14; i++) {
|
for (size_t i = 0; i <= 14; i++) {
|
||||||
if (Common::Bit(i, list)) {
|
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));
|
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);
|
ir.SetRegister(n, writeback_address);
|
||||||
}
|
}
|
||||||
if (Common::Bit<15>(list)) {
|
if (Common::Bit<15>(list)) {
|
||||||
ir.WriteMemory32(address, ir.Imm32(ir.PC()));
|
ir.WriteMemory32(address, ir.Imm32(ir.PC()), IR::AccType::ATOMIC);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,9 @@ bool TranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto data = ir.ReadMemory32(ir.GetRegister(n));
|
// TODO (HACK): Implement bus locking here
|
||||||
ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2));
|
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
|
// TODO: Alignment check
|
||||||
ir.SetRegister(t, data);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
return true;
|
||||||
@ -42,8 +43,9 @@ bool TranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto data = ir.ReadMemory8(ir.GetRegister(n));
|
// TODO (HACK): Implement bus locking here
|
||||||
ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2)));
|
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
|
// TODO: Alignment check
|
||||||
ir.SetRegister(t, ir.ZeroExtendByteToWord(data));
|
ir.SetRegister(t, ir.ZeroExtendByteToWord(data));
|
||||||
return true;
|
return true;
|
||||||
@ -60,7 +62,7 @@ bool TranslatorVisitor::arm_LDA(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
// LDAB<c> <Rt>, [<Rn>]
|
// LDAB<c> <Rt>, [<Rn>]
|
||||||
@ -74,7 +76,7 @@ bool TranslatorVisitor::arm_LDAB(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
// LDAH<c> <Rt>, [<Rn>]
|
// LDAH<c> <Rt>, [<Rn>]
|
||||||
@ -88,7 +90,7 @@ bool TranslatorVisitor::arm_LDAH(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +105,7 @@ bool TranslatorVisitor::arm_LDAEX(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +120,7 @@ bool TranslatorVisitor::arm_LDAEXB(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +135,7 @@ bool TranslatorVisitor::arm_LDAEXD(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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
|
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
|
||||||
ir.SetRegister(t, lo);
|
ir.SetRegister(t, lo);
|
||||||
ir.SetRegister(t + 1, hi);
|
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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +168,7 @@ bool TranslatorVisitor::arm_STL(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +183,7 @@ bool TranslatorVisitor::arm_STLB(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +198,7 @@ bool TranslatorVisitor::arm_STLH(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value_lo = ir.GetRegister(t);
|
const auto value_lo = ir.GetRegister(t);
|
||||||
const auto value_hi = ir.GetRegister(t2);
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value = ir.GetRegister(t);
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -296,7 +298,7 @@ bool TranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
const auto address = ir.GetRegister(n);
|
||||||
ir.SetRegister(t, ir.ExclusiveReadMemory32(address));
|
ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +313,7 @@ bool TranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +328,7 @@ bool TranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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
|
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
|
||||||
ir.SetRegister(t, lo);
|
ir.SetRegister(t, lo);
|
||||||
ir.SetRegister(t + 1, hi);
|
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);
|
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;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value = ir.GetRegister(t);
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value_lo = ir.GetRegister(t);
|
const auto value_lo = ir.GetRegister(t);
|
||||||
const auto value_hi = ir.GetRegister(t2);
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -444,7 +444,7 @@ bool TranslatorVisitor::thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) {
|
|||||||
bool TranslatorVisitor::thumb16_LDR_literal(Reg t, Imm<8> imm8) {
|
bool TranslatorVisitor::thumb16_LDR_literal(Reg t, Imm<8> imm8) {
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||||
const u32 address = ir.AlignPC(4) + imm32;
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
||||||
const auto data = ir.GetRegister(t);
|
const auto data = ir.GetRegister(t);
|
||||||
|
|
||||||
ir.WriteMemory32(address, data);
|
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
|
||||||
return true;
|
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 address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
||||||
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
|
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
|
||||||
|
|
||||||
ir.WriteMemory16(address, data);
|
ir.WriteMemory16(address, data, IR::AccType::NORMAL);
|
||||||
return true;
|
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 address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
||||||
const auto data = ir.LeastSignificantByte(ir.GetRegister(t));
|
const auto data = ir.LeastSignificantByte(ir.GetRegister(t));
|
||||||
|
|
||||||
ir.WriteMemory8(address, data);
|
ir.WriteMemory8(address, data, IR::AccType::NORMAL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,7 +484,7 @@ bool TranslatorVisitor::thumb16_STRB_reg(Reg m, Reg n, Reg t) {
|
|||||||
// Rt cannot encode R15.
|
// Rt cannot encode R15.
|
||||||
bool TranslatorVisitor::thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
|
bool TranslatorVisitor::thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
return true;
|
||||||
@ -494,7 +494,7 @@ bool TranslatorVisitor::thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
|
|||||||
// Rt cannot encode R15.
|
// Rt cannot encode R15.
|
||||||
bool TranslatorVisitor::thumb16_LDR_reg(Reg m, Reg n, Reg t) {
|
bool TranslatorVisitor::thumb16_LDR_reg(Reg m, Reg n, Reg t) {
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
return true;
|
||||||
@ -504,7 +504,7 @@ bool TranslatorVisitor::thumb16_LDR_reg(Reg m, Reg n, Reg t) {
|
|||||||
// Rt cannot encode R15.
|
// Rt cannot encode R15.
|
||||||
bool TranslatorVisitor::thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
|
bool TranslatorVisitor::thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
return true;
|
||||||
@ -514,7 +514,7 @@ bool TranslatorVisitor::thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
|
|||||||
// Rt cannot encode R15.
|
// Rt cannot encode R15.
|
||||||
bool TranslatorVisitor::thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
|
bool TranslatorVisitor::thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
return true;
|
||||||
@ -524,7 +524,7 @@ bool TranslatorVisitor::thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
|
|||||||
// Rt cannot encode R15.
|
// Rt cannot encode R15.
|
||||||
bool TranslatorVisitor::thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
|
bool TranslatorVisitor::thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.GetRegister(m));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
||||||
const auto data = ir.GetRegister(t);
|
const auto data = ir.GetRegister(t);
|
||||||
|
|
||||||
ir.WriteMemory32(address, data);
|
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
|
||||||
return true;
|
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) {
|
bool TranslatorVisitor::thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
const u32 imm32 = imm5.ZeroExtend() << 2;
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
||||||
const auto data = ir.LeastSignificantByte(ir.GetRegister(t));
|
const auto data = ir.LeastSignificantByte(ir.GetRegister(t));
|
||||||
|
|
||||||
ir.WriteMemory8(address, data);
|
ir.WriteMemory8(address, data, IR::AccType::NORMAL);
|
||||||
return true;
|
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) {
|
bool TranslatorVisitor::thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||||
const u32 imm32 = imm5.ZeroExtend();
|
const u32 imm32 = imm5.ZeroExtend();
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
||||||
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
|
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
|
||||||
|
|
||||||
ir.WriteMemory16(address, data);
|
ir.WriteMemory16(address, data, IR::AccType::NORMAL);
|
||||||
return true;
|
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) {
|
bool TranslatorVisitor::thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
const u32 imm32 = imm5.ZeroExtend() << 1;
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
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 address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
||||||
const auto data = ir.GetRegister(t);
|
const auto data = ir.GetRegister(t);
|
||||||
|
|
||||||
ir.WriteMemory32(address, data);
|
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +612,7 @@ bool TranslatorVisitor::thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) {
|
|||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||||
const Reg n = Reg::SP;
|
const Reg n = Reg::SP;
|
||||||
const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm32));
|
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);
|
ir.SetRegister(t, data);
|
||||||
return true;
|
return true;
|
||||||
@ -766,7 +766,7 @@ bool TranslatorVisitor::thumb16_PUSH(bool M, RegList reg_list) {
|
|||||||
if (Common::Bit(i, reg_list)) {
|
if (Common::Bit(i, reg_list)) {
|
||||||
// TODO: Deal with alignment
|
// TODO: Deal with alignment
|
||||||
const auto Ri = ir.GetRegister(static_cast<Reg>(i));
|
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));
|
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++) {
|
for (size_t i = 0; i < 15; i++) {
|
||||||
if (Common::Bit(i, reg_list)) {
|
if (Common::Bit(i, reg_list)) {
|
||||||
// TODO: Deal with alignment
|
// 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);
|
ir.SetRegister(static_cast<Reg>(i), data);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
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)) {
|
if (Common::Bit<15>(reg_list)) {
|
||||||
// TODO(optimization): Possible location for an RSB pop.
|
// 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.UpdateUpperLocationDescriptor();
|
||||||
ir.LoadWritePC(data);
|
ir.LoadWritePC(data);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
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++) {
|
for (size_t i = 0; i < 8; i++) {
|
||||||
if (Common::Bit(i, reg_list)) {
|
if (Common::Bit(i, reg_list)) {
|
||||||
const auto Ri = ir.GetRegister(static_cast<Reg>(i));
|
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));
|
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++) {
|
for (size_t i = 0; i < 8; i++) {
|
||||||
if (Common::Bit(i, reg_list)) {
|
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);
|
ir.SetRegister(static_cast<Reg>(i), data);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
|
|||||||
const u32 imm32 = imm12.ZeroExtend();
|
const u32 imm32 = imm12.ZeroExtend();
|
||||||
const u32 base = v.ir.AlignPC(4);
|
const u32 base = v.ir.AlignPC(4);
|
||||||
const u32 address = U ? (base + imm32) : (base - imm32);
|
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);
|
v.ir.SetRegister(t, data);
|
||||||
return true;
|
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 reg_m = v.ir.GetRegister(m);
|
||||||
const auto offset = v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(imm2.ZeroExtend<u8>()));
|
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 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);
|
v.ir.SetRegister(t, data);
|
||||||
return true;
|
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))
|
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))
|
||||||
: v.ir.Sub(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 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);
|
v.ir.SetRegister(t, data);
|
||||||
if (W) {
|
if (W) {
|
||||||
|
@ -13,7 +13,7 @@ static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
|
|||||||
const auto imm32 = imm12.ZeroExtend();
|
const auto imm32 = imm12.ZeroExtend();
|
||||||
const auto base = v.ir.AlignPC(4);
|
const auto base = v.ir.AlignPC(4);
|
||||||
const auto address = U ? (base + imm32) : (base - imm32);
|
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);
|
v.ir.SetRegister(t, data);
|
||||||
return true;
|
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 reg_n = v.ir.GetRegister(n);
|
||||||
const IR::U32 offset = v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(imm2.ZeroExtend<u8>()));
|
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 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);
|
v.ir.SetRegister(t, data);
|
||||||
return true;
|
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));
|
: v.ir.Sub(reg_n, v.ir.Imm32(imm32));
|
||||||
const IR::U32 address = P ? offset_address
|
const IR::U32 address = P ? offset_address
|
||||||
: reg_n;
|
: 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) {
|
if (W) {
|
||||||
v.ir.SetRegister(n, offset_address);
|
v.ir.SetRegister(n, offset_address);
|
||||||
|
@ -24,10 +24,10 @@ static bool TableBranch(TranslatorVisitor& v, Reg n, Reg m, bool half) {
|
|||||||
|
|
||||||
IR::U32 halfwords;
|
IR::U32 halfwords;
|
||||||
if (half) {
|
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);
|
halfwords = v.ir.ZeroExtendToWord(data);
|
||||||
} else {
|
} 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());
|
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 reg_n = v.ir.GetRegister(n);
|
||||||
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm))
|
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm))
|
||||||
: v.ir.Sub(reg_n, v.ir.Imm32(imm));
|
: v.ir.Sub(reg_n, v.ir.Imm32(imm));
|
||||||
const IR::U32 address_1 = P ? offset_address
|
const IR::U32 address = P ? offset_address : reg_n;
|
||||||
: reg_n;
|
|
||||||
const IR::U32 address_2 = v.ir.Add(address_1, v.ir.Imm32(4));
|
|
||||||
|
|
||||||
v.ir.SetRegister(t, v.ir.ReadMemory32(address_1));
|
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
|
||||||
v.ir.SetRegister(t2, v.ir.ReadMemory32(address_2));
|
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) {
|
if (W) {
|
||||||
v.ir.SetRegister(n, offset_address);
|
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 imm = imm8.ZeroExtend() << 2;
|
||||||
const auto address_1 = U ? v.ir.Add(v.ir.Imm32(v.ir.AlignPC(4)), v.ir.Imm32(imm))
|
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));
|
: 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));
|
|
||||||
|
|
||||||
v.ir.SetRegister(t, v.ir.ReadMemory32(address_1));
|
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
|
||||||
v.ir.SetRegister(t2, v.ir.ReadMemory32(address_2));
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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))
|
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm))
|
||||||
: v.ir.Sub(reg_n, v.ir.Imm32(imm));
|
: v.ir.Sub(reg_n, v.ir.Imm32(imm));
|
||||||
const IR::U32 address_1 = P ? offset_address
|
const IR::U32 address = P ? offset_address : reg_n;
|
||||||
: reg_n;
|
|
||||||
const IR::U32 address_2 = v.ir.Add(address_1, v.ir.Imm32(4));
|
|
||||||
|
|
||||||
v.ir.WriteMemory32(address_1, reg_t);
|
const IR::U64 data = v.ir.current_location.EFlag() ? v.ir.Pack2x32To1x64(reg_t2, reg_t)
|
||||||
v.ir.WriteMemory32(address_2, reg_t2);
|
: 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) {
|
if (W) {
|
||||||
v.ir.SetRegister(n, offset_address);
|
v.ir.SetRegister(n, offset_address);
|
||||||
@ -116,7 +131,7 @@ bool TranslatorVisitor::thumb32_LDA(Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
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 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);
|
ir.SetRegister(t, value);
|
||||||
return true;
|
return true;
|
||||||
@ -162,7 +177,7 @@ bool TranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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);
|
ir.SetRegister(t, value);
|
||||||
return true;
|
return true;
|
||||||
@ -174,7 +189,7 @@ bool TranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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
|
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
|
||||||
ir.SetRegister(t, lo);
|
ir.SetRegister(t, lo);
|
||||||
@ -188,7 +203,7 @@ bool TranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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);
|
ir.SetRegister(t, value);
|
||||||
return true;
|
return true;
|
||||||
@ -200,7 +215,7 @@ bool TranslatorVisitor::thumb32_STL(Reg n, Reg t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
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;
|
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 address = ir.Add(ir.GetRegister(n), ir.Imm32(imm8.ZeroExtend() << 2));
|
||||||
const auto value = ir.GetRegister(t);
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -229,7 +244,7 @@ bool TranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) {
|
|||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
const auto address = ir.GetRegister(n);
|
||||||
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
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 address = ir.GetRegister(n);
|
||||||
const auto value_lo = ir.GetRegister(t);
|
const auto value_lo = ir.GetRegister(t);
|
||||||
const auto value_hi = ir.GetRegister(t2);
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -260,7 +275,7 @@ bool TranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) {
|
|||||||
|
|
||||||
const auto address = ir.GetRegister(n);
|
const auto address = ir.GetRegister(n);
|
||||||
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
|
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);
|
ir.SetRegister(d, passed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32
|
|||||||
auto address = start_address;
|
auto address = start_address;
|
||||||
for (size_t i = 0; i <= 14; i++) {
|
for (size_t i = 0; i <= 14; i++) {
|
||||||
if (Common::Bit(i, list)) {
|
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));
|
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)) {
|
if (Common::Bit<15>(list)) {
|
||||||
ir.UpdateUpperLocationDescriptor();
|
ir.UpdateUpperLocationDescriptor();
|
||||||
ir.LoadWritePC(ir.ReadMemory32(address));
|
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC));
|
||||||
if (n == Reg::R13) {
|
if (n == Reg::R13) {
|
||||||
ir.SetTerm(IR::Term::PopRSBHint{});
|
ir.SetTerm(IR::Term::PopRSBHint{});
|
||||||
} else {
|
} else {
|
||||||
@ -39,7 +39,7 @@ static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32
|
|||||||
auto address = start_address;
|
auto address = start_address;
|
||||||
for (size_t i = 0; i <= 14; i++) {
|
for (size_t i = 0; i <= 14; i++) {
|
||||||
if (Common::Bit(i, list)) {
|
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));
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ bool TranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) {
|
|||||||
const u32 imm32 = imm12.ZeroExtend();
|
const u32 imm32 = imm12.ZeroExtend();
|
||||||
const u32 base = ir.AlignPC(4);
|
const u32 base = ir.AlignPC(4);
|
||||||
const u32 address = U ? base + imm32 : base - imm32;
|
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) {
|
if (t == Reg::PC) {
|
||||||
ir.UpdateUpperLocationDescriptor();
|
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));
|
: ir.Sub(reg_n, ir.Imm32(imm32));
|
||||||
const IR::U32 address = P ? offset_address
|
const IR::U32 address = P ? offset_address
|
||||||
: reg_n;
|
: reg_n;
|
||||||
const IR::U32 data = ir.ReadMemory32(address);
|
const IR::U32 data = ir.ReadMemory32(address, IR::AccType::NORMAL);
|
||||||
|
|
||||||
if (W) {
|
if (W) {
|
||||||
ir.SetRegister(n, offset_address);
|
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 imm32 = imm12.ZeroExtend();
|
||||||
const auto reg_n = ir.GetRegister(n);
|
const auto reg_n = ir.GetRegister(n);
|
||||||
const auto address = ir.Add(reg_n, ir.Imm32(imm32));
|
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) {
|
if (t == Reg::PC) {
|
||||||
ir.UpdateUpperLocationDescriptor();
|
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 reg_n = ir.GetRegister(n);
|
||||||
const auto offset = ir.LogicalShiftLeft(reg_m, ir.Imm8(imm2.ZeroExtend<u8>()));
|
const auto offset = ir.LogicalShiftLeft(reg_m, ir.Imm8(imm2.ZeroExtend<u8>()));
|
||||||
const auto address = ir.Add(reg_n, offset);
|
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) {
|
if (t == Reg::PC) {
|
||||||
ir.UpdateUpperLocationDescriptor();
|
ir.UpdateUpperLocationDescriptor();
|
||||||
|
@ -32,15 +32,15 @@ static bool StoreRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m
|
|||||||
using StoreImmFn = void (*)(TranslatorVisitor&, const IR::U32&, const IR::U32&);
|
using StoreImmFn = void (*)(TranslatorVisitor&, const IR::U32&, const IR::U32&);
|
||||||
|
|
||||||
static void StoreImmByteFn(TranslatorVisitor& v, const IR::U32& address, const IR::U32& data) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) {
|
||||||
ir.WriteMemory32(offset_address, data);
|
ir.WriteMemory32(offset_address, data, IR::AccType::NORMAL);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,16 +1186,16 @@ bool TranslatorVisitor::vfp_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm<8> i
|
|||||||
|
|
||||||
for (size_t i = 0; i < regs; ++i) {
|
for (size_t i = 0; i < regs; ++i) {
|
||||||
if (sz) {
|
if (sz) {
|
||||||
auto lo = ir.ReadMemory32(address);
|
auto lo = ir.ReadMemory32(address, IR::AccType::ATOMIC);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
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));
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
if (ir.current_location.EFlag()) {
|
if (ir.current_location.EFlag()) {
|
||||||
std::swap(lo, hi);
|
std::swap(lo, hi);
|
||||||
}
|
}
|
||||||
ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(lo, hi));
|
ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(lo, hi));
|
||||||
} else {
|
} else {
|
||||||
const auto res = ir.ReadMemory32(address);
|
const auto res = ir.ReadMemory32(address, IR::AccType::ATOMIC);
|
||||||
ir.SetExtendedRegister(d + i, res);
|
ir.SetExtendedRegister(d + i, res);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
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;
|
auto hi = ir.MostSignificantWord(reg_d).result;
|
||||||
if (ir.current_location.EFlag())
|
if (ir.current_location.EFlag())
|
||||||
std::swap(lo, hi);
|
std::swap(lo, hi);
|
||||||
ir.WriteMemory32(address, lo);
|
ir.WriteMemory32(address, lo, IR::AccType::ATOMIC);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
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));
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
} else {
|
} 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));
|
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));
|
const auto address = U ? ir.Add(base, ir.Imm32(imm32)) : ir.Sub(base, ir.Imm32(imm32));
|
||||||
|
|
||||||
if (sz) {
|
if (sz) {
|
||||||
auto lo = ir.ReadMemory32(address);
|
auto lo = ir.ReadMemory32(address, IR::AccType::ATOMIC);
|
||||||
auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4)));
|
auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4)), IR::AccType::ATOMIC);
|
||||||
if (ir.current_location.EFlag()) {
|
if (ir.current_location.EFlag()) {
|
||||||
std::swap(lo, hi);
|
std::swap(lo, hi);
|
||||||
}
|
}
|
||||||
ir.SetExtendedRegister(d, ir.Pack2x32To1x64(lo, hi));
|
ir.SetExtendedRegister(d, ir.Pack2x32To1x64(lo, hi));
|
||||||
} else {
|
} else {
|
||||||
ir.SetExtendedRegister(d, ir.ReadMemory32(address));
|
ir.SetExtendedRegister(d, ir.ReadMemory32(address, IR::AccType::ATOMIC));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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()) {
|
if (ir.current_location.EFlag()) {
|
||||||
std::swap(lo, hi);
|
std::swap(lo, hi);
|
||||||
}
|
}
|
||||||
ir.WriteMemory32(address, lo);
|
ir.WriteMemory32(address, lo, IR::AccType::ATOMIC);
|
||||||
ir.WriteMemory32(ir.Add(address, ir.Imm32(4)), hi);
|
ir.WriteMemory32(ir.Add(address, ir.Imm32(4)), hi, IR::AccType::ATOMIC);
|
||||||
} else {
|
} else {
|
||||||
ir.WriteMemory32(address, ir.GetExtendedRegister(d));
|
ir.WriteMemory32(address, ir.GetExtendedRegister(d), IR::AccType::ATOMIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
std::swap(word1, word2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ir.WriteMemory32(address, word1);
|
ir.WriteMemory32(address, word1, IR::AccType::ATOMIC);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
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));
|
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++) {
|
for (size_t i = 0; i < regs; i++) {
|
||||||
const auto word = ir.GetExtendedRegister(d + 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));
|
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);
|
ir.SetRegister(n, u ? IR::U32(ir.Add(address, ir.Imm32(imm32))) : address);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < regs; i++) {
|
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));
|
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));
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
|
|
||||||
if (ir.current_location.EFlag()) {
|
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);
|
ir.SetRegister(n, u ? IR::U32(ir.Add(address, ir.Imm32(imm32))) : address);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < regs; i++) {
|
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));
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
ir.SetExtendedRegister(d + i, word);
|
ir.SetExtendedRegister(d + i, word);
|
||||||
}
|
}
|
||||||
|
@ -105,84 +105,84 @@ void IREmitter::ClearExclusive() {
|
|||||||
Inst(Opcode::A64ClearExclusive);
|
Inst(Opcode::A64ClearExclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U8>(Opcode::A64ReadMemory8, vaddr, IR::Value(acctype));
|
return Inst<IR::U8>(Opcode::A64ReadMemory8, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U16>(Opcode::A64ReadMemory16, vaddr, IR::Value(acctype));
|
return Inst<IR::U16>(Opcode::A64ReadMemory16, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U32>(Opcode::A64ReadMemory32, vaddr, IR::Value(acctype));
|
return Inst<IR::U32>(Opcode::A64ReadMemory32, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U64>(Opcode::A64ReadMemory64, vaddr, IR::Value(acctype));
|
return Inst<IR::U64>(Opcode::A64ReadMemory64, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U128>(Opcode::A64ReadMemory128, vaddr, IR::Value(acctype));
|
return Inst<IR::U128>(Opcode::A64ReadMemory128, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, vaddr, IR::Value(acctype));
|
return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, vaddr, IR::Value(acctype));
|
return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, vaddr, IR::Value(acctype));
|
return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, vaddr, IR::Value(acctype));
|
return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, vaddr, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccessType acctype) {
|
IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) {
|
||||||
return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, vaddr, IR::Value(acctype));
|
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) {
|
void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) {
|
||||||
Inst(Opcode::A64WriteMemory8, vaddr, value, IR::Value(acctype));
|
Inst(Opcode::A64WriteMemory8, vaddr, value, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccessType acctype) {
|
void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) {
|
||||||
Inst(Opcode::A64WriteMemory16, vaddr, value, IR::Value(acctype));
|
Inst(Opcode::A64WriteMemory16, vaddr, value, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccessType acctype) {
|
void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) {
|
||||||
Inst(Opcode::A64WriteMemory32, vaddr, value, IR::Value(acctype));
|
Inst(Opcode::A64WriteMemory32, vaddr, value, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccessType acctype) {
|
void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) {
|
||||||
Inst(Opcode::A64WriteMemory64, vaddr, value, IR::Value(acctype));
|
Inst(Opcode::A64WriteMemory64, vaddr, value, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccessType acctype) {
|
void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) {
|
||||||
Inst(Opcode::A64WriteMemory128, vaddr, value, IR::Value(acctype));
|
Inst(Opcode::A64WriteMemory128, vaddr, value, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccessType 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(acctype));
|
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) {
|
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(acctype));
|
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) {
|
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(acctype));
|
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) {
|
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(acctype));
|
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) {
|
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(acctype));
|
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, vaddr, value, IR::Value{acc_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::GetW(Reg reg) {
|
IR::U32 IREmitter::GetW(Reg reg) {
|
||||||
|
@ -56,26 +56,26 @@ public:
|
|||||||
void SetTPIDR(const IR::U64& value);
|
void SetTPIDR(const IR::U64& value);
|
||||||
|
|
||||||
void ClearExclusive();
|
void ClearExclusive();
|
||||||
IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccessType acctype);
|
IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type);
|
||||||
void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
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::AccessType acctype);
|
IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type);
|
||||||
|
|
||||||
IR::U32 GetW(Reg source_reg);
|
IR::U32 GetW(Reg source_reg);
|
||||||
IR::U64 GetX(Reg source_reg);
|
IR::U64 GetX(Reg source_reg);
|
||||||
|
@ -217,74 +217,74 @@ void TranslatorVisitor::Vpart_scalar(size_t bitsize, Vec vec, size_t part, IR::U
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::UAnyU128 TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccessType acctype) {
|
IR::UAnyU128 TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, IR::AccType acc_type) {
|
||||||
switch (bytesize) {
|
switch (bytesize) {
|
||||||
case 1:
|
case 1:
|
||||||
return ir.ReadMemory8(address, acctype);
|
return ir.ReadMemory8(address, acc_type);
|
||||||
case 2:
|
case 2:
|
||||||
return ir.ReadMemory16(address, acctype);
|
return ir.ReadMemory16(address, acc_type);
|
||||||
case 4:
|
case 4:
|
||||||
return ir.ReadMemory32(address, acctype);
|
return ir.ReadMemory32(address, acc_type);
|
||||||
case 8:
|
case 8:
|
||||||
return ir.ReadMemory64(address, acctype);
|
return ir.ReadMemory64(address, acc_type);
|
||||||
case 16:
|
case 16:
|
||||||
return ir.ReadMemory128(address, acctype);
|
return ir.ReadMemory128(address, acc_type);
|
||||||
default:
|
default:
|
||||||
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
|
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) {
|
switch (bytesize) {
|
||||||
case 1:
|
case 1:
|
||||||
ir.WriteMemory8(address, value, acctype);
|
ir.WriteMemory8(address, value, acc_type);
|
||||||
return;
|
return;
|
||||||
case 2:
|
case 2:
|
||||||
ir.WriteMemory16(address, value, acctype);
|
ir.WriteMemory16(address, value, acc_type);
|
||||||
return;
|
return;
|
||||||
case 4:
|
case 4:
|
||||||
ir.WriteMemory32(address, value, acctype);
|
ir.WriteMemory32(address, value, acc_type);
|
||||||
return;
|
return;
|
||||||
case 8:
|
case 8:
|
||||||
ir.WriteMemory64(address, value, acctype);
|
ir.WriteMemory64(address, value, acc_type);
|
||||||
return;
|
return;
|
||||||
case 16:
|
case 16:
|
||||||
ir.WriteMemory128(address, value, acctype);
|
ir.WriteMemory128(address, value, acc_type);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
|
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) {
|
switch (bytesize) {
|
||||||
case 1:
|
case 1:
|
||||||
return ir.ExclusiveReadMemory8(address, acctype);
|
return ir.ExclusiveReadMemory8(address, acc_type);
|
||||||
case 2:
|
case 2:
|
||||||
return ir.ExclusiveReadMemory16(address, acctype);
|
return ir.ExclusiveReadMemory16(address, acc_type);
|
||||||
case 4:
|
case 4:
|
||||||
return ir.ExclusiveReadMemory32(address, acctype);
|
return ir.ExclusiveReadMemory32(address, acc_type);
|
||||||
case 8:
|
case 8:
|
||||||
return ir.ExclusiveReadMemory64(address, acctype);
|
return ir.ExclusiveReadMemory64(address, acc_type);
|
||||||
case 16:
|
case 16:
|
||||||
return ir.ExclusiveReadMemory128(address, acctype);
|
return ir.ExclusiveReadMemory128(address, acc_type);
|
||||||
default:
|
default:
|
||||||
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
|
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) {
|
switch (bytesize) {
|
||||||
case 1:
|
case 1:
|
||||||
return ir.ExclusiveWriteMemory8(address, value, acctype);
|
return ir.ExclusiveWriteMemory8(address, value, acc_type);
|
||||||
case 2:
|
case 2:
|
||||||
return ir.ExclusiveWriteMemory16(address, value, acctype);
|
return ir.ExclusiveWriteMemory16(address, value, acc_type);
|
||||||
case 4:
|
case 4:
|
||||||
return ir.ExclusiveWriteMemory32(address, value, acctype);
|
return ir.ExclusiveWriteMemory32(address, value, acc_type);
|
||||||
case 8:
|
case 8:
|
||||||
return ir.ExclusiveWriteMemory64(address, value, acctype);
|
return ir.ExclusiveWriteMemory64(address, value, acc_type);
|
||||||
case 16:
|
case 16:
|
||||||
return ir.ExclusiveWriteMemory128(address, value, acctype);
|
return ir.ExclusiveWriteMemory128(address, value, acc_type);
|
||||||
default:
|
default:
|
||||||
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
|
ASSERT_FALSE("Invalid bytesize parameter {}", bytesize);
|
||||||
}
|
}
|
||||||
|
@ -55,10 +55,10 @@ struct TranslatorVisitor final {
|
|||||||
IR::UAny Vpart_scalar(size_t bitsize, Vec vec, size_t part);
|
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);
|
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);
|
IR::UAnyU128 Mem(IR::U64 address, size_t size, IR::AccType acctype);
|
||||||
void Mem(IR::U64 address, size_t size, IR::AccessType acctype, IR::UAnyU128 value);
|
void Mem(IR::U64 address, size_t size, IR::AccType acctype, IR::UAnyU128 value);
|
||||||
IR::UAnyU128 ExclusiveMem(IR::U64 address, size_t size, IR::AccessType acctype);
|
IR::UAnyU128 ExclusiveMem(IR::U64 address, size_t size, IR::AccType acctype);
|
||||||
IR::U32 ExclusiveMem(IR::U64 address, size_t size, IR::AccessType acctype, IR::UAnyU128 value);
|
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 SignExtend(IR::UAny value, size_t to_size);
|
||||||
IR::U32U64 ZeroExtend(IR::UAny value, size_t to_size);
|
IR::U32U64 ZeroExtend(IR::UAny value, size_t to_size);
|
||||||
|
@ -12,7 +12,7 @@ namespace Dynarmic::A64 {
|
|||||||
static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, size_t size, bool L, bool o0, std::optional<Reg> Rs, std::optional<Reg> Rt2, Reg Rn, Reg Rt) {
|
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
|
// 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 auto memop = L ? IR::MemOp::LOAD : IR::MemOp::STORE;
|
||||||
const size_t elsize = 8 << size;
|
const size_t elsize = 8 << size;
|
||||||
const size_t regsize = elsize == 64 ? 64 : 32;
|
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) {
|
static bool OrderedSharedDecodeAndOperation(TranslatorVisitor& v, size_t size, bool L, bool o0, Reg Rn, Reg Rt) {
|
||||||
// Shared Decode
|
// 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 auto memop = L ? IR::MemOp::LOAD : IR::MemOp::STORE;
|
||||||
const size_t elsize = 8 << size;
|
const size_t elsize = 8 << size;
|
||||||
const size_t regsize = elsize == 64 ? 64 : 32;
|
const size_t regsize = elsize == 64 ? 64 : 32;
|
||||||
|
@ -12,7 +12,7 @@ bool TranslatorVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) {
|
|||||||
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
|
|
||||||
const u64 address = ir.PC() + offset;
|
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);
|
X(8 * size, Rt, data);
|
||||||
return true;
|
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 size = 4 << opc.ZeroExtend();
|
||||||
const u64 offset = imm19.SignExtend<u64>() << 2;
|
const u64 offset = imm19.SignExtend<u64>() << 2;
|
||||||
const IR::U64 address = ir.Imm64(ir.PC() + offset);
|
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) {
|
if (size == 16) {
|
||||||
V(128, Vt, data);
|
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) {
|
bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) {
|
||||||
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
const s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
const u64 address = ir.PC() + offset;
|
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));
|
X(64, Rt, ir.SignExtendWordToLong(data));
|
||||||
return true;
|
return true;
|
||||||
|
@ -67,11 +67,11 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp
|
|||||||
for (size_t r = 0; r < rpt; r++) {
|
for (size_t r = 0; r < rpt; r++) {
|
||||||
const Vec tt = static_cast<Vec>((VecNumber(Vt) + r) % 32);
|
const Vec tt = static_cast<Vec>((VecNumber(Vt) + r) % 32);
|
||||||
if (memop == IR::MemOp::LOAD) {
|
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);
|
v.V_scalar(datasize, tt, vec);
|
||||||
} else {
|
} else {
|
||||||
const IR::UAnyU128 vec = v.V_scalar(datasize, tt);
|
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));
|
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++) {
|
for (size_t s = 0; s < selem; s++) {
|
||||||
const Vec tt = static_cast<Vec>((VecNumber(Vt) + s) % 32);
|
const Vec tt = static_cast<Vec>((VecNumber(Vt) + s) % 32);
|
||||||
if (memop == IR::MemOp::LOAD) {
|
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);
|
const IR::U128 vec = v.ir.VectorSetElement(esize, v.V(datasize, tt), e, elem);
|
||||||
v.V(datasize, tt, vec);
|
v.V(datasize, tt, vec);
|
||||||
} else {
|
} else {
|
||||||
const IR::UAny elem = v.ir.VectorGetElement(esize, v.V(datasize, tt), e);
|
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));
|
offs = v.ir.Add(offs, v.ir.Imm64(ebytes));
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,11 @@ static bool LoadStoreRegisterImmediate(TranslatorVisitor& v, bool wback, bool po
|
|||||||
switch (memop) {
|
switch (memop) {
|
||||||
case IR::MemOp::STORE: {
|
case IR::MemOp::STORE: {
|
||||||
const auto data = v.X(datasize, Rt);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case IR::MemOp::LOAD: {
|
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_) {
|
if (signed_) {
|
||||||
v.X(regsize, Rt, v.SignExtend(data, regsize));
|
v.X(regsize, Rt, v.SignExtend(data, regsize));
|
||||||
} else {
|
} 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) {
|
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;
|
const size_t datasize = 8 << scale;
|
||||||
|
|
||||||
IR::U64 address;
|
IR::U64 address;
|
||||||
|
@ -46,13 +46,13 @@ bool TranslatorVisitor::STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback,
|
|||||||
case IR::MemOp::STORE: {
|
case IR::MemOp::STORE: {
|
||||||
const IR::U32U64 data1 = X(datasize, Rt);
|
const IR::U32U64 data1 = X(datasize, Rt);
|
||||||
const IR::U32U64 data2 = X(datasize, Rt2);
|
const IR::U32U64 data2 = X(datasize, Rt2);
|
||||||
Mem(address, dbytes, IR::AccessType::NORMAL, data1);
|
Mem(address, dbytes, IR::AccType::NORMAL, data1);
|
||||||
Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccessType::NORMAL, data2);
|
Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::NORMAL, data2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::MemOp::LOAD: {
|
case IR::MemOp::LOAD: {
|
||||||
const IR::U32U64 data1 = Mem(address, 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::AccessType::NORMAL);
|
const IR::U32U64 data2 = Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::NORMAL);
|
||||||
if (signed_) {
|
if (signed_) {
|
||||||
X(64, Rt, SignExtend(data1, 64));
|
X(64, Rt, SignExtend(data1, 64));
|
||||||
X(64, Rt2, SignExtend(data2, 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);
|
data1 = ir.VectorGetElement(datasize, data1, 0);
|
||||||
data2 = ir.VectorGetElement(datasize, data2, 0);
|
data2 = ir.VectorGetElement(datasize, data2, 0);
|
||||||
}
|
}
|
||||||
Mem(address, dbytes, IR::AccessType::VEC, data1);
|
Mem(address, dbytes, IR::AccType::VEC, data1);
|
||||||
Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccessType::VEC, data2);
|
Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::VEC, data2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::MemOp::LOAD: {
|
case IR::MemOp::LOAD: {
|
||||||
IR::UAnyU128 data1 = Mem(address, 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::AccessType::VEC);
|
IR::UAnyU128 data2 = Mem(ir.Add(address, ir.Imm64(dbytes)), dbytes, IR::AccType::VEC);
|
||||||
if (datasize != 128) {
|
if (datasize != 128) {
|
||||||
data1 = ir.ZeroExtendToQuad(data1);
|
data1 = ir.ZeroExtendToQuad(data1);
|
||||||
data2 = ir.ZeroExtendToQuad(data2);
|
data2 = ir.ZeroExtendToQuad(data2);
|
||||||
|
@ -10,7 +10,7 @@ namespace Dynarmic::A64 {
|
|||||||
static bool RegSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Reg Rt) {
|
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
|
// Shared Decode
|
||||||
|
|
||||||
const auto acctype = IR::AccessType::NORMAL;
|
const auto acctype = IR::AccType::NORMAL;
|
||||||
IR::MemOp memop;
|
IR::MemOp memop;
|
||||||
size_t regsize = 64;
|
size_t regsize = 64;
|
||||||
bool signed_ = false;
|
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) {
|
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
|
// 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 auto memop = opc_0 == 1 ? IR::MemOp::LOAD : IR::MemOp::STORE;
|
||||||
const size_t datasize = 8 << scale;
|
const size_t datasize = 8 << scale;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ namespace Dynarmic::A64 {
|
|||||||
|
|
||||||
static bool StoreRegister(TranslatorVisitor& v, const size_t datasize, const Imm<9> imm9, const Reg Rn, const Reg Rt) {
|
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 u64 offset = imm9.SignExtend<u64>();
|
||||||
const auto acctype = IR::AccessType::UNPRIV;
|
const auto acctype = IR::AccType::UNPRIV;
|
||||||
|
|
||||||
IR::U64 address;
|
IR::U64 address;
|
||||||
if (Rn == Reg::SP) {
|
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) {
|
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 u64 offset = imm9.SignExtend<u64>();
|
||||||
const auto acctype = IR::AccessType::UNPRIV;
|
const auto acctype = IR::AccType::UNPRIV;
|
||||||
|
|
||||||
IR::U64 address;
|
IR::U64 address;
|
||||||
if (Rn == Reg::SP) {
|
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) {
|
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 u64 offset = imm9.SignExtend<u64>();
|
||||||
const auto acctype = IR::AccessType::UNPRIV;
|
const auto acctype = IR::AccType::UNPRIV;
|
||||||
|
|
||||||
IR::MemOp memop;
|
IR::MemOp memop;
|
||||||
bool is_signed;
|
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) {
|
bool TranslatorVisitor::LDTRSW(Imm<9> imm9, Reg Rn, Reg Rt) {
|
||||||
const u64 offset = imm9.SignExtend<u64>();
|
const u64 offset = imm9.SignExtend<u64>();
|
||||||
const auto acctype = IR::AccessType::UNPRIV;
|
const auto acctype = IR::AccType::UNPRIV;
|
||||||
|
|
||||||
IR::U64 address;
|
IR::U64 address;
|
||||||
if (Rn == Reg::SP) {
|
if (Rn == Reg::SP) {
|
||||||
|
@ -62,7 +62,7 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp
|
|||||||
if (replicate) {
|
if (replicate) {
|
||||||
for (size_t s = 0; s < selem; s++) {
|
for (size_t s = 0; s < selem; s++) {
|
||||||
const Vec tt = static_cast<Vec>((VecNumber(Vt) + s) % 32);
|
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);
|
const IR::U128 broadcasted_element = v.ir.VectorBroadcast(esize, element);
|
||||||
|
|
||||||
v.V(datasize, tt, broadcasted_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);
|
const IR::U128 rval = v.V(128, tt);
|
||||||
|
|
||||||
if (memop == IR::MemOp::LOAD) {
|
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);
|
const IR::U128 vec = v.ir.VectorSetElement(esize, rval, index, elem);
|
||||||
v.V(128, tt, vec);
|
v.V(128, tt, vec);
|
||||||
} else {
|
} else {
|
||||||
const IR::UAny elem = v.ir.VectorGetElement(esize, rval, index);
|
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));
|
offs = v.ir.Add(offs, v.ir.Imm64(ebytes));
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,23 @@ namespace Dynarmic::A64 {
|
|||||||
|
|
||||||
bool TranslatorVisitor::IC_IALLU() {
|
bool TranslatorVisitor::IC_IALLU() {
|
||||||
ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoU, ir.Imm64(0));
|
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() {
|
bool TranslatorVisitor::IC_IALLUIS() {
|
||||||
ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoUInnerSharable, ir.Imm64(0));
|
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) {
|
bool TranslatorVisitor::IC_IVAU(Reg Rt) {
|
||||||
ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateByVAToPoU, X(64, 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
|
} // namespace Dynarmic::A64
|
||||||
|
29
externals/dynarmic/src/dynarmic/ir/acc_type.h
vendored
Executable file
29
externals/dynarmic/src/dynarmic/ir/acc_type.h
vendored
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2022 MerryMage
|
||||||
|
* SPDX-License-Identifier: 0BSD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Dynarmic::IR {
|
||||||
|
|
||||||
|
enum class AccType {
|
||||||
|
NORMAL,
|
||||||
|
VEC,
|
||||||
|
STREAM,
|
||||||
|
VECSTREAM,
|
||||||
|
ATOMIC,
|
||||||
|
ORDERED,
|
||||||
|
ORDEREDRW,
|
||||||
|
LIMITEDORDERED,
|
||||||
|
UNPRIV,
|
||||||
|
IFETCH,
|
||||||
|
PTW,
|
||||||
|
DC,
|
||||||
|
IC,
|
||||||
|
DCZVA,
|
||||||
|
AT,
|
||||||
|
SWAP, // TODO: Remove
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dynarmic::IR
|
@ -6,7 +6,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dynarmic/common/common_types.h"
|
#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/basic_block.h"
|
||||||
#include "dynarmic/ir/location_descriptor.h"
|
#include "dynarmic/ir/location_descriptor.h"
|
||||||
#include "dynarmic/ir/terminal.h"
|
#include "dynarmic/ir/terminal.h"
|
||||||
|
@ -43,7 +43,7 @@ constexpr Type CoprocInfo = Type::CoprocInfo;
|
|||||||
constexpr Type NZCV = Type::NZCVFlags;
|
constexpr Type NZCV = Type::NZCVFlags;
|
||||||
constexpr Type Cond = Type::Cond;
|
constexpr Type Cond = Type::Cond;
|
||||||
constexpr Type Table = Type::Table;
|
constexpr Type Table = Type::Table;
|
||||||
constexpr Type AccessType = Type::AccessType;
|
constexpr Type AccType = Type::AccType;
|
||||||
|
|
||||||
static const std::array opcode_info{
|
static const std::array opcode_info{
|
||||||
#define OPCODE(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
|
#define OPCODE(name, type, ...) Meta{#name, type, {__VA_ARGS__}},
|
||||||
|
72
externals/dynarmic/src/dynarmic/ir/opcodes.inc
vendored
72
externals/dynarmic/src/dynarmic/ir/opcodes.inc
vendored
@ -688,45 +688,45 @@ OPCODE(FPVectorToUnsignedFixed64, U128, U128
|
|||||||
|
|
||||||
// A32 Memory access
|
// A32 Memory access
|
||||||
A32OPC(ClearExclusive, Void, )
|
A32OPC(ClearExclusive, Void, )
|
||||||
A32OPC(ReadMemory8, U8, U32 )
|
A32OPC(ReadMemory8, U8, U32, AccType )
|
||||||
A32OPC(ReadMemory16, U16, U32 )
|
A32OPC(ReadMemory16, U16, U32, AccType )
|
||||||
A32OPC(ReadMemory32, U32, U32 )
|
A32OPC(ReadMemory32, U32, U32, AccType )
|
||||||
A32OPC(ReadMemory64, U64, U32 )
|
A32OPC(ReadMemory64, U64, U32, AccType )
|
||||||
A32OPC(ExclusiveReadMemory8, U8, U32 )
|
A32OPC(ExclusiveReadMemory8, U8, U32, AccType )
|
||||||
A32OPC(ExclusiveReadMemory16, U16, U32 )
|
A32OPC(ExclusiveReadMemory16, U16, U32, AccType )
|
||||||
A32OPC(ExclusiveReadMemory32, U32, U32 )
|
A32OPC(ExclusiveReadMemory32, U32, U32, AccType )
|
||||||
A32OPC(ExclusiveReadMemory64, U64, U32 )
|
A32OPC(ExclusiveReadMemory64, U64, U32, AccType )
|
||||||
A32OPC(WriteMemory8, Void, U32, U8 )
|
A32OPC(WriteMemory8, Void, U32, U8, AccType )
|
||||||
A32OPC(WriteMemory16, Void, U32, U16 )
|
A32OPC(WriteMemory16, Void, U32, U16, AccType )
|
||||||
A32OPC(WriteMemory32, Void, U32, U32 )
|
A32OPC(WriteMemory32, Void, U32, U32, AccType )
|
||||||
A32OPC(WriteMemory64, Void, U32, U64 )
|
A32OPC(WriteMemory64, Void, U32, U64, AccType )
|
||||||
A32OPC(ExclusiveWriteMemory8, U32, U32, U8 )
|
A32OPC(ExclusiveWriteMemory8, U32, U32, U8, AccType )
|
||||||
A32OPC(ExclusiveWriteMemory16, U32, U32, U16 )
|
A32OPC(ExclusiveWriteMemory16, U32, U32, U16, AccType )
|
||||||
A32OPC(ExclusiveWriteMemory32, U32, U32, U32 )
|
A32OPC(ExclusiveWriteMemory32, U32, U32, U32, AccType )
|
||||||
A32OPC(ExclusiveWriteMemory64, U32, U32, U64 )
|
A32OPC(ExclusiveWriteMemory64, U32, U32, U64, AccType )
|
||||||
|
|
||||||
// A64 Memory access
|
// A64 Memory access
|
||||||
A64OPC(ClearExclusive, Void, )
|
A64OPC(ClearExclusive, Void, )
|
||||||
A64OPC(ReadMemory8, U8, U64, AccessType )
|
A64OPC(ReadMemory8, U8, U64, AccType )
|
||||||
A64OPC(ReadMemory16, U16, U64, AccessType )
|
A64OPC(ReadMemory16, U16, U64, AccType )
|
||||||
A64OPC(ReadMemory32, U32, U64, AccessType )
|
A64OPC(ReadMemory32, U32, U64, AccType )
|
||||||
A64OPC(ReadMemory64, U64, U64, AccessType )
|
A64OPC(ReadMemory64, U64, U64, AccType )
|
||||||
A64OPC(ReadMemory128, U128, U64, AccessType )
|
A64OPC(ReadMemory128, U128, U64, AccType )
|
||||||
A64OPC(ExclusiveReadMemory8, U8, U64, AccessType )
|
A64OPC(ExclusiveReadMemory8, U8, U64, AccType )
|
||||||
A64OPC(ExclusiveReadMemory16, U16, U64, AccessType )
|
A64OPC(ExclusiveReadMemory16, U16, U64, AccType )
|
||||||
A64OPC(ExclusiveReadMemory32, U32, U64, AccessType )
|
A64OPC(ExclusiveReadMemory32, U32, U64, AccType )
|
||||||
A64OPC(ExclusiveReadMemory64, U64, U64, AccessType )
|
A64OPC(ExclusiveReadMemory64, U64, U64, AccType )
|
||||||
A64OPC(ExclusiveReadMemory128, U128, U64, AccessType )
|
A64OPC(ExclusiveReadMemory128, U128, U64, AccType )
|
||||||
A64OPC(WriteMemory8, Void, U64, U8, AccessType )
|
A64OPC(WriteMemory8, Void, U64, U8, AccType )
|
||||||
A64OPC(WriteMemory16, Void, U64, U16, AccessType )
|
A64OPC(WriteMemory16, Void, U64, U16, AccType )
|
||||||
A64OPC(WriteMemory32, Void, U64, U32, AccessType )
|
A64OPC(WriteMemory32, Void, U64, U32, AccType )
|
||||||
A64OPC(WriteMemory64, Void, U64, U64, AccessType )
|
A64OPC(WriteMemory64, Void, U64, U64, AccType )
|
||||||
A64OPC(WriteMemory128, Void, U64, U128, AccessType )
|
A64OPC(WriteMemory128, Void, U64, U128, AccType )
|
||||||
A64OPC(ExclusiveWriteMemory8, U32, U64, U8, AccessType )
|
A64OPC(ExclusiveWriteMemory8, U32, U64, U8, AccType )
|
||||||
A64OPC(ExclusiveWriteMemory16, U32, U64, U16, AccessType )
|
A64OPC(ExclusiveWriteMemory16, U32, U64, U16, AccType )
|
||||||
A64OPC(ExclusiveWriteMemory32, U32, U64, U32, AccessType )
|
A64OPC(ExclusiveWriteMemory32, U32, U64, U32, AccType )
|
||||||
A64OPC(ExclusiveWriteMemory64, U32, U64, U64, AccessType )
|
A64OPC(ExclusiveWriteMemory64, U32, U64, U64, AccType )
|
||||||
A64OPC(ExclusiveWriteMemory128, U32, U64, U128, AccessType )
|
A64OPC(ExclusiveWriteMemory128, U32, U64, U128, AccType )
|
||||||
|
|
||||||
// Coprocessor
|
// Coprocessor
|
||||||
A32OPC(CoprocInternalOperation, Void, CoprocInfo )
|
A32OPC(CoprocInternalOperation, Void, CoprocInfo )
|
||||||
|
@ -32,19 +32,19 @@ void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf) {
|
|||||||
|
|
||||||
const IR::U128 zero_u128 = ir.ZeroExtendToQuad(ir.Imm64(0));
|
const IR::U128 zero_u128 = ir.ZeroExtendToQuad(ir.Imm64(0));
|
||||||
while (bytes >= 16) {
|
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));
|
addr = ir.Add(addr, ir.Imm64(16));
|
||||||
bytes -= 16;
|
bytes -= 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (bytes >= 8) {
|
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));
|
addr = ir.Add(addr, ir.Imm64(8));
|
||||||
bytes -= 8;
|
bytes -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (bytes >= 4) {
|
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));
|
addr = ir.Add(addr, ir.Imm64(4));
|
||||||
bytes -= 4;
|
bytes -= 4;
|
||||||
}
|
}
|
||||||
|
2
externals/dynarmic/src/dynarmic/ir/type.h
vendored
2
externals/dynarmic/src/dynarmic/ir/type.h
vendored
@ -32,7 +32,7 @@ enum class Type {
|
|||||||
NZCVFlags = 1 << 12,
|
NZCVFlags = 1 << 12,
|
||||||
Cond = 1 << 13,
|
Cond = 1 << 13,
|
||||||
Table = 1 << 14,
|
Table = 1 << 14,
|
||||||
AccessType = 1 << 15,
|
AccType = 1 << 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Type operator|(Type a, Type b) {
|
constexpr Type operator|(Type a, Type b) {
|
||||||
|
8
externals/dynarmic/src/dynarmic/ir/value.cpp
vendored
8
externals/dynarmic/src/dynarmic/ir/value.cpp
vendored
@ -73,8 +73,8 @@ Value::Value(Cond value)
|
|||||||
inner.imm_cond = value;
|
inner.imm_cond = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(AccessType value)
|
Value::Value(AccType value)
|
||||||
: type(Type::AccessType) {
|
: type(Type::AccType) {
|
||||||
inner.imm_acctype = value;
|
inner.imm_acctype = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,10 +183,10 @@ Cond Value::GetCond() const {
|
|||||||
return inner.imm_cond;
|
return inner.imm_cond;
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessType Value::GetAccType() const {
|
AccType Value::GetAccType() const {
|
||||||
if (IsIdentity())
|
if (IsIdentity())
|
||||||
return inner.inst->GetArg(0).GetAccType();
|
return inner.inst->GetArg(0).GetAccType();
|
||||||
ASSERT(type == Type::AccessType);
|
ASSERT(type == Type::AccType);
|
||||||
return inner.imm_acctype;
|
return inner.imm_acctype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
externals/dynarmic/src/dynarmic/ir/value.h
vendored
8
externals/dynarmic/src/dynarmic/ir/value.h
vendored
@ -25,7 +25,7 @@ enum class Vec;
|
|||||||
namespace Dynarmic::IR {
|
namespace Dynarmic::IR {
|
||||||
|
|
||||||
class Inst;
|
class Inst;
|
||||||
enum class AccessType;
|
enum class AccType;
|
||||||
enum class Cond;
|
enum class Cond;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,7 +50,7 @@ public:
|
|||||||
explicit Value(u64 value);
|
explicit Value(u64 value);
|
||||||
explicit Value(CoprocessorInfo value);
|
explicit Value(CoprocessorInfo value);
|
||||||
explicit Value(Cond value);
|
explicit Value(Cond value);
|
||||||
explicit Value(AccessType value);
|
explicit Value(AccType value);
|
||||||
|
|
||||||
bool IsIdentity() const;
|
bool IsIdentity() const;
|
||||||
bool IsEmpty() const;
|
bool IsEmpty() const;
|
||||||
@ -70,7 +70,7 @@ public:
|
|||||||
u64 GetU64() const;
|
u64 GetU64() const;
|
||||||
CoprocessorInfo GetCoprocInfo() const;
|
CoprocessorInfo GetCoprocInfo() const;
|
||||||
Cond GetCond() const;
|
Cond GetCond() const;
|
||||||
AccessType GetAccType() const;
|
AccType GetAccType() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the immediate of a Value instance as a signed 64-bit value.
|
* Retrieves the immediate of a Value instance as a signed 64-bit value.
|
||||||
@ -143,7 +143,7 @@ private:
|
|||||||
u64 imm_u64;
|
u64 imm_u64;
|
||||||
CoprocessorInfo imm_coproc;
|
CoprocessorInfo imm_coproc;
|
||||||
Cond imm_cond;
|
Cond imm_cond;
|
||||||
AccessType imm_acctype;
|
AccType imm_acctype;
|
||||||
} inner;
|
} inner;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Value) <= 2 * sizeof(u64), "IR::Value should be kept small in size");
|
static_assert(sizeof(Value) <= 2 * sizeof(u64), "IR::Value should be kept small in size");
|
||||||
|
@ -93,17 +93,19 @@ public:
|
|||||||
static constexpr u64 ICACHE_LINE_SIZE = 64;
|
static constexpr u64 ICACHE_LINE_SIZE = 64;
|
||||||
|
|
||||||
const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
|
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
|
||||||
parent.ClearInstructionCache();
|
parent.system.InvalidateCpuInstructionCaches();
|
||||||
break;
|
break;
|
||||||
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
|
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
|
||||||
default:
|
default:
|
||||||
LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op);
|
LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parent.jit->HaltExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
|
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <bit>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
#include <boost/container/static_vector.hpp>
|
#include <boost/container/static_vector.hpp>
|
||||||
|
Loading…
Reference in New Issue
Block a user