mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-12-14 08:59:47 +00:00
riscv: Implement load and store ops.
This commit is contained in:
parent
c2da7d18bb
commit
165169eb31
@ -34,16 +34,82 @@ namespace MIPSComp {
|
||||
using namespace RiscVGen;
|
||||
using namespace RiscVJitConstants;
|
||||
|
||||
void RiscVJit::SetScratch1ToSrc1Address(IRReg src1) {
|
||||
gpr.MapReg(src1);
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
SLLIW(SCRATCH1, gpr.R(src1), 2);
|
||||
SRLIW(SCRATCH1, SCRATCH1, 2);
|
||||
ADD(SCRATCH1, SCRATCH1, MEMBASEREG);
|
||||
#else
|
||||
// Clear the top bits to be safe.
|
||||
if (cpu_info.RiscV_Zba) {
|
||||
ADD_UW(SCRATCH1, gpr.R(src1), MEMBASEREG);
|
||||
} else {
|
||||
_assert_(XLEN == 64);
|
||||
SLLI(SCRATCH1, gpr.R(src1), 32);
|
||||
SRLI(SCRATCH1, SCRATCH1, 32);
|
||||
ADD(SCRATCH1, SCRATCH1, MEMBASEREG);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t RiscVJit::AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t constant) {
|
||||
if (constant < -2048 || constant > 2047) {
|
||||
LI(SCRATCH2, constant);
|
||||
ADD(SCRATCH1, *reg, SCRATCH2);
|
||||
*reg = SCRATCH1;
|
||||
return 0;
|
||||
}
|
||||
return constant;
|
||||
}
|
||||
|
||||
void RiscVJit::CompIR_Load(IRInst inst) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
gpr.SpillLock(inst.dest, inst.src1);
|
||||
RiscVReg addrReg = INVALID_REG;
|
||||
if (inst.src1 == MIPS_REG_ZERO) {
|
||||
// This will get changed by AdjustForAddressOffset.
|
||||
addrReg = MEMBASEREG;
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if (jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
addrReg = SCRATCH1;
|
||||
}
|
||||
// If they're the same, MapReg may subtract MEMBASEREG, so just mark dirty.
|
||||
if (inst.dest == inst.src1)
|
||||
gpr.MarkDirty(gpr.R(inst.dest));
|
||||
else
|
||||
gpr.MapReg(inst.dest, MAP_NOINIT);
|
||||
gpr.ReleaseSpillLock(inst.dest, inst.src1);
|
||||
|
||||
s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);
|
||||
|
||||
// TODO: Safe memory? Or enough to have crash handler + validate?
|
||||
|
||||
switch (inst.op) {
|
||||
case IROp::Load8:
|
||||
LBU(gpr.R(inst.dest), addrReg, imm);
|
||||
break;
|
||||
|
||||
case IROp::Load8Ext:
|
||||
LB(gpr.R(inst.dest), addrReg, imm);
|
||||
break;
|
||||
|
||||
case IROp::Load16:
|
||||
LHU(gpr.R(inst.dest), addrReg, imm);
|
||||
break;
|
||||
|
||||
case IROp::Load16Ext:
|
||||
LH(gpr.R(inst.dest), addrReg, imm);
|
||||
break;
|
||||
|
||||
case IROp::Load32:
|
||||
CompIR_Generic(inst);
|
||||
LWU(gpr.R(inst.dest), addrReg, imm);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -98,11 +164,40 @@ void RiscVJit::CompIR_VecLoad(IRInst inst) {
|
||||
void RiscVJit::CompIR_Store(IRInst inst) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
gpr.SpillLock(inst.src3, inst.src1);
|
||||
RiscVReg addrReg = INVALID_REG;
|
||||
if (inst.src1 == MIPS_REG_ZERO) {
|
||||
// This will get changed by AdjustForAddressOffset.
|
||||
addrReg = MEMBASEREG;
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if ((jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
addrReg = SCRATCH1;
|
||||
}
|
||||
RiscVReg valueReg = gpr.TryMapTempImm(inst.src3);
|
||||
if (valueReg == INVALID_REG)
|
||||
valueReg = gpr.MapReg(inst.src3);
|
||||
gpr.ReleaseSpillLock(inst.src3, inst.src1);
|
||||
|
||||
s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);
|
||||
|
||||
// TODO: Safe memory? Or enough to have crash handler + validate?
|
||||
|
||||
switch (inst.op) {
|
||||
case IROp::Store8:
|
||||
SB(valueReg, addrReg, imm);
|
||||
break;
|
||||
|
||||
case IROp::Store16:
|
||||
SH(valueReg, addrReg, imm);
|
||||
break;
|
||||
|
||||
case IROp::Store32:
|
||||
CompIR_Generic(inst);
|
||||
SW(valueReg, addrReg, imm);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -104,6 +104,10 @@ private:
|
||||
void CompIR_VecStore(IRInst inst);
|
||||
void CompIR_ValidateAddress(IRInst inst);
|
||||
|
||||
void SetScratch1ToSrc1Address(IRReg src1);
|
||||
// Modifies SCRATCH regs.
|
||||
int32_t AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t constant);
|
||||
|
||||
RiscVRegCache gpr;
|
||||
|
||||
const u8 *enterDispatcher_ = nullptr;
|
||||
|
@ -169,6 +169,16 @@ void RiscVRegCache::MarkDirty(RiscVReg reg) {
|
||||
// Can't mark X0 dirty.
|
||||
_dbg_assert_(reg > X0 && reg <= X31);
|
||||
ar[reg].isDirty = true;
|
||||
// If reg is written to, pointerification is lost.
|
||||
ar[reg].pointerified = false;
|
||||
if (ar[reg].mipsReg != IRREG_INVALID) {
|
||||
RegStatusMIPS &m = mr[ar[reg].mipsReg];
|
||||
if (m.loc == MIPSLoc::RVREG_AS_PTR || m.loc == MIPSLoc::RVREG_IMM) {
|
||||
m.loc = MIPSLoc::RVREG;
|
||||
m.imm = -1;
|
||||
}
|
||||
_dbg_assert_(m.loc == MIPSLoc::RVREG);
|
||||
}
|
||||
}
|
||||
|
||||
void RiscVRegCache::SetRegImm(RiscVReg reg, u64 imm) {
|
||||
|
Loading…
Reference in New Issue
Block a user