Implement arm_SVC

This commit is contained in:
MerryMage 2016-07-14 14:04:43 +01:00
parent 672ffb93d0
commit 9b2aff166a
8 changed files with 93 additions and 5 deletions

View file

@ -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");
}

View file

@ -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);

View file

@ -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

View file

@ -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"; }

View file

@ -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 )

View file

@ -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, {});
}

View file

@ -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);

View file

@ -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;
}