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(); 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); Optimization::PolyfillPass(ir_block, polyfill_options);
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) { if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
Optimization::A32GetSetElimination(ir_block); Optimization::A32GetSetElimination(ir_block);

View file

@ -265,7 +265,7 @@ private:
// JIT Compile // JIT Compile
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }; const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
IR::Block ir_block = A64::Translate(A64::LocationDescriptor{current_location}, get_code, 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::PolyfillPass(ir_block, polyfill_options);
Optimization::A64CallbackConfigPass(ir_block, conf); Optimization::A64CallbackConfigPass(ir_block, conf);
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) { 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 false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction. /// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true; 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; 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) { IR::UAny TranslatorVisitor::I(size_t bitsize, u64 value) {
switch (bitsize) { switch (bitsize) {
case 8: case 8:

View file

@ -41,6 +41,7 @@ struct TranslatorVisitor final {
bool UndefinedInstruction(); bool UndefinedInstruction();
bool DecodeError(); bool DecodeError();
bool RaiseException(Exception exception); bool RaiseException(Exception exception);
bool MemoryInstructionContinues();
struct ImmAndCarry { struct ImmAndCarry {
u32 imm32; 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) { 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) { 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) { 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) { 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 } // 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); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDR <Rt>, [<Rn>, #+/-<imm>]{!} // 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); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDR <Rt>, [<Rn>, #+/-<Rm>]{!} // 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); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRB <Rt>, [PC, #+/-<imm>] // 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)); const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRB <Rt>, [<Rn>, #+/-<imm>]{!} // 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)); const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRB <Rt>, [<Rn>, #+/-<Rm>]{!} // 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)); const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRD <Rt>, <Rt2>, [PC, #+/-<imm>] // 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(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result); ir.SetRegister(t2, ir.MostSignificantWord(data).result);
} }
return true; return MemoryInstructionContinues();
} }
// LDRD <Rt>, [<Rn>, #+/-<imm>]{!} // 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(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result); ir.SetRegister(t2, ir.MostSignificantWord(data).result);
} }
return true; return MemoryInstructionContinues();
} }
// LDRD <Rt>, [<Rn>, #+/-<Rm>]{!} // 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(t, ir.LeastSignificantWord(data));
ir.SetRegister(t2, ir.MostSignificantWord(data).result); ir.SetRegister(t2, ir.MostSignificantWord(data).result);
} }
return true; return MemoryInstructionContinues();
} }
// LDRH <Rt>, [PC, #-/+<imm>] // 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)); const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRH <Rt>, [<Rn>, #+/-<imm>]{!} // 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)); const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRH <Rt>, [<Rn>, #+/-<Rm>]{!} // 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)); const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRSB <Rt>, [PC, #+/-<imm>] // 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)); const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRSB <Rt>, [<Rn>, #+/-<imm>]{!} // 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)); const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRSB <Rt>, [<Rn>, #+/-<Rm>]{!} // 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)); const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRSH <Rt>, [PC, #-/+<imm>] // 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)); const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address), IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRSH <Rt>, [<Rn>, #+/-<imm>]{!} // 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)); const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRSH <Rt>, [<Rn>, #+/-<Rm>]{!} // 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)); const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// STR <Rt>, [<Rn>, #+/-<imm>]{!} // 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 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::AccType::NORMAL); ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// STR <Rt>, [<Rn>, #+/-<Rm>]{!} // 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 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::AccType::NORMAL); ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// STRB <Rt>, [<Rn>, #+/-<imm>]{!} // 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 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::AccType::NORMAL); ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// STRB <Rt>, [<Rn>, #+/-<Rm>]{!} // 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 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::AccType::NORMAL); ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// STRD <Rt>, [<Rn>, #+/-<imm>]{!} // 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. // NOTE: If alignment is exactly off by 4, each word is an atomic access.
ir.WriteMemory64(address, data, IR::AccType::ATOMIC); ir.WriteMemory64(address, data, IR::AccType::ATOMIC);
return true; return MemoryInstructionContinues();
} }
// STRD <Rt>, [<Rn>, #+/-<Rm>]{!} // 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. // NOTE: If alignment is exactly off by 4, each word is an atomic access.
ir.WriteMemory64(address, data, IR::AccType::ATOMIC); ir.WriteMemory64(address, data, IR::AccType::ATOMIC);
return true; return MemoryInstructionContinues();
} }
// STRH <Rt>, [<Rn>, #+/-<imm>]{!} // 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); const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL); ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// STRH <Rt>, [<Rn>, #+/-<Rm>]{!} // 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); const auto address = GetAddress(ir, P, U, W, n, offset);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::NORMAL); 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; auto address = start_address;
for (size_t i = 0; i <= 14; i++) { for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) { if (mcl::bit::get_bit(i, list)) {
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC)); v.ir.SetRegister(static_cast<Reg>(i), v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = ir.Add(address, ir.Imm32(4)); address = v.ir.Add(address, v.ir.Imm32(4));
} }
} }
if (W && !mcl::bit::get_bit(RegNumber(n), list)) { 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)) { if (mcl::bit::get_bit<15>(list)) {
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC)); v.ir.LoadWritePC(v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (n == Reg::R13) if (v.options.check_halt_on_memory_access)
ir.SetTerm(IR::Term::PopRSBHint{}); v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
else if (n == Reg::R13)
v.ir.SetTerm(IR::Term::PopRSBHint{});
else else
ir.SetTerm(IR::Term::FastDispatchHint{}); v.ir.SetTerm(IR::Term::FastDispatchHint{});
return false; return false;
} }
return true; return v.MemoryInstructionContinues();
} }
// LDM <Rn>{!}, <reg_list> // 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 start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4))); 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> // 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 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)); 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> // 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 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = start_address; 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> // 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 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)))); 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() { bool TranslatorVisitor::arm_LDM_usr() {
@ -873,21 +875,21 @@ bool TranslatorVisitor::arm_LDM_eret() {
return InterpretThisInstruction(); 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; auto address = start_address;
for (size_t i = 0; i <= 14; i++) { for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) { if (mcl::bit::get_bit(i, list)) {
ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC); v.ir.WriteMemory32(address, v.ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = ir.Add(address, ir.Imm32(4)); address = v.ir.Add(address, v.ir.Imm32(4));
} }
} }
if (W) { if (W) {
ir.SetRegister(n, writeback_address); v.ir.SetRegister(n, writeback_address);
} }
if (mcl::bit::get_bit<15>(list)) { 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> // 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 start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(mcl::bit::count_ones(list) * 4))); 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> // 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 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)); 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> // 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 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * mcl::bit::count_ones(list))));
const auto writeback_address = start_address; 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> // 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 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)))); 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() { 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); 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 MemoryInstructionContinues();
} }
// SWPB<c> <Rt>, <Rt2>, [<Rn>] // 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); 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 MemoryInstructionContinues();
} }
// LDA<c> <Rt>, [<Rn>] // LDA<c> <Rt>, [<Rn>]
@ -63,7 +63,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, IR::AccType::ORDERED)); ir.SetRegister(t, ir.ReadMemory32(address, IR::AccType::ORDERED));
return true; return MemoryInstructionContinues();
} }
// LDAB<c> <Rt>, [<Rn>] // LDAB<c> <Rt>, [<Rn>]
bool TranslatorVisitor::arm_LDAB(Cond cond, Reg n, Reg t) { 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); const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory8(address, IR::AccType::ORDERED))); ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory8(address, IR::AccType::ORDERED)));
return true; return MemoryInstructionContinues();
} }
// LDAH<c> <Rt>, [<Rn>] // LDAH<c> <Rt>, [<Rn>]
bool TranslatorVisitor::arm_LDAH(Cond cond, Reg n, Reg t) { 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); const auto address = ir.GetRegister(n);
ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory16(address, IR::AccType::ORDERED))); ir.SetRegister(t, ir.ZeroExtendToWord(ir.ReadMemory16(address, IR::AccType::ORDERED)));
return true; return MemoryInstructionContinues();
} }
// LDAEX<c> <Rt>, [<Rn>] // LDAEX<c> <Rt>, [<Rn>]
@ -106,7 +106,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, IR::AccType::ORDERED)); ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ORDERED));
return true; return MemoryInstructionContinues();
} }
// LDAEXB<c> <Rt>, [<Rn>] // LDAEXB<c> <Rt>, [<Rn>]
@ -121,7 +121,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, IR::AccType::ORDERED))); ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ORDERED)));
return true; return MemoryInstructionContinues();
} }
// LDAEXD<c> <Rt>, <Rt2>, [<Rn>] // 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 // 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);
return true; return MemoryInstructionContinues();
} }
// LDAEXH<c> <Rt>, [<Rn>] // LDAEXH<c> <Rt>, [<Rn>]
@ -154,7 +154,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, IR::AccType::ORDERED))); ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ORDERED)));
return true; return MemoryInstructionContinues();
} }
// STL<c> <Rt>, [<Rn>] // STL<c> <Rt>, [<Rn>]
@ -169,7 +169,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), IR::AccType::ORDERED); ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED);
return true; return MemoryInstructionContinues();
} }
// STLB<c> <Rt>, [<Rn>] // STLB<c> <Rt>, [<Rn>]
@ -184,7 +184,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)), IR::AccType::ORDERED); ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)), IR::AccType::ORDERED);
return true; return MemoryInstructionContinues();
} }
// STLH<c> <Rd>, <Rt>, [<Rn>] // 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); const auto address = ir.GetRegister(n);
ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::ORDERED); ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)), IR::AccType::ORDERED);
return true; return MemoryInstructionContinues();
} }
// STLEXB<c> <Rd>, <Rt>, [<Rn>] // 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 value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ORDERED); const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
// STLEXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>] // STLEXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
bool TranslatorVisitor::arm_STLEXD(Cond cond, Reg n, Reg d, Reg t) { 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 value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::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 MemoryInstructionContinues();
} }
// STLEXH<c> <Rd>, <Rt>, [<Rn>] // 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 value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ORDERED); const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
// STLEX<c> <Rd>, <Rt>, [<Rn>] // 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 value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ORDERED); const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ORDERED);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
// LDREX<c> <Rt>, [<Rn>] // LDREX<c> <Rt>, [<Rn>]
@ -299,7 +299,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::AccType::ATOMIC)); ir.SetRegister(t, ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC));
return true; return MemoryInstructionContinues();
} }
// LDREXB<c> <Rt>, [<Rn>] // LDREXB<c> <Rt>, [<Rn>]
@ -314,7 +314,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::AccType::ATOMIC))); ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC)));
return true; return MemoryInstructionContinues();
} }
// LDREXD<c> <Rt>, <Rt2>, [<Rn>] // 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 // 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);
return true; return MemoryInstructionContinues();
} }
// LDREXH<c> <Rt>, [<Rn>] // LDREXH<c> <Rt>, [<Rn>]
@ -347,7 +347,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::AccType::ATOMIC))); ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC)));
return true; return MemoryInstructionContinues();
} }
// STREX<c> <Rd>, <Rt>, [<Rn>] // 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 value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
// STREXB<c> <Rd>, <Rt>, [<Rn>] // 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 value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
// STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>] // 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 value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
// STREXH<c> <Rd>, <Rt>, [<Rn>] // 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 value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
} // namespace Dynarmic::A32 } // 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); const auto data = ir.ReadMemory32(ir.Imm32(address), IR::AccType::NORMAL);
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// STR <Rt>, [<Rn>, <Rm>] // 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); const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL); ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// STRH <Rt>, [<Rn>, <Rm>] // 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)); const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
ir.WriteMemory16(address, data, IR::AccType::NORMAL); ir.WriteMemory16(address, data, IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// STRB <Rt>, [<Rn>, <Rm>] // 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)); const auto data = ir.LeastSignificantByte(ir.GetRegister(t));
ir.WriteMemory8(address, data, IR::AccType::NORMAL); ir.WriteMemory8(address, data, IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// LDRSB <Rt>, [<Rn>, <Rm>] // 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)); const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDR <Rt>, [<Rn>, <Rm>] // 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); const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRH <Rt>, [<Rn>, <Rm>] // 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)); const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRB <Rt>, [<Rn>, <Rm>] // 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)); const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// LDRH <Rt>, [<Rn>, <Rm>] // 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)); const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// STR <Rt>, [<Rn>, #<imm>] // 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); const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL); ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// LDR <Rt>, [<Rn>, #<imm>] // 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); const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// STRB <Rt>, [<Rn>, #<imm>] // 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)); const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// STRH <Rt>, [<Rn>, #<imm5>] // 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)); const auto data = ir.LeastSignificantHalf(ir.GetRegister(t));
ir.WriteMemory16(address, data, IR::AccType::NORMAL); ir.WriteMemory16(address, data, IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// LDRH <Rt>, [<Rn>, #<imm5>] // 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)); const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address, IR::AccType::NORMAL));
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// STR <Rt>, [<Rn>, #<imm>] // 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); const auto data = ir.GetRegister(t);
ir.WriteMemory32(address, data, IR::AccType::NORMAL); ir.WriteMemory32(address, data, IR::AccType::NORMAL);
return true; return MemoryInstructionContinues();
} }
// LDR <Rt>, [<Rn>, #<imm>] // 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); const auto data = ir.ReadMemory32(address, IR::AccType::NORMAL);
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
// ADR <Rd>, <label> // ADR <Rd>, <label>
@ -775,7 +775,7 @@ bool TranslatorVisitor::thumb16_PUSH(bool M, RegList reg_list) {
ir.SetRegister(Reg::SP, final_address); ir.SetRegister(Reg::SP, final_address);
// TODO(optimization): Possible location for an RSB push. // TODO(optimization): Possible location for an RSB push.
return true; return MemoryInstructionContinues();
} }
// POP <reg_list> // POP <reg_list>
@ -804,11 +804,15 @@ bool TranslatorVisitor::thumb16_POP(bool P, RegList reg_list) {
ir.LoadWritePC(data); ir.LoadWritePC(data);
address = ir.Add(address, ir.Imm32(4)); address = ir.Add(address, ir.Imm32(4));
ir.SetRegister(Reg::SP, address); 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; return false;
} else { } else {
ir.SetRegister(Reg::SP, address); 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); ir.SetRegister(n, address);
return true; return MemoryInstructionContinues();
} }
// LDM <Rn>!, <reg_list> // LDM <Rn>!, <reg_list>
@ -910,7 +914,7 @@ bool TranslatorVisitor::thumb16_LDMIA(Reg n, RegList reg_list) {
if (write_back) { if (write_back) {
ir.SetRegister(n, address); ir.SetRegister(n, address);
} }
return true; return MemoryInstructionContinues();
} }
// CB{N}Z <Rn>, <label> // 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)); 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 v.MemoryInstructionContinues();
} }
static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) { 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)); 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 v.MemoryInstructionContinues();
} }
static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) { 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) { if (W) {
v.ir.SetRegister(n, offset_address); v.ir.SetRegister(n, offset_address);
} }
return true; return v.MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_PLD_lit(bool /*U*/, Imm<12> /*imm12*/) { 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)); 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 v.MemoryInstructionContinues();
} }
static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) { 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)); 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 v.MemoryInstructionContinues();
} }
static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) { 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); v.ir.SetRegister(t, data);
return true; return v.MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12) { 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.UpdateUpperLocationDescriptor();
v.ir.BranchWritePC(branch_value); 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; return false;
} }
@ -68,7 +72,7 @@ static bool LoadDualImmediate(TranslatorVisitor& v, bool P, bool U, bool W, Reg
if (W) { if (W) {
v.ir.SetRegister(n, offset_address); 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) { 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); 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) { 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) { if (W) {
v.ir.SetRegister(n, offset_address); v.ir.SetRegister(n, offset_address);
} }
return true; return v.MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDA(Reg n, Reg t) { 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); const auto value = ir.ExclusiveReadMemory32(address, IR::AccType::ATOMIC);
ir.SetRegister(t, value); ir.SetRegister(t, value);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) { 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)); const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory8(address, IR::AccType::ATOMIC));
ir.SetRegister(t, value); ir.SetRegister(t, value);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) { 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 // DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
ir.SetRegister(t, lo); ir.SetRegister(t, lo);
ir.SetRegister(t2, hi); ir.SetRegister(t2, hi);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) { 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)); const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory16(address, IR::AccType::ATOMIC));
ir.SetRegister(t, value); ir.SetRegister(t, value);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_STL(Reg n, Reg t) { 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); const auto address = ir.GetRegister(n);
ir.WriteMemory32(address, ir.GetRegister(t), IR::AccType::ORDERED); 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) { 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 value = ir.GetRegister(t);
const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory32(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) { 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 value = ir.LeastSignificantByte(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory8(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d) { 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 value_hi = ir.GetRegister(t2);
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) { 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 value = ir.LeastSignificantHalf(ir.GetRegister(t));
const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC); const auto passed = ir.ExclusiveWriteMemory16(address, value, IR::AccType::ATOMIC);
ir.SetRegister(d, passed); ir.SetRegister(d, passed);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_TBB(Reg n, Reg m) { 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(); 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; auto address = start_address;
for (size_t i = 0; i <= 14; i++) { for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) { if (mcl::bit::get_bit(i, list)) {
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address, IR::AccType::ATOMIC)); v.ir.SetRegister(static_cast<Reg>(i), v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
address = ir.Add(address, ir.Imm32(4)); address = v.ir.Add(address, v.ir.Imm32(4));
} }
} }
if (W && !mcl::bit::get_bit(RegNumber(n), list)) { 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)) { if (mcl::bit::get_bit<15>(list)) {
ir.UpdateUpperLocationDescriptor(); v.ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(ir.ReadMemory32(address, IR::AccType::ATOMIC)); v.ir.LoadWritePC(v.ir.ReadMemory32(address, IR::AccType::ATOMIC));
if (n == Reg::R13) { if (v.options.check_halt_on_memory_access) {
ir.SetTerm(IR::Term::PopRSBHint{}); v.ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
} else if (n == Reg::R13) {
v.ir.SetTerm(IR::Term::PopRSBHint{});
} else { } else {
ir.SetTerm(IR::Term::FastDispatchHint{}); v.ir.SetTerm(IR::Term::FastDispatchHint{});
} }
return false; 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; auto address = start_address;
for (size_t i = 0; i <= 14; i++) { for (size_t i = 0; i <= 14; i++) {
if (mcl::bit::get_bit(i, list)) { if (mcl::bit::get_bit(i, list)) {
ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC); v.ir.WriteMemory32(address, v.ir.GetRegister(static_cast<Reg>(i)), IR::AccType::ATOMIC);
address = ir.Add(address, ir.Imm32(4)); address = v.ir.Add(address, v.ir.Imm32(4));
} }
} }
if (W) { 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) { 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. // Start address is the same as the writeback address.
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs)); 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) { 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 start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4)); 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) { 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 start_address = ir.GetRegister(n);
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4)); 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) { 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. // Start address is the same as the writeback address.
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs)); 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 } // 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) { if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor(); ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data); 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; return false;
} }
ir.SetRegister(t, data); 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) { 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.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data); 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{}); ir.SetTerm(IR::Term::PopRSBHint{});
} else { } else {
ir.SetTerm(IR::Term::FastDispatchHint{}); 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); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12) { 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) { if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor(); ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data); 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; return false;
} }
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) { 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) { if (t == Reg::PC) {
ir.UpdateUpperLocationDescriptor(); ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data); 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; return false;
} }
ir.SetRegister(t, data); ir.SetRegister(t, data);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::thumb32_LDRT(Reg n, Reg t, Imm<8> imm8) { 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> // 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>}] // 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)); ir.SetExtendedRegister(d, ir.ReadMemory32(address, IR::AccType::ATOMIC));
} }
return true; return MemoryInstructionContinues();
} }
// VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}] // 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); ir.WriteMemory32(address, ir.GetExtendedRegister(d), IR::AccType::ATOMIC);
} }
return true; return MemoryInstructionContinues();
} }
// VSTM{mode}<c> <Rn>{!}, <list of double registers> // 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)); address = ir.Add(address, ir.Imm32(4));
} }
return true; return MemoryInstructionContinues();
} }
// VSTM{mode}<c> <Rn>{!}, <list of single registers> // 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)); address = ir.Add(address, ir.Imm32(4));
} }
return true; return MemoryInstructionContinues();
} }
// VLDM{mode}<c> <Rn>{!}, <list of double registers> // 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)); ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(word1, word2));
} }
return true; return MemoryInstructionContinues();
} }
// VLDM{mode}<c> <Rn>{!}, <list of single registers> // 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); ir.SetExtendedRegister(d + i, word);
} }
return true; return MemoryInstructionContinues();
} }
} // namespace Dynarmic::A32 } // 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 false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction. /// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true; 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; 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) { 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)); const int len = mcl::bit::highest_set_bit((immN ? 1 << 6 : 0) | (imms.ZeroExtend() ^ 0b111111));
if (len < 1) { if (len < 1) {

View file

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

View file

@ -72,7 +72,7 @@ static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, s
UNREACHABLE(); UNREACHABLE();
} }
return true; return v.MemoryInstructionContinues();
} }
bool TranslatorVisitor::STXR(Imm<2> sz, Reg Rs, Reg Rn, Reg Rt) { 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(); UNREACHABLE();
} }
return true; return v.MemoryInstructionContinues();
} }
bool TranslatorVisitor::STLLR(Imm<2> sz, Reg Rn, Reg Rt) { 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); const auto data = Mem(ir.Imm64(address), size, IR::AccType::NORMAL);
X(8 * size, Rt, data); X(8 * size, Rt, data);
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) { 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 { } else {
V(128, Vt, ir.ZeroExtendToQuad(data)); V(128, Vt, ir.ZeroExtendToQuad(data));
} }
return true; return MemoryInstructionContinues();
} }
bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) { 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); 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 MemoryInstructionContinues();
} }
bool TranslatorVisitor::PRFM_lit(Imm<19> /*imm19*/, Imm<5> /*prfop*/) { 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) { 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) { 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) { 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) { 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 } // namespace Dynarmic::A64

View file

@ -70,7 +70,7 @@ static bool RegSharedDecodeAndOperation(TranslatorVisitor& v, size_t scale, u8 s
UNREACHABLE(); 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) { 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(); 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) { 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); const IR::UAny data = v.X(datasize, Rt);
v.Mem(address, datasize / 8, acctype, data); 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) { 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 // max is used to zeroextend < 32 to 32, and > 32 to 64
const size_t extended_size = std::max<size_t>(32, datasize); const size_t extended_size = std::max<size_t>(32, datasize);
v.X(extended_size, Rt, v.ZeroExtend(data, extended_size)); 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) { 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); // Prefetch(address, Rt);
break; break;
} }
return true; return v.MemoryInstructionContinues();
} }
bool TranslatorVisitor::STTRB(Imm<9> imm9, Reg Rn, Reg Rt) { 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); const IR::UAny data = Mem(address, 4, acctype);
X(64, Rt, SignExtend(data, 64)); X(64, Rt, SignExtend(data, 64));
return true; return MemoryInstructionContinues();
} }
} // namespace Dynarmic::A64 } // 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) { 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. /// to avoid writting certain unnecessary code only needed for cycle timers.
bool wall_clock_cntpct = false; 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, /// 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. /// AddTicks and GetTicksRemaining are never called, and no cycle counting is done.
bool enable_cycle_counting = true; bool enable_cycle_counting = true;

View file

@ -273,6 +273,10 @@ struct UserConfig {
/// to avoid writting certain unnecessary code only needed for cycle timers. /// to avoid writting certain unnecessary code only needed for cycle timers.
bool wall_clock_cntpct = false; 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, /// 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. /// AddTicks and GetTicksRemaining are never called, and no cycle counting is done.
bool enable_cycle_counting = true; bool enable_cycle_counting = true;