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:
parent
e99ba06cf3
commit
5ad1d02351
28 changed files with 239 additions and 172 deletions
|
@ -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);
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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*/) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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*/) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue