riscv: Initial untested dispatcher.

The minimum to actually, probably, running code.  Pretty slow.
This commit is contained in:
Unknown W. Brackets 2023-07-17 23:28:43 -07:00
parent e271e43ec5
commit 47b81985bd
10 changed files with 541 additions and 11 deletions

View File

@ -1609,8 +1609,10 @@ list(APPEND CoreExtra
)
list(APPEND CoreExtra
Core/MIPS/RiscV/RiscVAsm.cpp
Core/MIPS/RiscV/RiscVJit.cpp
Core/MIPS/RiscV/RiscVJit.h
Core/MIPS/RiscV/RiscVRegCache.h
GPU/Common/VertexDecoderRiscV.cpp
)

View File

@ -1180,6 +1180,16 @@ bool RiscVEmitter::CJInRange(const void *src, const void *dst) const {
return BJInRange(src, dst, 12);
}
void RiscVEmitter::QuickCallFunction(RiscVReg scratchreg, const u8 *func) {
if (!JInRange(GetCodePointer(), func)) {
// TODO: Might be able to optimize a tiny bit by taking advantage of simm12.
LI(scratchreg, (uintptr_t)func);
JALR(R_RA, scratchreg, 0);
} else {
JAL(R_RA, func);
}
}
void RiscVEmitter::SetRegToImmediate(RiscVReg rd, uint64_t value, RiscVReg temp) {
int64_t svalue = (int64_t)value;
_assert_msg_(IsGPR(rd) && IsGPR(temp), "SetRegToImmediate only supports GPRs");

View File

@ -213,6 +213,13 @@ public:
bool BInRange(const void *func) const;
bool JInRange(const void *func) const;
void QuickCallFunction(RiscVReg scratchreg, const u8 *func);
template <typename T>
void QuickCallFunction(RiscVReg scratchreg, T *func) {
static_assert(std::is_function<T>::value, "QuickCallFunction without function");
QuickCallFunction(scratchreg, (const u8 *)func);
}
void LUI(RiscVReg rd, s32 simm32);
void AUIPC(RiscVReg rd, s32 simm32);

View File

@ -593,6 +593,7 @@
<ClCompile Include="MIPS\IR\IRPassSimplify.cpp" />
<ClCompile Include="MIPS\IR\IRRegCache.cpp" />
<ClCompile Include="MIPS\MIPSVFPUFallbacks.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVAsm.cpp" />
<ClCompile Include="MIPS\RiscV\RiscVJit.cpp" />
<ClCompile Include="Replay.cpp" />
<ClCompile Include="Compatibility.cpp" />
@ -1163,6 +1164,7 @@
<ClInclude Include="MIPS\IR\IRRegCache.h" />
<ClInclude Include="MIPS\MIPSVFPUFallbacks.h" />
<ClInclude Include="MIPS\RiscV\RiscVJit.h" />
<ClInclude Include="MIPS\RiscV\RiscVRegCache.h" />
<ClInclude Include="Replay.h" />
<ClInclude Include="Compatibility.h" />
<ClInclude Include="Config.h" />

View File

@ -1210,6 +1210,9 @@
<ClCompile Include="MIPS\RiscV\RiscVJit.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
<ClCompile Include="MIPS\RiscV\RiscVAsm.cpp">
<Filter>MIPS\RiscV</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -1959,6 +1962,9 @@
<ClInclude Include="MIPS\RiscV\RiscVJit.h">
<Filter>MIPS\RiscV</Filter>
</ClInclude>
<ClInclude Include="MIPS\RiscV\RiscVRegCache.h">
<Filter>MIPS\RiscV</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE.TXT" />

View File

@ -213,7 +213,9 @@ private:
bool ReplaceJalTo(u32 dest);
// Clobbers SCRATCH2.
void SaveStaticRegisters();
// Clobbers SCRATCH2.
void LoadStaticRegisters();
void WriteExit(u32 destination, int exit_num);

View File

@ -0,0 +1,281 @@
// Copyright (c) 2023- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/Log.h"
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/MIPS/JitCommon/JitState.h"
#include "Core/System.h"
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
static const bool enableDebug = false;
static const bool enableDisasm = false;
static void ShowPC(u32 downcount, void *membase, void *jitbase) {
static int count = 0;
if (currentMIPS) {
ERROR_LOG(JIT, "ShowPC : %08x Downcount : %08x %d %p %p", currentMIPS->pc, downcount, count, membase, jitbase);
} else {
ERROR_LOG(JIT, "Universe corrupt?");
}
//if (count > 2000)
// exit(0);
count++;
}
void RiscVJit::GenerateFixedCode(const JitOptions &jo) {
BeginWrite(GetMemoryProtectPageSize());
const u8 *start = AlignCodePage();
// TODO
if (jo.useStaticAlloc) {
//saveStaticRegisters = AlignCode16();
//SW(DOWNCOUNTREG, CTXREG, offsetof(MIPSState, downcount));
//gpr.EmitSaveStaticRegisters();
//RET();
//loadStaticRegisters = AlignCode16();
//gpr.EmitLoadStaticRegisters();
//LW(DOWNCOUNTREG, CTXREG, offsetof(MIPSState, downcount));
//RET();
//start = saveStaticRegisters;
} else {
//saveStaticRegisters = nullptr;
//loadStaticRegisters = nullptr;
}
// TODO: Do we actually need updateRoundingMode_? Hm.
//applyRoundingMode_ = AlignCode16();
if (false) {
// Not sure if RISC-V has any flush to zero capability? Leaving it off for now...
LWU(SCRATCH2, CTXREG, offsetof(MIPSState, fcr31));
// We can skip if the rounding mode is nearest (0) and flush is not set.
// (as restoreRoundingMode cleared it out anyway)
FixupBranch skip = BEQ(SCRATCH2, R_ZERO);
// MIPS Rounding Mode: RISC-V
// 0: Round nearest 0
// 1: Round to zero 1
// 2: Round up (ceil) 3
// 3: Round down (floor) 2
if (cpu_info.RiscV_Zbs) {
BEXTI(SCRATCH1, SCRATCH2, 1);
} else {
ANDI(SCRATCH1, SCRATCH2, 2);
SRLI(SCRATCH1, SCRATCH1, 1);
}
// Swap the lowest bit by the second bit.
XOR(SCRATCH2, SCRATCH2, SCRATCH1);
FSRM(SCRATCH2);
SetJumpTarget(skip);
RET();
}
//updateRoundingMode_ = AlignCode16();
if (false) {
LWU(SCRATCH2, CTXREG, offsetof(MIPSState, fcr31));
// Set SCRATCH2 to FZ:RM (FZ is bit 24, and RM are lowest 2 bits.)
ANDI(SCRATCH1, SCRATCH2, 1 << 24);
ANDI(SCRATCH2, SCRATCH2, 3);
SRLI(SCRATCH1, SCRATCH1, 22);
OR(SCRATCH2, SCRATCH2, SCRATCH1);
// Let's update js.currentRoundingFunc with the right convertS0ToSCRATCH1 func.
//LI(SCRATCH1, convertS0ToSCRATCH1);
if (cpu_info.RiscV_Zba) {
SH_ADD(3, SCRATCH1, SCRATCH2, SCRATCH1);
} else {
SLLI(SCRATCH2, SCRATCH2, 3);
ADD(SCRATCH1, SCRATCH1, SCRATCH2);
}
LD(SCRATCH2, SCRATCH1, 0);
//LI(SCRATCH1, &js.currentRoundingFunc);
SW(SCRATCH2, SCRATCH1, 0);
RET();
}
enterDispatcher_ = AlignCode16();
// Start by saving some regs on the stack. There are 12 GPs and 12 FPs we want.
// Note: we leave R_SP as, well, SP, so it doesn't need to be saved.
_assert_msg_(cpu_info.Mode64bit, "RiscVAsm currently assumes RV64, not RV32 or RV128");
static constexpr RiscVReg regs_to_save[]{ R_RA, X8, X9, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27 };
// TODO: Maybe we shouldn't regalloc all of these? Is it worth it?
static constexpr RiscVReg regs_to_save_fp[]{ F8, F9, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27 };
int saveSize = 8 * (int)(ARRAY_SIZE(regs_to_save) + ARRAY_SIZE(regs_to_save_fp));
if (saveSize & 0xF)
saveSize += 8;
_assert_msg_((saveSize & 0xF) == 0, "Stack must be kept aligned");
int saveOffset = 0;
ADDI(R_SP, R_SP, -saveSize);
for (RiscVReg r : regs_to_save) {
SD(r, R_SP, saveOffset);
saveOffset += 8;
}
for (RiscVReg r : regs_to_save_fp) {
FS(64, r, R_SP, saveOffset);
saveOffset += 8;
}
_assert_(saveOffset <= saveSize);
// Fixed registers, these are always kept when in Jit context.
LI(MEMBASEREG, Memory::base, SCRATCH1);
LI(CTXREG, mips_, SCRATCH1);
LI(JITBASEREG, blockStartAddrs_, SCRATCH1);
LoadStaticRegisters();
MovFromPC(SCRATCH1);
outerLoopPCInSCRATCH1_ = GetCodePtr();
MovToPC(SCRATCH1);
outerLoop_ = GetCodePtr();
// Advance can change the downcount (or thread), so must save/restore around it.
SaveStaticRegisters();
RestoreRoundingMode(true);
QuickCallFunction(SCRATCH1, &CoreTiming::Advance);
ApplyRoundingMode(true);
LoadStaticRegisters();
dispatcherCheckCoreState_ = GetCodePtr();
LI(SCRATCH1, &coreState, SCRATCH2);
LW(SCRATCH1, SCRATCH1, 0);
FixupBranch badCoreState = BNE(SCRATCH1, R_ZERO);
// We just checked coreState, so go to advance if downcount is negative.
BLT(DOWNCOUNTREG, R_ZERO, outerLoop_);
FixupBranch skipToRealDispatch = J();
dispatcherPCInSCRATCH1_ = GetCodePtr();
MovToPC(SCRATCH1);
dispatcher_ = GetCodePtr();
FixupBranch bail = BLT(DOWNCOUNTREG, R_ZERO);
SetJumpTarget(skipToRealDispatch);
dispatcherNoCheck_ = GetCodePtr();
// Debug
if (enableDebug) {
MV(X10, DOWNCOUNTREG);
MV(X11, MEMBASEREG);
MV(X12, JITBASEREG);
QuickCallFunction(X13, &ShowPC);
}
LWU(SCRATCH1, CTXREG, offsetof(MIPSState, pc));
#ifdef MASKED_PSP_MEMORY
LI(SCRATCH2, 0x3FFFFFFF);
AND(SCRATCH1, SCRATCH1, SCRATCH2);
#endif
ADD(SCRATCH1, SCRATCH1, MEMBASEREG);
dispatcherFetch_ = GetCodePtr();
LWU(SCRATCH1, SCRATCH1, 0);
SRLI(SCRATCH2, SCRATCH1, 24);
// We're in other words comparing to the top 8 bits of MIPS_EMUHACK_OPCODE by subtracting.
ADDI(SCRATCH2, SCRATCH2, -(MIPS_EMUHACK_OPCODE >> 24));
FixupBranch skipJump = BNE(SCRATCH2, R_ZERO);
// Use a wall to mask by 0x00FFFFFF and extract the block number.
SLLI(SCRATCH1, SCRATCH1, XLEN - 24);
// But actually, we want * 8, so skip shifting back just a bit.
_assert_msg_(sizeof(blockStartAddrs_[0]) == 8, "RiscVAsm currently assumes pointers are 64-bit");
SRLI(SCRATCH1, SCRATCH1, XLEN - 24 - 3);
ADD(SCRATCH1, JITBASEREG, SCRATCH1);
// TODO: Consider replacing the block nums after all, just trying to use IR block cache.
LD(SCRATCH1, SCRATCH1, 0);
JR(SCRATCH1);
SetJumpTarget(skipJump);
// No block found, let's jit. Might be able to optimize reg/frm saving later.
SaveStaticRegisters();
RestoreRoundingMode(true);
QuickCallFunction(SCRATCH1, &MIPSComp::JitAt);
ApplyRoundingMode(true);
LoadStaticRegisters();
// Try again, the block index should be set now.
J(dispatcherNoCheck_);
SetJumpTarget(bail);
LI(SCRATCH1, &coreState, SCRATCH2);
LW(SCRATCH1, SCRATCH1, 0);
BEQ(SCRATCH1, R_ZERO, outerLoop_);
const uint8_t *quitLoop = GetCodePtr();
SetJumpTarget(badCoreState);
SaveStaticRegisters();
RestoreRoundingMode(true);
_assert_msg_(cpu_info.Mode64bit, "RiscVAsm currently assumes RV64, not RV32 or RV128");
saveOffset = 0;
for (RiscVReg r : regs_to_save) {
LD(r, R_SP, saveOffset);
saveOffset += 8;
}
for (RiscVReg r : regs_to_save_fp) {
FL(64, r, R_SP, saveOffset);
saveOffset += 8;
}
ADDI(R_SP, R_SP, saveSize);
RET();
// TODO
crashHandler_ = GetCodePtr();
LI(SCRATCH1, &coreState, SCRATCH2);
LI(SCRATCH2, CORE_RUNTIME_ERROR);
SW(SCRATCH2, SCRATCH1, 0);
J(quitLoop);
// TODO: Do we need this?
static const Round roundModes[8] = { Round::NEAREST_EVEN, Round::TOZERO, Round::UP, Round::DOWN, Round::NEAREST_EVEN, Round::TOZERO, Round::UP, Round::DOWN };
for (size_t i = 0; i < ARRAY_SIZE(roundModes); ++i) {
//convertS0ToSCRATCH1[i] = AlignCode16();
//FCVT(FConv::W, FConv::S, SCRATCH1, F0, roundModes[i]);
//RET();
}
// Leave this at the end, add more stuff above.
if (enableDisasm) {
std::vector<std::string> lines = DisassembleRV64(start, GetCodePtr() - start);
for (auto s : lines) {
INFO_LOG(JIT, "%s", s.c_str());
}
}
// Let's spare the pre-generated code from unprotect-reprotect.
AlignCodePage();
jitStartOffset_ = (int)(GetCodePtr() - start);
// Don't forget to zap the instruction cache! This must stay at the end of this function.
FlushIcache();
EndWrite();
}
} // namespace MIPSComp

View File

@ -15,15 +15,37 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/StringUtils.h"
#include "Core/MemMap.h"
#include "Core/MIPS/RiscV/RiscVJit.h"
#include "Core/MIPS/RiscV/RiscVRegCache.h"
#include "Common/Profiler/Profiler.h"
namespace MIPSComp {
using namespace RiscVGen;
using namespace RiscVJitConstants;
static constexpr int MAX_ALLOWED_JIT_BLOCKS = 262144;
RiscVJit::RiscVJit(MIPSState *mipsState) : IRJit(mipsState) {
// Automatically disable incompatible options.
if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) {
jo.enablePointerify = false;
}
AllocCodeSpace(1024 * 1024 * 16);
// TODO: gpr, fpr, GenerateFixedCode(jo);
// TODO: Consider replacing block num method form IRJit - this is 2MB.
blockStartAddrs_ = new const u8 *[MAX_ALLOWED_JIT_BLOCKS];
// TODO: gpr, fpr
GenerateFixedCode(jo);
}
RiscVJit::~RiscVJit() {
delete [] blockStartAddrs_;
}
void RiscVJit::RunLoopUntil(u64 globalticks) {
@ -32,16 +54,117 @@ void RiscVJit::RunLoopUntil(u64 globalticks) {
}
bool RiscVJit::CompileBlock(u32 em_address, std::vector<IRInst> &instructions, u32 &mipsBytes, bool preload) {
// Check that we're not full (we allow less blocks than IR itself.)
if (blocks_.GetNumBlocks() >= MAX_ALLOWED_JIT_BLOCKS - 1)
return false;
if (!IRJit::CompileBlock(em_address, instructions, mipsBytes, preload))
return false;
// TODO: Compile native.
// TODO: Block linking, checked entries and such.
int block_num = blocks_.GetBlockNumberFromStartAddress(em_address);
_assert_msg_(blockStartAddrs_[block_num] == nullptr, "Block reused before clear");
blockStartAddrs_[block_num] = GetCodePointer();
// TODO: gpr, fpr.
for (const IRInst &inst : instructions) {
CompileIRInst(inst);
// TODO
if (jo.Disabled(JitDisable::REGALLOC_GPR)) {
//gpr.FlushAll();
}
if (jo.Disabled(JitDisable::REGALLOC_FPR)) {
//fpr.FlushAll();
}
// Safety check, in case we get a bunch of really large jit ops without a lot of branching.
if (GetSpaceLeft() < 0x800) {
return false;
}
}
// Note: a properly constructed block should never get here.
// TODO: Need to do more than just this? Call a func to set an exception?
LI(SCRATCH2, crashHandler_);
JALR(R_ZERO, SCRATCH2, 0);
FlushIcache();
return true;
}
static u32 DoIRInst(uint64_t value) {
IRInst inst;
memcpy(&inst, &value, sizeof(inst));
return IRInterpret(currentMIPS, &inst, 1);
}
void RiscVJit::CompileIRInst(IRInst inst) {
// For now, we're gonna do it the slow and ugly way.
uint64_t value;
memcpy(&value, &inst, sizeof(inst));
LI(X10, value, SCRATCH2);
SaveStaticRegisters();
QuickCallFunction(SCRATCH2, &DoIRInst);
LoadStaticRegisters();
// Result in X10 aka SCRATCH1.
_assert_(X10 == SCRATCH1);
if (BInRange(dispatcherPCInSCRATCH1_)) {
BNE(X10, R_ZERO, dispatcherPCInSCRATCH1_);
} else {
FixupBranch skip = BEQ(X10, R_ZERO);
LI(SCRATCH2, dispatcherPCInSCRATCH1_);
JALR(R_ZERO, SCRATCH2, 0);
SetJumpTarget(skip);
}
}
bool RiscVJit::DescribeCodePtr(const u8 *ptr, std::string &name) {
// TODO: Describe for debugging / profiling.
return false;
// Used in disassembly viewer.
if (ptr == dispatcher_) {
name = "dispatcher";
} else if (ptr == dispatcherPCInSCRATCH1_) {
name = "dispatcher (PC in SCRATCH1)";
} else if (ptr == dispatcherNoCheck_) {
name = "dispatcherNoCheck";
} else if (ptr == enterDispatcher_) {
name = "enterDispatcher";
} else if (!IsInSpace(ptr)) {
return false;
} else {
uintptr_t uptr = (uintptr_t)ptr;
int block_num = -1;
for (int i = 0; i < MAX_ALLOWED_JIT_BLOCKS; ++i) {
uintptr_t blockptr = (uintptr_t)blockStartAddrs_[i];
// Out of allocated blocks.
if (uptr == 0)
break;
if (uptr >= blockptr)
block_num = i;
if (uptr < blockptr)
break;
}
if (block_num == -1) {
name = "(unknown or deleted block)";
return true;
}
const IRBlock *block = blocks_.GetBlock(block_num);
if (block) {
u32 start = 0, size = 0;
block->GetRange(start, size);
name = StringFromFormat("(block %d at %08x)", block_num, start);
return true;
}
return false;
}
return true;
}
bool RiscVJit::CodeInRange(const u8 *ptr) const {
@ -49,18 +172,15 @@ bool RiscVJit::CodeInRange(const u8 *ptr) const {
}
bool RiscVJit::IsAtDispatchFetch(const u8 *ptr) const {
// TODO
return false;
return ptr == dispatcherFetch_;
}
const u8 *RiscVJit::GetDispatcher() const {
// TODO
return nullptr;
return dispatcher_;
}
const u8 *RiscVJit::GetCrashHandler() const {
// TODO: Implement a crash handler
return nullptr;
return crashHandler_;
}
void RiscVJit::ClearCache() {
@ -68,12 +188,51 @@ void RiscVJit::ClearCache() {
ClearCodeSpace(jitStartOffset_);
FlushIcacheSection(region + jitStartOffset_, region + region_size - jitStartOffset_);
memset(blockStartAddrs_, 0, sizeof(blockStartAddrs_[0]) * MAX_ALLOWED_JIT_BLOCKS);
}
void RiscVJit::UpdateFCR31() {
IRJit::UpdateFCR31();
// TODO: Handle rounding modes.
// TODO: Handle rounding modes?
}
void RiscVJit::RestoreRoundingMode(bool force) {
// TODO: Could maybe skip if not hasSetRounding? But that's on IRFrontend...
FSRMI(Round::NEAREST_EVEN);
}
void RiscVJit::ApplyRoundingMode(bool force) {
// TODO: Also could maybe sometimes skip?
//QuickCallFunction(SCRATCH2, applyRoundingMode_);
}
void RiscVJit::MovFromPC(RiscVGen::RiscVReg r) {
LWU(r, CTXREG, offsetof(MIPSState, pc));
}
void RiscVJit::MovToPC(RiscVGen::RiscVReg r) {
SW(r, CTXREG, offsetof(MIPSState, pc));
}
void RiscVJit::SaveStaticRegisters() {
// TODO
//if (jo.useStaticAlloc) {
// QuickCallFunction(SCRATCH2, saveStaticRegisters_);
//} else {
// Inline the single operation
SW(DOWNCOUNTREG, CTXREG, offsetof(MIPSState, downcount));
//}
}
void RiscVJit::LoadStaticRegisters() {
// TODO
//if (jo.useStaticAlloc) {
// QuickCallFunction(SCRATCH2, loadStaticRegisters_);
//} else {
LW(DOWNCOUNTREG, CTXREG, offsetof(MIPSState, downcount));
//}
}
} // namespace MIPSComp

View File

@ -17,14 +17,19 @@
#pragma once
#include <string>
#include <vector>
#include "Common/RiscVEmitter.h"
#include "Core/MIPS/IR/IRJit.h"
#include "Core/MIPS/JitCommon/JitState.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
namespace MIPSComp {
class RiscVJit : public RiscVGen::RiscVCodeBlock, public IRJit {
public:
RiscVJit(MIPSState *mipsState);
~RiscVJit();
void RunLoopUntil(u64 globalticks) override;
@ -42,12 +47,33 @@ public:
protected:
bool CompileBlock(u32 em_address, std::vector<IRInst> &instructions, u32 &mipsBytes, bool preload) override;
void CompileIRInst(IRInst inst);
private:
void GenerateFixedCode(const JitOptions &jo);
void RestoreRoundingMode(bool force = false);
void ApplyRoundingMode(bool force = false);
void MovFromPC(RiscVGen::RiscVReg r);
void MovToPC(RiscVGen::RiscVReg r);
void SaveStaticRegisters();
void LoadStaticRegisters();
const u8 *enterDispatcher_ = nullptr;
const u8 *outerLoop_ = nullptr;
const u8 *outerLoopPCInSCRATCH1_ = nullptr;
const u8 *dispatcherCheckCoreState_ = nullptr;
const u8 *dispatcherPCInSCRATCH1_ = nullptr;
const u8 *dispatcher_ = nullptr;
const u8 *dispatcherNoCheck_ = nullptr;
const u8 *dispatcherFetch_ = nullptr;
const u8 *crashHandler_ = nullptr;
int jitStartOffset_ = 0;
const u8 **blockStartAddrs_ = nullptr;
};
} // namespace MIPSComp

View File

@ -0,0 +1,35 @@
// Copyright (c) 2023- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "Common/RiscVEmitter.h"
namespace RiscVJitConstants {
// Note: we don't support 32-bit or 128-bit CPUs currently.
constexpr int XLEN = 64;
const RiscVGen::RiscVReg DOWNCOUNTREG = RiscVGen::X24;
const RiscVGen::RiscVReg JITBASEREG = RiscVGen::X25;
const RiscVGen::RiscVReg CTXREG = RiscVGen::X26;
const RiscVGen::RiscVReg MEMBASEREG = RiscVGen::X27;
// TODO: Experiment. X7-X13 are compressed regs. X8/X9 are saved so nice for static alloc, though.
const RiscVGen::RiscVReg SCRATCH1 = RiscVGen::X10;
const RiscVGen::RiscVReg SCRATCH2 = RiscVGen::X11;
} // namespace RiscVJitConstants