frontend: Add option to halt after memory accesses (#682)

Intended to be used for library users wishing implement accurate memory watchpoints.

* A32: optionally make memory instructions the end of basic blocks
* A64: optionally make memory instructions the end of basic blocks
* Make memory halt checking a user configurable
* oops
This commit is contained in:
liamwhite 2022-06-16 13:09:04 -04:00 committed by GitHub
parent e99ba06cf3
commit 5ad1d02351
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 239 additions and 172 deletions

View file

@ -167,7 +167,8 @@ private:
PerformCacheInvalidation();
}
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks,
{conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions, conf.check_halt_on_memory_access});
Optimization::PolyfillPass(ir_block, polyfill_options);
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
Optimization::A32GetSetElimination(ir_block);

View file

@ -265,7 +265,7 @@ private:
// JIT Compile
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
IR::Block ir_block = A64::Translate(A64::LocationDescriptor{current_location}, get_code,
{conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
{conf.define_unpredictable_behaviour, conf.wall_clock_cntpct, conf.hook_hint_instructions, conf.check_halt_on_memory_access});
Optimization::PolyfillPass(ir_block, polyfill_options);
Optimization::A64CallbackConfigPass(ir_block, conf);
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {

View file

@ -29,6 +29,12 @@ struct TranslationOptions {
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
/// This changes what IR we emit when we translate a memory instruction.
/// If this is false, memory accesses are not considered terminal.
/// If this is true, memory access are considered terminal. This allows
/// accurately emulating protection fault handlers.
bool check_halt_on_memory_access = false;
};
/**

View file

@ -53,6 +53,15 @@ bool TranslatorVisitor::RaiseException(Exception exception) {
return false;
}
bool TranslatorVisitor::MemoryInstructionContinues() {
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(static_cast<s32>(current_instruction_size))});
return false;
}
return true;
}
IR::UAny TranslatorVisitor::I(size_t bitsize, u64 value) {
switch (bitsize) {
case 8:

View file

@ -41,6 +41,7 @@ struct TranslatorVisitor final {
bool UndefinedInstruction();
bool DecodeError();
bool RaiseException(Exception exception);
bool MemoryInstructionContinues();
struct ImmAndCarry {
u32 imm32;

View file

@ -119,7 +119,7 @@ bool TranslatorVisitor::v8_VST_multiple(bool D, Reg n, size_t Vd, Imm<4> type, s
}
}
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t size, size_t align, Reg m) {
@ -176,7 +176,7 @@ bool TranslatorVisitor::v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, s
}
}
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::v8_VLD_all_lanes(bool D, Reg n, size_t Vd, size_t nn, size_t sz, bool T, bool a, Reg m) {
@ -241,7 +241,7 @@ bool TranslatorVisitor::v8_VLD_all_lanes(bool D, Reg n, size_t Vd, size_t nn, si
}
}
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::v8_VST_single(bool D, Reg n, size_t Vd, size_t sz, size_t nn, size_t index_align, Reg m) {
@ -305,7 +305,7 @@ bool TranslatorVisitor::v8_VST_single(bool D, Reg n, size_t Vd, size_t sz, size_
}
}
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::v8_VLD_single(bool D, Reg n, size_t Vd, size_t sz, size_t nn, size_t index_align, Reg m) {
@ -370,6 +370,6 @@ bool TranslatorVisitor::v8_VLD_single(bool D, Reg n, size_t Vd, size_t sz, size_
}
}
return true;
return MemoryInstructionContinues();
}
} // namespace Dynarmic::A32

View file

@ -83,7 +83,7 @@ bool TranslatorVisitor::arm_LDR_lit(Cond cond, bool U, Reg t, Imm<12> imm12) {
}
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDR <Rt>, [<Rn>, #+/-<imm>]{!}
@ -120,7 +120,7 @@ bool TranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re
}
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDR <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -150,7 +150,7 @@ bool TranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Re
}
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRB <Rt>, [PC, #+/-<imm>]
@ -170,7 +170,7 @@ bool TranslatorVisitor::arm_LDRB_lit(Cond cond, bool U, Reg t, Imm<12> imm12) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRB <Rt>, [<Rn>, #+/-<imm>]{!}
@ -199,7 +199,7 @@ bool TranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRB <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -223,7 +223,7 @@ bool TranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRD <Rt>, <Rt2>, [PC, #+/-<imm>]
@ -257,7 +257,7 @@ bool TranslatorVisitor::arm_LDRD_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm
ir.SetRegister(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result);
}
return true;
return MemoryInstructionContinues();
}
// LDRD <Rt>, [<Rn>, #+/-<imm>]{!}
@ -303,7 +303,7 @@ bool TranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, R
ir.SetRegister(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result);
}
return true;
return MemoryInstructionContinues();
}
// LDRD <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -343,7 +343,7 @@ bool TranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, R
ir.SetRegister(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result);
}
return true;
return MemoryInstructionContinues();
}
// LDRH <Rt>, [PC, #-/+<imm>]
@ -368,7 +368,7 @@ bool TranslatorVisitor::arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, I
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRH <Rt>, [<Rn>, #+/-<imm>]{!}
@ -397,7 +397,7 @@ bool TranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRH <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -421,7 +421,7 @@ bool TranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRSB <Rt>, [PC, #+/-<imm>]
@ -442,7 +442,7 @@ bool TranslatorVisitor::arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Im
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRSB <Rt>, [<Rn>, #+/-<imm>]{!}
@ -471,7 +471,7 @@ bool TranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRSB <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -495,7 +495,7 @@ bool TranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRSH <Rt>, [PC, #-/+<imm>]
@ -515,7 +515,7 @@ bool TranslatorVisitor::arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Im
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRSH <Rt>, [<Rn>, #+/-<imm>]{!}
@ -544,7 +544,7 @@ bool TranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRSH <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -568,7 +568,7 @@ bool TranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n,
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// STR <Rt>, [<Rn>, #+/-<imm>]{!}
@ -585,7 +585,7 @@ bool TranslatorVisitor::arm_STR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re
const auto offset = ir.Imm32(imm12.ZeroExtend());
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// STR <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -606,7 +606,7 @@ bool TranslatorVisitor::arm_STR_reg(Cond cond, bool P, bool U, bool W, Reg n, Re
const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// STRB <Rt>, [<Rn>, #+/-<imm>]{!}
@ -627,7 +627,7 @@ bool TranslatorVisitor::arm_STRB_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto offset = ir.Imm32(imm12.ZeroExtend());
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// STRB <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -648,7 +648,7 @@ bool TranslatorVisitor::arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// STRD <Rt>, [<Rn>, #+/-<imm>]{!}
@ -686,7 +686,7 @@ bool TranslatorVisitor::arm_STRD_imm(Cond cond, bool P, bool U, bool W, Reg n, R
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
ir.WriteMemory64(address, data, IR::AccType::ATOMIC);
return true;
return MemoryInstructionContinues();
}
// STRD <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -723,7 +723,7 @@ bool TranslatorVisitor::arm_STRD_reg(Cond cond, bool P, bool U, bool W, Reg n, R
// NOTE: If alignment is exactly off by 4, each word is an atomic access.
ir.WriteMemory64(address, data, IR::AccType::ATOMIC);
return true;
return MemoryInstructionContinues();
}
// STRH <Rt>, [<Rn>, #+/-<imm>]{!}
@ -746,7 +746,7 @@ bool TranslatorVisitor::arm_STRH_imm(Cond cond, bool P, bool U, bool W, Reg n, R
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// STRH <Rt>, [<Rn>, #+/-<Rm>]{!}
@ -768,29 +768,31 @@ bool TranslatorVisitor::arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n, R
const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
static bool LDMHelper(TranslatorVisitor& v, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
auto address = start_address;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = ir.Add(address, ir.Imm32(4));
v.ir.SetRegister(static_cast<Reg>(i), v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = v.ir.Add(address, v.ir.Imm32(4));
}
}
if (W && !mcl::bit::get_bit(RegNumber(n), list)) {
ir.SetRegister(n, writeback_address);
v.ir.SetRegister(n, writeback_address);
}
if (mcl::bit::get_bit<15>(list)) {
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (n == Reg::R13)
ir.SetTerm(IR::Term::PopRSBHint{});
v.ir.LoadWritePC(v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (v.options.check_halt_on_memory_access)
v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
else if (n == Reg::R13)
v.ir.SetTerm(IR::Term::PopRSBHint{});
else
ir.SetTerm(IR::Term::FastDispatchHint{});
v.ir.SetTerm(IR::Term::FastDispatchHint{});
return false;
}
return true;
return v.MemoryInstructionContinues();
}
// LDM <Rn>{!}, <reg_list>
@ -808,7 +810,7 @@ bool TranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4)));
return LDMHelper(ir, W, n, list, start_address, writeback_address);
return LDMHelper(*this, W, n, list, start_address, writeback_address);
}
// LDMDA <Rn>{!}, <reg_list>
@ -826,7 +828,7 @@ bool TranslatorVisitor::arm_LDMDA(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list) - 4)));
const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
return LDMHelper(ir, W, n, list, start_address, writeback_address);
return LDMHelper(*this, W, n, list, start_address, writeback_address);
}
// LDMDB <Rn>{!}, <reg_list>
@ -844,7 +846,7 @@ bool TranslatorVisitor::arm_LDMDB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = start_address;
return LDMHelper(ir, W, n, list, start_address, writeback_address);
return LDMHelper(*this, W, n, list, start_address, writeback_address);
}
// LDMIB <Rn>{!}, <reg_list>
@ -862,7 +864,7 @@ bool TranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
return LDMHelper(ir, W, n, list, start_address, writeback_address);
return LDMHelper(*this, W, n, list, start_address, writeback_address);
}
bool TranslatorVisitor::arm_LDM_usr() {
@ -873,21 +875,21 @@ bool TranslatorVisitor::arm_LDM_eret() {
return InterpretThisInstruction();
}
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
static bool STMHelper(TranslatorVisitor& v, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
auto address = start_address;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = ir.Add(address, ir.Imm32(4));
v.ir.WriteMemory32(address, v.ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = v.ir.Add(address, v.ir.Imm32(4));
}
}
if (W) {
ir.SetRegister(n, writeback_address);
v.ir.SetRegister(n, writeback_address);
}
if (mcl::bit::get_bit<15>(list)) {
ir.WriteMemory32(address, ir.Imm32(ir.PC()), IR::AccType::ATOMIC);
v.ir.WriteMemory32(address, v.ir.Imm32(v.ir.PC()), IR::AccType::ATOMIC);
}
return true;
return v.MemoryInstructionContinues();
}
// STM <Rn>{!}, <reg_list>
@ -902,7 +904,7 @@ bool TranslatorVisitor::arm_STM(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4)));
return STMHelper(ir, W, n, list, start_address, writeback_address);
return STMHelper(*this, W, n, list, start_address, writeback_address);
}
// STMDA <Rn>{!}, <reg_list>
@ -917,7 +919,7 @@ bool TranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list) - 4)));
const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
return STMHelper(ir, W, n, list, start_address, writeback_address);
return STMHelper(*this, W, n, list, start_address, writeback_address);
}
// STMDB <Rn>{!}, <reg_list>
@ -932,7 +934,7 @@ bool TranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = start_address;
return STMHelper(ir, W, n, list, start_address, writeback_address);
return STMHelper(*this, W, n, list, start_address, writeback_address);
}
// STMIB <Rn>{!}, <reg_list>
@ -947,7 +949,7 @@ bool TranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) {
const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
return STMHelper(ir, W, n, list, start_address, writeback_address);
return STMHelper(*this, W, n, list, start_address, writeback_address);
}
bool TranslatorVisitor::arm_STM_usr() {

View file

@ -29,7 +29,7 @@ bool TranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) {
ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2), IR::AccType::SWAP);
// TODO: Alignment check
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// SWPB<c> <Rt>, <Rt2>, [<Rn>]
@ -48,7 +48,7 @@ bool TranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) {
ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2)), IR::AccType::SWAP);
// TODO: Alignment check
ir.SetRegister(t, ir.ZeroExtendByteToWord(data));
return true;
return MemoryInstructionContinues();
}
// LDA<c> <Rt>, [<Rn>]
@ -63,7 +63,7 @@ bool TranslatorVisitor::arm_LDA(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ReadMemory32(address, IR::AccType::ORDERED));
return true;
return MemoryInstructionContinues();
}
// LDAB<c> <Rt>, [<Rn>]
bool TranslatorVisitor::arm_LDAB(Cond cond, Reg n, Reg t) {
@ -77,7 +77,7 @@ bool TranslatorVisitor::arm_LDAB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory8(address, IR::AccType::ORDERED)));
return true;
return MemoryInstructionContinues();
}
// LDAH<c> <Rt>, [<Rn>]
bool TranslatorVisitor::arm_LDAH(Cond cond, Reg n, Reg t) {
@ -91,7 +91,7 @@ bool TranslatorVisitor::arm_LDAH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory16(address, IR::AccType::ORDERED)));
return true;
return MemoryInstructionContinues();
}
// LDAEX<c> <Rt>, [<Rn>]
@ -106,7 +106,7 @@ bool TranslatorVisitor::arm_LDAEX(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ORDERED));
return true;
return MemoryInstructionContinues();
}
// LDAEXB<c> <Rt>, [<Rn>]
@ -121,7 +121,7 @@ bool TranslatorVisitor::arm_LDAEXB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ORDERED)));
return true;
return MemoryInstructionContinues();
}
// LDAEXD<c> <Rt>, <Rt2>, [<Rn>]
@ -139,7 +139,7 @@ bool TranslatorVisitor::arm_LDAEXD(Cond cond, Reg n, Reg t) {
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
ir.SetRegister(t, lo);
ir.SetRegister(t + 1, hi);
return true;
return MemoryInstructionContinues();
}
// LDAEXH<c> <Rt>, [<Rn>]
@ -154,7 +154,7 @@ bool TranslatorVisitor::arm_LDAEXH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ORDERED)));
return true;
return MemoryInstructionContinues();
}
// STL<c> <Rt>, [<Rn>]
@ -169,7 +169,7 @@ bool TranslatorVisitor::arm_STL(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED);
return true;
return MemoryInstructionContinues();
}
// STLB<c> <Rt>, [<Rn>]
@ -184,7 +184,7 @@ bool TranslatorVisitor::arm_STLB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::ORDERED);
return true;
return MemoryInstructionContinues();
}
// STLH<c> <Rd>, <Rt>, [<Rn>]
@ -199,7 +199,7 @@ bool TranslatorVisitor::arm_STLH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::ORDERED);
return true;
return MemoryInstructionContinues();
}
// STLEXB<c> <Rd>, <Rt>, [<Rn>]
@ -220,7 +220,7 @@ bool TranslatorVisitor::arm_STLEXB(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
// STLEXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
bool TranslatorVisitor::arm_STLEXD(Cond cond, Reg n, Reg d, Reg t) {
@ -242,7 +242,7 @@ bool TranslatorVisitor::arm_STLEXD(Cond cond, Reg n, Reg d, Reg t) {
const auto value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
// STLEXH<c> <Rd>, <Rt>, [<Rn>]
@ -263,7 +263,7 @@ bool TranslatorVisitor::arm_STLEXH(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
// STLEX<c> <Rd>, <Rt>, [<Rn>]
@ -284,7 +284,7 @@ bool TranslatorVisitor::arm_STLEX(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
// LDREX<c> <Rt>, [<Rn>]
@ -299,7 +299,7 @@ bool TranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC));
return true;
return MemoryInstructionContinues();
}
// LDREXB<c> <Rt>, [<Rn>]
@ -314,7 +314,7 @@ bool TranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC)));
return true;
return MemoryInstructionContinues();
}
// LDREXD<c> <Rt>, <Rt2>, [<Rn>]
@ -332,7 +332,7 @@ bool TranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg t) {
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
ir.SetRegister(t, lo);
ir.SetRegister(t + 1, hi);
return true;
return MemoryInstructionContinues();
}
// LDREXH<c> <Rt>, [<Rn>]
@ -347,7 +347,7 @@ bool TranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC)));
return true;
return MemoryInstructionContinues();
}
// STREX<c> <Rd>, <Rt>, [<Rn>]
@ -368,7 +368,7 @@ bool TranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
// STREXB<c> <Rd>, <Rt>, [<Rn>]
@ -389,7 +389,7 @@ bool TranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
// STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
@ -412,7 +412,7 @@ bool TranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg t) {
const auto value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
// STREXH<c> <Rd>, <Rt>, [<Rn>]
@ -433,7 +433,7 @@ bool TranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg t) {
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
} // namespace Dynarmic::A32

View file

@ -449,7 +449,7 @@ bool TranslatorVisitor::thumb16_LDR_literal(Reg t, Imm<8> imm8) {
const auto data = ir.ReadMemory32(ir.Imm32(address), IR::AccType::NORMAL);
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// STR <Rt>, [<Rn>, <Rm>]
@ -459,7 +459,7 @@ bool TranslatorVisitor::thumb16_STR_reg(Reg m, Reg n, Reg t) {
const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// STRH <Rt>, [<Rn>, <Rm>]
@ -469,7 +469,7 @@ bool TranslatorVisitor::thumb16_STRH_reg(Reg m, Reg n, Reg t) {
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
ir.WriteMemory16(address, data, IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// STRB <Rt>, [<Rn>, <Rm>]
@ -479,7 +479,7 @@ bool TranslatorVisitor::thumb16_STRB_reg(Reg m, Reg n, Reg t) {
const auto data = ir.LeastSignificantByte(ir.GetRegister(t));
ir.WriteMemory8(address, data, IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// LDRSB <Rt>, [<Rn>, <Rm>]
@ -489,7 +489,7 @@ bool TranslatorVisitor::thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDR <Rt>, [<Rn>, <Rm>]
@ -499,7 +499,7 @@ bool TranslatorVisitor::thumb16_LDR_reg(Reg m, Reg n, Reg t) {
const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRH <Rt>, [<Rn>, <Rm>]
@ -509,7 +509,7 @@ bool TranslatorVisitor::thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRB <Rt>, [<Rn>, <Rm>]
@ -519,7 +519,7 @@ bool TranslatorVisitor::thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// LDRH <Rt>, [<Rn>, <Rm>]
@ -529,7 +529,7 @@ bool TranslatorVisitor::thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// STR <Rt>, [<Rn>, #<imm>]
@ -540,7 +540,7 @@ bool TranslatorVisitor::thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// LDR <Rt>, [<Rn>, #<imm>]
@ -551,7 +551,7 @@ bool TranslatorVisitor::thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// STRB <Rt>, [<Rn>, #<imm>]
@ -573,7 +573,7 @@ bool TranslatorVisitor::thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// STRH <Rt>, [<Rn>, #<imm5>]
@ -583,7 +583,7 @@ bool TranslatorVisitor::thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
ir.WriteMemory16(address, data, IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// LDRH <Rt>, [<Rn>, #<imm5>]
@ -593,7 +593,7 @@ bool TranslatorVisitor::thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) {
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// STR <Rt>, [<Rn>, #<imm>]
@ -605,7 +605,7 @@ bool TranslatorVisitor::thumb16_STR_imm_t2(Reg t, Imm<8> imm8) {
const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return true;
return MemoryInstructionContinues();
}
// LDR <Rt>, [<Rn>, #<imm>]
@ -617,7 +617,7 @@ bool TranslatorVisitor::thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) {
const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
// ADR <Rd>, <label>
@ -775,7 +775,7 @@ bool TranslatorVisitor::thumb16_PUSH(bool M, RegList reg_list) {
ir.SetRegister(Reg::SP, final_address);
// TODO(optimization): Possible location for an RSB push.
return true;
return MemoryInstructionContinues();
}
// POP <reg_list>
@ -804,11 +804,15 @@ bool TranslatorVisitor::thumb16_POP(bool P, RegList reg_list) {
ir.LoadWritePC(data);
address = ir.Add(address, ir.Imm32(4));
ir.SetRegister(Reg::SP, address);
ir.SetTerm(IR::Term::PopRSBHint{});
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::PopRSBHint{}});
} else {
ir.SetTerm(IR::Term::PopRSBHint{});
}
return false;
} else {
ir.SetRegister(Reg::SP, address);
return true;
return MemoryInstructionContinues();
}
}
@ -887,7 +891,7 @@ bool TranslatorVisitor::thumb16_STMIA(Reg n, RegList reg_list) {
}
ir.SetRegister(n, address);
return true;
return MemoryInstructionContinues();
}
// LDM <Rn>!, <reg_list>
@ -910,7 +914,7 @@ bool TranslatorVisitor::thumb16_LDMIA(Reg n, RegList reg_list) {
if (write_back) {
ir.SetRegister(n, address);
}
return true;
return MemoryInstructionContinues();
}
// CB{N}Z <Rn>, <label>

View file

@ -34,7 +34,7 @@ static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(v.ir.Imm32(address), IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return true;
return v.MemoryInstructionContinues();
}
static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
@ -49,7 +49,7 @@ static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address, IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return true;
return v.MemoryInstructionContinues();
}
static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
@ -64,7 +64,7 @@ static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U
if (W) {
v.ir.SetRegister(n, offset_address);
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_PLD_lit(bool /*U*/, Imm<12> /*imm12*/) {

View file

@ -16,7 +16,7 @@ static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory16(v.ir.Imm32(address), IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return true;
return v.MemoryInstructionContinues();
}
static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
@ -31,7 +31,7 @@ static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address, IR::AccType::NORMAL));
v.ir.SetRegister(t, data);
return true;
return v.MemoryInstructionContinues();
}
static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
@ -48,7 +48,7 @@ static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U
}
v.ir.SetRegister(t, data);
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12) {

View file

@ -36,7 +36,11 @@ static bool TableBranch(TranslatorVisitor& v, Reg n, Reg m, bool half) {
v.ir.UpdateUpperLocationDescriptor();
v.ir.BranchWritePC(branch_value);
v.ir.SetTerm(IR::Term::FastDispatchHint{});
if (v.options.check_halt_on_memory_access) {
v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
v.ir.SetTerm(IR::Term::FastDispatchHint{});
}
return false;
}
@ -68,7 +72,7 @@ static bool LoadDualImmediate(TranslatorVisitor& v, bool P, bool U, bool W, Reg
if (W) {
v.ir.SetRegister(n, offset_address);
}
return true;
return v.MemoryInstructionContinues();
}
static bool LoadDualLiteral(TranslatorVisitor& v, bool U, bool W, Reg t, Reg t2, Imm<8> imm8) {
@ -94,7 +98,7 @@ static bool LoadDualLiteral(TranslatorVisitor& v, bool U, bool W, Reg t, Reg t2,
v.ir.SetRegister(t2, v.ir.MostSignificantWord(data).result);
}
return true;
return v.MemoryInstructionContinues();
}
static bool StoreDual(TranslatorVisitor& v, bool P, bool U, bool W, Reg n, Reg t, Reg t2, Imm<8> imm8) {
@ -123,7 +127,7 @@ static bool StoreDual(TranslatorVisitor& v, bool P, bool U, bool W, Reg n, Reg t
if (W) {
v.ir.SetRegister(n, offset_address);
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDA(Reg n, Reg t) {
@ -169,7 +173,7 @@ bool TranslatorVisitor::thumb32_LDREX(Reg n, Reg t, Imm<8> imm8) {
const auto value = ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC);
ir.SetRegister(t, value);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) {
@ -181,7 +185,7 @@ bool TranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) {
const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC));
ir.SetRegister(t, value);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) {
@ -195,7 +199,7 @@ bool TranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) {
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
ir.SetRegister(t, lo);
ir.SetRegister(t2, hi);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) {
@ -207,7 +211,7 @@ bool TranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) {
const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC));
ir.SetRegister(t, value);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_STL(Reg n, Reg t) {
@ -217,7 +221,7 @@ bool TranslatorVisitor::thumb32_STL(Reg n, Reg t) {
const auto address = ir.GetRegister(n);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8) {
@ -232,7 +236,7 @@ bool TranslatorVisitor::thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8) {
const auto value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) {
@ -247,7 +251,7 @@ bool TranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) {
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d) {
@ -263,7 +267,7 @@ bool TranslatorVisitor::thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d) {
const auto value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) {
@ -278,7 +282,7 @@ bool TranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) {
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_TBB(Reg n, Reg m) {

View file

@ -12,42 +12,44 @@ static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
static bool LDMHelper(TranslatorVisitor& v, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
auto address = start_address;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = ir.Add(address, ir.Imm32(4));
v.ir.SetRegister(static_cast<Reg>(i), v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = v.ir.Add(address, v.ir.Imm32(4));
}
}
if (W && !mcl::bit::get_bit(RegNumber(n), list)) {
ir.SetRegister(n, writeback_address);
v.ir.SetRegister(n, writeback_address);
}
if (mcl::bit::get_bit<15>(list)) {
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (n == Reg::R13) {
ir.SetTerm(IR::Term::PopRSBHint{});
v.ir.UpdateUpperLocationDescriptor();
v.ir.LoadWritePC(v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (v.options.check_halt_on_memory_access) {
v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else if (n == Reg::R13) {
v.ir.SetTerm(IR::Term::PopRSBHint{});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
v.ir.SetTerm(IR::Term::FastDispatchHint{});
}
return false;
}
return true;
return v.MemoryInstructionContinues();
}
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
static bool STMHelper(TranslatorVisitor& v, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
auto address = start_address;
for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) {
ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = ir.Add(address, ir.Imm32(4));
v.ir.WriteMemory32(address, v.ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = v.ir.Add(address, v.ir.Imm32(4));
}
}
if (W) {
ir.SetRegister(n, writeback_address);
v.ir.SetRegister(n, writeback_address);
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
@ -72,7 +74,7 @@ bool TranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
// Start address is the same as the writeback address.
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
return LDMHelper(ir, W, n, regs_imm, start_address, start_address);
return LDMHelper(*this, W, n, regs_imm, start_address, start_address);
}
bool TranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) {
@ -97,7 +99,7 @@ bool TranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
return LDMHelper(ir, W, n, regs_imm, start_address, writeback_address);
return LDMHelper(*this, W, n, regs_imm, start_address, writeback_address);
}
bool TranslatorVisitor::thumb32_POP(Imm<16> reg_list) {
@ -124,7 +126,7 @@ bool TranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) {
const auto start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
return STMHelper(ir, W, n, regs_imm, start_address, writeback_address);
return STMHelper(*this, W, n, regs_imm, start_address, writeback_address);
}
bool TranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) {
@ -143,7 +145,7 @@ bool TranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) {
// Start address is the same as the writeback address.
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
return STMHelper(ir, W, n, regs_imm, start_address, start_address);
return STMHelper(*this, W, n, regs_imm, start_address, start_address);
}
} // namespace Dynarmic::A32

View file

@ -23,12 +23,16 @@ bool TranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) {
if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
ir.SetTerm(IR::Term::FastDispatchHint{});
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
}
return false;
}
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) {
@ -58,7 +62,9 @@ bool TranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, I
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
if (!P && W && n == Reg::R13) {
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else if (!P && W && n == Reg::R13) {
ir.SetTerm(IR::Term::PopRSBHint{});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
@ -68,7 +74,7 @@ bool TranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, I
}
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12) {
@ -84,12 +90,16 @@ bool TranslatorVisitor::thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12) {
if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
ir.SetTerm(IR::Term::FastDispatchHint{});
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
}
return false;
}
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
@ -109,12 +119,16 @@ bool TranslatorVisitor::thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data);
ir.SetTerm(IR::Term::FastDispatchHint{});
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else {
ir.SetTerm(IR::Term::FastDispatchHint{});
}
return false;
}
ir.SetRegister(t, data);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::thumb32_LDRT(Reg n, Reg t, Imm<8> imm8) {

View file

@ -1201,7 +1201,7 @@ bool TranslatorVisitor::vfp_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm<8> i
}
}
return true;
return MemoryInstructionContinues();
}
// VPUSH.{F32,F64} <list>
@ -1242,7 +1242,7 @@ bool TranslatorVisitor::vfp_VPUSH(Cond cond, bool D, size_t Vd, bool sz, Imm<8>
}
}
return true;
return MemoryInstructionContinues();
}
// VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
@ -1268,7 +1268,7 @@ bool TranslatorVisitor::vfp_VLDR(Cond cond, bool U, bool D, Reg n, size_t Vd, bo
ir.SetExtendedRegister(d, ir.ReadMemory32(address, IR::AccType::ATOMIC));
}
return true;
return MemoryInstructionContinues();
}
// VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
@ -1295,7 +1295,7 @@ bool TranslatorVisitor::vfp_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd, bo
ir.WriteMemory32(address, ir.GetExtendedRegister(d), IR::AccType::ATOMIC);
}
return true;
return MemoryInstructionContinues();
}
// VSTM{mode}<c> <Rn>{!}, <list of double registers>
@ -1347,7 +1347,7 @@ bool TranslatorVisitor::vfp_VSTM_a1(Cond cond, bool p, bool u, bool D, bool w, R
address = ir.Add(address, ir.Imm32(4));
}
return true;
return MemoryInstructionContinues();
}
// VSTM{mode}<c> <Rn>{!}, <list of single registers>
@ -1390,7 +1390,7 @@ bool TranslatorVisitor::vfp_VSTM_a2(Cond cond, bool p, bool u, bool D, bool w, R
address = ir.Add(address, ir.Imm32(4));
}
return true;
return MemoryInstructionContinues();
}
// VLDM{mode}<c> <Rn>{!}, <list of double registers>
@ -1440,7 +1440,7 @@ bool TranslatorVisitor::vfp_VLDM_a1(Cond cond, bool p, bool u, bool D, bool w, R
ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(word1, word2));
}
return true;
return MemoryInstructionContinues();
}
// VLDM{mode}<c> <Rn>{!}, <list of single registers>
@ -1483,7 +1483,7 @@ bool TranslatorVisitor::vfp_VLDM_a2(Cond cond, bool p, bool u, bool D, bool w, R
ir.SetExtendedRegister(d + i, word);
}
return true;
return MemoryInstructionContinues();
}
} // namespace Dynarmic::A32

View file

@ -34,6 +34,12 @@ struct TranslationOptions {
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
/// This changes what IR we emit when we translate a memory instruction.
/// If this is false, memory accesses are not considered terminal.
/// If this is true, memory access are considered terminal. This allows
/// accurately emulating protection fault handlers.
bool check_halt_on_memory_access = false;
};
/**

View file

@ -41,6 +41,15 @@ bool TranslatorVisitor::RaiseException(Exception exception) {
return false;
}
bool TranslatorVisitor::MemoryInstructionContinues() {
if (options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->AdvancePC(4)});
return false;
}
return true;
}
std::optional<TranslatorVisitor::BitMasks> TranslatorVisitor::DecodeBitMasks(bool immN, Imm<6> imms, Imm<6> immr, bool immediate) {
const int len = mcl::bit::highest_set_bit((immN ? 1 << 6 : 0) | (imms.ZeroExtend() ^ 0b111111));
if (len < 1) {

View file

@ -30,6 +30,7 @@ struct TranslatorVisitor final {
bool ReservedValue();
bool UnallocatedEncoding();
bool RaiseException(Exception exception);
bool MemoryInstructionContinues();
struct BitMasks {
u64 wmask, tmask;

View file

@ -72,7 +72,7 @@ static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, s
UNREACHABLE();
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STXR(Imm<2> sz, Reg Rs, Reg Rn, Reg Rt) {
@ -175,7 +175,7 @@ static bool OrderedSharedDecodeAndOperation(TranslatorVisitor& v, size_t size, b
UNREACHABLE();
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STLLR(Imm<2> sz, Reg Rn, Reg Rt) {

View file

@ -15,7 +15,7 @@ bool TranslatorVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) {
const auto data = Mem(ir.Imm64(address), size, IR::AccType::NORMAL);
X(8 * size, Rt, data);
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
@ -33,7 +33,7 @@ bool TranslatorVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
} else {
V(128, Vt, ir.ZeroExtendToQuad(data));
}
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) {
@ -42,7 +42,7 @@ bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) {
const auto data = Mem(ir.Imm64(address), 4, IR::AccType::NORMAL);
X(64, Rt, ir.SignExtendWordToLong(data));
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::PRFM_lit(Imm<19> /*imm19*/, Imm<5> /*prfop*/) {

View file

@ -104,7 +104,7 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp
}
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STx_mult_1(bool Q, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) {

View file

@ -72,7 +72,7 @@ static bool LoadStoreRegisterImmediate(TranslatorVisitor& v, bool wback, bool po
}
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn, Reg Rt) {
@ -165,7 +165,7 @@ static bool LoadStoreSIMD(TranslatorVisitor& v, bool wback, bool postindex, size
}
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn, Vec Vt) {

View file

@ -78,7 +78,7 @@ bool TranslatorVisitor::STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback,
}
}
return true;
return MemoryInstructionContinues();
}
bool TranslatorVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Vec Vt2, Reg Rn, Vec Vt) {
@ -148,7 +148,7 @@ bool TranslatorVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wbac
}
}
return true;
return MemoryInstructionContinues();
}
} // namespace Dynarmic::A64

View file

@ -70,7 +70,7 @@ static bool RegSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 s
UNREACHABLE();
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt) {
@ -128,7 +128,7 @@ static bool VecSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 s
UNREACHABLE();
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Vec Vt) {

View file

@ -22,7 +22,7 @@ static bool StoreRegister(TranslatorVisitor& v, const size_t datasize, const Imm
const IR::UAny data = v.X(datasize, Rt);
v.Mem(address, datasize / 8, acctype, data);
return true;
return v.MemoryInstructionContinues();
}
static bool LoadRegister(TranslatorVisitor& v, const size_t datasize, const Imm<9> imm9, const Reg Rn, const Reg Rt) {
@ -42,7 +42,7 @@ static bool LoadRegister(TranslatorVisitor& v, const size_t datasize, const Imm<
// max is used to zeroextend < 32 to 32, and > 32 to 64
const size_t extended_size = std::max<size_t>(32, datasize);
v.X(extended_size, Rt, v.ZeroExtend(data, extended_size));
return true;
return v.MemoryInstructionContinues();
}
static bool LoadRegisterSigned(TranslatorVisitor& v, const size_t datasize, const Imm<2> opc, const Imm<9> imm9, const Reg Rn, const Reg Rt) {
@ -90,7 +90,7 @@ static bool LoadRegisterSigned(TranslatorVisitor& v, const size_t datasize, cons
// Prefetch(address, Rt);
break;
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::STTRB(Imm<9> imm9, Reg Rn, Reg Rt) {
@ -144,6 +144,6 @@ bool TranslatorVisitor::LDTRSW(Imm<9> imm9, Reg Rn, Reg Rt) {
const IR::UAny data = Mem(address, 4, acctype);
X(64, Rt, SignExtend(data, 64));
return true;
return MemoryInstructionContinues();
}
} // namespace Dynarmic::A64

View file

@ -98,7 +98,7 @@ static bool SharedDecodeAndOperation(TranslatorVisitor& v, bool wback, IR::MemOp
}
}
return true;
return v.MemoryInstructionContinues();
}
bool TranslatorVisitor::LD1_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {

View file

@ -208,6 +208,10 @@ struct UserConfig {
/// to avoid writting certain unnecessary code only needed for cycle timers.
bool wall_clock_cntpct = false;
/// This allows accurately emulating protection fault handlers. If true, we check
/// for exit after every data memory access by the emulated program.
bool check_halt_on_memory_access = false;
/// This option allows you to disable cycle counting. If this is set to false,
/// AddTicks and GetTicksRemaining are never called, and no cycle counting is done.
bool enable_cycle_counting = true;

View file

@ -273,6 +273,10 @@ struct UserConfig {
/// to avoid writting certain unnecessary code only needed for cycle timers.
bool wall_clock_cntpct = false;
/// This allows accurately emulating protection fault handlers. If true, we check
/// for exit after every data memory access by the emulated program.
bool check_halt_on_memory_access = false;
/// This option allows you to disable cycle counting. If this is set to false,
/// AddTicks and GetTicksRemaining are never called, and no cycle counting is done.
bool enable_cycle_counting = true;