Implement coprocessor-related microinstructions

* CoprocInternalOperation
* CoprocSendOneWord
* CoprocSendTwoWords
* CoprocGetOneWord
* CoprocGetTwoWords
* CoprocLoadWords
* CoprocStoreWords
This commit is contained in:
MerryMage
2016-12-31 11:17:47 +00:00
committed by Merry
parent b3ae57619d
commit 48693eb6ff
6 changed files with 312 additions and 1 deletions

View File

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