Implement arm_SVC
This commit is contained in:
parent
672ffb93d0
commit
9b2aff166a
8 changed files with 93 additions and 5 deletions
|
@ -250,6 +250,15 @@ void EmitX64::EmitBXWritePC(IR::Value* value_) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void EmitX64::EmitCallSupervisor(IR::Value* value_) {
|
||||
auto value = reinterpret_cast<IR::Inst*>(value_);
|
||||
|
||||
auto imm32 = value->GetArg(0).get();
|
||||
reg_alloc.HostCall(nullptr, imm32);
|
||||
|
||||
code->ABI_CallFunction(reinterpret_cast<void*>(cb.CallSVC));
|
||||
}
|
||||
|
||||
void EmitX64::EmitGetCarryFromOp(IR::Value*) {
|
||||
ASSERT_MSG(0, "should never happen");
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ private:
|
|||
void EmitGetVFlag(IR::Value* value);
|
||||
void EmitSetVFlag(IR::Value* value);
|
||||
void EmitBXWritePC(IR::Value* value);
|
||||
void EmitCallSupervisor(IR::Value* value);
|
||||
void EmitGetCarryFromOp(IR::Value* value);
|
||||
void EmitGetOverflowFromOp(IR::Value* value);
|
||||
void EmitLeastSignificantHalf(IR::Value* value);
|
||||
|
|
|
@ -59,7 +59,7 @@ private:
|
|||
};
|
||||
|
||||
template <typename V>
|
||||
static const std::array<ArmMatcher<V>, 1> g_arm_instruction_table = {
|
||||
static const std::array<ArmMatcher<V>, 2> g_arm_instruction_table = {
|
||||
|
||||
#define INST(fn, name, bitstring) detail::detail<ArmMatcher, u32, 32>::GetMatcher<decltype(fn), fn>(name, bitstring)
|
||||
|
||||
|
@ -139,7 +139,7 @@ static const std::array<ArmMatcher<V>, 1> g_arm_instruction_table = {
|
|||
|
||||
// Exception Generating instructions
|
||||
//INST(&V::arm_BKPT, "BKPT", "cccc00010010vvvvvvvvvvvv0111vvvv"), // v5
|
||||
//INST(&V::arm_SVC, "SVC", "cccc1111vvvvvvvvvvvvvvvvvvvvvvvv"), // all
|
||||
INST(&V::arm_SVC, "SVC", "cccc1111vvvvvvvvvvvvvvvvvvvvvvvv"), // all
|
||||
INST(&V::arm_UDF, "UDF", "111001111111------------1111----"), // all
|
||||
|
||||
// Extension instructions
|
||||
|
|
|
@ -326,8 +326,12 @@ public:
|
|||
|
||||
// Exception generation instructions
|
||||
std::string arm_BKPT(Cond cond, Imm12 imm12, Imm4 imm4) { return "ice"; }
|
||||
std::string arm_SVC(Cond cond, Imm24 imm24) { return "ice"; }
|
||||
std::string arm_UDF() { return "ice"; }
|
||||
std::string arm_SVC(Cond cond, Imm24 imm24) {
|
||||
return Common::StringFromFormat("svc%s #%u", CondStr(cond), imm24);
|
||||
}
|
||||
std::string arm_UDF() {
|
||||
return Common::StringFromFormat("udf");
|
||||
}
|
||||
|
||||
// Extension functions
|
||||
std::string arm_SXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) { return "ice"; }
|
||||
|
|
|
@ -18,6 +18,7 @@ OPCODE(SetCFlag, T::Void, T::U1
|
|||
OPCODE(GetVFlag, T::U1, )
|
||||
OPCODE(SetVFlag, T::Void, T::U1 )
|
||||
OPCODE(BXWritePC, T::Void, T::U32 )
|
||||
OPCODE(CallSupervisor, T::Void, T::U32 )
|
||||
|
||||
// Pseudo-operation, handled specially at final emit
|
||||
OPCODE(GetCarryFromOp, T::U1, T::U32 )
|
||||
|
|
|
@ -72,6 +72,10 @@ void IREmitter::LoadWritePC(IR::ValuePtr value) {
|
|||
Inst(IR::Opcode::BXWritePC, {value});
|
||||
}
|
||||
|
||||
void IREmitter::CallSupervisor(IR::ValuePtr value) {
|
||||
Inst(IR::Opcode::CallSupervisor, {value});
|
||||
}
|
||||
|
||||
IR::ValuePtr IREmitter::GetCFlag() {
|
||||
return Inst(IR::Opcode::GetCFlag, {});
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
|
||||
void ALUWritePC(IR::ValuePtr value);
|
||||
void LoadWritePC(IR::ValuePtr value);
|
||||
void CallSupervisor(IR::ValuePtr value);
|
||||
|
||||
IR::ValuePtr GetCFlag();
|
||||
void SetNFlag(IR::ValuePtr value);
|
||||
|
|
|
@ -16,12 +16,22 @@ namespace Arm {
|
|||
|
||||
namespace {
|
||||
|
||||
enum class ConditionalState {
|
||||
/// We haven't met any conditional instructions yet.
|
||||
None,
|
||||
/// Current instruction is a conditional. This marks the end of this basic block.
|
||||
Break,
|
||||
/// This basic block is made up solely of conditional instructions.
|
||||
Translating,
|
||||
};
|
||||
|
||||
struct ArmTranslatorVisitor final {
|
||||
explicit ArmTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
|
||||
ASSERT_MSG(!descriptor.TFlag, "The processor must be in Arm mode");
|
||||
}
|
||||
|
||||
IREmitter ir;
|
||||
ConditionalState cond_state = ConditionalState::None;
|
||||
|
||||
bool TranslateThisInstruction() {
|
||||
ir.SetTerm(IR::Term::Interpret(ir.current_location));
|
||||
|
@ -33,6 +43,53 @@ struct ArmTranslatorVisitor final {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool LinkToNextInstruction() {
|
||||
auto next_location = ir.current_location;
|
||||
next_location.arm_pc += 4;
|
||||
ir.SetTerm(IR::Term::LinkBlock{next_location});
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConditionPassed(Cond cond) {
|
||||
ASSERT_MSG(cond_state != ConditionalState::Translating,
|
||||
"In the current impl, ConditionPassed should never be called again once a non-AL cond is hit. "
|
||||
"(i.e.: one and only one conditional instruction per block)");
|
||||
ASSERT_MSG(cond_state != ConditionalState::Break,
|
||||
"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::AL) {
|
||||
// Everything is fine with the world
|
||||
return true;
|
||||
}
|
||||
|
||||
// non-AL cond
|
||||
|
||||
if (!ir.block.instructions.empty()) {
|
||||
// We've already emitted instructions. Quit for now, we'll make a new block here later.
|
||||
cond_state = ConditionalState::Break;
|
||||
ir.SetTerm(IR::Term::LinkBlock{ir.current_location});
|
||||
return false;
|
||||
}
|
||||
|
||||
// We've not emitted instructions yet.
|
||||
// We'll emit one instruction, and set the block-entry conditional appropriately.
|
||||
|
||||
cond_state = ConditionalState::Translating;
|
||||
ir.block.cond = cond;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool arm_SVC(Cond cond, Imm24 imm24) {
|
||||
u32 imm32 = imm24;
|
||||
// SVC<c> #<imm24>
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.CallSupervisor(ir.Imm32(imm32));
|
||||
return LinkToNextInstruction();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool arm_UDF() {
|
||||
return TranslateThisInstruction();
|
||||
}
|
||||
|
@ -44,7 +101,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memor
|
|||
ArmTranslatorVisitor visitor{descriptor};
|
||||
|
||||
bool should_continue = true;
|
||||
while (should_continue) {
|
||||
while (should_continue && visitor.cond_state == ConditionalState::None) {
|
||||
const u32 arm_pc = visitor.ir.current_location.arm_pc;
|
||||
const u32 arm_instruction = (*memory_read_32)(arm_pc);
|
||||
|
||||
|
@ -55,10 +112,21 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memor
|
|||
should_continue = visitor.arm_UDF();
|
||||
}
|
||||
|
||||
if (visitor.cond_state == ConditionalState::Break) {
|
||||
break;
|
||||
}
|
||||
|
||||
visitor.ir.current_location.arm_pc += 4;
|
||||
visitor.ir.block.cycle_count++;
|
||||
}
|
||||
|
||||
if (visitor.cond_state == ConditionalState::Translating) {
|
||||
if (should_continue) {
|
||||
visitor.ir.SetTerm(IR::Term::LinkBlock{visitor.ir.current_location});
|
||||
}
|
||||
visitor.ir.block.cond_failed = { visitor.ir.current_location };
|
||||
}
|
||||
|
||||
return visitor.ir.block;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue