A32/translate: Add TranslateSingleInstruction
This commit is contained in:
parent
5fc197c564
commit
d345220251
4 changed files with 84 additions and 13 deletions
|
@ -17,4 +17,11 @@ IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory
|
||||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code);
|
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
||||||
|
bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
||||||
|
|
||||||
|
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
|
||||||
|
return (descriptor.TFlag() ? TranslateSingleThumbInstruction : TranslateSingleArmInstruction)(block, descriptor, instruction);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
} // namespace Dynarmic::A32
|
||||||
|
|
|
@ -25,4 +25,13 @@ using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
|
||||||
*/
|
*/
|
||||||
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function translates a single provided instruction into our intermediate representation.
|
||||||
|
* @param block The block to append the IR for the instruction to.
|
||||||
|
* @param descriptor The location of the instruction. Includes information like PC, Thumb state, &c.
|
||||||
|
* @param instruction The instruction to translate.
|
||||||
|
* @return The translated instruction translated to the intermediate representation.
|
||||||
|
*/
|
||||||
|
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
} // namespace Dynarmic::A32
|
||||||
|
|
|
@ -37,9 +37,9 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||||
const u32 arm_instruction = memory_read_code(arm_pc);
|
const u32 arm_instruction = memory_read_code(arm_pc);
|
||||||
|
|
||||||
if (auto vfp_decoder = DecodeVFP2<ArmTranslatorVisitor>(arm_instruction)) {
|
if (const auto vfp_decoder = DecodeVFP2<ArmTranslatorVisitor>(arm_instruction)) {
|
||||||
should_continue = vfp_decoder->call(visitor, arm_instruction);
|
should_continue = vfp_decoder->call(visitor, arm_instruction);
|
||||||
} else if (auto decoder = DecodeArm<ArmTranslatorVisitor>(arm_instruction)) {
|
} else if (const auto decoder = DecodeArm<ArmTranslatorVisitor>(arm_instruction)) {
|
||||||
should_continue = decoder->call(visitor, arm_instruction);
|
should_continue = decoder->call(visitor, arm_instruction);
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.arm_UDF();
|
should_continue = visitor.arm_UDF();
|
||||||
|
@ -66,10 +66,38 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) {
|
||||||
|
ArmTranslatorVisitor visitor{block, descriptor};
|
||||||
|
|
||||||
|
// TODO: Proper cond handling
|
||||||
|
|
||||||
|
bool should_continue = true;
|
||||||
|
if (const auto vfp_decoder = DecodeVFP2<ArmTranslatorVisitor>(arm_instruction)) {
|
||||||
|
should_continue = vfp_decoder->call(visitor, arm_instruction);
|
||||||
|
} else if (const auto decoder = DecodeArm<ArmTranslatorVisitor>(arm_instruction)) {
|
||||||
|
should_continue = decoder->call(visitor, arm_instruction);
|
||||||
|
} else {
|
||||||
|
should_continue = visitor.arm_UDF();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Feedback resulting cond status to caller somehow.
|
||||||
|
|
||||||
|
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
|
||||||
|
block.CycleCount()++;
|
||||||
|
|
||||||
|
block.SetEndLocation(visitor.ir.current_location);
|
||||||
|
|
||||||
|
return should_continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::ConditionPassed(Cond cond) {
|
bool ArmTranslatorVisitor::ConditionPassed(Cond cond) {
|
||||||
ASSERT_MSG(cond_state != ConditionalState::Break,
|
ASSERT_MSG(cond_state != ConditionalState::Break,
|
||||||
"This should never happen. We requested a break but that wasn't honored.");
|
"This should never happen. We requested a break but that wasn't honored.");
|
||||||
ASSERT_MSG(cond != Cond::NV, "NV conditional is obsolete");
|
if (cond == Cond::NV) {
|
||||||
|
// NV conditional is obsolete
|
||||||
|
ir.ExceptionRaised(Exception::UnpredictableInstruction);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (cond_state == ConditionalState::Translating) {
|
if (cond_state == ConditionalState::Translating) {
|
||||||
if (ir.block.ConditionFailedLocation() != ir.current_location || cond == Cond::AL) {
|
if (ir.block.ConditionFailedLocation() != ir.current_location || cond == Cond::AL) {
|
||||||
|
|
|
@ -851,13 +851,17 @@ enum class ThumbInstSize {
|
||||||
Thumb16, Thumb32
|
Thumb16, Thumb32
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsThumb16(u16 first_part) {
|
||||||
|
return (first_part & 0xF800) <= 0xE800;
|
||||||
|
}
|
||||||
|
|
||||||
std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFuncType memory_read_code) {
|
std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFuncType memory_read_code) {
|
||||||
u32 first_part = memory_read_code(arm_pc & 0xFFFFFFFC);
|
u32 first_part = memory_read_code(arm_pc & 0xFFFFFFFC);
|
||||||
if ((arm_pc & 0x2) != 0)
|
if ((arm_pc & 0x2) != 0)
|
||||||
first_part >>= 16;
|
first_part >>= 16;
|
||||||
first_part &= 0xFFFF;
|
first_part &= 0xFFFF;
|
||||||
|
|
||||||
if ((first_part & 0xF800) <= 0xE800) {
|
if (IsThumb16(static_cast<u16>(first_part))) {
|
||||||
// 16-bit thumb instruction
|
// 16-bit thumb instruction
|
||||||
return std::make_tuple(first_part, ThumbInstSize::Thumb16);
|
return std::make_tuple(first_part, ThumbInstSize::Thumb16);
|
||||||
}
|
}
|
||||||
|
@ -882,28 +886,23 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
while (should_continue) {
|
while (should_continue) {
|
||||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||||
|
const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, memory_read_code);
|
||||||
u32 thumb_instruction;
|
|
||||||
ThumbInstSize inst_size;
|
|
||||||
std::tie(thumb_instruction, inst_size) = ReadThumbInstruction(arm_pc, memory_read_code);
|
|
||||||
|
|
||||||
if (inst_size == ThumbInstSize::Thumb16) {
|
if (inst_size == ThumbInstSize::Thumb16) {
|
||||||
auto decoder = DecodeThumb16<ThumbTranslatorVisitor>(static_cast<u16>(thumb_instruction));
|
if (const auto decoder = DecodeThumb16<ThumbTranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
|
||||||
if (decoder) {
|
|
||||||
should_continue = decoder->call(visitor, static_cast<u16>(thumb_instruction));
|
should_continue = decoder->call(visitor, static_cast<u16>(thumb_instruction));
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb16_UDF();
|
should_continue = visitor.thumb16_UDF();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto decoder = DecodeThumb32<ThumbTranslatorVisitor>(thumb_instruction);
|
if (const auto decoder = DecodeThumb32<ThumbTranslatorVisitor>(thumb_instruction)) {
|
||||||
if (decoder) {
|
|
||||||
should_continue = decoder->call(visitor, thumb_instruction);
|
should_continue = decoder->call(visitor, thumb_instruction);
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb32_UDF();
|
should_continue = visitor.thumb32_UDF();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 advance_pc = (inst_size == ThumbInstSize::Thumb16) ? 2 : 4;
|
const s32 advance_pc = (inst_size == ThumbInstSize::Thumb16) ? 2 : 4;
|
||||||
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc);
|
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc);
|
||||||
block.CycleCount()++;
|
block.CycleCount()++;
|
||||||
}
|
}
|
||||||
|
@ -913,4 +912,32 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) {
|
||||||
|
ThumbTranslatorVisitor visitor{block, descriptor};
|
||||||
|
|
||||||
|
const bool is_thumb_16 = IsThumb16(static_cast<u16>(thumb_instruction));
|
||||||
|
bool should_continue = true;
|
||||||
|
if (is_thumb_16) {
|
||||||
|
if (const auto decoder = DecodeThumb16<ThumbTranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
|
||||||
|
should_continue = decoder->call(visitor, static_cast<u16>(thumb_instruction));
|
||||||
|
} else {
|
||||||
|
should_continue = visitor.thumb16_UDF();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (const auto decoder = DecodeThumb32<ThumbTranslatorVisitor>(thumb_instruction)) {
|
||||||
|
should_continue = decoder->call(visitor, thumb_instruction);
|
||||||
|
} else {
|
||||||
|
should_continue = visitor.thumb32_UDF();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const s32 advance_pc = is_thumb_16 ? 2 : 4;
|
||||||
|
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc);
|
||||||
|
block.CycleCount()++;
|
||||||
|
|
||||||
|
block.SetEndLocation(visitor.ir.current_location);
|
||||||
|
|
||||||
|
return should_continue;
|
||||||
|
}
|
||||||
|
|
||||||
} // namepsace Dynarmic::A32
|
} // namepsace Dynarmic::A32
|
||||||
|
|
Loading…
Reference in a new issue