Merge pull request #486 from lioncash/barrier

A32: Implement barrier instructions introduced in ARMv7
This commit is contained in:
Merry 2019-04-27 14:40:06 +01:00 committed by MerryMage
commit 08c0cc84a8
11 changed files with 139 additions and 14 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

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

View file

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