commit
24cb650078
|
@ -145,12 +145,12 @@ struct ARAMInfo
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
static ARAMInfo g_ARAM;
|
static ARAMInfo g_ARAM;
|
||||||
static UDSPControl g_dspState;
|
|
||||||
static AudioDMA g_audioDMA;
|
static AudioDMA g_audioDMA;
|
||||||
static ARAM_DMA g_arDMA;
|
static ARAM_DMA g_arDMA;
|
||||||
static u32 last_mmaddr;
|
static u32 last_mmaddr;
|
||||||
static u32 last_aram_dma_count;
|
static u32 last_aram_dma_count;
|
||||||
static bool instant_dma;
|
static bool instant_dma;
|
||||||
|
UDSPControl g_dspState;
|
||||||
|
|
||||||
union ARAM_Info
|
union ARAM_Info
|
||||||
{
|
{
|
||||||
|
@ -216,6 +216,22 @@ void EnableInstantDMA()
|
||||||
instant_dma = true;
|
instant_dma = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlushInstantDMA(u32 address)
|
||||||
|
{
|
||||||
|
u64 dma_in_progress = DSP::DMAInProgress();
|
||||||
|
if (dma_in_progress != 0)
|
||||||
|
{
|
||||||
|
u32 start_addr = (dma_in_progress >> 32) & Memory::RAM_MASK;
|
||||||
|
u32 end_addr = (dma_in_progress & Memory::RAM_MASK) & 0xffffffff;
|
||||||
|
u32 invalidated_addr = (address & Memory::RAM_MASK) & ~0x1f;
|
||||||
|
|
||||||
|
if (invalidated_addr >= start_addr && invalidated_addr <= end_addr)
|
||||||
|
{
|
||||||
|
DSP::EnableInstantDMA();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DSPEmulator *GetDSPEmulator()
|
DSPEmulator *GetDSPEmulator()
|
||||||
{
|
{
|
||||||
return dsp_emulator;
|
return dsp_emulator;
|
||||||
|
|
|
@ -56,6 +56,8 @@ union UDSPControl
|
||||||
UDSPControl(u16 _Hex = 0) : Hex(_Hex) {}
|
UDSPControl(u16 _Hex = 0) : Hex(_Hex) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern UDSPControl g_dspState;
|
||||||
|
|
||||||
void Init(bool hle);
|
void Init(bool hle);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
|
@ -78,5 +80,6 @@ void UpdateAudioDMA();
|
||||||
void UpdateDSPSlice(int cycles);
|
void UpdateDSPSlice(int cycles);
|
||||||
u64 DMAInProgress();
|
u64 DMAInProgress();
|
||||||
void EnableInstantDMA();
|
void EnableInstantDMA();
|
||||||
|
void FlushInstantDMA(u32 address);
|
||||||
|
|
||||||
}// end of namespace DSP
|
}// end of namespace DSP
|
||||||
|
|
|
@ -340,18 +340,7 @@ void Interpreter::dcbi(UGeckoInstruction _inst)
|
||||||
// The following detects a situation where the game is writing to the dcache at the address being DMA'd. As we do not
|
// The following detects a situation where the game is writing to the dcache at the address being DMA'd. As we do not
|
||||||
// have dcache emulation, invalid data is being DMA'd causing audio glitches. The following code detects this and
|
// have dcache emulation, invalid data is being DMA'd causing audio glitches. The following code detects this and
|
||||||
// enables the DMA to complete instantly before the invalid data is written. Resident Evil 2 & 3 trigger this.
|
// enables the DMA to complete instantly before the invalid data is written. Resident Evil 2 & 3 trigger this.
|
||||||
u64 dma_in_progress = DSP::DMAInProgress();
|
DSP::FlushInstantDMA(address);
|
||||||
if (dma_in_progress != 0)
|
|
||||||
{
|
|
||||||
u32 start_addr = (dma_in_progress >> 32) & Memory::RAM_MASK;
|
|
||||||
u32 end_addr = (dma_in_progress & Memory::RAM_MASK) & 0xffffffff;
|
|
||||||
u32 invalidated_addr = (address & Memory::RAM_MASK) & ~0x1f;
|
|
||||||
|
|
||||||
if (invalidated_addr >= start_addr && invalidated_addr <= end_addr)
|
|
||||||
{
|
|
||||||
DSP::EnableInstantDMA();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dcbst(UGeckoInstruction _inst)
|
void Interpreter::dcbst(UGeckoInstruction _inst)
|
||||||
|
|
|
@ -255,4 +255,6 @@ public:
|
||||||
|
|
||||||
void lmw(UGeckoInstruction inst);
|
void lmw(UGeckoInstruction inst);
|
||||||
void stmw(UGeckoInstruction inst);
|
void stmw(UGeckoInstruction inst);
|
||||||
|
|
||||||
|
void dcbx(UGeckoInstruction inst);
|
||||||
};
|
};
|
||||||
|
|
|
@ -214,11 +214,11 @@ static GekkoOPTemplate table31[] =
|
||||||
{824, &Jit64::srawix}, // srawix
|
{824, &Jit64::srawix}, // srawix
|
||||||
{24, &Jit64::slwx}, // slwx
|
{24, &Jit64::slwx}, // slwx
|
||||||
|
|
||||||
{54, &Jit64::FallBackToInterpreter}, // dcbst
|
{54, &Jit64::dcbx}, // dcbst
|
||||||
{86, &Jit64::FallBackToInterpreter}, // dcbf
|
{86, &Jit64::dcbx}, // dcbf
|
||||||
{246, &Jit64::dcbt }, // dcbtst
|
{246, &Jit64::dcbt}, // dcbtst
|
||||||
{278, &Jit64::dcbt }, // dcbt
|
{278, &Jit64::dcbt}, // dcbt
|
||||||
{470, &Jit64::FallBackToInterpreter}, // dcbi
|
{470, &Jit64::dcbx}, // dcbi
|
||||||
{758, &Jit64::DoNothing}, // dcba
|
{758, &Jit64::DoNothing}, // dcba
|
||||||
{1014, &Jit64::dcbz}, // dcbz
|
{1014, &Jit64::dcbz}, // dcbz
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
#include "Core/HW/DSP.h"
|
||||||
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
#include "Core/PowerPC/Jit64/Jit.h"
|
#include "Core/PowerPC/Jit64/Jit.h"
|
||||||
#include "Core/PowerPC/Jit64/JitAsm.h"
|
#include "Core/PowerPC/Jit64/JitAsm.h"
|
||||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||||
|
@ -290,6 +292,70 @@ void Jit64::lXXx(UGeckoInstruction inst)
|
||||||
gpr.UnlockAllX();
|
gpr.UnlockAllX();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Jit64::dcbx(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
INSTRUCTION_START
|
||||||
|
JITDISABLE(bJITLoadStoreOff);
|
||||||
|
|
||||||
|
X64Reg addr = RSCRATCH;
|
||||||
|
X64Reg value = RSCRATCH2;
|
||||||
|
X64Reg tmp = gpr.GetFreeXReg();
|
||||||
|
gpr.FlushLockX(tmp);
|
||||||
|
|
||||||
|
if (inst.RA && gpr.R(inst.RA).IsSimpleReg() && gpr.R(inst.RB).IsSimpleReg())
|
||||||
|
{
|
||||||
|
LEA(32, addr, MRegSum(gpr.RX(inst.RA), gpr.RX(inst.RB)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MOV(32, R(addr), gpr.R(inst.RB));
|
||||||
|
if (inst.RA)
|
||||||
|
ADD(32, R(addr), gpr.R(inst.RA));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether a JIT cache line needs to be invalidated.
|
||||||
|
LEA(32, value, MScaled(addr, SCALE_8, 0)); // addr << 3 (masks the first 3 bits)
|
||||||
|
SHR(32, R(value), Imm8(3 + 5 + 5)); // >> 5 for cache line size, >> 5 for width of bitset
|
||||||
|
MOV(64, R(tmp), ImmPtr(jit->GetBlockCache()->GetBlockBitSet()));
|
||||||
|
MOV(32, R(value), MComplex(tmp, value, SCALE_4, 0));
|
||||||
|
SHR(32, R(addr), Imm8(5));
|
||||||
|
BT(32, R(value), R(addr));
|
||||||
|
|
||||||
|
FixupBranch c = J_CC(CC_C, true);
|
||||||
|
SwitchToFarCode();
|
||||||
|
SetJumpTarget(c);
|
||||||
|
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
||||||
|
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||||
|
MOV(32, R(ABI_PARAM1), R(addr));
|
||||||
|
SHL(32, R(ABI_PARAM1), Imm8(5));
|
||||||
|
MOV(32, R(ABI_PARAM2), Imm32(32));
|
||||||
|
XOR(32, R(ABI_PARAM3), R(ABI_PARAM3));
|
||||||
|
ABI_CallFunction((void*)JitInterface::InvalidateICache);
|
||||||
|
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||||
|
c = J(true);
|
||||||
|
SwitchToNearCode();
|
||||||
|
SetJumpTarget(c);
|
||||||
|
|
||||||
|
// dcbi
|
||||||
|
if (inst.SUBOP10 == 470)
|
||||||
|
{
|
||||||
|
// Flush DSP DMA if DMAState bit is set
|
||||||
|
TEST(16, M(&DSP::g_dspState), Imm16(1 << 9));
|
||||||
|
c = J_CC(CC_NZ, true);
|
||||||
|
SwitchToFarCode();
|
||||||
|
SetJumpTarget(c);
|
||||||
|
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||||
|
SHL(32, R(addr), Imm8(5));
|
||||||
|
ABI_CallFunctionR((void*)DSP::FlushInstantDMA, addr);
|
||||||
|
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||||
|
c = J(true);
|
||||||
|
SwitchToNearCode();
|
||||||
|
SetJumpTarget(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpr.UnlockAllX();
|
||||||
|
}
|
||||||
|
|
||||||
void Jit64::dcbt(UGeckoInstruction inst)
|
void Jit64::dcbt(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
|
|
@ -60,14 +60,15 @@ typedef void (*CompiledCode)();
|
||||||
// implementation of std::bitset is slow.
|
// implementation of std::bitset is slow.
|
||||||
class ValidBlockBitSet final
|
class ValidBlockBitSet final
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
VALID_BLOCK_MASK_SIZE = 0x20000000 / 32,
|
VALID_BLOCK_MASK_SIZE = 0x20000000 / 32,
|
||||||
VALID_BLOCK_ALLOC_ELEMENTS = VALID_BLOCK_MASK_SIZE / 32
|
VALID_BLOCK_ALLOC_ELEMENTS = VALID_BLOCK_MASK_SIZE / 32
|
||||||
};
|
};
|
||||||
|
// Directly accessed by Jit64.
|
||||||
std::unique_ptr<u32[]> m_valid_block;
|
std::unique_ptr<u32[]> m_valid_block;
|
||||||
|
|
||||||
public:
|
|
||||||
ValidBlockBitSet()
|
ValidBlockBitSet()
|
||||||
{
|
{
|
||||||
m_valid_block.reset(new u32[VALID_BLOCK_ALLOC_ELEMENTS]);
|
m_valid_block.reset(new u32[VALID_BLOCK_ALLOC_ELEMENTS]);
|
||||||
|
@ -157,6 +158,11 @@ public:
|
||||||
|
|
||||||
// DOES NOT WORK CORRECTLY WITH INLINING
|
// DOES NOT WORK CORRECTLY WITH INLINING
|
||||||
void InvalidateICache(u32 address, const u32 length, bool forced);
|
void InvalidateICache(u32 address, const u32 length, bool forced);
|
||||||
|
|
||||||
|
u32* GetBlockBitSet() const
|
||||||
|
{
|
||||||
|
return valid_block.m_valid_block.get();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// x86 BlockCache
|
// x86 BlockCache
|
||||||
|
|
Loading…
Reference in New Issue