Implement coprocessor-related microinstructions
* CoprocInternalOperation * CoprocSendOneWord * CoprocSendTwoWords * CoprocGetOneWord * CoprocGetTwoWords * CoprocLoadWords * CoprocStoreWords
This commit is contained in:
parent
b3ae57619d
commit
48693eb6ff
6 changed files with 312 additions and 1 deletions
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dynarmic/coprocessor.h>
|
||||
|
||||
#include "backend_x64/abi.h"
|
||||
#include "backend_x64/block_of_code.h"
|
||||
#include "backend_x64/emit_x64.h"
|
||||
|
@ -2955,6 +2957,202 @@ void EmitX64::EmitExclusiveWriteMemory64(IR::Block&, IR::Inst* inst) {
|
|||
code->L(end);
|
||||
}
|
||||
|
||||
static void EmitCoprocessorException() {
|
||||
ASSERT_MSG(false, "Should raise coproc exception here");
|
||||
}
|
||||
|
||||
static void CallCoprocCallback(BlockOfCode* code, RegAlloc& reg_alloc, Jit* jit_interface, Coprocessor::Callback callback, IR::Inst* inst = nullptr, IR::Value arg0 = {}, IR::Value arg1 = {}) {
|
||||
reg_alloc.HostCall(inst, {}, {}, arg0, arg1);
|
||||
|
||||
code->mov(code->ABI_PARAM1, reinterpret_cast<u64>(jit_interface));
|
||||
if (callback.user_arg) {
|
||||
code->mov(code->ABI_PARAM2, reinterpret_cast<u64>(*callback.user_arg));
|
||||
}
|
||||
|
||||
code->CallFunction(callback.function);
|
||||
}
|
||||
|
||||
void EmitX64::EmitCoprocInternalOperation(IR::Block&, IR::Inst* inst) {
|
||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||
|
||||
size_t coproc_num = coproc_info[0];
|
||||
bool two = coproc_info[1] != 0;
|
||||
unsigned opc1 = static_cast<unsigned>(coproc_info[2]);
|
||||
Arm::CoprocReg CRd = static_cast<Arm::CoprocReg>(coproc_info[3]);
|
||||
Arm::CoprocReg CRn = static_cast<Arm::CoprocReg>(coproc_info[4]);
|
||||
Arm::CoprocReg CRm = static_cast<Arm::CoprocReg>(coproc_info[5]);
|
||||
unsigned opc2 = static_cast<unsigned>(coproc_info[6]);
|
||||
|
||||
std::shared_ptr<Coprocessor> coproc = cb.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = coproc->CompileInternalOperation(two, opc1, CRd, CRn, CRm, opc2);
|
||||
if (!action) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
CallCoprocCallback(code, reg_alloc, jit_interface, *action);
|
||||
}
|
||||
|
||||
void EmitX64::EmitCoprocSendOneWord(IR::Block&, IR::Inst* inst) {
|
||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||
|
||||
size_t coproc_num = coproc_info[0];
|
||||
bool two = coproc_info[1] != 0;
|
||||
unsigned opc1 = static_cast<unsigned>(coproc_info[2]);
|
||||
Arm::CoprocReg CRn = static_cast<Arm::CoprocReg>(coproc_info[3]);
|
||||
Arm::CoprocReg CRm = static_cast<Arm::CoprocReg>(coproc_info[4]);
|
||||
unsigned opc2 = static_cast<unsigned>(coproc_info[5]);
|
||||
|
||||
IR::Value word = inst->GetArg(1);
|
||||
|
||||
std::shared_ptr<Coprocessor> coproc = cb.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = coproc->CompileSendOneWord(two, opc1, CRn, CRm, opc2);
|
||||
if (!action) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, word);
|
||||
}
|
||||
|
||||
void EmitX64::EmitCoprocSendTwoWords(IR::Block&, IR::Inst* inst) {
|
||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||
|
||||
size_t coproc_num = coproc_info[0];
|
||||
bool two = coproc_info[1] != 0;
|
||||
unsigned opc = static_cast<unsigned>(coproc_info[2]);
|
||||
Arm::CoprocReg CRm = static_cast<Arm::CoprocReg>(coproc_info[3]);
|
||||
|
||||
IR::Value word1 = inst->GetArg(1);
|
||||
IR::Value word2 = inst->GetArg(2);
|
||||
|
||||
std::shared_ptr<Coprocessor> coproc = cb.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = coproc->CompileSendTwoWords(two, opc, CRm);
|
||||
if (!action) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, word1, word2);
|
||||
}
|
||||
|
||||
void EmitX64::EmitCoprocGetOneWord(IR::Block&, IR::Inst* inst) {
|
||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||
|
||||
size_t coproc_num = coproc_info[0];
|
||||
bool two = coproc_info[1] != 0;
|
||||
unsigned opc1 = static_cast<unsigned>(coproc_info[2]);
|
||||
Arm::CoprocReg CRn = static_cast<Arm::CoprocReg>(coproc_info[3]);
|
||||
Arm::CoprocReg CRm = static_cast<Arm::CoprocReg>(coproc_info[4]);
|
||||
unsigned opc2 = static_cast<unsigned>(coproc_info[5]);
|
||||
|
||||
std::shared_ptr<Coprocessor> coproc = cb.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = coproc->CompileGetOneWord(two, opc1, CRn, CRm, opc2);
|
||||
if (!action) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
|
||||
}
|
||||
|
||||
void EmitX64::EmitCoprocGetTwoWords(IR::Block&, IR::Inst* inst) {
|
||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||
|
||||
size_t coproc_num = coproc_info[0];
|
||||
bool two = coproc_info[1] != 0;
|
||||
unsigned opc = coproc_info[2];
|
||||
Arm::CoprocReg CRm = static_cast<Arm::CoprocReg>(coproc_info[3]);
|
||||
|
||||
std::shared_ptr<Coprocessor> coproc = cb.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = coproc->CompileGetTwoWords(two, opc, CRm);
|
||||
if (!action) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
|
||||
}
|
||||
|
||||
void EmitX64::EmitCoprocLoadWords(IR::Block&, IR::Inst* inst) {
|
||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||
|
||||
size_t coproc_num = coproc_info[0];
|
||||
bool two = coproc_info[1] != 0;
|
||||
bool long_transfer = coproc_info[2] != 0;
|
||||
Arm::CoprocReg CRd = static_cast<Arm::CoprocReg>(coproc_info[3]);
|
||||
bool has_option = coproc_info[4] != 0;
|
||||
boost::optional<u8> option{has_option, coproc_info[5]};
|
||||
|
||||
IR::Value address = inst->GetArg(1);
|
||||
|
||||
std::shared_ptr<Coprocessor> coproc = cb.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = coproc->CompileLoadWords(two, long_transfer, CRd, option);
|
||||
if (!action) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
CallCoprocCallback(code, reg_alloc, jit_interface, *action, nullptr, address);
|
||||
}
|
||||
|
||||
void EmitX64::EmitCoprocStoreWords(IR::Block&, IR::Inst* inst) {
|
||||
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
|
||||
|
||||
size_t coproc_num = coproc_info[0];
|
||||
bool two = coproc_info[1] != 0;
|
||||
bool long_transfer = coproc_info[2] != 0;
|
||||
Arm::CoprocReg CRd = static_cast<Arm::CoprocReg>(coproc_info[3]);
|
||||
bool has_option = coproc_info[4] != 0;
|
||||
boost::optional<u8> option{has_option, coproc_info[5]};
|
||||
|
||||
IR::Value address = inst->GetArg(1);
|
||||
|
||||
std::shared_ptr<Coprocessor> coproc = cb.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = coproc->CompileStoreWords(two, long_transfer, CRd, option);
|
||||
if (!action) {
|
||||
EmitCoprocessorException();
|
||||
return;
|
||||
}
|
||||
|
||||
CallCoprocCallback(code, reg_alloc, jit_interface, *action, nullptr, address);
|
||||
}
|
||||
|
||||
void EmitX64::EmitAddCycles(size_t cycles) {
|
||||
using namespace Xbyak::util;
|
||||
ASSERT(cycles < std::numeric_limits<u32>::max());
|
||||
|
|
|
@ -709,6 +709,80 @@ Value IREmitter::ExclusiveWriteMemory64(const Value& vaddr, const Value& value_l
|
|||
}
|
||||
}
|
||||
|
||||
void IREmitter::CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRd, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2) {
|
||||
ASSERT(coproc_no <= 15);
|
||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||
static_cast<u8>(two ? 1 : 0),
|
||||
static_cast<u8>(opc1),
|
||||
static_cast<u8>(CRd),
|
||||
static_cast<u8>(CRn),
|
||||
static_cast<u8>(CRm),
|
||||
static_cast<u8>(opc2)};
|
||||
Inst(Opcode::CoprocInternalOperation, {Value(coproc_info)});
|
||||
}
|
||||
|
||||
void IREmitter::CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2, const Value& word) {
|
||||
ASSERT(coproc_no <= 15);
|
||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||
static_cast<u8>(two ? 1 : 0),
|
||||
static_cast<u8>(opc1),
|
||||
static_cast<u8>(CRn),
|
||||
static_cast<u8>(CRm),
|
||||
static_cast<u8>(opc2)};
|
||||
Inst(Opcode::CoprocSendOneWord, {Value(coproc_info), word});
|
||||
}
|
||||
|
||||
void IREmitter::CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm, const Value& word1, const Value& word2) {
|
||||
ASSERT(coproc_no <= 15);
|
||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||
static_cast<u8>(two ? 1 : 0),
|
||||
static_cast<u8>(opc),
|
||||
static_cast<u8>(CRm)};
|
||||
Inst(Opcode::CoprocSendTwoWords, {Value(coproc_info), word1, word2});
|
||||
}
|
||||
|
||||
Value IREmitter::CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2) {
|
||||
ASSERT(coproc_no <= 15);
|
||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||
static_cast<u8>(two ? 1 : 0),
|
||||
static_cast<u8>(opc1),
|
||||
static_cast<u8>(CRn),
|
||||
static_cast<u8>(CRm),
|
||||
static_cast<u8>(opc2)};
|
||||
return Inst(Opcode::CoprocGetOneWord, {Value(coproc_info)});
|
||||
}
|
||||
|
||||
Value IREmitter::CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm) {
|
||||
ASSERT(coproc_no <= 15);
|
||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||
static_cast<u8>(two ? 1 : 0),
|
||||
static_cast<u8>(opc),
|
||||
static_cast<u8>(CRm)};
|
||||
return Inst(Opcode::CoprocGetTwoWords, {Value(coproc_info)});
|
||||
}
|
||||
|
||||
void IREmitter::CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option) {
|
||||
ASSERT(coproc_no <= 15);
|
||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||
static_cast<u8>(two ? 1 : 0),
|
||||
static_cast<u8>(long_transfer ? 1 : 0),
|
||||
static_cast<u8>(CRd),
|
||||
static_cast<u8>(has_option ? 1 : 0),
|
||||
static_cast<u8>(option)};
|
||||
Inst(Opcode::CoprocLoadWords, {Value(coproc_info), address});
|
||||
}
|
||||
|
||||
void IREmitter::CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option) {
|
||||
ASSERT(coproc_no <= 15);
|
||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||
static_cast<u8>(two ? 1 : 0),
|
||||
static_cast<u8>(long_transfer ? 1 : 0),
|
||||
static_cast<u8>(CRd),
|
||||
static_cast<u8>(has_option ? 1 : 0),
|
||||
static_cast<u8>(option)};
|
||||
Inst(Opcode::CoprocStoreWords, {Value(coproc_info), address});
|
||||
}
|
||||
|
||||
void IREmitter::Breakpoint() {
|
||||
Inst(Opcode::Breakpoint, {});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <initializer_list>
|
||||
|
||||
#include <dynarmic/coprocessor_util.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "frontend/ir/basic_block.h"
|
||||
#include "frontend/ir/location_descriptor.h"
|
||||
|
@ -213,6 +215,14 @@ public:
|
|||
Value ExclusiveWriteMemory32(const Value& vaddr, const Value& value);
|
||||
Value ExclusiveWriteMemory64(const Value& vaddr, const Value& value_lo, const Value& value_hi);
|
||||
|
||||
void CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRd, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2);
|
||||
void CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2, const Value& word);
|
||||
void CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm, const Value& word1, const Value& word2);
|
||||
Value CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2);
|
||||
Value CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm);
|
||||
void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option);
|
||||
void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option);
|
||||
|
||||
void Breakpoint();
|
||||
|
||||
void SetTerm(const Terminal& terminal);
|
||||
|
|
|
@ -213,6 +213,22 @@ bool Inst::AltersExclusiveState() const {
|
|||
IsExclusiveMemoryWrite();
|
||||
}
|
||||
|
||||
bool Inst::IsCoprocessorInstruction() const {
|
||||
switch (op) {
|
||||
case Opcode::CoprocInternalOperation:
|
||||
case Opcode::CoprocSendOneWord:
|
||||
case Opcode::CoprocSendTwoWords:
|
||||
case Opcode::CoprocGetOneWord:
|
||||
case Opcode::CoprocGetTwoWords:
|
||||
case Opcode::CoprocLoadWords:
|
||||
case Opcode::CoprocStoreWords:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Inst::MayHaveSideEffects() const {
|
||||
return op == Opcode::PushRSB ||
|
||||
CausesCPUException() ||
|
||||
|
@ -220,7 +236,8 @@ bool Inst::MayHaveSideEffects() const {
|
|||
WritesToCPSR() ||
|
||||
WritesToFPSCR() ||
|
||||
AltersExclusiveState() ||
|
||||
IsMemoryWrite();
|
||||
IsMemoryWrite() ||
|
||||
IsCoprocessorInstruction();
|
||||
}
|
||||
|
||||
void Inst::DecrementRemainingUses() {
|
||||
|
|
|
@ -67,6 +67,9 @@ public:
|
|||
/// Determines whether or not this instruction alters memory-exclusivity.
|
||||
bool AltersExclusiveState() const;
|
||||
|
||||
/// Determines whether or not this instruction accesses a coprocessor.
|
||||
bool IsCoprocessorInstruction() const;
|
||||
|
||||
/// Determines whether or not this instruction causes a CPU exception.
|
||||
bool CausesCPUException() const;
|
||||
|
||||
|
|
|
@ -158,3 +158,12 @@ OPCODE(ExclusiveWriteMemory8, T::U32, T::U32, T::U8
|
|||
OPCODE(ExclusiveWriteMemory16, T::U32, T::U32, T::U16 )
|
||||
OPCODE(ExclusiveWriteMemory32, T::U32, T::U32, T::U32 )
|
||||
OPCODE(ExclusiveWriteMemory64, T::U32, T::U32, T::U32, T::U32 )
|
||||
|
||||
// Coprocessor
|
||||
OPCODE(CoprocInternalOperation, T::Void, T::CoprocInfo )
|
||||
OPCODE(CoprocSendOneWord, T::Void, T::CoprocInfo, T::U32 )
|
||||
OPCODE(CoprocSendTwoWords, T::Void, T::CoprocInfo, T::U32, T::U32 )
|
||||
OPCODE(CoprocGetOneWord, T::U32, T::CoprocInfo )
|
||||
OPCODE(CoprocGetTwoWords, T::U64, T::CoprocInfo )
|
||||
OPCODE(CoprocLoadWords, T::Void, T::CoprocInfo, T::U32 )
|
||||
OPCODE(CoprocStoreWords, T::Void, T::CoprocInfo, T::U32 )
|
||||
|
|
Loading…
Reference in a new issue