emit_arm64_a32: Implement barriers
This commit is contained in:
parent
a7f675864b
commit
8a0359ec52
6 changed files with 24 additions and 20 deletions
|
@ -111,6 +111,7 @@ void A32AddressSpace::EmitPrelude() {
|
||||||
prelude_info.write_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
prelude_info.write_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
prelude_info.write_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
prelude_info.write_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||||
|
prelude_info.isb_raised = EmitCallTrampoline<&A32::UserCallbacks::InstructionSynchronizationBarrierRaised>(code, conf.callbacks);
|
||||||
|
|
||||||
prelude_info.end_of_prelude = code.ptr<u32*>();
|
prelude_info.end_of_prelude = code.ptr<u32*>();
|
||||||
|
|
||||||
|
@ -129,6 +130,7 @@ EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) {
|
||||||
mem.unprotect();
|
mem.unprotect();
|
||||||
|
|
||||||
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), {
|
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), {
|
||||||
|
.hook_isb = conf.hook_isb,
|
||||||
.enable_cycle_counting = conf.enable_cycle_counting,
|
.enable_cycle_counting = conf.enable_cycle_counting,
|
||||||
.always_little_endian = conf.always_little_endian,
|
.always_little_endian = conf.always_little_endian,
|
||||||
});
|
});
|
||||||
|
@ -176,6 +178,9 @@ void A32AddressSpace::Link(EmittedBlockInfo& block_info) {
|
||||||
case LinkTarget::WriteMemory64:
|
case LinkTarget::WriteMemory64:
|
||||||
c.BL(prelude_info.write_memory_64);
|
c.BL(prelude_info.write_memory_64);
|
||||||
break;
|
break;
|
||||||
|
case LinkTarget::InstructionSynchronizationBarrierRaised:
|
||||||
|
c.BL(prelude_info.isb_raised);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT_FALSE("Invalid relocation target");
|
ASSERT_FALSE("Invalid relocation target");
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ private:
|
||||||
void* write_memory_16;
|
void* write_memory_16;
|
||||||
void* write_memory_32;
|
void* write_memory_32;
|
||||||
void* write_memory_64;
|
void* write_memory_64;
|
||||||
|
void* isb_raised;
|
||||||
} prelude_info;
|
} prelude_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -117,11 +117,11 @@ void EmitIR<IR::Opcode::NZCVFromPackedFlags>(oaknut::CodeGenerator&, EmitContext
|
||||||
ctx.reg_alloc.DefineAsExisting(inst, args[0]);
|
ctx.reg_alloc.DefineAsExisting(inst, args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& emit_conf) {
|
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& conf) {
|
||||||
EmittedBlockInfo ebi;
|
EmittedBlockInfo ebi;
|
||||||
|
|
||||||
RegAlloc reg_alloc{code, GPR_ORDER, FPR_ORDER};
|
RegAlloc reg_alloc{code, GPR_ORDER, FPR_ORDER};
|
||||||
EmitContext ctx{block, reg_alloc, emit_conf, ebi, {}};
|
EmitContext ctx{block, reg_alloc, conf, ebi, {}};
|
||||||
|
|
||||||
ebi.entry_point = code.ptr<CodePtr>();
|
ebi.entry_point = code.ptr<CodePtr>();
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
|
||||||
|
|
||||||
reg_alloc.AssertNoMoreUses();
|
reg_alloc.AssertNoMoreUses();
|
||||||
|
|
||||||
if (emit_conf.enable_cycle_counting) {
|
if (ctx.conf.enable_cycle_counting) {
|
||||||
const size_t cycles_to_add = block.CycleCount();
|
const size_t cycles_to_add = block.CycleCount();
|
||||||
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_remaining));
|
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_remaining));
|
||||||
if (oaknut::AddSubImm::is_valid(cycles_to_add)) {
|
if (oaknut::AddSubImm::is_valid(cycles_to_add)) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ enum class LinkTarget {
|
||||||
WriteMemory16,
|
WriteMemory16,
|
||||||
WriteMemory32,
|
WriteMemory32,
|
||||||
WriteMemory64,
|
WriteMemory64,
|
||||||
|
InstructionSynchronizationBarrierRaised,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Relocation {
|
struct Relocation {
|
||||||
|
@ -53,6 +54,7 @@ struct EmittedBlockInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmitConfig {
|
struct EmitConfig {
|
||||||
|
bool hook_isb;
|
||||||
bool enable_cycle_counting;
|
bool enable_cycle_counting;
|
||||||
bool always_little_endian;
|
bool always_little_endian;
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,7 +47,7 @@ void EmitSetUpperLocationDescriptor(oaknut::CodeGenerator& code, EmitContext& ct
|
||||||
|
|
||||||
const u32 old_upper = get_upper(old_location);
|
const u32 old_upper = get_upper(old_location);
|
||||||
const u32 new_upper = [&] {
|
const u32 new_upper = [&] {
|
||||||
const u32 mask = ~u32(ctx.emit_conf.always_little_endian ? 0x2 : 0);
|
const u32 mask = ~u32(ctx.conf.always_little_endian ? 0x2 : 0);
|
||||||
return get_upper(new_location) & mask;
|
return get_upper(new_location) & mask;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -396,27 +396,23 @@ void EmitIR<IR::Opcode::A32ExceptionRaised>(oaknut::CodeGenerator& code, EmitCon
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::A32DataSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::A32DataSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) {
|
||||||
(void)code;
|
code.DSB(oaknut::BarrierOp::SY);
|
||||||
(void)ctx;
|
|
||||||
(void)inst;
|
|
||||||
ASSERT_FALSE("Unimplemented");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::A32DataMemoryBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::A32DataMemoryBarrier>(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) {
|
||||||
(void)code;
|
code.DMB(oaknut::BarrierOp::SY);
|
||||||
(void)ctx;
|
|
||||||
(void)inst;
|
|
||||||
ASSERT_FALSE("Unimplemented");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*) {
|
||||||
(void)code;
|
if (!ctx.conf.hook_isb) {
|
||||||
(void)ctx;
|
return;
|
||||||
(void)inst;
|
}
|
||||||
ASSERT_FALSE("Unimplemented");
|
|
||||||
|
ctx.reg_alloc.PrepareForCall(nullptr);
|
||||||
|
EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -24,7 +24,7 @@ struct FpsrManager {
|
||||||
struct EmitContext {
|
struct EmitContext {
|
||||||
IR::Block& block;
|
IR::Block& block;
|
||||||
RegAlloc& reg_alloc;
|
RegAlloc& reg_alloc;
|
||||||
const EmitConfig& emit_conf;
|
const EmitConfig& conf;
|
||||||
EmittedBlockInfo& ebi;
|
EmittedBlockInfo& ebi;
|
||||||
FpsrManager fpsr;
|
FpsrManager fpsr;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue