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.cpp
|
||||||
frontend/A32/translate/translate.h
|
frontend/A32/translate/translate.h
|
||||||
frontend/A32/translate/translate_arm.cpp
|
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/branch.cpp
|
||||||
frontend/A32/translate/translate_arm/coprocessor.cpp
|
frontend/A32/translate/translate_arm/coprocessor.cpp
|
||||||
frontend/A32/translate/translate_arm/data_processing.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) {
|
void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
auto& arg = args[0];
|
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
|
// Branch instructions
|
||||||
INST(arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv") // v5
|
INST(arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv") // v5
|
||||||
INST(arm_BLX_reg, "BLX (reg)", "cccc000100101111111111110011mmmm") // v5
|
INST(arm_BLX_reg, "BLX (reg)", "cccc000100101111111111110011mmmm") // v5
|
||||||
|
|
|
@ -76,6 +76,29 @@ public:
|
||||||
return "<internal error>";
|
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) {
|
std::string FPRegStr(bool dp_operation, size_t base, bool bit) {
|
||||||
size_t reg_num;
|
size_t reg_num;
|
||||||
if (dp_operation) {
|
if (dp_operation) {
|
||||||
|
@ -100,6 +123,17 @@ public:
|
||||||
return cond == Cond::NV ? "2" : CondToString(cond);
|
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
|
// Branch instructions
|
||||||
std::string arm_B(Cond cond, Imm24 imm24) {
|
std::string arm_B(Cond cond, Imm24 imm24) {
|
||||||
s32 offset = Common::SignExtend<26, s32>(imm24 << 2) + 8;
|
s32 offset = Common::SignExtend<26, s32>(imm24 << 2) + 8;
|
||||||
|
|
|
@ -142,6 +142,18 @@ void IREmitter::SetGEFlagsCompressed(const IR::U32& value) {
|
||||||
Inst(Opcode::A32SetGEFlagsCompressed, 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() {
|
IR::U32 IREmitter::GetFpscr() {
|
||||||
return Inst<IR::U32>(Opcode::A32GetFpscr);
|
return Inst<IR::U32>(Opcode::A32GetFpscr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ public:
|
||||||
void SetGEFlags(const IR::U32& value);
|
void SetGEFlags(const IR::U32& value);
|
||||||
void SetGEFlagsCompressed(const IR::U32& value);
|
void SetGEFlagsCompressed(const IR::U32& value);
|
||||||
|
|
||||||
|
void DataSynchronizationBarrier();
|
||||||
|
void DataMemoryBarrier();
|
||||||
|
void InstructionSynchronizationBarrier();
|
||||||
|
|
||||||
IR::U32 GetFpscr();
|
IR::U32 GetFpscr();
|
||||||
void SetFpscr(const IR::U32& new_fpscr);
|
void SetFpscr(const IR::U32& new_fpscr);
|
||||||
IR::U32 GetFpscrNZCV();
|
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 n, ExtReg m, const FnT& fn);
|
||||||
template <typename FnT> bool EmitVfpVectorOperation(bool sz, ExtReg d, 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
|
// Branch instructions
|
||||||
bool arm_B(Cond cond, Imm24 imm24);
|
bool arm_B(Cond cond, Imm24 imm24);
|
||||||
bool arm_BL(Cond cond, Imm24 imm24);
|
bool arm_BL(Cond cond, Imm24 imm24);
|
||||||
|
|
|
@ -45,6 +45,21 @@ bool Inst::IsShift() const {
|
||||||
IsLogicalShift();
|
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 {
|
bool Inst::IsSharedMemoryRead() const {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Opcode::A32ReadMemory8:
|
case Opcode::A32ReadMemory8:
|
||||||
|
@ -466,9 +481,7 @@ bool Inst::MayHaveSideEffects() const {
|
||||||
return op == Opcode::PushRSB ||
|
return op == Opcode::PushRSB ||
|
||||||
op == Opcode::A64SetCheckBit ||
|
op == Opcode::A64SetCheckBit ||
|
||||||
op == Opcode::A64DataCacheOperationRaised ||
|
op == Opcode::A64DataCacheOperationRaised ||
|
||||||
op == Opcode::A64DataSynchronizationBarrier ||
|
IsBarrier() ||
|
||||||
op == Opcode::A64DataMemoryBarrier ||
|
|
||||||
op == Opcode::A64InstructionSynchronizationBarrier ||
|
|
||||||
CausesCPUException() ||
|
CausesCPUException() ||
|
||||||
WritesToCoreRegister() ||
|
WritesToCoreRegister() ||
|
||||||
WritesToSystemRegister() ||
|
WritesToSystemRegister() ||
|
||||||
|
|
|
@ -36,6 +36,9 @@ public:
|
||||||
/// Determines whether or not this instruction performs any kind of shift.
|
/// Determines whether or not this instruction performs any kind of shift.
|
||||||
bool IsShift() const;
|
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.
|
/// Determines whether or not this instruction performs a shared memory read.
|
||||||
bool IsSharedMemoryRead() const;
|
bool IsSharedMemoryRead() const;
|
||||||
/// Determines whether or not this instruction performs a shared memory write.
|
/// Determines whether or not this instruction performs a shared memory write.
|
||||||
|
|
|
@ -30,6 +30,9 @@ A32OPC(SetGEFlagsCompressed, Void, U32
|
||||||
A32OPC(BXWritePC, Void, U32 )
|
A32OPC(BXWritePC, Void, U32 )
|
||||||
A32OPC(CallSupervisor, Void, U32 )
|
A32OPC(CallSupervisor, Void, U32 )
|
||||||
A32OPC(ExceptionRaised, Void, U32, U64 )
|
A32OPC(ExceptionRaised, Void, U32, U64 )
|
||||||
|
A32OPC(DataSynchronizationBarrier, Void, )
|
||||||
|
A32OPC(DataMemoryBarrier, Void, )
|
||||||
|
A32OPC(InstructionSynchronizationBarrier, Void, )
|
||||||
A32OPC(GetFpscr, U32, )
|
A32OPC(GetFpscr, U32, )
|
||||||
A32OPC(SetFpscr, Void, U32, )
|
A32OPC(SetFpscr, Void, U32, )
|
||||||
A32OPC(GetFpscrNZCV, U32, )
|
A32OPC(GetFpscrNZCV, U32, )
|
||||||
|
|
Loading…
Reference in a new issue