A32: Allow for user-adjustable per-instruction tick counts

This commit is contained in:
Merry 2022-11-19 21:42:13 +00:00
parent 07c614f91b
commit 93b18ee8e2
4 changed files with 28 additions and 7 deletions

View file

@ -28,10 +28,13 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c
bool should_continue = true;
do {
const u32 arm_pc = visitor.ir.current_location.PC();
visitor.current_instruction_size = 4;
u64 ticks_for_instruction = 1;
if (const auto arm_instruction = tcb->MemoryReadCode(arm_pc)) {
visitor.current_instruction_size = 4;
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
ticks_for_instruction = tcb->GetTicksForCode(false, arm_pc, *arm_instruction);
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(*arm_instruction)) {
should_continue = vfp_decoder->get().call(visitor, *arm_instruction);
@ -43,6 +46,8 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c
should_continue = visitor.arm_UDF();
}
} else {
visitor.current_instruction_size = 4;
should_continue = visitor.RaiseException(Exception::NoExecuteFault);
}
@ -51,7 +56,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c
}
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
block.CycleCount()++;
block.CycleCount() += ticks_for_instruction;
} while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step);
if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) {
@ -74,9 +79,14 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) {
TranslatorVisitor visitor{block, descriptor, {}};
bool should_continue = true;
// TODO: Proper cond handling
bool should_continue = true;
visitor.current_instruction_size = 4;
const u64 ticks_for_instruction = 1;
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(arm_instruction)) {
should_continue = vfp_decoder->get().call(visitor, arm_instruction);
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(arm_instruction)) {
@ -90,7 +100,7 @@ bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descript
// TODO: Feedback resulting cond status to caller somehow.
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
block.CycleCount()++;
block.CycleCount() += ticks_for_instruction;
block.SetEndLocation(visitor.ir.current_location);

View file

@ -21,6 +21,9 @@ struct TranslateCallbacks {
// Thus function is called before the instruction at pc is interpreted.
// IR code can be emitted by the callee prior to translation of the instruction.
virtual void PreCodeTranslationHook(bool is_thumb, VAddr pc, A32::IREmitter& ir) = 0;
// How many ticks should this instruction take to execute?
virtual std::uint64_t GetTicksForCode(bool is_thumb, VAddr vaddr, std::uint32_t instruction) = 0;
};
} // namespace Dynarmic::A32

View file

@ -109,12 +109,15 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb,
bool should_continue = true;
do {
const u32 arm_pc = visitor.ir.current_location.PC();
u64 ticks_for_instruction = 1;
if (const auto maybe_instruction = ReadThumbInstruction(arm_pc, tcb)) {
const auto [thumb_instruction, inst_size] = *maybe_instruction;
const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16;
visitor.current_instruction_size = is_thumb_16 ? 2 : 4;
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
tcb->PreCodeTranslationHook(true, arm_pc, visitor.ir);
ticks_for_instruction = tcb->GetTicksForCode(true, arm_pc, thumb_instruction);
if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) {
if (is_thumb_16) {
@ -143,6 +146,7 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb,
}
} else {
visitor.current_instruction_size = 2;
should_continue = visitor.RaiseException(Exception::NoExecuteFault);
}
@ -151,7 +155,7 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb,
}
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(static_cast<int>(visitor.current_instruction_size)).AdvanceIT();
block.CycleCount()++;
block.CycleCount() += ticks_for_instruction;
} while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step);
if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) {
@ -179,6 +183,8 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri
const bool is_thumb_16 = IsThumb16(static_cast<u16>(thumb_instruction));
visitor.current_instruction_size = is_thumb_16 ? 2 : 4;
const u64 ticks_for_instruction = 1;
if (is_thumb_16) {
if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
should_continue = decoder->get().call(visitor, static_cast<u16>(thumb_instruction));
@ -206,7 +212,7 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri
const s32 advance_pc = is_thumb_16 ? 2 : 4;
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc);
block.CycleCount()++;
block.CycleCount() += ticks_for_instruction;
block.SetEndLocation(visitor.ir.current_location);

View file

@ -109,6 +109,8 @@ struct UserCallbacks : public TranslateCallbacks {
virtual void AddTicks(std::uint64_t ticks) = 0;
// How many more ticks am I allowed to execute?
virtual std::uint64_t GetTicksRemaining() = 0;
// How many ticks should this instruction take to execute?
std::uint64_t GetTicksForCode(bool /*is_thumb*/, VAddr /*vaddr*/, std::uint32_t /*instruction*/) override { return 1; }
};
struct UserConfig {