IR: Implement IR microinstructions ALUWritePC and LoadWritePC
This commit is contained in:
parent
65d27f3486
commit
09420d190b
5 changed files with 52 additions and 3 deletions
|
@ -37,12 +37,13 @@ static IR::Inst* FindUseWithOpcode(IR::Inst* inst, IR::Opcode opcode) {
|
||||||
return iter == uses.end() ? nullptr : reinterpret_cast<IR::Inst*>(iter->get());
|
return iter == uses.end() ? nullptr : reinterpret_cast<IR::Inst*>(iter->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
CodePtr EmitX64::Emit(Arm::LocationDescriptor descriptor, Dynarmic::IR::Block block) {
|
CodePtr EmitX64::Emit(const Arm::LocationDescriptor descriptor, Dynarmic::IR::Block block) {
|
||||||
inhibit_emission.clear();
|
inhibit_emission.clear();
|
||||||
reg_alloc.Reset();
|
reg_alloc.Reset();
|
||||||
|
|
||||||
code->INT3();
|
code->INT3();
|
||||||
CodePtr code_ptr = code->GetCodePtr();
|
CodePtr code_ptr = code->GetCodePtr();
|
||||||
|
basic_blocks[descriptor] = code_ptr;
|
||||||
|
|
||||||
for (const auto& value : block.instructions) {
|
for (const auto& value : block.instructions) {
|
||||||
if (inhibit_emission.count(value.get()) != 0)
|
if (inhibit_emission.count(value.get()) != 0)
|
||||||
|
@ -215,6 +216,38 @@ void EmitX64::EmitSetVFlag(IR::Value* value_) {
|
||||||
code->OR(32, MJitStateCpsr(), R(to_store));
|
code->OR(32, MJitStateCpsr(), R(to_store));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitBXWritePC(IR::Value* value_) {
|
||||||
|
auto value = reinterpret_cast<IR::Inst*>(value_);
|
||||||
|
|
||||||
|
X64Reg new_pc = reg_alloc.UseRegister(value->GetArg(0).get());
|
||||||
|
X64Reg tmp = reg_alloc.ScratchRegister();
|
||||||
|
X64Reg cpsr = reg_alloc.ScratchRegister();
|
||||||
|
|
||||||
|
// Note: new_pc<1:0> == '10' is UNPREDICTABLE
|
||||||
|
|
||||||
|
// Alternative implementations
|
||||||
|
#if 0
|
||||||
|
code->MOV(32, R(tmp), MJitStateCpsr());
|
||||||
|
code->MOV(32, R(cpsr), R(tmp));
|
||||||
|
code->OR(32, R(tmp), Imm32(1 << 5));
|
||||||
|
code->AND(32, R(cpsr), Imm32(~(1 << 5)));
|
||||||
|
code->BTR(32, R(new_pc), Imm8(0));
|
||||||
|
code->CMOVcc(32, cpsr, R(tmp), CC_C);
|
||||||
|
code->MOV(32, MJitStateReg(Arm::Reg::PC), R(new_pc));
|
||||||
|
code->MOV(32, MJitStateCpsr(), R(cpsr));
|
||||||
|
#else
|
||||||
|
code->MOV(32, R(tmp), R(new_pc));
|
||||||
|
code->AND(32, R(tmp), Imm8(1));
|
||||||
|
code->AND(32, R(new_pc), Imm32(0xFFFFFFFE));
|
||||||
|
code->MOV(32, R(cpsr), MJitStateCpsr());
|
||||||
|
code->SHL(32, R(tmp), Imm8(5));
|
||||||
|
code->AND(32, R(cpsr), Imm32(~(1 << 5)));
|
||||||
|
code->OR(32, R(cpsr), R(tmp));
|
||||||
|
code->MOV(32, MJitStateReg(Arm::Reg::PC), R(new_pc));
|
||||||
|
code->MOV(32, MJitStateCpsr(), R(cpsr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitGetCarryFromOp(IR::Value*) {
|
void EmitX64::EmitGetCarryFromOp(IR::Value*) {
|
||||||
ASSERT_MSG(0, "should never happen");
|
ASSERT_MSG(0, "should never happen");
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
EmitX64(Gen::XEmitter* code, Routines* routines, UserCallbacks cb, Jit* jit_interface)
|
EmitX64(Gen::XEmitter* code, Routines* routines, UserCallbacks cb, Jit* jit_interface)
|
||||||
: reg_alloc(code), code(code), routines(routines), cb(cb), jit_interface(jit_interface) {}
|
: reg_alloc(code), code(code), routines(routines), cb(cb), jit_interface(jit_interface) {}
|
||||||
|
|
||||||
CodePtr Emit(Arm::LocationDescriptor descriptor, IR::Block ir);
|
CodePtr Emit(const Arm::LocationDescriptor descriptor, IR::Block ir);
|
||||||
|
|
||||||
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor) {
|
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor) {
|
||||||
auto iter = basic_blocks.find(descriptor);
|
auto iter = basic_blocks.find(descriptor);
|
||||||
|
@ -44,6 +44,7 @@ public:
|
||||||
void EmitSetCFlag(IR::Value* value);
|
void EmitSetCFlag(IR::Value* value);
|
||||||
void EmitGetVFlag(IR::Value* value);
|
void EmitGetVFlag(IR::Value* value);
|
||||||
void EmitSetVFlag(IR::Value* value);
|
void EmitSetVFlag(IR::Value* value);
|
||||||
|
void EmitBXWritePC(IR::Value* value);
|
||||||
void EmitGetCarryFromOp(IR::Value* value);
|
void EmitGetCarryFromOp(IR::Value* value);
|
||||||
void EmitGetOverflowFromOp(IR::Value* value);
|
void EmitGetOverflowFromOp(IR::Value* value);
|
||||||
void EmitLeastSignificantHalf(IR::Value* value);
|
void EmitLeastSignificantHalf(IR::Value* value);
|
||||||
|
|
|
@ -17,6 +17,7 @@ OPCODE(GetCFlag, T::U1,
|
||||||
OPCODE(SetCFlag, T::Void, T::U1 )
|
OPCODE(SetCFlag, T::Void, T::U1 )
|
||||||
OPCODE(GetVFlag, T::U1, )
|
OPCODE(GetVFlag, T::U1, )
|
||||||
OPCODE(SetVFlag, T::Void, T::U1 )
|
OPCODE(SetVFlag, T::Void, T::U1 )
|
||||||
|
OPCODE(BXWritePC, T::Void, T::U32 )
|
||||||
|
|
||||||
// Pseudo-operation, handled specially at final emit
|
// Pseudo-operation, handled specially at final emit
|
||||||
OPCODE(GetCarryFromOp, T::U1, T::U32 )
|
OPCODE(GetCarryFromOp, T::U1, T::U32 )
|
||||||
|
|
|
@ -56,7 +56,20 @@ void IREmitter::SetRegister(const Reg reg, IR::ValuePtr value) {
|
||||||
|
|
||||||
void IREmitter::ALUWritePC(IR::ValuePtr value) {
|
void IREmitter::ALUWritePC(IR::ValuePtr value) {
|
||||||
// This behaviour is ARM version-dependent.
|
// This behaviour is ARM version-dependent.
|
||||||
ASSERT_MSG(false, "Unimplemented");
|
// The below implementation is for ARMv6k
|
||||||
|
if (!current_location.TFlag) {
|
||||||
|
auto new_pc = And(value, Imm32(0xFFFFFFFC));
|
||||||
|
Inst(IR::Opcode::SetRegister, { RegRef(Reg::PC), new_pc });
|
||||||
|
} else {
|
||||||
|
auto new_pc = And(value, Imm32(0xFFFFFFFE));
|
||||||
|
Inst(IR::Opcode::SetRegister, { RegRef(Reg::PC), new_pc });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::LoadWritePC(IR::ValuePtr value) {
|
||||||
|
// This behaviour is ARM version-dependent.
|
||||||
|
// The below implementation is for ARMv6k
|
||||||
|
Inst(IR::Opcode::BXWritePC, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::ValuePtr IREmitter::GetCFlag() {
|
IR::ValuePtr IREmitter::GetCFlag() {
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
void SetRegister(const Reg dest_reg, IR::ValuePtr value);
|
void SetRegister(const Reg dest_reg, IR::ValuePtr value);
|
||||||
|
|
||||||
void ALUWritePC(IR::ValuePtr value);
|
void ALUWritePC(IR::ValuePtr value);
|
||||||
|
void LoadWritePC(IR::ValuePtr value);
|
||||||
|
|
||||||
IR::ValuePtr GetCFlag();
|
IR::ValuePtr GetCFlag();
|
||||||
void SetNFlag(IR::ValuePtr value);
|
void SetNFlag(IR::ValuePtr value);
|
||||||
|
|
Loading…
Reference in a new issue