Merge pull request #486 from lioncash/barrier
A32: Implement barrier instructions introduced in ARMv7
This commit is contained in:
commit
08c0cc84a8
11 changed files with 139 additions and 14 deletions
|
@ -95,6 +95,7 @@ add_library(dynarmic
|
|||
frontend/A32/translate/translate.cpp
|
||||
frontend/A32/translate/translate.h
|
||||
frontend/A32/translate/translate_arm.cpp
|
||||
frontend/A32/translate/translate_arm/barrier.cpp
|
||||
frontend/A32/translate/translate_arm/branch.cpp
|
||||
frontend/A32/translate/translate_arm/coprocessor.cpp
|
||||
frontend/A32/translate/translate_arm/data_processing.cpp
|
||||
|
|
|
@ -615,6 +615,23 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(A32EmitContext& ctx, IR::Inst* inst
|
|||
}
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32DataSynchronizationBarrier(A32EmitContext&, IR::Inst*) {
|
||||
code.mfence();
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32DataMemoryBarrier(A32EmitContext&, IR::Inst*) {
|
||||
code.lfence();
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32InstructionSynchronizationBarrier(A32EmitContext& ctx, IR::Inst*) {
|
||||
ctx.reg_alloc.HostCall(nullptr);
|
||||
|
||||
code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(jit_interface));
|
||||
code.CallFunction(static_cast<void(*)(A32::Jit*)>([](A32::Jit* jit) {
|
||||
jit->ClearCache();
|
||||
}));
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
auto& arg = args[0];
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// Barrier instructions
|
||||
INST(arm_DMB, "DMB", "1111010101111111111100000101oooo") // v7
|
||||
INST(arm_DSB, "DSB", "1111010101111111111100000100oooo") // v7
|
||||
INST(arm_ISB, "ISB", "1111010101111111111100000110oooo") // v7
|
||||
|
||||
// Branch instructions
|
||||
INST(arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv") // v5
|
||||
INST(arm_BLX_reg, "BLX (reg)", "cccc000100101111111111110011mmmm") // v5
|
||||
|
|
|
@ -76,6 +76,29 @@ public:
|
|||
return "<internal error>";
|
||||
}
|
||||
|
||||
static const char* BarrierOptionStr(Imm4 option) {
|
||||
switch (option) {
|
||||
case 0b0010:
|
||||
return " oshst";
|
||||
case 0b0011:
|
||||
return " osh";
|
||||
case 0b0110:
|
||||
return " nshst";
|
||||
case 0b0111:
|
||||
return " nsh";
|
||||
case 0b1010:
|
||||
return " ishst";
|
||||
case 0b1011:
|
||||
return " ish";
|
||||
case 0b1110:
|
||||
return " st";
|
||||
case 0b1111: // SY can be omitted.
|
||||
return "";
|
||||
default:
|
||||
return " unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string FPRegStr(bool dp_operation, size_t base, bool bit) {
|
||||
size_t reg_num;
|
||||
if (dp_operation) {
|
||||
|
@ -100,6 +123,17 @@ public:
|
|||
return cond == Cond::NV ? "2" : CondToString(cond);
|
||||
}
|
||||
|
||||
// Barrier instructions
|
||||
std::string arm_DMB(Imm4 option) {
|
||||
return fmt::format("dmb{}", BarrierOptionStr(option));
|
||||
}
|
||||
std::string arm_DSB(Imm4 option) {
|
||||
return fmt::format("dsb{}", BarrierOptionStr(option));
|
||||
}
|
||||
std::string arm_ISB([[maybe_unused]] Imm4 option) {
|
||||
return "isb";
|
||||
}
|
||||
|
||||
// Branch instructions
|
||||
std::string arm_B(Cond cond, Imm24 imm24) {
|
||||
s32 offset = Common::SignExtend<26, s32>(imm24 << 2) + 8;
|
||||
|
|
|
@ -142,6 +142,18 @@ void IREmitter::SetGEFlagsCompressed(const IR::U32& value) {
|
|||
Inst(Opcode::A32SetGEFlagsCompressed, value);
|
||||
}
|
||||
|
||||
void IREmitter::DataSynchronizationBarrier() {
|
||||
Inst(Opcode::A32DataSynchronizationBarrier);
|
||||
}
|
||||
|
||||
void IREmitter::DataMemoryBarrier() {
|
||||
Inst(Opcode::A32DataMemoryBarrier);
|
||||
}
|
||||
|
||||
void IREmitter::InstructionSynchronizationBarrier() {
|
||||
Inst(Opcode::A32InstructionSynchronizationBarrier);
|
||||
}
|
||||
|
||||
IR::U32 IREmitter::GetFpscr() {
|
||||
return Inst<IR::U32>(Opcode::A32GetFpscr);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,10 @@ public:
|
|||
void SetGEFlags(const IR::U32& value);
|
||||
void SetGEFlagsCompressed(const IR::U32& value);
|
||||
|
||||
void DataSynchronizationBarrier();
|
||||
void DataMemoryBarrier();
|
||||
void InstructionSynchronizationBarrier();
|
||||
|
||||
IR::U32 GetFpscr();
|
||||
void SetFpscr(const IR::U32& new_fpscr);
|
||||
IR::U32 GetFpscrNZCV();
|
||||
|
|
28
src/frontend/A32/translate/translate_arm/barrier.cpp
Normal file
28
src/frontend/A32/translate/translate_arm/barrier.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2019 MerryMage
|
||||
* This software may be used and distributed according to the terms of the GNU
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "translate_arm.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
bool ArmTranslatorVisitor::arm_DMB([[maybe_unused]] Imm4 option) {
|
||||
ir.DataMemoryBarrier();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_DSB([[maybe_unused]] Imm4 option) {
|
||||
ir.DataSynchronizationBarrier();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_ISB([[maybe_unused]] Imm4 option) {
|
||||
ir.InstructionSynchronizationBarrier();
|
||||
ir.SetRegister(Reg::PC, ir.Imm32(ir.current_location.PC() + 4));
|
||||
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
|
@ -64,6 +64,11 @@ struct ArmTranslatorVisitor final {
|
|||
template <typename FnT> bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg n, ExtReg m, const FnT& fn);
|
||||
template <typename FnT> bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg m, const FnT& fn);
|
||||
|
||||
// Barrier instructions
|
||||
bool arm_DMB(Imm4 option);
|
||||
bool arm_DSB(Imm4 option);
|
||||
bool arm_ISB(Imm4 option);
|
||||
|
||||
// Branch instructions
|
||||
bool arm_B(Cond cond, Imm24 imm24);
|
||||
bool arm_BL(Cond cond, Imm24 imm24);
|
||||
|
|
|
@ -45,6 +45,21 @@ bool Inst::IsShift() const {
|
|||
IsLogicalShift();
|
||||
}
|
||||
|
||||
bool Inst::IsBarrier() const {
|
||||
switch (op) {
|
||||
case Opcode::A32DataMemoryBarrier:
|
||||
case Opcode::A32DataSynchronizationBarrier:
|
||||
case Opcode::A32InstructionSynchronizationBarrier:
|
||||
case Opcode::A64DataMemoryBarrier:
|
||||
case Opcode::A64DataSynchronizationBarrier:
|
||||
case Opcode::A64InstructionSynchronizationBarrier:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Inst::IsSharedMemoryRead() const {
|
||||
switch (op) {
|
||||
case Opcode::A32ReadMemory8:
|
||||
|
@ -463,20 +478,18 @@ bool Inst::IsCoprocessorInstruction() const {
|
|||
}
|
||||
|
||||
bool Inst::MayHaveSideEffects() const {
|
||||
return op == Opcode::PushRSB ||
|
||||
op == Opcode::A64SetCheckBit ||
|
||||
op == Opcode::A64DataCacheOperationRaised ||
|
||||
op == Opcode::A64DataSynchronizationBarrier ||
|
||||
op == Opcode::A64DataMemoryBarrier ||
|
||||
op == Opcode::A64InstructionSynchronizationBarrier ||
|
||||
CausesCPUException() ||
|
||||
WritesToCoreRegister() ||
|
||||
WritesToSystemRegister() ||
|
||||
WritesToCPSR() ||
|
||||
WritesToFPCR() ||
|
||||
WritesToFPSR() ||
|
||||
AltersExclusiveState() ||
|
||||
IsMemoryWrite() ||
|
||||
return op == Opcode::PushRSB ||
|
||||
op == Opcode::A64SetCheckBit ||
|
||||
op == Opcode::A64DataCacheOperationRaised ||
|
||||
IsBarrier() ||
|
||||
CausesCPUException() ||
|
||||
WritesToCoreRegister() ||
|
||||
WritesToSystemRegister() ||
|
||||
WritesToCPSR() ||
|
||||
WritesToFPCR() ||
|
||||
WritesToFPSR() ||
|
||||
AltersExclusiveState() ||
|
||||
IsMemoryWrite() ||
|
||||
IsCoprocessorInstruction();
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@ public:
|
|||
/// Determines whether or not this instruction performs any kind of shift.
|
||||
bool IsShift() const;
|
||||
|
||||
/// Determines whether or not this instruction is a form of barrier.
|
||||
bool IsBarrier() const;
|
||||
|
||||
/// Determines whether or not this instruction performs a shared memory read.
|
||||
bool IsSharedMemoryRead() const;
|
||||
/// Determines whether or not this instruction performs a shared memory write.
|
||||
|
|
|
@ -30,6 +30,9 @@ A32OPC(SetGEFlagsCompressed, Void, U32
|
|||
A32OPC(BXWritePC, Void, U32 )
|
||||
A32OPC(CallSupervisor, Void, U32 )
|
||||
A32OPC(ExceptionRaised, Void, U32, U64 )
|
||||
A32OPC(DataSynchronizationBarrier, Void, )
|
||||
A32OPC(DataMemoryBarrier, Void, )
|
||||
A32OPC(InstructionSynchronizationBarrier, Void, )
|
||||
A32OPC(GetFpscr, U32, )
|
||||
A32OPC(SetFpscr, Void, U32, )
|
||||
A32OPC(GetFpscrNZCV, U32, )
|
||||
|
|
Loading…
Reference in a new issue