mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-28 09:24:41 -04:00
Feature/agressive recompiler (#146)
* feat: added guestBranchKind enum to categorize branch types feat: added missingFunctionPolicy enum to define behaviors for missing function scenarios refactor: added handle guest branches and report missing functions feat lookupFunction to utilize new dispatch logic and improve error handling for unregistered functions * fix: fix test conflict * feat: added debug sound driver logs * feat: emmiter for return * feat: added recompiler reporter feat: added strict diagnostics flag for heavy debug calls * feat: staticc table insted of hashmap for runtime * feat: back file to ignore * feat: explode code across helpers and classes * feat: update codegen test feat: better guest nop check * feat: fix link problem on linux * feat: fix Segmentation fault * feat: added recompile replace for DMA and MMIO feat: added a clean memory helpers feat: use memory helpers across the project feat: fix ucrt on msvc * feat: undo messup merge
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
@@ -209,11 +210,27 @@ namespace ps2recomp
|
||||
return emitter.emit();
|
||||
}
|
||||
|
||||
std::string CodeGenerator::handleBranchDelaySlots(
|
||||
const Instruction &branchInst,
|
||||
const Instruction &delaySlot,
|
||||
const Function &function,
|
||||
const AnalysisResult &analysisResult,
|
||||
std::string delaySlotOverride)
|
||||
{
|
||||
ControlFlowEmitter emitter(*this, branchInst, delaySlot, function, analysisResult, std::move(delaySlotOverride));
|
||||
return emitter.emit();
|
||||
}
|
||||
|
||||
CodeGenerator::~CodeGenerator() = default;
|
||||
|
||||
std::string CodeGenerator::translateInstruction(const Instruction &inst)
|
||||
{
|
||||
return InstructionTranslator(*this).translate(inst);
|
||||
return InstructionTranslator(*this).translate(inst, {});
|
||||
}
|
||||
|
||||
std::string CodeGenerator::translateInstruction(const Instruction &inst, const MemoryAccessHint &memoryHint)
|
||||
{
|
||||
return InstructionTranslator(*this).translate(inst, memoryHint);
|
||||
}
|
||||
|
||||
std::string CodeGenerator::translateSpecialInstruction(const Instruction &inst)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <algorithm>
|
||||
#include <fmt/format.h>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace ps2recomp
|
||||
{
|
||||
@@ -15,12 +16,14 @@ namespace ps2recomp
|
||||
const Instruction &branchInst,
|
||||
const Instruction &delaySlot,
|
||||
const Function &function,
|
||||
const CodeGenerator::AnalysisResult &analysisResult)
|
||||
const CodeGenerator::AnalysisResult &analysisResult,
|
||||
std::string delaySlotOverride)
|
||||
: m_gen(generator),
|
||||
m_branchInst(branchInst),
|
||||
m_delaySlot(delaySlot),
|
||||
m_function(function),
|
||||
m_analysisResult(analysisResult)
|
||||
m_analysisResult(analysisResult),
|
||||
m_delaySlotOverride(std::move(delaySlotOverride))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -41,7 +44,7 @@ namespace ps2recomp
|
||||
|
||||
bool ControlFlowEmitter::hasRealDelaySlot() const
|
||||
{
|
||||
return !isGuestNop(m_delaySlot);
|
||||
return !m_delaySlotOverride.empty() || !isGuestNop(m_delaySlot);
|
||||
}
|
||||
|
||||
bool ControlFlowEmitter::isCallLikeEdge() const
|
||||
@@ -100,6 +103,11 @@ namespace ps2recomp
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_delaySlotOverride.empty())
|
||||
{
|
||||
return m_delaySlotOverride;
|
||||
}
|
||||
|
||||
std::string code;
|
||||
if (m_gen.m_emitInstructionComments)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ps2recomp/Emitters/function_emitter.h"
|
||||
#include "ps2recomp/code_generator.h"
|
||||
#include "ps2recomp/gif_dma_kick_analyzer.h"
|
||||
#include "ps2recomp/instructions.h"
|
||||
#include "ps2recomp/r5900_decoder.h"
|
||||
#include "ps2recomp/recompiler_reporter.h"
|
||||
@@ -69,6 +70,8 @@ namespace ps2recomp
|
||||
}
|
||||
|
||||
const std::unordered_set<uint32_t> &internalTargets = analysisResult.entryPoints;
|
||||
ConstantRegisterState constantRegisters;
|
||||
GifDmaKickPlan gifDmaKickPlan{};
|
||||
ss << "// Function: " << function.name << "\n";
|
||||
ss << "// Address: 0x" << std::hex << function.start << " - 0x" << function.end << std::dec << "\n";
|
||||
|
||||
@@ -106,6 +109,7 @@ namespace ps2recomp
|
||||
|
||||
if (internalTargets.contains(inst.address))
|
||||
{
|
||||
constantRegisters.clear();
|
||||
ss << "label_" << std::hex << inst.address << std::dec << ":\n";
|
||||
}
|
||||
|
||||
@@ -145,24 +149,65 @@ namespace ps2recomp
|
||||
ss << "label_" << std::hex << delaySlot->address << std::dec << ":\n";
|
||||
}
|
||||
|
||||
ss << cg.handleBranchDelaySlots(inst, *delaySlot, function, analysisResult);
|
||||
if (gifDmaKickPlan.valid &&
|
||||
gifDmaKickPlan.completesInDelaySlot &&
|
||||
gifDmaKickPlan.branchIndex == i &&
|
||||
hasDecodedDelaySlot)
|
||||
{
|
||||
ss << cg.handleBranchDelaySlots(
|
||||
inst,
|
||||
*delaySlot,
|
||||
function,
|
||||
analysisResult,
|
||||
gifDmaDelaySlotOverride(*delaySlot, gifDmaKickPlan, cg.m_emitInstructionComments));
|
||||
gifDmaKickPlan = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << cg.handleBranchDelaySlots(inst, *delaySlot, function, analysisResult);
|
||||
}
|
||||
|
||||
if (hasDecodedDelaySlot)
|
||||
{
|
||||
++i; // Skip delay slot instruction (handled inside branch logic)
|
||||
}
|
||||
constantRegisters.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gifDmaKickPlan.valid)
|
||||
{
|
||||
gifDmaKickPlan = tryBuildGifDmaKickPlan(instructions, i, constantRegisters, internalTargets);
|
||||
}
|
||||
|
||||
if (gifDmaKickPlan.suppresses(i))
|
||||
{
|
||||
const size_t slot = gifDmaKickPlan.slotFor(i);
|
||||
emitGifDmaCapture(ss, gifDmaKickPlan, slot, " ");
|
||||
|
||||
if (gifDmaKickPlan.completesAt(i))
|
||||
{
|
||||
ss << " ctx->pc = 0x" << std::hex << inst.address << "u;\n"
|
||||
<< std::dec;
|
||||
ss << " " << gifDmaKickCall(gifDmaKickPlan) << "\n";
|
||||
gifDmaKickPlan = {};
|
||||
}
|
||||
|
||||
updateConstantRegisters(inst, constantRegisters);
|
||||
continue;
|
||||
}
|
||||
|
||||
ss << " ctx->pc = 0x" << std::hex << inst.address << "u;\n"
|
||||
<< std::dec;
|
||||
|
||||
ss << " " << cg.translateInstruction(inst);
|
||||
const MemoryAccessHint memoryHint = resolveMemoryAccessHint(inst, constantRegisters);
|
||||
ss << " " << cg.translateInstruction(inst, memoryHint);
|
||||
if (inst.isMmio)
|
||||
{
|
||||
ss << " // MMIO: 0x" << std::hex << inst.mmioAddress << std::dec;
|
||||
}
|
||||
ss << "\n";
|
||||
|
||||
updateConstantRegisters(inst, constantRegisters);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
#include "ps2recomp/gif_dma_kick_analyzer.h"
|
||||
|
||||
#include "ps2recomp/instructions.h"
|
||||
#include "ps2recomp/r5900_decoder.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace ps2recomp
|
||||
{
|
||||
namespace
|
||||
{
|
||||
uint32_t add32(uint32_t lhs, uint32_t rhs)
|
||||
{
|
||||
return lhs + rhs;
|
||||
}
|
||||
|
||||
std::string formatU32Literal(uint32_t value)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "0x" << std::hex << value << "u";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string gprU32Expression(uint32_t reg)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "GPR_U32(ctx, " << std::dec << reg << ")";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string gifDmaKickTempName(uint32_t address, size_t slot)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "gifDmaKickValue_" << std::hex << address << "_" << std::dec << slot;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool isReturnWithDelaySlot(const Instruction &inst)
|
||||
{
|
||||
return inst.opcode == OPCODE_SPECIAL &&
|
||||
inst.function == SPECIAL_JR &&
|
||||
inst.rs == 31u &&
|
||||
inst.hasDelaySlot;
|
||||
}
|
||||
|
||||
bool tryMatchGifDmaStore(size_t instructionIndex,
|
||||
const Instruction &inst,
|
||||
const MemoryAccessHint &hint,
|
||||
const ConstantRegisterState &constants,
|
||||
uint32_t target,
|
||||
size_t slot,
|
||||
GifDmaKickPlan &plan)
|
||||
{
|
||||
if (inst.opcode != OPCODE_SW || !hint.hasAddress || hint.address != target)
|
||||
return false;
|
||||
|
||||
plan.storeIndices[slot] = instructionIndex;
|
||||
uint32_t constantValue = 0u;
|
||||
if (constants.read(inst.rt, constantValue))
|
||||
{
|
||||
plan.values[slot] = formatU32Literal(constantValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string tempName = gifDmaKickTempName(inst.address, slot);
|
||||
plan.values[slot] = tempName;
|
||||
plan.captureExpressions[slot] = gprU32Expression(inst.rt);
|
||||
plan.captures[slot] = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ConstantRegisterState::ConstantRegisterState()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void ConstantRegisterState::clear()
|
||||
{
|
||||
known.fill(false);
|
||||
values.fill(0u);
|
||||
known[0] = true;
|
||||
}
|
||||
|
||||
bool ConstantRegisterState::read(uint32_t reg, uint32_t &value) const
|
||||
{
|
||||
if (reg >= known.size() || !known[reg])
|
||||
return false;
|
||||
|
||||
value = values[reg];
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConstantRegisterState::write(uint32_t reg, uint32_t value)
|
||||
{
|
||||
if (reg == 0 || reg >= known.size())
|
||||
return;
|
||||
|
||||
known[reg] = true;
|
||||
values[reg] = value;
|
||||
}
|
||||
|
||||
void ConstantRegisterState::invalidate(uint32_t reg)
|
||||
{
|
||||
if (reg == 0 || reg >= known.size())
|
||||
return;
|
||||
|
||||
known[reg] = false;
|
||||
values[reg] = 0u;
|
||||
}
|
||||
|
||||
bool GifDmaKickPlan::suppresses(size_t index) const
|
||||
{
|
||||
return valid && std::find(storeIndices.begin(), storeIndices.end(), index) != storeIndices.end();
|
||||
}
|
||||
|
||||
bool GifDmaKickPlan::completesAt(size_t index) const
|
||||
{
|
||||
return valid && index == endIndex;
|
||||
}
|
||||
|
||||
size_t GifDmaKickPlan::slotFor(size_t index) const
|
||||
{
|
||||
for (size_t i = 0; i < storeIndices.size(); ++i)
|
||||
{
|
||||
if (storeIndices[i] == index)
|
||||
return i;
|
||||
}
|
||||
return storeIndices.size();
|
||||
}
|
||||
|
||||
bool isDirectMemoryAccess(const Instruction &inst)
|
||||
{
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case OPCODE_LB:
|
||||
case OPCODE_LH:
|
||||
case OPCODE_LW:
|
||||
case OPCODE_LBU:
|
||||
case OPCODE_LHU:
|
||||
case OPCODE_LWU:
|
||||
case OPCODE_LQ:
|
||||
case OPCODE_LD:
|
||||
case OPCODE_LWC1:
|
||||
case OPCODE_LDC2:
|
||||
case OPCODE_SB:
|
||||
case OPCODE_SH:
|
||||
case OPCODE_SW:
|
||||
case OPCODE_SQ:
|
||||
case OPCODE_SD:
|
||||
case OPCODE_SWC1:
|
||||
case OPCODE_SDC2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryAccessHint resolveMemoryAccessHint(const Instruction &inst, const ConstantRegisterState &constants)
|
||||
{
|
||||
MemoryAccessHint hint{};
|
||||
if (!isDirectMemoryAccess(inst))
|
||||
return hint;
|
||||
|
||||
uint32_t base = 0u;
|
||||
if (!constants.read(inst.rs, base))
|
||||
return hint;
|
||||
|
||||
hint.hasAddress = true;
|
||||
hint.address = add32(base, inst.simmediate);
|
||||
return hint;
|
||||
}
|
||||
|
||||
void updateConstantRegisters(const Instruction &inst, ConstantRegisterState &constants)
|
||||
{
|
||||
uint32_t lhs = 0u;
|
||||
uint32_t rhs = 0u;
|
||||
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case OPCODE_LUI:
|
||||
constants.write(inst.rt, inst.immediate << 16);
|
||||
return;
|
||||
case OPCODE_ORI:
|
||||
if (constants.read(inst.rs, lhs))
|
||||
constants.write(inst.rt, lhs | (inst.immediate & 0xFFFFu));
|
||||
else
|
||||
constants.invalidate(inst.rt);
|
||||
return;
|
||||
case OPCODE_ADDIU:
|
||||
if (constants.read(inst.rs, lhs))
|
||||
constants.write(inst.rt, add32(lhs, inst.simmediate));
|
||||
else
|
||||
constants.invalidate(inst.rt);
|
||||
return;
|
||||
case OPCODE_ANDI:
|
||||
if (constants.read(inst.rs, lhs))
|
||||
constants.write(inst.rt, lhs & (inst.immediate & 0xFFFFu));
|
||||
else
|
||||
constants.invalidate(inst.rt);
|
||||
return;
|
||||
case OPCODE_XORI:
|
||||
if (constants.read(inst.rs, lhs))
|
||||
constants.write(inst.rt, lhs ^ (inst.immediate & 0xFFFFu));
|
||||
else
|
||||
constants.invalidate(inst.rt);
|
||||
return;
|
||||
case OPCODE_LB:
|
||||
case OPCODE_LH:
|
||||
case OPCODE_LWL:
|
||||
case OPCODE_LW:
|
||||
case OPCODE_LBU:
|
||||
case OPCODE_LHU:
|
||||
case OPCODE_LWR:
|
||||
case OPCODE_LWU:
|
||||
case OPCODE_LDL:
|
||||
case OPCODE_LDR:
|
||||
case OPCODE_LQ:
|
||||
case OPCODE_LL:
|
||||
case OPCODE_LD:
|
||||
constants.invalidate(inst.rt);
|
||||
return;
|
||||
case OPCODE_SC:
|
||||
constants.invalidate(inst.rt);
|
||||
return;
|
||||
case OPCODE_SPECIAL:
|
||||
switch (inst.function)
|
||||
{
|
||||
case SPECIAL_ADDU:
|
||||
case SPECIAL_DADDU:
|
||||
if (constants.read(inst.rs, lhs) && constants.read(inst.rt, rhs))
|
||||
constants.write(inst.rd, add32(lhs, rhs));
|
||||
else
|
||||
constants.invalidate(inst.rd);
|
||||
return;
|
||||
case SPECIAL_OR:
|
||||
if (constants.read(inst.rs, lhs) && constants.read(inst.rt, rhs))
|
||||
constants.write(inst.rd, lhs | rhs);
|
||||
else
|
||||
constants.invalidate(inst.rd);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst.modificationInfo.modifiesGPR || inst.modificationInfo.modifiesControl)
|
||||
constants.clear();
|
||||
}
|
||||
|
||||
std::string gifDmaKickCall(const GifDmaKickPlan &plan)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "runtime->kickGifDmaChainFromMMIO(rdram, ctx, "
|
||||
<< plan.values[0] << ", "
|
||||
<< plan.values[1] << ", "
|
||||
<< plan.values[2] << ", "
|
||||
<< plan.values[3] << ");";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void emitGifDmaCapture(std::ostream &out, const GifDmaKickPlan &plan, size_t slot, std::string_view indent)
|
||||
{
|
||||
if (slot >= plan.captures.size() || !plan.captures[slot])
|
||||
return;
|
||||
|
||||
out << indent << "uint32_t " << plan.values[slot] << " = " << plan.captureExpressions[slot] << ";\n";
|
||||
}
|
||||
|
||||
std::string gifDmaDelaySlotOverride(const Instruction &delaySlot, const GifDmaKickPlan &plan, bool emitComments)
|
||||
{
|
||||
std::ostringstream code;
|
||||
const size_t slot = plan.slotFor(plan.endIndex);
|
||||
if (emitComments)
|
||||
{
|
||||
code << "// 0x" << std::hex << delaySlot.address << ": 0x" << delaySlot.raw << std::dec;
|
||||
std::string disassembly = R5900Decoder::disassembleInstruction(delaySlot);
|
||||
if (!disassembly.empty())
|
||||
code << " " << disassembly;
|
||||
code << " (Delay Slot)\n";
|
||||
}
|
||||
|
||||
if (slot < plan.captures.size() && plan.captures[slot])
|
||||
code << "uint32_t " << plan.values[slot] << " = " << plan.captureExpressions[slot] << ";\n";
|
||||
code << gifDmaKickCall(plan);
|
||||
return code.str();
|
||||
}
|
||||
|
||||
GifDmaKickPlan tryBuildGifDmaKickPlan(const std::vector<Instruction> &instructions,
|
||||
size_t startIndex,
|
||||
const ConstantRegisterState &constants,
|
||||
const std::unordered_set<uint32_t> &internalTargets)
|
||||
{
|
||||
static constexpr std::array<uint32_t, 4> kTargets = {
|
||||
0x1000E020u, // D_PCR
|
||||
0x1000E010u, // D_STAT
|
||||
0x1000A030u, // GIF TADR
|
||||
0x1000A000u, // GIF CHCR
|
||||
};
|
||||
static constexpr size_t kMaxScanInstructions = 32u;
|
||||
|
||||
GifDmaKickPlan plan{};
|
||||
if (startIndex >= instructions.size())
|
||||
return plan;
|
||||
|
||||
ConstantRegisterState scanConstants = constants;
|
||||
size_t matched = 0;
|
||||
const size_t scanEnd = std::min(instructions.size(), startIndex + kMaxScanInstructions);
|
||||
|
||||
for (size_t j = startIndex; j < scanEnd; ++j)
|
||||
{
|
||||
const Instruction &inst = instructions[j];
|
||||
if (j != startIndex && matched > 0 && internalTargets.contains(inst.address))
|
||||
return {};
|
||||
|
||||
const MemoryAccessHint hint = resolveMemoryAccessHint(inst, scanConstants);
|
||||
if (isDirectMemoryAccess(inst))
|
||||
{
|
||||
if (matched >= kTargets.size() ||
|
||||
!tryMatchGifDmaStore(j, inst, hint, scanConstants, kTargets[matched], matched, plan))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
++matched;
|
||||
updateConstantRegisters(inst, scanConstants);
|
||||
if (matched == kTargets.size())
|
||||
{
|
||||
plan.valid = true;
|
||||
plan.endIndex = j;
|
||||
return plan;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isReturnWithDelaySlot(inst))
|
||||
{
|
||||
const size_t delayIndex = j + 1u;
|
||||
if (matched != kTargets.size() - 1u ||
|
||||
delayIndex >= instructions.size() ||
|
||||
instructions[delayIndex].address != inst.address + 4u ||
|
||||
internalTargets.contains(instructions[delayIndex].address))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const Instruction &delayInst = instructions[delayIndex];
|
||||
const MemoryAccessHint delayHint = resolveMemoryAccessHint(delayInst, scanConstants);
|
||||
if (!tryMatchGifDmaStore(delayIndex, delayInst, delayHint, scanConstants, kTargets[matched], matched, plan))
|
||||
return {};
|
||||
|
||||
plan.valid = true;
|
||||
plan.completesInDelaySlot = true;
|
||||
plan.branchIndex = j;
|
||||
plan.endIndex = delayIndex;
|
||||
return plan;
|
||||
}
|
||||
|
||||
if (inst.hasDelaySlot || inst.isBranch || inst.isJump || inst.modificationInfo.modifiesControl)
|
||||
return {};
|
||||
|
||||
updateConstantRegisters(inst, scanConstants);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -4,42 +4,145 @@
|
||||
#include "ps2recomp/instructions.h"
|
||||
#include "ps2recomp/types.h"
|
||||
#include "ps2recomp/control_flow_utils.h"
|
||||
#include "runtime/ps2_address.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace ps2recomp
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::string addressLiteral(uint32_t address)
|
||||
{
|
||||
return fmt::format("0x{:X}u", address);
|
||||
}
|
||||
|
||||
uint32_t memoryAccessSize(int width)
|
||||
{
|
||||
return static_cast<uint32_t>(width / 8);
|
||||
}
|
||||
|
||||
std::string memoryValueType(int width)
|
||||
{
|
||||
switch (width)
|
||||
{
|
||||
case 8:
|
||||
return "uint8_t";
|
||||
case 16:
|
||||
return "uint16_t";
|
||||
case 32:
|
||||
return "uint32_t";
|
||||
case 64:
|
||||
return "uint64_t";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string genFastWrite(int width, uint32_t address, const std::string &val)
|
||||
{
|
||||
const std::string addr = addressLiteral(address);
|
||||
if (width == 128)
|
||||
{
|
||||
return fmt::format(
|
||||
"do {{ __m128i _value = ({}); "
|
||||
"const uint64_t _lo = static_cast<uint64_t>(PS2_EXTRACT_EPI64_0(_value)); "
|
||||
"const uint64_t _hi = static_cast<uint64_t>(PS2_EXTRACT_EPI64_1(_value)); "
|
||||
"ps2TraceGuestWrite(rdram, {}, 16u, _lo, _hi, \"WRITE128\", ctx); "
|
||||
"FAST_WRITE128({}, _value); }} while (0)",
|
||||
val, addr, addr);
|
||||
}
|
||||
|
||||
const std::string valueType = memoryValueType(width);
|
||||
return fmt::format(
|
||||
"do {{ {} _value = static_cast<{}>({}); "
|
||||
"ps2TraceGuestWrite(rdram, {}, {}u, _value, 0u, \"WRITE{}\", ctx); "
|
||||
"FAST_WRITE{}({}, _value); }} while (0)",
|
||||
valueType, valueType, val, addr, memoryAccessSize(width), width, width, addr);
|
||||
}
|
||||
}
|
||||
|
||||
InstructionTranslator::InstructionTranslator(CodeGenerator &codeGenerator)
|
||||
: m_codeGenerator(codeGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
std::string InstructionTranslator::translate(const Instruction &inst)
|
||||
MemoryAccessHint InstructionTranslator::effectiveMemoryHintFor(const Instruction &inst, const MemoryAccessHint &memoryHint) const
|
||||
{
|
||||
MemoryAccessHint effectiveMemoryHint = memoryHint;
|
||||
if (inst.isMmio)
|
||||
{
|
||||
effectiveMemoryHint.hasAddress = true;
|
||||
effectiveMemoryHint.address = inst.mmioAddress;
|
||||
}
|
||||
|
||||
return effectiveMemoryHint;
|
||||
}
|
||||
|
||||
std::string InstructionTranslator::translateMemoryRead(const Instruction &inst,
|
||||
const MemoryAccessHint &memoryHint,
|
||||
int width,
|
||||
const std::string &addr) const
|
||||
{
|
||||
if (memoryHint.hasAddress)
|
||||
{
|
||||
const uint32_t resolvedAddress = memoryHint.address;
|
||||
const std::string resolvedAddressExpr = addressLiteral(resolvedAddress);
|
||||
if (inst.isMmio || Ps2IsSpecialAddress(resolvedAddress))
|
||||
{
|
||||
return fmt::format("runtime->Load{}(rdram, ctx, {})", width, resolvedAddressExpr);
|
||||
}
|
||||
return fmt::format("FAST_READ{}({})", width, resolvedAddressExpr);
|
||||
}
|
||||
|
||||
if (inst.isMmio)
|
||||
{
|
||||
return fmt::format("runtime->Load{}(rdram, ctx, {})", width, addr);
|
||||
}
|
||||
return fmt::format("READ{}({})", width, addr);
|
||||
}
|
||||
|
||||
std::string InstructionTranslator::translateMemoryWrite(const Instruction &inst,
|
||||
const MemoryAccessHint &memoryHint,
|
||||
int width,
|
||||
const std::string &addr,
|
||||
const std::string &value) const
|
||||
{
|
||||
if (memoryHint.hasAddress)
|
||||
{
|
||||
const uint32_t resolvedAddress = memoryHint.address;
|
||||
const std::string resolvedAddressExpr = addressLiteral(resolvedAddress);
|
||||
if (inst.isMmio || Ps2IsSpecialAddress(resolvedAddress))
|
||||
{
|
||||
return fmt::format("runtime->Store{}(rdram, ctx, {}, {})", width, resolvedAddressExpr, value);
|
||||
}
|
||||
return genFastWrite(width, resolvedAddress, value);
|
||||
}
|
||||
|
||||
if (inst.isMmio)
|
||||
{
|
||||
return fmt::format("runtime->Store{}(rdram, ctx, {}, {})", width, addr, value);
|
||||
}
|
||||
return fmt::format("WRITE{}({}, {})", width, addr, value);
|
||||
}
|
||||
|
||||
std::string InstructionTranslator::translate(const Instruction &inst, const MemoryAccessHint &memoryHint)
|
||||
{
|
||||
if (inst.isMMI)
|
||||
{
|
||||
return m_codeGenerator.translateMMIInstruction(inst);
|
||||
}
|
||||
|
||||
const MemoryAccessHint effectiveMemoryHint = effectiveMemoryHintFor(inst, memoryHint);
|
||||
|
||||
auto genRead = [&](int width, const std::string &addr)
|
||||
{
|
||||
if (inst.isMmio)
|
||||
{
|
||||
return fmt::format("runtime->Load{}(rdram, ctx, {})", width, addr);
|
||||
}
|
||||
return fmt::format("READ{}({})", width, addr);
|
||||
return translateMemoryRead(inst, effectiveMemoryHint, width, addr);
|
||||
};
|
||||
|
||||
auto genWrite = [&](int width, const std::string &addr, const std::string &val)
|
||||
{
|
||||
if (inst.isMmio)
|
||||
{
|
||||
return fmt::format("runtime->Store{}(rdram, ctx, {}, {})", width, addr, val);
|
||||
}
|
||||
return fmt::format("WRITE{}({}, {})", width, addr, val);
|
||||
return translateMemoryWrite(inst, effectiveMemoryHint, width, addr, val);
|
||||
};
|
||||
|
||||
switch (inst.opcode)
|
||||
|
||||
Reference in New Issue
Block a user