mirror of https://github.com/PCSX2/pcsx2.git
Updated savestates to version 0x12 (0x02 VTLB) -- added a couple missing SIF vars and added support for cottonvibes' new VIregs structure format in r576.
Fixed a few bugs in the GS-on-Close recovery system. It should work more and crash less now. Restructured the entire initialization process of Ps2 memory and cpu resources. All emulation system resources are allocated when the app first starts now, giving Pcsx2 the best possible chance to allocate needed Virtual Memory resources. And *Hopefully* this resolves some memory corruption issues that have persisted since r488. Added several new functions to System.cpp as partof the new API: SysAllocateMem(), SysAllocateDynarecs(), etc. Created some new files: VU0microInterp.cpp and VU1microInterp.cpp, and separated the VU cpus into their own "cpu" structure (they used to be grouped in with the R5900, which made it awkward to work with them). Turned off speed optimizations for the WinMain.cpp and WinSysExec.cpp files, due to a compiler bug in MSVC that causes it to completely break codegen for the RunExecute() function. git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@577 a6443dda-0b58-4228-96e9-037be469359c
This commit is contained in:
parent
d6383a4a04
commit
7488e930d4
|
@ -867,6 +867,8 @@ int cdvdReadSector() {
|
|||
|
||||
FreezeMMXRegs(1);
|
||||
|
||||
const u32 madr = HW_DMA3_MADR;
|
||||
|
||||
// if raw dvd sector 'fill in the blanks'
|
||||
if (cdvd.BlockSize == 2064) {
|
||||
// get info on dvd type and layer1 start
|
||||
|
@ -892,40 +894,44 @@ int cdvdReadSector() {
|
|||
lsn += 0x30000;
|
||||
} // ENDLONGIF- Assumed the other dualType is 0.
|
||||
|
||||
PSXMu8(HW_DMA3_MADR+0) = 0x20 | layerNum;
|
||||
PSXMu8(HW_DMA3_MADR+1) = (u8)(lsn >> 16);
|
||||
PSXMu8(HW_DMA3_MADR+2) = (u8)(lsn >> 8);
|
||||
PSXMu8(HW_DMA3_MADR+3) = (u8)(lsn );
|
||||
PSXMu8(madr+0) = 0x20 | layerNum;
|
||||
PSXMu8(madr+1) = (u8)(lsn >> 16);
|
||||
PSXMu8(madr+2) = (u8)(lsn >> 8);
|
||||
PSXMu8(madr+3) = (u8)(lsn );
|
||||
|
||||
// sector IED (not calculated at present)
|
||||
PSXMu8(HW_DMA3_MADR+4) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+5) = 0;
|
||||
PSXMu8(madr+4) = 0;
|
||||
PSXMu8(madr+5) = 0;
|
||||
|
||||
// sector CPR_MAI (not calculated at present)
|
||||
PSXMu8(HW_DMA3_MADR+ 6) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+ 7) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+ 8) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+ 9) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+10) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+11) = 0;
|
||||
PSXMu8(madr+ 6) = 0;
|
||||
PSXMu8(madr+ 7) = 0;
|
||||
PSXMu8(madr+ 8) = 0;
|
||||
PSXMu8(madr+ 9) = 0;
|
||||
PSXMu8(madr+10) = 0;
|
||||
PSXMu8(madr+11) = 0;
|
||||
|
||||
// normal 2048 bytes of sector data
|
||||
memcpy_fast(PSXM(HW_DMA3_MADR+12), cdr.pTransfer, 2048);
|
||||
memcpy_fast(PSXM(madr+12), cdr.pTransfer, 2048);
|
||||
|
||||
// 4 bytes of edc (not calculated at present)
|
||||
PSXMu8(HW_DMA3_MADR+2060) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+2061) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+2062) = 0;
|
||||
PSXMu8(HW_DMA3_MADR+2063) = 0;
|
||||
PSXMu8(madr+2060) = 0;
|
||||
PSXMu8(madr+2061) = 0;
|
||||
PSXMu8(madr+2062) = 0;
|
||||
PSXMu8(madr+2063) = 0;
|
||||
} else {
|
||||
// normal read
|
||||
memcpy_fast(PSXM(HW_DMA3_MADR), cdr.pTransfer, cdvd.BlockSize);
|
||||
memcpy_fast((u8*)PSXM(madr), cdr.pTransfer, cdvd.BlockSize);
|
||||
}
|
||||
// decrypt sector's bytes
|
||||
if(cdvd.decSet)
|
||||
mechaDecryptBytes((unsigned char*)PSXM(HW_DMA3_MADR), cdvd.BlockSize);
|
||||
mechaDecryptBytes((u8*)PSXM(madr), cdvd.BlockSize);
|
||||
|
||||
// SysPrintf("sector %x;%x;%x\n", PSXMu8(HW_DMA3_MADR+0), PSXMu8(HW_DMA3_MADR+1), PSXMu8(HW_DMA3_MADR+2));
|
||||
// Added a clear after memory write .. never seemed to be necessary before but *should*
|
||||
// be more correct. (air)
|
||||
psxCpu->Clear( madr, cdvd.BlockSize/4);
|
||||
|
||||
// SysPrintf("sector %x;%x;%x\n", PSXMu8(madr+0), PSXMu8(madr+1), PSXMu8(madr+2));
|
||||
|
||||
HW_DMA3_BCR_H16-= (cdvd.BlockSize / (HW_DMA3_BCR_L16*4));
|
||||
HW_DMA3_MADR+= cdvd.BlockSize;
|
||||
|
|
|
@ -951,7 +951,7 @@ void cdrReset() {
|
|||
void SaveState::cdrFreeze() {
|
||||
Freeze(cdr);
|
||||
|
||||
// Alrighty! This code ised to, for some reason, recalculate the pTransfer value
|
||||
// Alrighty! This code used to, for some reason, recalculate the pTransfer value
|
||||
// even though it's being saved as part of the cdr struct. Probably a backwards
|
||||
// compat fix with an earlier save version.
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ namespace Console
|
|||
|
||||
va_list list;
|
||||
va_start(list,dummy);
|
||||
_WriteLn( Color_Yellow, fmt, list );
|
||||
_WriteLn( Color_Green, fmt, list );
|
||||
va_end(list);
|
||||
return false;
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ namespace Console
|
|||
// Newline is automatically appended.
|
||||
bool Status( const string& fmt )
|
||||
{
|
||||
WriteLn( Color_Yellow, fmt );
|
||||
WriteLn( Color_Green, fmt );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "Common.h"
|
||||
#include "PsxCommon.h"
|
||||
#include "GS.h"
|
||||
#include "VU.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
|
@ -263,8 +263,8 @@ u32 UpdateVSyncRate()
|
|||
cpuRcntSet();
|
||||
|
||||
// Initialize VU Skip Stuff...
|
||||
assert(Cpu != NULL && Cpu->ExecuteVU1Block != NULL );
|
||||
s_prevExecuteVU1Block = Cpu->ExecuteVU1Block;
|
||||
assert(CpuVU1 != NULL && CpuVU1->ExecuteBlock != NULL );
|
||||
s_prevExecuteVU1Block = CpuVU1->ExecuteBlock;
|
||||
g_vu1SkipCount = 0;
|
||||
|
||||
return (u32)m_iTicks;
|
||||
|
@ -442,12 +442,12 @@ static __forceinline void VSyncEnd(u32 sCycle)
|
|||
{
|
||||
gsPostVsyncEnd( false );
|
||||
AtomicDecrement( g_vu1SkipCount );
|
||||
Cpu->ExecuteVU1Block = DummyExecuteVU1Block;
|
||||
CpuVU1->ExecuteBlock = DummyExecuteVU1Block;
|
||||
}
|
||||
else
|
||||
{
|
||||
gsPostVsyncEnd( true );
|
||||
Cpu->ExecuteVU1Block = s_prevExecuteVU1Block;
|
||||
CpuVU1->ExecuteBlock = s_prevExecuteVU1Block;
|
||||
}
|
||||
|
||||
hwIntcIrq(3); // HW Irq
|
||||
|
|
|
@ -185,7 +185,6 @@ void gsSetVideoRegionType( u32 isPal )
|
|||
}
|
||||
|
||||
|
||||
// Initializes MultiGS ringbuffer and registers.
|
||||
// Make sure framelimiter options are in sync with the plugin's capabilities.
|
||||
void gsInit()
|
||||
{
|
||||
|
@ -224,19 +223,20 @@ s32 gsOpen()
|
|||
m_gsOpened = !GSopen((void *)&pDsp, "PCSX2", 0);
|
||||
}
|
||||
|
||||
if( m_gsOpened )
|
||||
/*if( m_gsOpened )
|
||||
{
|
||||
gsOnModeChanged(
|
||||
(Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC,
|
||||
UpdateVSyncRate()
|
||||
);
|
||||
}
|
||||
}*/
|
||||
return !m_gsOpened;
|
||||
}
|
||||
|
||||
void gsClose()
|
||||
{
|
||||
if( !m_gsOpened ) return;
|
||||
m_gsOpened = false;
|
||||
|
||||
// Throw an assert if our multigs setting and mtgsThread status
|
||||
// aren't synched. It shouldn't break the code anyway but it's a
|
||||
|
@ -249,8 +249,6 @@ void gsClose()
|
|||
}
|
||||
else
|
||||
GSclose();
|
||||
|
||||
m_gsOpened = false;
|
||||
}
|
||||
|
||||
void gsReset()
|
||||
|
|
26
pcsx2/Hw.cpp
26
pcsx2/Hw.cpp
|
@ -33,24 +33,13 @@ using namespace Dynarec::R5900;
|
|||
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
u8 *psH; // hw mem
|
||||
u16 *psHW;
|
||||
u32 *psHL;
|
||||
u64 *psHD;
|
||||
#endif
|
||||
|
||||
int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX
|
||||
int rdram_sdevid = 0;
|
||||
|
||||
int hwInit() {
|
||||
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
psH = (u8*)_aligned_malloc(0x00010000, 16);
|
||||
if (psH == NULL) {
|
||||
Msgbox::Alert("Error allocating memory");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void hwInit()
|
||||
{
|
||||
gsInit();
|
||||
vif0Init();
|
||||
vif1Init();
|
||||
|
@ -58,21 +47,18 @@ int hwInit() {
|
|||
sifInit();
|
||||
sprInit();
|
||||
ipuInit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hwShutdown() {
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
if (psH == NULL) return;
|
||||
_aligned_free(psH); psH = NULL;
|
||||
#endif
|
||||
ipuShutdown();
|
||||
}
|
||||
|
||||
void hwReset()
|
||||
{
|
||||
memset(PS2MEM_HW+0x2000, 0, 0x0000e000);
|
||||
hwInit();
|
||||
|
||||
memset(PS2MEM_HW, 0, Ps2MemSize::Hardware);
|
||||
//memset(PS2MEM_HW+0x2000, 0, 0x0000e000);
|
||||
|
||||
psHu32(0xf520) = 0x1201;
|
||||
psHu32(0xf260) = 0x1D000060;
|
||||
|
|
|
@ -24,9 +24,6 @@
|
|||
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
extern u8 *psH; // hw mem
|
||||
extern u16 *psHW;
|
||||
extern u32 *psHL;
|
||||
extern u64 *psHD;
|
||||
#endif
|
||||
|
||||
#define psHs8(mem) (*(s8 *)&PS2MEM_HW[(mem) & 0xffff])
|
||||
|
@ -359,7 +356,7 @@ static __forceinline void *dmaGetAddr(u32 addr) {
|
|||
|
||||
#endif
|
||||
|
||||
int hwInit();
|
||||
void hwInit();
|
||||
void hwReset();
|
||||
void hwShutdown();
|
||||
|
||||
|
|
|
@ -980,8 +980,8 @@ void MTSAH() {
|
|||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
void intInit() {
|
||||
//detect cpu for use the optimaze asm code
|
||||
void intAlloc() {
|
||||
// fixme : detect cpu for use the optimaze asm code
|
||||
}
|
||||
|
||||
void intReset() {
|
||||
|
@ -998,60 +998,6 @@ static void intExecuteBlock() {
|
|||
while (!branch2) execI();
|
||||
}
|
||||
|
||||
void intExecuteVU0Block() {
|
||||
int i;
|
||||
|
||||
#ifdef _DEBUG
|
||||
int prevbranch;
|
||||
#endif
|
||||
|
||||
for (i = 128; i--;) {
|
||||
|
||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0)
|
||||
break;
|
||||
|
||||
#ifdef _DEBUG
|
||||
prevbranch = vu0branch;
|
||||
#endif
|
||||
vu0Exec(&VU0);
|
||||
}
|
||||
|
||||
if( i < 0 && (VU0.branch || VU0.ebit) ) {
|
||||
// execute one more
|
||||
vu0Exec(&VU0);
|
||||
}
|
||||
}
|
||||
|
||||
void intExecuteVU1Block() {
|
||||
|
||||
int i;
|
||||
#ifdef _DEBUG
|
||||
int prevbranch;
|
||||
#endif
|
||||
|
||||
for (i = 128; i--;) {
|
||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0)
|
||||
break;
|
||||
|
||||
#ifdef _DEBUG
|
||||
prevbranch = vu1branch;
|
||||
#endif
|
||||
vu1Exec(&VU1);
|
||||
}
|
||||
|
||||
if( i < 0 && (VU1.branch || VU1.ebit) ) {
|
||||
// execute one more
|
||||
vu1Exec(&VU1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void intEnableVU0micro(int enable) {
|
||||
}
|
||||
|
||||
void intEnableVU1micro(int enable) {
|
||||
}
|
||||
|
||||
void intStep() {
|
||||
execI();
|
||||
}
|
||||
|
@ -1059,12 +1005,6 @@ void intStep() {
|
|||
void intClear(u32 Addr, u32 Size) {
|
||||
}
|
||||
|
||||
void intVU0Clear(u32 Addr, u32 Size) {
|
||||
}
|
||||
|
||||
void intVU1Clear(u32 Addr, u32 Size) {
|
||||
}
|
||||
|
||||
void intShutdown() {
|
||||
}
|
||||
|
||||
|
@ -1073,18 +1013,12 @@ void intShutdown() {
|
|||
using namespace Interpreter;
|
||||
|
||||
R5900cpu intCpu = {
|
||||
intInit,
|
||||
intAlloc,
|
||||
intReset,
|
||||
intStep,
|
||||
intExecute,
|
||||
intExecuteBlock,
|
||||
intExecuteVU0Block,
|
||||
intExecuteVU1Block,
|
||||
intEnableVU0micro,
|
||||
intEnableVU1micro,
|
||||
intClear,
|
||||
intVU0Clear,
|
||||
intVU1Clear,
|
||||
intShutdown
|
||||
};
|
||||
|
||||
|
|
|
@ -100,18 +100,18 @@ u32 GIFPath::GetReg()
|
|||
return regs[curreg];
|
||||
}
|
||||
|
||||
static void _mtgsFreezeGIF( SaveState& state, GIFPath paths[3] )
|
||||
static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] )
|
||||
{
|
||||
for(int i=0; i<3; i++ )
|
||||
{
|
||||
state.Freeze( paths[i].tag );
|
||||
|
||||
// Earlier versions had an extra u32 in the tag struct:
|
||||
state.Freeze( paths[i].curreg );
|
||||
}
|
||||
|
||||
for(int i=0; i<3; i++ )
|
||||
{
|
||||
state.Freeze( paths[i].regs );
|
||||
}
|
||||
}
|
||||
|
||||
void SaveState::mtgsFreeze()
|
||||
|
|
387
pcsx2/Memory.cpp
387
pcsx2/Memory.cpp
|
@ -37,10 +37,6 @@ BIOS
|
|||
0xBFC00000 - 0xBFFFFFFF un-cached
|
||||
*/
|
||||
|
||||
//////////
|
||||
// Rewritten by zerofrog(@gmail.com) to add os virtual memory
|
||||
//////////
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#pragma warning(disable:4799) // No EMMS at end of function
|
||||
|
@ -161,7 +157,7 @@ static void ReserveExtraMem( void* base, uint size )
|
|||
throw vm_alloc_failed_exception( base, size, pExtraMem);
|
||||
}
|
||||
|
||||
int memInit() {
|
||||
void memAlloc() {
|
||||
|
||||
int i;
|
||||
LPVOID pExtraMem = NULL;
|
||||
|
@ -177,12 +173,12 @@ int memInit() {
|
|||
VIRTUAL_ALLOC(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READONLY);
|
||||
VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READONLY);
|
||||
VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READONLY);
|
||||
PHYSICAL_ALLOC(PS2MEM_SCRATCH, 0x00010000, s_psS);
|
||||
PHYSICAL_ALLOC(PS2MEM_HW, 0x00010000, s_psHw);
|
||||
PHYSICAL_ALLOC(PS2MEM_PSX, 0x00200000, s_psxM);
|
||||
PHYSICAL_ALLOC(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS);
|
||||
PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
|
||||
PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
|
||||
PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
|
||||
|
||||
VIRTUAL_ALLOC(PS2MEM_PSXHW, 0x00010000, PAGE_READWRITE);
|
||||
VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PAGE_READWRITE);
|
||||
//VIRTUAL_ALLOC(PS2MEM_PSXHW2, 0x00010000, PAGE_READWRITE);
|
||||
VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PAGE_NOACCESS);
|
||||
VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PAGE_READWRITE);
|
||||
|
@ -197,7 +193,7 @@ int memInit() {
|
|||
ReserveExtraMem( PS2MEM_BASE+Ps2MemSize::Base, 0x0e000000 );
|
||||
|
||||
// reserve left over psx mem
|
||||
ReserveExtraMem( PS2MEM_PSX+0x00200000, 0x00600000 );
|
||||
ReserveExtraMem( PS2MEM_PSX+Ps2MemSize::IopRam, 0x00600000 );
|
||||
|
||||
// reserve gs mem
|
||||
ReserveExtraMem( PS2MEM_BASE+0x20000000, 0x10000000 );
|
||||
|
@ -206,29 +202,10 @@ int memInit() {
|
|||
VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PAGE_READWRITE);
|
||||
|
||||
// alloc virtual mappings
|
||||
if( memLUT == NULL )
|
||||
memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(PSMEMORYMAP), 16);
|
||||
if( memLUT == NULL )
|
||||
throw Exception::OutOfMemory( "Out of memory when allocating memLUT." );
|
||||
|
||||
memset(memLUT, 0, sizeof(PSMEMORYMAP)*0x100000);
|
||||
for (i=0; i<0x02000; i++) memLUT[i + 0x00000] = initMemoryMap(&s_psM.aPFNs[i], &s_psM.aVFNs[i]);
|
||||
for (i=2; i<0x00010; i++) memLUT[i + 0x10000] = initMemoryMap(&s_psHw.aPFNs[i], &s_psHw.aVFNs[i]);
|
||||
for (i=0; i<0x00800; i++) memLUT[i + 0x1c000] = initMemoryMap(&s_psxM.aPFNs[(i & 0x1ff)], &s_psxM.aVFNs[(i & 0x1ff)]);
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x11000] = initMemoryMap(&s_psVuMem.aPFNs[0], &s_psVuMem.aVFNs[0]);
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x11004] = initMemoryMap(&s_psVuMem.aPFNs[1], &s_psVuMem.aVFNs[1]);
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x11008] = initMemoryMap(&s_psVuMem.aPFNs[4+i], &s_psVuMem.aVFNs[4+i]);
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x1100c] = initMemoryMap(&s_psVuMem.aPFNs[8+i], &s_psVuMem.aVFNs[8+i]);
|
||||
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x50000] = initMemoryMap(&s_psS.aPFNs[i], &s_psS.aVFNs[i]);
|
||||
|
||||
// map to other modes
|
||||
memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(PSMEMORYMAP));
|
||||
memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(PSMEMORYMAP));
|
||||
|
||||
if(psxInit() == -1)
|
||||
Exception::OutOfMemory( "IOP memory allocations failed" );
|
||||
|
||||
return 0;
|
||||
throw Exception::OutOfMemory( "memAlloc VM > failed to allocated memory for LUT." );
|
||||
}
|
||||
catch( vm_alloc_failed_exception& ex )
|
||||
{
|
||||
|
@ -244,28 +221,28 @@ int memInit() {
|
|||
{
|
||||
memShutdown();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void memShutdown()
|
||||
{
|
||||
// Free up the "extra mem" reservations
|
||||
VirtualFree(PS2MEM_BASE+Ps2MemSize::Base, 0, MEM_RELEASE);
|
||||
VirtualFree(PS2MEM_PSX+0x00200000, 0, MEM_RELEASE);
|
||||
VirtualFree(PS2MEM_BASE+0x20000000, 0, MEM_RELEASE);
|
||||
VirtualFree(PS2MEM_PSX+Ps2MemSize::IopRam, 0, MEM_RELEASE);
|
||||
VirtualFree(PS2MEM_BASE+0x20000000, 0, MEM_RELEASE); // GS reservation
|
||||
|
||||
PHYSICAL_FREE(PS2MEM_BASE, Ps2MemSize::Base, s_psM);
|
||||
SysMunmap(PS2MEM_ROM, Ps2MemSize::Rom);
|
||||
SysMunmap(PS2MEM_ROM1, Ps2MemSize::Rom1);
|
||||
SysMunmap(PS2MEM_ROM2, Ps2MemSize::Rom2);
|
||||
SysMunmap(PS2MEM_EROM, Ps2MemSize::ERom);
|
||||
PHYSICAL_FREE(PS2MEM_SCRATCH, 0x00010000, s_psS);
|
||||
PHYSICAL_FREE(PS2MEM_HW, 0x00010000, s_psHw);
|
||||
PHYSICAL_FREE(PS2MEM_PSX, 0x00200000, s_psxM);
|
||||
PHYSICAL_FREE(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS);
|
||||
PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
|
||||
PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
|
||||
PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
|
||||
|
||||
SysMunmap(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs
|
||||
|
||||
SysMunmap(PS2MEM_PSXHW, 0x00010000);
|
||||
SysMunmap(PS2MEM_PSXHW, Ps2MemSize::IopHardware);
|
||||
//SysMunmap(PS2MEM_PSXHW2, 0x00010000);
|
||||
SysMunmap(PS2MEM_PSXHW4, 0x00010000);
|
||||
SysMunmap(PS2MEM_GS, 0x00002000);
|
||||
|
@ -465,7 +442,7 @@ DefaultHandler:
|
|||
|
||||
uptr *memLUT = NULL;
|
||||
|
||||
int memInit()
|
||||
void memAlloc()
|
||||
{
|
||||
int i;
|
||||
LPVOID pExtraMem = NULL;
|
||||
|
@ -480,11 +457,11 @@ int memInit()
|
|||
VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PROT_READ);
|
||||
VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PROT_READ);
|
||||
PHYSICAL_ALLOC(PS2MEM_SCRATCH, 0x00010000, s_psS);
|
||||
PHYSICAL_ALLOC(PS2MEM_HW, 0x00010000, s_psHw);
|
||||
PHYSICAL_ALLOC(PS2MEM_PSX, 0x00200000, s_psxM);
|
||||
PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
|
||||
PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
|
||||
PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
|
||||
|
||||
VIRTUAL_ALLOC(PS2MEM_PSXHW, 0x00010000, PROT_READ|PROT_WRITE);
|
||||
VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PROT_READ|PROT_WRITE);
|
||||
VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PROT_NONE);
|
||||
VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PROT_READ|PROT_WRITE);
|
||||
VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PROT_NONE);
|
||||
|
@ -497,26 +474,6 @@ int memInit()
|
|||
// special addrs mmap
|
||||
VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PROT_READ|PROT_WRITE);
|
||||
|
||||
// alloc virtual mappings
|
||||
memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(uptr), 16);
|
||||
memset(memLUT, 0, sizeof(uptr)*0x100000);
|
||||
for (i=0; i<0x02000; i++) memLUT[i + 0x00000] = PS2MEM_BASE+(i<<12);
|
||||
for (i=2; i<0x00010; i++) memLUT[i + 0x10000] = PS2MEM_BASE+0x10000000+(i<<12);
|
||||
for (i=0; i<0x00800; i++) memLUT[i + 0x1c000] = PS2MEM_BASE+0x1c000000+(i<<12);
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x11000] = PS2MEM_VU0MICRO;
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x11004] = PS2MEM_VU0MEM;
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x11008] = PS2MEM_VU1MICRO+(i<<12);
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x1100c] = PS2MEM_VU1MEM+(i<<12);
|
||||
|
||||
for (i=0; i<0x00004; i++) memLUT[i + 0x50000] = PS2MEM_SCRATCH+(i<<12);
|
||||
|
||||
// map to other modes
|
||||
memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(uptr));
|
||||
memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(uptr));
|
||||
|
||||
if (psxInit() == -1)
|
||||
goto eCleanupAndExit;
|
||||
|
||||
eCleanupAndExit:
|
||||
memShutdown();
|
||||
return -1;
|
||||
|
@ -533,13 +490,13 @@ void memShutdown()
|
|||
VIRTUAL_FREE(PS2MEM_ROM2, Ps2MemSize::Rom2);
|
||||
VIRTUAL_FREE(PS2MEM_EROM, Ps2MemSize::ERom);
|
||||
PHYSICAL_FREE(PS2MEM_SCRATCH, 0x00010000, s_psS);
|
||||
PHYSICAL_FREE(PS2MEM_HW, 0x00010000, s_psHw);
|
||||
PHYSICAL_FREE(PS2MEM_PSX, 0x00800000, s_psxM);
|
||||
PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
|
||||
PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
|
||||
PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
|
||||
|
||||
VIRTUAL_FREE(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs
|
||||
|
||||
VIRTUAL_FREE(PS2MEM_PSXHW, 0x00010000);
|
||||
VIRTUAL_FREE(PS2MEM_PSXHW, Ps2MemSize::IopHardware);
|
||||
VIRTUAL_FREE(PS2MEM_PSXHW4, 0x00010000);
|
||||
VIRTUAL_FREE(PS2MEM_GS, 0x00002000);
|
||||
VIRTUAL_FREE(PS2MEM_DEV9, 0x00010000);
|
||||
|
@ -551,7 +508,7 @@ void memShutdown()
|
|||
|
||||
VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE);
|
||||
|
||||
_aligned_free(memLUT); memLUT = NULL;
|
||||
safe_aligned_free(memLUT);
|
||||
|
||||
// reserve mem
|
||||
if( mmap(PS2MEM_BASE, 0x40000000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) != PS2MEM_BASE ) {
|
||||
|
@ -561,6 +518,30 @@ void memShutdown()
|
|||
|
||||
#endif // _WIN32
|
||||
|
||||
void vm_Reset()
|
||||
{
|
||||
jASSUME( memLUT != NULL );
|
||||
|
||||
memset(memLUT, 0, sizeof(PSMEMORYMAP)*0x100000);
|
||||
for (int i=0; i<0x02000; i++) memLUT[i + 0x00000] = initMemoryMap(&s_psM.aPFNs[i], &s_psM.aVFNs[i]);
|
||||
for (int i=2; i<0x00010; i++) memLUT[i + 0x10000] = initMemoryMap(&s_psHw.aPFNs[i], &s_psHw.aVFNs[i]);
|
||||
for (int i=0; i<0x00800; i++) memLUT[i + 0x1c000] = initMemoryMap(&s_psxM.aPFNs[(i & 0x1ff)], &s_psxM.aVFNs[(i & 0x1ff)]);
|
||||
for (int i=0; i<0x00004; i++)
|
||||
{
|
||||
memLUT[i + 0x11000] = initMemoryMap(&s_psVuMem.aPFNs[0], &s_psVuMem.aVFNs[0]);
|
||||
memLUT[i + 0x11004] = initMemoryMap(&s_psVuMem.aPFNs[1], &s_psVuMem.aVFNs[1]);
|
||||
memLUT[i + 0x11008] = initMemoryMap(&s_psVuMem.aPFNs[4+i], &s_psVuMem.aVFNs[4+i]);
|
||||
memLUT[i + 0x1100c] = initMemoryMap(&s_psVuMem.aPFNs[8+i], &s_psVuMem.aVFNs[8+i]);
|
||||
|
||||
// Yay! Scratchpad mapping! We love the scratchpad.
|
||||
memLUT[i + 0x50000] = initMemoryMap(&s_psS.aPFNs[i], &s_psS.aVFNs[i]);
|
||||
}
|
||||
|
||||
// map to other modes
|
||||
memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(PSMEMORYMAP));
|
||||
memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(PSMEMORYMAP));
|
||||
}
|
||||
|
||||
// Some games read/write between different addrs but same physical memory
|
||||
// this causes major slowdowns because it goes into the exception handler, so use this (zerofrog)
|
||||
u32 VM_RETRANSLATE(u32 mem)
|
||||
|
@ -1298,13 +1279,13 @@ int recMemConstWrite8(u32 mem, int mmreg)
|
|||
if( mem < 0x11004000 ) {
|
||||
PUSH32I(1);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU0);
|
||||
CALLFunc((u32)CpuVU0->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
|
||||
PUSH32I(1);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU1);
|
||||
CALLFunc((u32)CpuVU1->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1379,13 +1360,13 @@ int recMemConstWrite16(u32 mem, int mmreg)
|
|||
if( mem < 0x11004000 ) {
|
||||
PUSH32I(1);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU0);
|
||||
CALLFunc((u32)CpuVU0->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
|
||||
PUSH32I(1);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU1);
|
||||
CALLFunc((u32)CpuVU1->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1456,10 +1437,10 @@ vuwrite:
|
|||
jge vu1write
|
||||
and ecx, 0x3ff8
|
||||
// clear vu0mem
|
||||
mov eax, Cpu
|
||||
mov eax, CpuVU0
|
||||
push 1
|
||||
push ecx
|
||||
call [eax]Cpu.ClearVU0
|
||||
call [eax]CpuVU0.Clear
|
||||
add esp, 8
|
||||
ret
|
||||
|
||||
|
@ -1470,10 +1451,10 @@ vu1write:
|
|||
jge vuend
|
||||
// clear vu1mem
|
||||
and ecx, 0x3ff8
|
||||
mov eax, Cpu
|
||||
mov eax, CpuVU1
|
||||
push 1
|
||||
push ecx
|
||||
call [eax]Cpu.ClearVU1
|
||||
call [eax]CpuVU1.Clear
|
||||
add esp, 8
|
||||
vuend:
|
||||
ret
|
||||
|
@ -1508,13 +1489,13 @@ int recMemConstWrite32(u32 mem, int mmreg)
|
|||
if( mem < 0x11004000 ) {
|
||||
PUSH32I(1);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU0);
|
||||
CALLFunc((u32)CpuVU0->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
|
||||
PUSH32I(1);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU1);
|
||||
CALLFunc((u32)CpuVU1->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1569,10 +1550,10 @@ vuwrite:
|
|||
jge vu1write
|
||||
and ecx, 0x3ff8
|
||||
// clear vu0mem
|
||||
mov eax, Cpu
|
||||
mov eax, CpuVU0
|
||||
push 2
|
||||
push ecx
|
||||
call [eax]Cpu.ClearVU0
|
||||
call [eax]CpuVU0.Clear
|
||||
add esp, 8
|
||||
ret
|
||||
|
||||
|
@ -1583,10 +1564,10 @@ vu1write:
|
|||
jge vuend
|
||||
// clear vu1mem
|
||||
and ecx, 0x3ff8
|
||||
mov eax, Cpu
|
||||
mov eax, CpuVU0
|
||||
push 2
|
||||
push ecx
|
||||
call [eax]Cpu.ClearVU1
|
||||
call [eax]CpuVU1.Clear
|
||||
add esp, 8
|
||||
vuend:
|
||||
ret
|
||||
|
@ -1607,13 +1588,13 @@ int recMemConstWrite64(u32 mem, int mmreg)
|
|||
if( mem < 0x11004000 ) {
|
||||
PUSH32I(2);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU0);
|
||||
CALLFunc((u32)CpuVU0->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
|
||||
PUSH32I(2);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU1);
|
||||
CALLFunc((u32)CpuVU1->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1665,10 +1646,10 @@ vuwrite:
|
|||
jge vu1write
|
||||
and ecx, 0x3ff8
|
||||
// clear vu0mem
|
||||
mov eax, Cpu
|
||||
mov eax, CpuVU0
|
||||
push 4
|
||||
push ecx
|
||||
call [eax]Cpu.ClearVU0
|
||||
call [eax]CpuVU0.Clear
|
||||
add esp, 8
|
||||
ret
|
||||
|
||||
|
@ -1679,10 +1660,10 @@ vu1write:
|
|||
jge vuend
|
||||
// clear vu1mem
|
||||
and ecx, 0x3ff8
|
||||
mov eax, Cpu
|
||||
mov eax, CpuVU1
|
||||
push 4
|
||||
push ecx
|
||||
call [eax]Cpu.ClearVU1
|
||||
call [eax]CpuVU1.Clear
|
||||
add esp, 8
|
||||
vuend:
|
||||
|
||||
|
@ -1743,13 +1724,13 @@ int recMemConstWrite128(u32 mem, int mmreg)
|
|||
if( mem < 0x11004000 ) {
|
||||
PUSH32I(4);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU0);
|
||||
CALLFunc((u32)CpuVU0->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
|
||||
PUSH32I(4);
|
||||
PUSH32I(mem&0x3ff8);
|
||||
CALLFunc((u32)Cpu->ClearVU1);
|
||||
CALLFunc((u32)CpuVU1->Clear);
|
||||
ADD32ItoR(ESP, 8);
|
||||
}
|
||||
return 0;
|
||||
|
@ -2505,6 +2486,9 @@ int __fastcall vuMicroRead128(u32 addr,mem128_t* data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// [TODO] : Profile this code and see how often the VUs get written, and how
|
||||
// often it changes the values being written (invoking a cpuClear).
|
||||
|
||||
template<int vunum>
|
||||
void __fastcall vuMicroWrite8(u32 addr,mem8_t data)
|
||||
{
|
||||
|
@ -2516,9 +2500,9 @@ void __fastcall vuMicroWrite8(u32 addr,mem8_t data)
|
|||
vu->Micro[addr]=data;
|
||||
|
||||
if (vunum==0)
|
||||
Cpu->ClearVU0(addr&(~7),1);
|
||||
CpuVU0->Clear(addr&(~7),1);
|
||||
else
|
||||
Cpu->ClearVU1(addr&(~7),1);
|
||||
CpuVU1->Clear(addr&(~7),1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2533,9 +2517,9 @@ void __fastcall vuMicroWrite16(u32 addr,mem16_t data)
|
|||
*(u16*)&vu->Micro[addr]=data;
|
||||
|
||||
if (vunum==0)
|
||||
Cpu->ClearVU0(addr&(~7),1);
|
||||
CpuVU0->Clear(addr&(~7),1);
|
||||
else
|
||||
Cpu->ClearVU1(addr&(~7),1);
|
||||
CpuVU1->Clear(addr&(~7),1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2550,9 +2534,9 @@ void __fastcall vuMicroWrite32(u32 addr,mem32_t data)
|
|||
*(u32*)&vu->Micro[addr]=data;
|
||||
|
||||
if (vunum==0)
|
||||
Cpu->ClearVU0(addr&(~7),1);
|
||||
CpuVU0->Clear(addr&(~7),1);
|
||||
else
|
||||
Cpu->ClearVU1(addr&(~7),1);
|
||||
CpuVU1->Clear(addr&(~7),1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2567,9 +2551,9 @@ void __fastcall vuMicroWrite64(u32 addr,const mem64_t* data)
|
|||
*(u64*)&vu->Micro[addr]=data[0];
|
||||
|
||||
if (vunum==0)
|
||||
Cpu->ClearVU0(addr,1);
|
||||
CpuVU0->Clear(addr&(~7),1);
|
||||
else
|
||||
Cpu->ClearVU1(addr,1);
|
||||
CpuVU1->Clear(addr&(~7),1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2585,39 +2569,45 @@ void __fastcall vuMicroWrite128(u32 addr,const mem128_t* data)
|
|||
*(u64*)&vu->Micro[addr+8]=data[1];
|
||||
|
||||
if (vunum==0)
|
||||
Cpu->ClearVU0(addr,2);
|
||||
CpuVU0->Clear(addr&(~7),1);
|
||||
else
|
||||
Cpu->ClearVU1(addr,2);
|
||||
CpuVU1->Clear(addr&(~7),1);
|
||||
}
|
||||
}
|
||||
|
||||
void memSetPageAddr(u32 vaddr, u32 paddr)
|
||||
{
|
||||
//SysPrintf("memSetPageAddr: %8.8x -> %8.8x\n", vaddr, paddr);
|
||||
|
||||
vtlb_VMap(vaddr,paddr,0x1000);
|
||||
|
||||
}
|
||||
|
||||
void memClearPageAddr(u32 vaddr)
|
||||
{
|
||||
//SysPrintf("memClearPageAddr: %8.8x\n", vaddr);
|
||||
|
||||
vtlb_VMapUnmap(vaddr,0x1000); // -> whut ?
|
||||
|
||||
#ifdef FULLTLB
|
||||
memLUTRK[vaddr >> 12] = 0;
|
||||
memLUTWK[vaddr >> 12] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// VTLB Memory Init / Reset / Shutdown
|
||||
|
||||
static const uint m_allMemSize =
|
||||
Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2 + Ps2MemSize::ERom +
|
||||
Ps2MemSize::Base + Ps2MemSize::Scratch;
|
||||
;
|
||||
Ps2MemSize::Base + Ps2MemSize::Hardware + Ps2MemSize::Scratch;
|
||||
|
||||
static u8* m_psAllMem = NULL;
|
||||
|
||||
int memInit()
|
||||
void memAlloc()
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
InstallLinuxExceptionHandler();
|
||||
#endif
|
||||
if (!vtlb_Init()) return -1;
|
||||
|
||||
tlb_fallback_0=vtlb_RegisterHandlerTempl1(_ext_mem,0);
|
||||
tlb_fallback_1=vtlb_RegisterHandlerTempl1(_ext_mem,1);
|
||||
tlb_fallback_2=vtlb_RegisterHandlerTempl1(_ext_mem,2);
|
||||
tlb_fallback_3=vtlb_RegisterHandlerTempl1(_ext_mem,3);
|
||||
tlb_fallback_4=vtlb_RegisterHandlerTempl1(_ext_mem,4);
|
||||
tlb_fallback_5=vtlb_RegisterHandlerTempl1(_ext_mem,5);
|
||||
tlb_fallback_6=vtlb_RegisterHandlerTempl1(_ext_mem,6);
|
||||
tlb_fallback_7=vtlb_RegisterHandlerTempl1(_ext_mem,7);
|
||||
tlb_fallback_8=vtlb_RegisterHandlerTempl1(_ext_mem,8);
|
||||
|
||||
vu0_micro_mem=vtlb_RegisterHandlerTempl1(vuMicro,0);
|
||||
vu1_micro_mem=vtlb_RegisterHandlerTempl1(vuMicro,1);
|
||||
|
||||
#ifdef __LINUX__
|
||||
|
||||
// For Linux we need to use the system virtual memory mapper so that we
|
||||
// can coerce an allocation below the 2GB line.
|
||||
|
@ -2648,10 +2638,8 @@ int memInit()
|
|||
m_psAllMem = (u8*)_aligned_malloc(m_allMemSize, 4096 );
|
||||
#endif
|
||||
|
||||
if( m_psAllMem == NULL) {
|
||||
Msgbox::Alert("Error allocating memory");
|
||||
return -1;
|
||||
}
|
||||
if( m_psAllMem == NULL)
|
||||
throw Exception::OutOfMemory( "memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
|
||||
|
||||
u8* curpos = m_psAllMem;
|
||||
psM = curpos; curpos += Ps2MemSize::Base;
|
||||
|
@ -2659,27 +2647,8 @@ int memInit()
|
|||
psR1 = curpos; curpos += Ps2MemSize::Rom1;
|
||||
psR2 = curpos; curpos += Ps2MemSize::Rom2;
|
||||
psER = curpos; curpos += Ps2MemSize::ERom;
|
||||
psH = curpos; curpos += Ps2MemSize::Hardware;
|
||||
psS = curpos; //curpos += Ps2MemSize::Scratch;
|
||||
|
||||
memset( m_psAllMem, 0, m_allMemSize );
|
||||
|
||||
if (psxInit() == -1)
|
||||
return -1;
|
||||
|
||||
memMapPhy();
|
||||
|
||||
memMapKernelMem();
|
||||
memMapSupervisorMem();
|
||||
memMapUserMem();
|
||||
|
||||
memSetKernelMode();
|
||||
|
||||
|
||||
#ifdef ENABLECACHE
|
||||
memset(pCache,0,sizeof(_cacheS)*64);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void memShutdown()
|
||||
|
@ -2687,31 +2656,14 @@ void memShutdown()
|
|||
#ifdef __LINUX__
|
||||
SafeSysMunmap( m_psAllMem, m_allMemSize );
|
||||
#else
|
||||
// Make sure and unprotect memory first, since CrtDebug will try to write to it.
|
||||
DWORD old;
|
||||
VirtualProtect( m_psAllMem, m_allMemSize, PAGE_READWRITE, &old );
|
||||
safe_aligned_free(m_psAllMem);
|
||||
#endif
|
||||
psM = psR = psR1 = psR2 = psER = psS = NULL;
|
||||
psM = psR = psR1 = psR2 = psER = psS = psH = NULL;
|
||||
vtlb_Term();
|
||||
}
|
||||
|
||||
void memSetPageAddr(u32 vaddr, u32 paddr)
|
||||
{
|
||||
//SysPrintf("memSetPageAddr: %8.8x -> %8.8x\n", vaddr, paddr);
|
||||
|
||||
vtlb_VMap(vaddr,paddr,0x1000);
|
||||
|
||||
}
|
||||
|
||||
void memClearPageAddr(u32 vaddr)
|
||||
{
|
||||
//SysPrintf("memClearPageAddr: %8.8x\n", vaddr);
|
||||
|
||||
vtlb_VMapUnmap(vaddr,0x1000); // -> whut ?
|
||||
|
||||
#ifdef FULLTLB
|
||||
memLUTRK[vaddr >> 12] = 0;
|
||||
memLUTWK[vaddr >> 12] = 0;
|
||||
#endif
|
||||
}
|
||||
#endif // PCSX2_VIRTUAL_MEM
|
||||
|
||||
// Attempts to load a BIOS rom file, by trying multiple combinations of base filename
|
||||
|
@ -2724,15 +2676,18 @@ void loadBiosRom( const char *ext, u8 *dest, long maxSize )
|
|||
|
||||
Path::Combine( Bios, Config.BiosDir, Config.Bios );
|
||||
|
||||
// Try first a basic extension concatenation (normally results in something like name.bin.rom1)
|
||||
ssprintf(Bios1, "%hs.%s", params &Bios, ext);
|
||||
if( (filesize=Path::isFile( Bios1 ) ) <= 0 )
|
||||
if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 )
|
||||
{
|
||||
// Try the name properly extensioned next (name.rom1)
|
||||
Path::ReplaceExtension( Bios1, Bios, ext );
|
||||
if( (filesize=Path::isFile( Bios1 ) ) <= 0 )
|
||||
if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 )
|
||||
{
|
||||
// And this check is... well I'm not sure wtf this check is trying to accomplish! (air)
|
||||
ssprintf( Bios1, "%s%s.bin", params Config.BiosDir, ext );
|
||||
if( (filesize=Path::isFile( Bios1 ) ) <= 0 )
|
||||
// Try for the old-style method (rom1.bin)
|
||||
Path::Combine( Bios1, Config.BiosDir, ext );
|
||||
Bios1 += ".bin";
|
||||
if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 )
|
||||
{
|
||||
Console::Error( "\n\n\n"
|
||||
"**************\n"
|
||||
|
@ -2751,48 +2706,86 @@ void loadBiosRom( const char *ext, u8 *dest, long maxSize )
|
|||
fclose(fp);
|
||||
}
|
||||
|
||||
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||
void memReset()
|
||||
{
|
||||
string Bios;
|
||||
FILE *fp;
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
|
||||
DWORD OldProtect;
|
||||
|
||||
memset(PS2MEM_BASE, 0, Ps2MemSize::Base);
|
||||
memset(PS2MEM_SCRATCH, 0, Ps2MemSize::Scratch);
|
||||
vm_Reset();
|
||||
|
||||
# ifdef _WIN32
|
||||
// make sure can write
|
||||
VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READWRITE, &OldProtect);
|
||||
VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READWRITE, &OldProtect);
|
||||
VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READWRITE, &OldProtect);
|
||||
VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READWRITE, &OldProtect);
|
||||
# else
|
||||
mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ|PROT_WRITE);
|
||||
mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ|PROT_WRITE);
|
||||
mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ|PROT_WRITE);
|
||||
mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ|PROT_WRITE);
|
||||
# endif
|
||||
|
||||
#else
|
||||
vtlb_Reset();
|
||||
memset(psM, 0, Ps2MemSize::Base);
|
||||
memset(psS, 0, Ps2MemSize::Scratch);
|
||||
|
||||
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
|
||||
// resets of the system hardware would only clear vtlb mappings, but since the
|
||||
// rest of the emu is not really set up to support a "soft" reset of that sort
|
||||
// we opt for the hard/safe version.
|
||||
|
||||
memset( m_psAllMem, 0, m_allMemSize );
|
||||
#ifdef ENABLECACHE
|
||||
memset(pCache,0,sizeof(_cacheS)*64);
|
||||
#endif
|
||||
|
||||
vtlb_Init();
|
||||
|
||||
tlb_fallback_0=vtlb_RegisterHandlerTempl1(_ext_mem,0);
|
||||
tlb_fallback_1=vtlb_RegisterHandlerTempl1(_ext_mem,1);
|
||||
tlb_fallback_2=vtlb_RegisterHandlerTempl1(_ext_mem,2);
|
||||
tlb_fallback_3=vtlb_RegisterHandlerTempl1(_ext_mem,3);
|
||||
tlb_fallback_4=vtlb_RegisterHandlerTempl1(_ext_mem,4);
|
||||
tlb_fallback_5=vtlb_RegisterHandlerTempl1(_ext_mem,5);
|
||||
tlb_fallback_6=vtlb_RegisterHandlerTempl1(_ext_mem,6);
|
||||
tlb_fallback_7=vtlb_RegisterHandlerTempl1(_ext_mem,7);
|
||||
tlb_fallback_8=vtlb_RegisterHandlerTempl1(_ext_mem,8);
|
||||
|
||||
vu0_micro_mem=vtlb_RegisterHandlerTempl1(vuMicro,0);
|
||||
vu1_micro_mem=vtlb_RegisterHandlerTempl1(vuMicro,1);
|
||||
|
||||
//vtlb_Reset();
|
||||
|
||||
// reset memLUT (?)
|
||||
//vtlb_VMap(0x00000000,0x00000000,0x20000000);
|
||||
//vtlb_VMapUnmap(0x20000000,0x60000000);
|
||||
|
||||
memMapPhy();
|
||||
memMapKernelMem();
|
||||
memMapSupervisorMem();
|
||||
memMapUserMem();
|
||||
memSetKernelMode();
|
||||
|
||||
vtlb_VMap(0x00000000,0x00000000,0x20000000);
|
||||
vtlb_VMapUnmap(0x20000000,0x60000000);
|
||||
#endif
|
||||
|
||||
string Bios;
|
||||
FILE *fp;
|
||||
|
||||
Path::Combine( Bios, Config.BiosDir, Config.Bios );
|
||||
|
||||
long filesize;
|
||||
if( ( filesize = Path::getFileSize( Bios ) ) <= 0 )
|
||||
{
|
||||
Console::Error("Unable to load bios: '%s', PCSX2 can't run without that", params Bios);
|
||||
//Console::Error("Unable to load bios: '%s', PCSX2 can't run without that", params Bios);
|
||||
throw Exception::FileNotFound( Bios,
|
||||
"The specified Bios file was not found. A bios is required for Pcsx2 to run.\n\nFile not found" );
|
||||
}
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
|
||||
#ifdef _WIN32
|
||||
// make sure can write
|
||||
VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READWRITE, &OldProtect);
|
||||
VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READWRITE, &OldProtect);
|
||||
VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READWRITE, &OldProtect);
|
||||
VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READWRITE, &OldProtect);
|
||||
#else
|
||||
mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ|PROT_WRITE);
|
||||
mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ|PROT_WRITE);
|
||||
mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ|PROT_WRITE);
|
||||
mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ|PROT_WRITE);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
fp = fopen(Bios.c_str(), "rb");
|
||||
fread(PS2MEM_ROM, 1, std::min( (long)Ps2MemSize::Rom, filesize ), fp);
|
||||
fclose(fp);
|
||||
|
@ -2802,12 +2795,6 @@ void memReset()
|
|||
|
||||
//injectIRX("host.irx"); //not fully tested; still buggy
|
||||
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
// reset memLUT (?)
|
||||
vtlb_VMap(0x00000000,0x00000000,0x20000000);
|
||||
vtlb_VMapUnmap(0x20000000,0x60000000);
|
||||
#endif
|
||||
|
||||
loadBiosRom("rom1", PS2MEM_ROM1, Ps2MemSize::Rom1);
|
||||
loadBiosRom("rom2", PS2MEM_ROM2, Ps2MemSize::Rom2);
|
||||
loadBiosRom("erom", PS2MEM_EROM, Ps2MemSize::ERom);
|
||||
|
@ -2857,7 +2844,9 @@ void mmap_MarkCountedRamPage(void* ptr,u32 vaddr)
|
|||
DWORD old;
|
||||
VirtualProtect(ptr,1,PAGE_READONLY,&old);
|
||||
#else
|
||||
mprotect(ptr, 1, PROT_READ);
|
||||
// fixed? mprotect needs input and size to be aligned to 4096 bytes pagesize.
|
||||
// 'ptr' should be aligned properly, but a size of 1 was invalid. (air)
|
||||
mprotect(ptr, getpagesize(), PROT_READ);
|
||||
#endif
|
||||
|
||||
u32 offset=((u8*)ptr-psM);
|
||||
|
|
|
@ -36,7 +36,11 @@ namespace Ps2MemSize
|
|||
static const uint Rom1 = 0x00040000; // fixme - TLB allocates 0x00080000 ?
|
||||
static const uint Rom2 = 0x00080000;
|
||||
static const uint ERom = 0x001C0000;
|
||||
static const uint Hardware = 0x00010000;
|
||||
static const uint Scratch = 0x00004000; // fixme - VM allocates 0x10000 ?
|
||||
|
||||
static const uint IopRam = 0x200000; // 2MB main ram on the IOP.
|
||||
static const uint IopHardware = 0x00010000;
|
||||
}
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
|
@ -226,7 +230,7 @@ extern u8 g_RealGSMem[0x2000];
|
|||
#define PSMu32(mem) (*(u32*)PSM(mem))
|
||||
#define PSMu64(mem) (*(u64*)PSM(mem))
|
||||
|
||||
int memInit();
|
||||
void memAlloc();
|
||||
void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error.
|
||||
void memSetKernelMode();
|
||||
void memSetSupervisorMode();
|
||||
|
|
|
@ -565,18 +565,17 @@ void ProcessFKeys(int fkey, int shift)
|
|||
{
|
||||
Console::Notice( _("Saveslot %d cannot be loaded; slot does not exist (file not found)"), params StatesC );
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
// This is the bad one. Chances are the cpu has been reset, so emulation has
|
||||
// to be aborted. Sorry user! We'll give you some info for your trouble:
|
||||
|
||||
Console::Error( _("An error occured while trying to load saveslot %d"), params StatesC );
|
||||
Console::Error( ex.what() );
|
||||
Console::Error( ex.Message() );
|
||||
Msgbox::Alert(
|
||||
"Pcsx2 encountered an error while trying to load the savestate\n"
|
||||
"and emulation had to be aborted." );
|
||||
|
||||
R5900::cpuShutdown();
|
||||
ClosePlugins();
|
||||
|
||||
throw Exception::CpuStateShutdown(
|
||||
|
|
27
pcsx2/Misc.h
27
pcsx2/Misc.h
|
@ -71,6 +71,26 @@ namespace Path
|
|||
|
||||
// <<--- END Path Utilities [PathUtil.c]
|
||||
|
||||
// [TODO] : Move the config options mess from Misc.h into "config.h" or someting more sensible.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Session Configuration Override Flags
|
||||
//
|
||||
// a handful of flags that can override user configurations for the current application session
|
||||
// only. This allows us to do things like force-disable recompilers if the memory allocations
|
||||
// for them fail.
|
||||
struct SessionOverrideFlags
|
||||
{
|
||||
bool ForceDisableEErec:1;
|
||||
bool ForceDisableVU0rec:1;
|
||||
bool ForceDisableVU1rec:1;
|
||||
};
|
||||
|
||||
extern SessionOverrideFlags g_Session;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Pcsx2 User Configuration Options!
|
||||
|
||||
#define PCSX2_GSMULTITHREAD 1 // uses multithreaded gs
|
||||
#define PCSX2_EEREC 0x10
|
||||
#define PCSX2_VU0REC 0x20
|
||||
|
@ -83,8 +103,7 @@ namespace Path
|
|||
#define PCSX2_FRAMELIMIT_VUSKIP 0xc00
|
||||
|
||||
#define CHECK_MULTIGS (Config.Options&PCSX2_GSMULTITHREAD)
|
||||
#define CHECK_EEREC (Config.Options&PCSX2_EEREC)
|
||||
#define CHECK_COP2REC (Config.Options&PCSX2_COP2REC) // goes with ee option
|
||||
#define CHECK_EEREC (!g_Session.ForceDisableEErec && Config.Options&PCSX2_EEREC)
|
||||
//------------ SPEED/MISC HACKS!!! ---------------
|
||||
#define CHECK_EE_CYCLERATE (Config.Hacks & 0x03)
|
||||
#define CHECK_IOP_CYCLERATE (Config.Hacks & (1<<3))
|
||||
|
@ -111,8 +130,8 @@ namespace Path
|
|||
|
||||
#define CHECK_FRAMELIMIT (Config.Options&PCSX2_FRAMELIMIT_MASK)
|
||||
|
||||
#define CHECK_VU0REC (Config.Options&PCSX2_VU0REC)
|
||||
#define CHECK_VU1REC (Config.Options&PCSX2_VU1REC)
|
||||
#define CHECK_VU0REC (!g_Session.ForceDisableVU0rec && Config.Options&PCSX2_VU0REC)
|
||||
#define CHECK_VU1REC (!g_Session.ForceDisableVU1rec && (Config.Options&PCSX2_VU1REC))
|
||||
|
||||
|
||||
struct PcsxConfig
|
||||
|
|
|
@ -739,7 +739,7 @@ int OpenPlugins(const char* pTitleFilename) {
|
|||
{
|
||||
SPU2irqCallback(spu2Irq,spu2DMA4Irq,spu2DMA7Irq);
|
||||
if( SPU2setDMABaseAddr != NULL )
|
||||
SPU2setDMABaseAddr((uptr)PSXM(0));
|
||||
SPU2setDMABaseAddr((uptr)psxM);
|
||||
|
||||
if(SPU2setClockPtr != NULL)
|
||||
SPU2setClockPtr(&psxRegs.cycle);
|
||||
|
@ -754,7 +754,7 @@ int OpenPlugins(const char* pTitleFilename) {
|
|||
{
|
||||
DEV9irqCallback(dev9Irq);
|
||||
dev9Handler = DEV9irqHandler();
|
||||
ret = DEV9open(&(psxRegs.pc)); //((void *)&pDsp);
|
||||
ret = DEV9open(&psxRegs.pc); //((void *)&pDsp);
|
||||
if (ret != 0) { Msgbox::Alert("Error Opening DEV9 Plugin"); goto OpenError; }
|
||||
OpenStatus.DEV9 = true;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
|
||||
// NOTE: Any modifications to read/write fns should also go into their const counterparts
|
||||
// found in iPsxHw.cpp.
|
||||
|
||||
void psxHwReset() {
|
||||
/* if (Config.Sio) psxHu32(0x1070) |= 0x80;
|
||||
|
|
|
@ -752,8 +752,7 @@ static void doBranch(s32 tar) {
|
|||
psxBranchTest();
|
||||
}
|
||||
|
||||
static int intInit() {
|
||||
return 0;
|
||||
static void intAlloc() {
|
||||
}
|
||||
|
||||
static void intReset() {
|
||||
|
@ -789,7 +788,7 @@ static void intShutdown() {
|
|||
}
|
||||
|
||||
R3000Acpu psxInt = {
|
||||
intInit,
|
||||
intAlloc,
|
||||
intReset,
|
||||
intExecute,
|
||||
intExecuteBlock,
|
||||
|
|
170
pcsx2/PsxMem.cpp
170
pcsx2/PsxMem.cpp
|
@ -28,11 +28,9 @@ int g_psxWriteOk=1;
|
|||
static u32 writectrl;
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
|
||||
int psxMemInit()
|
||||
void psxMemAlloc()
|
||||
{
|
||||
// all mem taken care by memInit
|
||||
return 0;
|
||||
// In VirtualMemory land all mem taken care by memAlloc
|
||||
}
|
||||
|
||||
void psxMemReset()
|
||||
|
@ -346,20 +344,17 @@ u8 *psxM;
|
|||
u8 *psxP;
|
||||
u8 *psxH;
|
||||
u8 *psxS;
|
||||
|
||||
uptr *psxMemWLUT;
|
||||
uptr *psxMemRLUT;
|
||||
const uptr *psxMemRLUT;
|
||||
|
||||
static u8* m_psxAllMem = NULL;
|
||||
static const uint m_psxMemSize = 0x00200000 + 0x00010000 + 0x00010000 + 0x00010000 ;
|
||||
static const uint m_psxMemSize = Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x00010000 + 0x00010000 ;
|
||||
|
||||
int psxMemInit()
|
||||
void psxMemAlloc()
|
||||
{
|
||||
int i;
|
||||
|
||||
psxMemRLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
memset(psxMemRLUT, 0, 0x10000 * sizeof(uptr));
|
||||
memset(psxMemWLUT, 0, 0x10000 * sizeof(uptr));
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr) * 2,16);
|
||||
psxMemRLUT = psxMemWLUT + 0x10000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
|
||||
#ifdef __LINUX__
|
||||
|
||||
|
@ -390,65 +385,77 @@ int psxMemInit()
|
|||
#endif
|
||||
|
||||
if( m_psxAllMem == NULL)
|
||||
{
|
||||
Msgbox::Alert("Error allocating memory for the IOP processor.");
|
||||
return -1;
|
||||
}
|
||||
throw Exception::OutOfMemory( "psxMemAlloc > failed allocating memory for the IOP processor." );
|
||||
|
||||
u8* curpos = m_psxAllMem;
|
||||
psxM = curpos; curpos += 0x00200000;
|
||||
psxP = curpos; curpos += 0x00010000;
|
||||
psxH = curpos; curpos += 0x00010000;
|
||||
psxS = curpos; curpos += 0x00010000;
|
||||
psxH = curpos; curpos += Ps2MemSize::IopHardware;
|
||||
psxS = curpos; //curpos += 0x00010000;
|
||||
|
||||
//assert( (uptr)psxM <= 0xffffffff && (uptr)psxP <= 0xffffffff && (uptr)psxH <= 0xffffffff && (uptr)psxS <= 0xffffffff);
|
||||
|
||||
memset( m_psxAllMem, 0, m_psxMemSize );
|
||||
|
||||
|
||||
// MemR
|
||||
for (i=0; i<0x0080; i++) psxMemRLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
for (i=0; i<0x0080; i++) psxMemRLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
for (i=0; i<0x0080; i++) psxMemRLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
|
||||
for (i=0; i<0x0001; i++) psxMemRLUT[i + 0x1f00] = (uptr)&psxP[i << 16];
|
||||
|
||||
for (i=0; i<0x0001; i++) psxMemRLUT[i + 0x1f80] = (uptr)&psxH[i << 16];
|
||||
for (i=0; i<0x0001; i++) psxMemRLUT[i + 0xbf80] = (uptr)&psxH[i << 16];
|
||||
|
||||
for (i=0; i<0x0040; i++) psxMemRLUT[i + 0x1fc0] = (uptr)&PS2MEM_ROM[i << 16];
|
||||
for (i=0; i<0x0040; i++) psxMemRLUT[i + 0x9fc0] = (uptr)&PS2MEM_ROM[i << 16];
|
||||
for (i=0; i<0x0040; i++) psxMemRLUT[i + 0xbfc0] = (uptr)&PS2MEM_ROM[i << 16];
|
||||
|
||||
for (i=0; i<0x0004; i++) psxMemRLUT[i + 0x1e00] = (uptr)&PS2MEM_ROM1[i << 16];
|
||||
for (i=0; i<0x0004; i++) psxMemRLUT[i + 0x9e00] = (uptr)&PS2MEM_ROM1[i << 16];
|
||||
for (i=0; i<0x0004; i++) psxMemRLUT[i + 0xbe00] = (uptr)&PS2MEM_ROM1[i << 16];
|
||||
|
||||
for (i=0; i<0x0001; i++) psxMemRLUT[i + 0x1d00] = (uptr)&psxS[i << 16];
|
||||
for (i=0; i<0x0001; i++) psxMemRLUT[i + 0xbd00] = (uptr)&psxS[i << 16];
|
||||
|
||||
// MemW
|
||||
for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
for (i=0; i<0x0080; i++) psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
|
||||
for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1f00] = (uptr)&psxP[i << 16];
|
||||
|
||||
for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1f80] = (uptr)&psxH[i << 16];
|
||||
for (i=0; i<0x0001; i++) psxMemWLUT[i + 0xbf80] = (uptr)&psxH[i << 16];
|
||||
|
||||
// for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
|
||||
|
||||
// for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1d00] = (uptr)&psxS[i << 16];
|
||||
// for (i=0; i<0x0001; i++) psxMemWLUT[i + 0xbd00] = (uptr)&psxS[i << 16];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void psxMemReset() {
|
||||
memset(psxM, 0, 0x00200000);
|
||||
memset(psxP, 0, 0x00010000);
|
||||
//memset(psxS, 0, 0x00010000);
|
||||
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
|
||||
// which is performed by MemInit and PsxMemInit()
|
||||
void psxMemReset()
|
||||
{
|
||||
jASSUME( psxMemWLUT != NULL );
|
||||
jASSUME( m_psxAllMem != NULL );
|
||||
|
||||
DbgCon::Status( "psxMemReset > Resetting core memory!" );
|
||||
|
||||
memset( psxMemWLUT, 0, 0x10000 * sizeof(uptr) * 2 ); // clears both allocations, RLUT and WLUT
|
||||
memset( m_psxAllMem, 0, m_psxMemSize );
|
||||
|
||||
// Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer.
|
||||
// So the ones with a 1 prefixed (ala 0x18000, etc) are RLUT tables.
|
||||
for (int i=0; i<0x0080; i++)
|
||||
{
|
||||
psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
|
||||
// RLUTs, accessed through WLUT.
|
||||
psxMemWLUT[i + 0x10000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
psxMemWLUT[i + 0x18000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
psxMemWLUT[i + 0x1a000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
}
|
||||
|
||||
// A few single-page allocations...
|
||||
psxMemWLUT[0x11f00] = (uptr)psxP;
|
||||
psxMemWLUT[0x11f80] = (uptr)psxH;
|
||||
psxMemWLUT[0x1bf80] = (uptr)psxH;
|
||||
|
||||
psxMemWLUT[0x1f00] = (uptr)psxP;
|
||||
psxMemWLUT[0x1f80] = (uptr)psxH;
|
||||
psxMemWLUT[0xbf80] = (uptr)psxH;
|
||||
|
||||
// Read-only memory areas, so don't map WLUT for these...
|
||||
for (int i=0; i<0x0040; i++)
|
||||
{
|
||||
psxMemWLUT[i + 0x11fc0] = (uptr)&PS2MEM_ROM[i << 16];
|
||||
psxMemWLUT[i + 0x19fc0] = (uptr)&PS2MEM_ROM[i << 16];
|
||||
psxMemWLUT[i + 0x1bfc0] = (uptr)&PS2MEM_ROM[i << 16];
|
||||
}
|
||||
|
||||
for (int i=0; i<0x0004; i++)
|
||||
{
|
||||
psxMemWLUT[i + 0x11e00] = (uptr)&PS2MEM_ROM1[i << 16];
|
||||
psxMemWLUT[i + 0x19e00] = (uptr)&PS2MEM_ROM1[i << 16];
|
||||
psxMemWLUT[i + 0x1be00] = (uptr)&PS2MEM_ROM1[i << 16];
|
||||
}
|
||||
|
||||
// Scratchpad! (which is read only? (air))
|
||||
psxMemWLUT[0x11d00] = (uptr)psxS;
|
||||
psxMemWLUT[0x1bd00] = (uptr)psxS;
|
||||
|
||||
// why isn't scratchpad read/write? (air)
|
||||
//for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1d00] = (uptr)&psxS[i << 16];
|
||||
//for (i=0; i<0x0001; i++) psxMemWLUT[i + 0xbd00] = (uptr)&psxS[i << 16];
|
||||
|
||||
// this one looks like an old hack for some special write-only memory area,
|
||||
// but leaving it in for reference (air)
|
||||
//for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
|
||||
}
|
||||
|
||||
void psxMemShutdown()
|
||||
|
@ -461,12 +468,12 @@ void psxMemShutdown()
|
|||
|
||||
psxM = psxP = psxH = psxS = NULL;
|
||||
|
||||
safe_aligned_free(psxMemRLUT);
|
||||
safe_aligned_free(psxMemWLUT);
|
||||
psxMemRLUT = NULL;
|
||||
}
|
||||
|
||||
u8 psxMemRead8(u32 mem) {
|
||||
char *p;
|
||||
const u8* p;
|
||||
u32 t;
|
||||
|
||||
t = (mem >> 16) & 0x1fff;
|
||||
|
@ -481,9 +488,9 @@ u8 psxMemRead8(u32 mem) {
|
|||
mem&= 0x1fffffff;
|
||||
return psxHw4Read8(mem);
|
||||
} else {
|
||||
p = (char *)(psxMemRLUT[mem >> 16]);
|
||||
p = (const u8*)(psxMemRLUT[mem >> 16]);
|
||||
if (p != NULL) {
|
||||
return *(u8 *)(p + (mem & 0xffff));
|
||||
return *(const u8 *)(p + (mem & 0xffff));
|
||||
} else {
|
||||
if (t == 0x1000) return DEV9read8(mem & 0x1FFFFFFF);
|
||||
PSXMEM_LOG("err lb %8.8lx\n", mem);
|
||||
|
@ -493,7 +500,7 @@ u8 psxMemRead8(u32 mem) {
|
|||
}
|
||||
|
||||
u16 psxMemRead16(u32 mem) {
|
||||
char *p;
|
||||
const u8* p;
|
||||
u32 t;
|
||||
|
||||
t = (mem >> 16) & 0x1fff;
|
||||
|
@ -504,7 +511,7 @@ u16 psxMemRead16(u32 mem) {
|
|||
else
|
||||
return psxHwRead16(mem);
|
||||
} else {
|
||||
p = (char *)(psxMemRLUT[mem >> 16]);
|
||||
p = (const u8*)(psxMemRLUT[mem >> 16]);
|
||||
if (p != NULL) {
|
||||
if (t == 0x1d00) {
|
||||
u16 ret;
|
||||
|
@ -529,7 +536,7 @@ u16 psxMemRead16(u32 mem) {
|
|||
SIF_LOG("Sif reg read %x value %x\n", mem, ret);
|
||||
return ret;
|
||||
}
|
||||
return *(u16 *)(p + (mem & 0xffff));
|
||||
return *(const u16 *)(p + (mem & 0xffff));
|
||||
} else {
|
||||
if (t == 0x1F90)
|
||||
return SPU2read(mem & 0x1FFFFFFF);
|
||||
|
@ -541,7 +548,7 @@ u16 psxMemRead16(u32 mem) {
|
|||
}
|
||||
|
||||
u32 psxMemRead32(u32 mem) {
|
||||
char *p;
|
||||
const u8* p;
|
||||
u32 t;
|
||||
t = (mem >> 16) & 0x1fff;
|
||||
if (t == 0x1f80) {
|
||||
|
@ -552,7 +559,7 @@ u32 psxMemRead32(u32 mem) {
|
|||
return psxHwRead32(mem);
|
||||
} else {
|
||||
//see also Hw.c
|
||||
p = (char *)(psxMemRLUT[mem >> 16]);
|
||||
p = (const u8*)(psxMemRLUT[mem >> 16]);
|
||||
if (p != NULL) {
|
||||
if (t == 0x1d00) {
|
||||
u32 ret;
|
||||
|
@ -583,7 +590,7 @@ u32 psxMemRead32(u32 mem) {
|
|||
SIF_LOG("Sif reg read %x value %x\n", mem, ret);
|
||||
return ret;
|
||||
}
|
||||
return *(u32 *)(p + (mem & 0xffff));
|
||||
return *(const u32 *)(p + (mem & 0xffff));
|
||||
} else {
|
||||
if (t == 0x1000) return DEV9read32(mem & 0x1FFFFFFF);
|
||||
|
||||
|
@ -755,12 +762,8 @@ void psxMemWrite32(u32 mem, u32 value) {
|
|||
}
|
||||
|
||||
//if (!g_psxWriteOk) psxCpu->Clear(mem&~3, 1);
|
||||
#ifdef PSXMEM_LOG
|
||||
if (g_psxWriteOk) { PSXMEM_LOG("err sw %8.8lx = %x\n", mem, value); }
|
||||
#endif
|
||||
} else {
|
||||
int i;
|
||||
|
||||
writectrl = value;
|
||||
switch (value) {
|
||||
case 0x800: case 0x804:
|
||||
|
@ -778,9 +781,12 @@ void psxMemWrite32(u32 mem, u32 value) {
|
|||
case 0x1edd8:
|
||||
if (g_psxWriteOk == 1) break;
|
||||
g_psxWriteOk = 1;
|
||||
for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
for (i=0; i<0x0080; i++) psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
for (i=0; i<0x0080; i++) psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
for (int i=0; i<0x0080; i++)
|
||||
{
|
||||
psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
}
|
||||
//PSXMEM_LOG("writectrl: write ok\n");
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -36,7 +36,7 @@ extern u8 *psxP;
|
|||
extern u8 *psxH;
|
||||
extern u8 *psxS;
|
||||
extern uptr *psxMemWLUT;
|
||||
extern uptr *psxMemRLUT;
|
||||
extern const uptr *psxMemRLUT;
|
||||
|
||||
//#define TLB_DEBUG_MEM
|
||||
#ifdef TLB_DEBUG_MEM
|
||||
|
@ -44,7 +44,7 @@ void* PSXM(u32 mem);
|
|||
void* _PSXM(u32 mem);
|
||||
#else
|
||||
#define PSXM(mem) (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff)))
|
||||
#define _PSXM(mem) ((void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff)))
|
||||
#define _PSXM(mem) ((const void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff)))
|
||||
#endif
|
||||
|
||||
#define psxSs8(mem) psxS[(mem) & 0xffff]
|
||||
|
@ -85,7 +85,7 @@ void* _PSXM(u32 mem);
|
|||
#define PSXMu16(mem) (*(u16*)_PSXM(mem))
|
||||
#define PSXMu32(mem) (*(u32*)_PSXM(mem))
|
||||
|
||||
int psxMemInit();
|
||||
void psxMemAlloc();
|
||||
void psxMemReset();
|
||||
void psxMemShutdown();
|
||||
|
||||
|
|
|
@ -49,46 +49,30 @@ bool iopEventTestIsActive = false;
|
|||
|
||||
PCSX2_ALIGNED16(psxRegisters psxRegs);
|
||||
|
||||
int psxInit()
|
||||
void psxReset()
|
||||
{
|
||||
psxCpu = CHECK_EEREC ? &psxRec : &psxInt;
|
||||
|
||||
g_psxNextBranchCycle = 8;
|
||||
psxBreak = 0;
|
||||
psxCycleEE = -1;
|
||||
|
||||
if (psxMemInit() == -1) return -1;
|
||||
|
||||
return psxCpu->Init();
|
||||
}
|
||||
|
||||
void psxReset() {
|
||||
|
||||
psxCpu->Reset();
|
||||
|
||||
psxMemReset();
|
||||
|
||||
memset(&psxRegs, 0, sizeof(psxRegs));
|
||||
|
||||
psxRegs.pc = 0xbfc00000; // Start in bootstrap
|
||||
|
||||
psxRegs.CP0.n.Status = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
|
||||
psxRegs.CP0.n.PRid = 0x0000001f; // PRevID = Revision ID, same as the IOP R3000A
|
||||
|
||||
psxBreak = 0;
|
||||
psxCycleEE = -1;
|
||||
g_psxNextBranchCycle = psxRegs.cycle + 2;
|
||||
g_psxNextBranchCycle = psxRegs.cycle + 4;
|
||||
|
||||
psxHwReset();
|
||||
psxBiosInit();
|
||||
psxExecuteBios();
|
||||
//psxExecuteBios();
|
||||
}
|
||||
|
||||
void psxShutdown() {
|
||||
psxMemShutdown();
|
||||
psxBiosShutdown();
|
||||
psxSIOShutdown();
|
||||
psxCpu->Shutdown();
|
||||
//psxCpu->Shutdown();
|
||||
}
|
||||
|
||||
void psxException(u32 code, u32 bd) {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
extern u32 g_psxNextBranchCycle;
|
||||
|
||||
struct R3000Acpu {
|
||||
int (*Init)();
|
||||
void (*Allocate)();
|
||||
void (*Reset)();
|
||||
void (*Execute)();
|
||||
s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles.
|
||||
|
@ -205,7 +205,7 @@ extern u32 EEoCycle;
|
|||
|
||||
#endif
|
||||
|
||||
int psxInit();
|
||||
void psxMemReset();
|
||||
void psxReset();
|
||||
void psxShutdown();
|
||||
void psxException(u32 code, u32 step);
|
||||
|
|
123
pcsx2/R5900.cpp
123
pcsx2/R5900.cpp
|
@ -26,6 +26,8 @@
|
|||
#include "VUmicro.h"
|
||||
#include "GS.h"
|
||||
|
||||
#include "iVUzerorec.h" // for SuperVUReset
|
||||
|
||||
#include "Paths.h"
|
||||
|
||||
namespace R5900
|
||||
|
@ -51,91 +53,44 @@ static uint eeWaitCycles = 1024;
|
|||
|
||||
bool EventTestIsActive = false;
|
||||
|
||||
bool cpuInit()
|
||||
// A run-once procedure for initializing the emulation state.
|
||||
// Can be done anytime after allocating memory, and before calling Cpu->Execute().
|
||||
// Multiple calls to this function are automatically ignored.
|
||||
/*void cpuInit()
|
||||
{
|
||||
if( cpuIsInitialized ) return true;
|
||||
DevCon::WriteLn( "cpuInit > %s", params cpuIsInitialized ? "Initializing..." : "Skipping (already initialized)" );
|
||||
|
||||
if( cpuIsInitialized ) return;
|
||||
|
||||
cpuIsInitialized = true;
|
||||
cpuRegs.constzero = 0;
|
||||
Cpu = CHECK_EEREC ? &recCpu : &intCpu;
|
||||
|
||||
try
|
||||
{
|
||||
Cpu->Init();
|
||||
}
|
||||
catch( std::exception& ex )
|
||||
{
|
||||
Console::Error( "Error > %s", params ex.what() );
|
||||
|
||||
if( Cpu == &recCpu )
|
||||
{
|
||||
Console::Error( _("\t... attempting to initialize the Interpreter (slow!)") );
|
||||
Config.Options &= ~(PCSX2_EEREC|PCSX2_VU1REC|PCSX2_VU0REC);
|
||||
Cpu = &intCpu;
|
||||
Cpu->Init();
|
||||
|
||||
// if the interpreter fails, let the exception bubble to the surface.
|
||||
// fixme: this would probably be better if all exceptions pasesed to
|
||||
// the caller, and it was the caller's duty to clear the EEREC flag and
|
||||
// re-run the init process. But for now this is how it works.
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
if (memInit() == -1) {
|
||||
if( MessageBox(NULL,
|
||||
"Failed to allocate enough physical memory to run pcsx2. Try closing\n"
|
||||
"down background programs, restarting windows, or buying more memory.\n\n"
|
||||
"Launch TLB version of pcsx2 (pcsx2t.exe)?", "Memory Allocation Error", MB_YESNO) == IDYES )
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
|
||||
MemoryAlloc<char> strdir( GetCurrentDirectory( 0, NULL )+2, "VTLB Launcher" );
|
||||
string strexe;
|
||||
|
||||
GetCurrentDirectory(strdir.GetLength(), strdir.GetPtr());
|
||||
Path::Combine( strexe, strdir.GetPtr(), "pcsx2-vtlb.exe" );
|
||||
memset(&si, 0, sizeof(si));
|
||||
|
||||
if( !CreateProcess(strexe.c_str(), "", NULL, NULL, FALSE, DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP, NULL, strdir.GetPtr(), &si, &pi))
|
||||
{
|
||||
MessageBox(NULL, fmt_string( "Failed to launch %hs\n", params &strexe ).c_str(), "Failure", MB_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (hwInit() == -1) return false;
|
||||
if (vu0Init() == -1) return false;
|
||||
if (vu1Init() == -1) return false;
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
if (memInit() == -1) return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
// non memInit() currently since we don't support soft resets. memory is initialized in full
|
||||
// instead during cpuReset() [using memReset()]
|
||||
//memInit();
|
||||
}*/
|
||||
|
||||
void cpuReset()
|
||||
{
|
||||
if( cpuIsInitialized )
|
||||
mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||
//cpuInit(); // more just-in-caseness!
|
||||
|
||||
//if( !cpuIsInitialized )
|
||||
{
|
||||
for( int i=0; i<48; i++ )
|
||||
UnmapTLB(i);
|
||||
cpuIsInitialized = true;
|
||||
}
|
||||
|
||||
mtgsWaitGS(); // GS better be done before we reset the EE, just in case.
|
||||
Cpu = CHECK_EEREC ? &recCpu : &intCpu;
|
||||
|
||||
cpuInit();
|
||||
Cpu->Reset();
|
||||
// safeguard the VUcpu structs. None of the memReset ops should try to
|
||||
// use them, and this ensures if they do it'll assert/DEP.
|
||||
|
||||
CpuVU0 = CpuVU1 = NULL;
|
||||
|
||||
memReset();
|
||||
psxMemReset();
|
||||
vuMicroMemReset();
|
||||
|
||||
Cpu->Reset();
|
||||
|
||||
memset(&cpuRegs, 0, sizeof(cpuRegs));
|
||||
memset(&fpuRegs, 0, sizeof(fpuRegs));
|
||||
|
@ -148,16 +103,22 @@ void cpuReset()
|
|||
fpuRegs.fprc[0] = 0x00002e00; // fpu Revision..
|
||||
fpuRegs.fprc[31] = 0x01000001; // fpu Status/Control
|
||||
|
||||
g_nextBranchCycle = cpuRegs.cycle + 2;
|
||||
g_nextBranchCycle = cpuRegs.cycle + 4;
|
||||
EEsCycle = 0;
|
||||
EEoCycle = cpuRegs.cycle;
|
||||
eeWaitCycles = CHECK_WAITCYCLE_HACK ? 3072 : 768;
|
||||
|
||||
// Cyclerate hacks effectively speed up the rate of event tests, so we can safely boost
|
||||
// the WaitCycles value here for x2 and x3 modes:
|
||||
if( CHECK_EE_CYCLERATE > 1 )
|
||||
eeWaitCycles += 1024;
|
||||
|
||||
// SuperVUreset will do nothing is none of the recs are initialized.
|
||||
Dynarec::SuperVUReset(-1);
|
||||
|
||||
vu0Reset();
|
||||
vu1Reset();
|
||||
|
||||
hwReset();
|
||||
vif0Reset();
|
||||
vif1Reset();
|
||||
|
@ -167,25 +128,17 @@ void cpuReset()
|
|||
|
||||
void cpuShutdown()
|
||||
{
|
||||
if( !cpuIsInitialized ) return;
|
||||
//if( !cpuIsInitialized ) return;
|
||||
//cpuIsInitialized = false;
|
||||
|
||||
mtgsWaitGS();
|
||||
//gsShutdown(); // shut down the GS first because it's running a thread.
|
||||
|
||||
for( int i=0; i<48; i++ )
|
||||
UnmapTLB(i);
|
||||
|
||||
hwShutdown();
|
||||
// biosShutdown();
|
||||
psxShutdown();
|
||||
vu0Shutdown();
|
||||
vu1Shutdown();
|
||||
memShutdown();
|
||||
disR5900FreeSyms();
|
||||
|
||||
Cpu->Shutdown();
|
||||
|
||||
cpuIsInitialized = false;
|
||||
//Cpu->Shutdown();
|
||||
}
|
||||
|
||||
void cpuException(u32 code, u32 bd) {
|
||||
|
@ -578,7 +531,7 @@ static __forceinline void _cpuBranchTest_Shared()
|
|||
{
|
||||
// We're in a BranchTest. All dynarec registers are flushed
|
||||
// so there is no need to freeze registers here.
|
||||
Cpu->ExecuteVU0Block();
|
||||
CpuVU0->ExecuteBlock();
|
||||
|
||||
// This might be needed to keep the EE and VU0 in sync.
|
||||
// A better fix will require hefty changes to the VU recs. -_-
|
||||
|
|
|
@ -27,19 +27,13 @@ namespace R5900
|
|||
extern const char* const bios[256];
|
||||
|
||||
struct R5900cpu {
|
||||
void (*Init)(); // throws exceptions on failure.
|
||||
void (*Allocate)(); // throws exceptions on failure.
|
||||
void (*Reset)();
|
||||
void (*Step)();
|
||||
void (*Execute)(); /* executes up to a break */
|
||||
void (*ExecuteBlock)();
|
||||
void (*ExecuteVU0Block)();
|
||||
void (*ExecuteVU1Block)();
|
||||
void (*EnableVU0micro)(int enable);
|
||||
void (*EnableVU1micro)(int enable);
|
||||
void (*Clear)(u32 Addr, u32 Size);
|
||||
void (*ClearVU0)(u32 Addr, u32 Size);
|
||||
void (*ClearVU1)(u32 Addr, u32 Size);
|
||||
void (*Shutdown)();
|
||||
void (*Shutdown)(); // deallocates memory reserved by Allocate
|
||||
};
|
||||
|
||||
extern s32 EEsCycle;
|
||||
|
@ -222,7 +216,7 @@ struct tlbs
|
|||
|
||||
#endif
|
||||
|
||||
bool cpuInit();
|
||||
void cpuInit();
|
||||
void cpuReset(); // can throw Exception::FileNotFound.
|
||||
void cpuShutdown();
|
||||
void cpuExecuteBios();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Common.h"
|
||||
#include "SPR.h"
|
||||
#include "iR5900.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
using R5900::Cpu;
|
||||
|
||||
|
@ -51,16 +52,12 @@ static void TestClearVUs(u32 madr, u32 size)
|
|||
{
|
||||
if( madr >= 0x11000000 ) {
|
||||
if( madr < 0x11004000 ) {
|
||||
#ifdef _DEBUG
|
||||
SysPrintf("scratch pad clearing vu0\n");
|
||||
#endif
|
||||
Cpu->ClearVU0(madr&0xfff, size);
|
||||
DbgCon::Notice("scratch pad clearing vu0");
|
||||
CpuVU0->Clear(madr&0xfff, size);
|
||||
}
|
||||
else if( madr >= 0x11008000 && madr < 0x1100c000 ) {
|
||||
#ifdef _DEBUG
|
||||
SysPrintf("scratch pad clearing vu1\n");
|
||||
#endif
|
||||
Cpu->ClearVU1(madr&0x3fff, size);
|
||||
DbgCon::Notice("scratch pad clearing vu1\n");
|
||||
CpuVU1->Clear(madr&0x3fff, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@ static void PostLoadPrep()
|
|||
VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READONLY, &OldProtect);
|
||||
#endif
|
||||
|
||||
memset(pCache,0,sizeof(_cacheS)*64);
|
||||
WriteCP0Status(cpuRegs.CP0.n.Status.val);
|
||||
memset(pCache,0,sizeof(pCache));
|
||||
// WriteCP0Status(cpuRegs.CP0.n.Status.val);
|
||||
for(int i=0; i<48; i++) MapTLB(i);
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ void SaveState::FreezeAll()
|
|||
FreezeMem(PS2MEM_ROM, Ps2MemSize::Rom); // 4 mb rom memory
|
||||
FreezeMem(PS2MEM_ROM1, Ps2MemSize::Rom1); // 256kb rom1 memory
|
||||
FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad
|
||||
FreezeMem(PS2MEM_HW, 0x00010000); // hardware memory
|
||||
FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory
|
||||
|
||||
Freeze(cpuRegs); // cpu regs + COP0
|
||||
Freeze(psxRegs); // iop regs
|
||||
|
@ -137,16 +137,15 @@ void SaveState::FreezeAll()
|
|||
|
||||
rcntFreeze();
|
||||
gsFreeze();
|
||||
vu0Freeze();
|
||||
vu1Freeze();
|
||||
vuMicroFreeze();
|
||||
vif0Freeze();
|
||||
vif1Freeze();
|
||||
sifFreeze();
|
||||
ipuFreeze();
|
||||
|
||||
// iop now
|
||||
FreezeMem(psxM, 0x00200000); // 2 MB main memory
|
||||
FreezeMem(psxH, 0x00010000); // hardware memory
|
||||
FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory
|
||||
FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory
|
||||
//FreezeMem(psxS, 0x00010000); // sif memory
|
||||
|
||||
sioFreeze();
|
||||
|
@ -164,7 +163,7 @@ void SaveState::FreezeAll()
|
|||
PostLoadPrep();
|
||||
}
|
||||
|
||||
// this function is yet incomplete. Version numbers hare still < 12 so it won't be run.
|
||||
// this function is yet incomplete. Version numbers hare still < 0x12 so it won't be run.
|
||||
// (which is good because it won't work :P)
|
||||
void SaveState::_testCdvdCrc()
|
||||
{
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
// If you make changes to the savestate version, please increment the value below.
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
static const u32 g_SaveVersion = 0x7a300011;
|
||||
static const u32 g_SaveVersion = 0x7a300012;
|
||||
#else
|
||||
static const u32 g_SaveVersion = 0x8b400001;
|
||||
static const u32 g_SaveVersion = 0x8b400002;
|
||||
#endif
|
||||
|
||||
// this function is meant to be sued in the place of GSfreeze, and provides a safe layer
|
||||
|
@ -115,8 +115,7 @@ protected:
|
|||
// Load/Save functions for the various components of our glorious emulator!
|
||||
|
||||
void rcntFreeze();
|
||||
void vu0Freeze();
|
||||
void vu1Freeze();
|
||||
void vuMicroFreeze();
|
||||
void vif0Freeze();
|
||||
void vif1Freeze();
|
||||
void sifFreeze();
|
||||
|
|
|
@ -61,22 +61,26 @@ struct _sif1 {
|
|||
int counter;
|
||||
};
|
||||
|
||||
_sif0 sif0;
|
||||
_sif1 sif1;
|
||||
static _sif0 sif0;
|
||||
static _sif1 sif1;
|
||||
|
||||
int wP0, wP1;
|
||||
int eesifbusy[2] = { 0, 0 };
|
||||
extern int iopsifbusy[2];
|
||||
|
||||
void sifInit() {
|
||||
void sifInit()
|
||||
{
|
||||
memset(&sif0, 0, sizeof(sif0));
|
||||
memset(&sif1, 0, sizeof(sif1));
|
||||
memset(eesifbusy, 0, sizeof(eesifbusy));
|
||||
memset(iopsifbusy, 0, sizeof(iopsifbusy));
|
||||
}
|
||||
|
||||
static __forceinline void SIF0write(u32 *from, int words)
|
||||
{
|
||||
/*if(FIFO_SIF0_W < (words+sif0.fifoWritePos)) {*/
|
||||
wP0 = min((FIFO_SIF0_W-sif0.fifoWritePos),words);
|
||||
wP1 = words - wP0;
|
||||
|
||||
const int wP0 = min((FIFO_SIF0_W-sif0.fifoWritePos),words);
|
||||
const int wP1 = words - wP0;
|
||||
|
||||
memcpy(&sif0.fifoData[sif0.fifoWritePos], from, wP0 << 2);
|
||||
memcpy(&sif0.fifoData[0], &from[wP0], wP1 << 2);
|
||||
|
@ -91,18 +95,14 @@ static __forceinline void SIF0write(u32 *from, int words)
|
|||
|
||||
sif0.fifoSize += words;
|
||||
SIF_LOG(" SIF0 + %d = %d (pos=%d)\n", words, sif0.fifoSize, sif0.fifoWritePos);
|
||||
|
||||
/* if (sif0.fifoSize == FIFO_SIF0_W) {
|
||||
Cpu->ExecuteBlock();
|
||||
}*/
|
||||
}
|
||||
|
||||
static __forceinline void SIF0read(u32 *to, int words)
|
||||
{
|
||||
/*if(FIFO_SIF0_W < (words+sif0.fifoReadPos))
|
||||
{*/
|
||||
wP0 = min((FIFO_SIF0_W-sif0.fifoReadPos),words);
|
||||
wP1 = words - wP0;
|
||||
const int wP0 = min((FIFO_SIF0_W-sif0.fifoReadPos),words);
|
||||
const int wP1 = words - wP0;
|
||||
|
||||
memcpy(to, &sif0.fifoData[sif0.fifoReadPos], wP0 << 2);
|
||||
memcpy(&to[wP0], &sif0.fifoData[0], wP1 << 2);
|
||||
|
@ -123,8 +123,8 @@ __forceinline void SIF1write(u32 *from, int words)
|
|||
{
|
||||
/*if(FIFO_SIF1_W < (words+sif1.fifoWritePos))
|
||||
{*/
|
||||
wP0 = min((FIFO_SIF1_W-sif1.fifoWritePos),words);
|
||||
wP1 = words - wP0;
|
||||
const int wP0 = min((FIFO_SIF1_W-sif1.fifoWritePos),words);
|
||||
const int wP1 = words - wP0;
|
||||
|
||||
memcpy(&sif1.fifoData[sif1.fifoWritePos], from, wP0 << 2);
|
||||
memcpy(&sif1.fifoData[0], &from[wP0], wP1 << 2);
|
||||
|
@ -139,18 +139,14 @@ __forceinline void SIF1write(u32 *from, int words)
|
|||
|
||||
sif1.fifoSize += words;
|
||||
SIF_LOG(" SIF1 + %d = %d (pos=%d)\n", words, sif1.fifoSize, sif1.fifoWritePos);
|
||||
|
||||
/* if (sif1.fifoSize == FIFO_SIF1_W) {
|
||||
psxCpu->ExecuteBlock();
|
||||
}*/
|
||||
}
|
||||
|
||||
static __forceinline void SIF1read(u32 *to, int words)
|
||||
{
|
||||
/*if(FIFO_SIF1_W < (words+sif1.fifoReadPos))
|
||||
{*/
|
||||
wP0 = min((FIFO_SIF1_W-sif1.fifoReadPos),words);
|
||||
wP1 = words - wP0;
|
||||
const int wP0 = min((FIFO_SIF1_W-sif1.fifoReadPos),words);
|
||||
const int wP1 = words - wP0;
|
||||
|
||||
memcpy(to, &sif1.fifoData[sif1.fifoReadPos], wP0 << 2);
|
||||
memcpy(&to[wP0], &sif1.fifoData[0], wP1 << 2);
|
||||
|
@ -594,4 +590,19 @@ __forceinline void dmaSIF2() {
|
|||
void SaveState::sifFreeze() {
|
||||
Freeze(sif0);
|
||||
Freeze(sif1);
|
||||
|
||||
if( GetVersion() >= 0x0012 )
|
||||
{
|
||||
Freeze(eesifbusy);
|
||||
Freeze(iopsifbusy);
|
||||
}
|
||||
else if( IsLoading() )
|
||||
{
|
||||
// Old savestate, inferior data so...
|
||||
// Take an educated guess on what they should be. Or well, set to 1 because
|
||||
// it more or less forces them to "kick"
|
||||
|
||||
iopsifbusy[0] = eesifbusy[0] = 1;
|
||||
iopsifbusy[1] = eesifbusy[1] = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,8 @@ u8 sio_xor(u8 *buf, unsigned int length){
|
|||
return x & 0xFF;
|
||||
}
|
||||
|
||||
int sioInit() {
|
||||
void sioInit()
|
||||
{
|
||||
memset(&sio, 0, sizeof(sio));
|
||||
|
||||
MemoryCard1 = LoadMcd(1);
|
||||
|
@ -74,8 +75,6 @@ int sioInit() {
|
|||
sio.StatReg = TX_RDY | TX_EMPTY;
|
||||
sio.packetsize = 0;
|
||||
sio.terminator =0x55; // Command terminator 'U'
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void psxSIOShutdown()
|
||||
|
@ -517,8 +516,8 @@ void SaveState::sioFreeze()
|
|||
{
|
||||
Freeze( sio );
|
||||
|
||||
if( IsLoading() )
|
||||
sio.count = 0;
|
||||
//if( IsLoading() )
|
||||
// sio.count = 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ extern _sio sio;
|
|||
#define RTS 0x0020
|
||||
#define SIO_RESET 0x0040
|
||||
|
||||
int sioInit();
|
||||
void sioInit();
|
||||
void sioShutdown();
|
||||
void psxSIOShutdown();
|
||||
u8 sioRead8();
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/* Pcsx2 - Pc Ps2 Emulator
|
||||
* Copyright (C) 2002-2008 Pcsx2 Team
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "System.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void _format_vstring( string& dest, const char* format, va_list args )
|
||||
{
|
||||
int writtenCount;
|
||||
int newSize = strlen(format) * 2;
|
||||
char *buf, *out;
|
||||
|
||||
while( true )
|
||||
{
|
||||
buf = new char[newSize + 1];
|
||||
|
||||
// note! vsnprintf doesn't always return consistent results on GCC.
|
||||
// We can't assume it returns -1;
|
||||
writtenCount = vsnprintf(buf, newSize, format, args);
|
||||
|
||||
if (writtenCount >= newSize)
|
||||
writtenCount = -1;
|
||||
else if( writtenCount != -1 ) break;
|
||||
|
||||
// Gotta try again -_-
|
||||
newSize += newSize / 2;
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
buf[writtenCount] = '\0';
|
||||
cout << buf;
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
string format_string( const char* format, ... )
|
||||
{
|
||||
string joe;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_format_vstring( joe, format, args );
|
||||
va_end(args);
|
||||
return joe;
|
||||
}
|
||||
|
||||
void format_string( string& dest, const char* format, ... )
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_format_vstring( dest, format, args );
|
||||
va_end(args);
|
||||
}
|
153
pcsx2/System.cpp
153
pcsx2/System.cpp
|
@ -20,12 +20,19 @@
|
|||
|
||||
#include "Common.h"
|
||||
#include "PsxCommon.h"
|
||||
#include "VUmicro.h"
|
||||
#include "Threading.h"
|
||||
|
||||
#include "iVUzerorec.h"
|
||||
|
||||
#include "x86/ix86/ix86.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Console;
|
||||
using R5900::cpuRegs;
|
||||
|
||||
// disable all session overrides by default...
|
||||
SessionOverrideFlags g_Session = {false};
|
||||
|
||||
bool sysInitialized = false;
|
||||
|
||||
|
@ -34,11 +41,11 @@ namespace Exception
|
|||
BaseException::~BaseException() throw() {}
|
||||
}
|
||||
|
||||
|
||||
// I can't believe I had to make my own version of trim. C++'s STL is totally whack.
|
||||
// And I still had to fix it too. I found three samples of trim online and *all* three
|
||||
// were buggy. People really need to learn to code before they start posting trim
|
||||
// functions in their blogs. (air)
|
||||
|
||||
static void trim( string& line )
|
||||
{
|
||||
if ( line.empty() )
|
||||
|
@ -82,7 +89,6 @@ static void trim( string& line )
|
|||
line.erase( 0, beginning_of_string );
|
||||
}
|
||||
|
||||
using R5900::cpuRegs;
|
||||
|
||||
// This function should be called once during program execution.
|
||||
void SysDetect()
|
||||
|
@ -149,3 +155,146 @@ void SysDetect()
|
|||
|
||||
Console::ClearColor();
|
||||
}
|
||||
|
||||
// Allocates memory for all PS2 systems.
|
||||
bool SysAllocateMem()
|
||||
{
|
||||
// Allocate PS2 system ram space (required by interpreters and recompilers both)
|
||||
|
||||
try
|
||||
{
|
||||
memAlloc();
|
||||
psxMemAlloc();
|
||||
vuMicroMemAlloc();
|
||||
}
|
||||
catch( Exception::OutOfMemory& ex )
|
||||
{
|
||||
// Failures on the core initialization of memory is bad, since it means the emulator is
|
||||
// completely non-functional. If the failure is in the VM build then we can try running
|
||||
// the VTLB build instead. If it's the VTLB build then ... ouch.
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
Console::Error( ex.Message() );
|
||||
if( MessageBox(NULL,
|
||||
"Failed to allocate enough physical memory to run pcsx2. Try closing\n"
|
||||
"down background programs, restarting windows, or buying more memory.\n\n"
|
||||
"Launch TLB version of pcsx2 (pcsx2t.exe)?", "Memory Allocation Error", MB_YESNO) == IDYES )
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
|
||||
MemoryAlloc<char> strdir( GetCurrentDirectory( 0, NULL )+2, "VTLB Launcher" );
|
||||
string strexe;
|
||||
|
||||
GetCurrentDirectory(strdir.GetLength(), strdir.GetPtr());
|
||||
Path::Combine( strexe, strdir.GetPtr(), "pcsx2-vtlb.exe" );
|
||||
memset(&si, 0, sizeof(si));
|
||||
|
||||
if( !CreateProcess(strexe.c_str(), "", NULL, NULL, FALSE, DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP, NULL, strdir.GetPtr(), &si, &pi))
|
||||
{
|
||||
MessageBox(NULL, fmt_string( "Failed to launch %hs\n", params &strexe ).c_str(), "Failure", MB_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// VTLB build must fail outright...
|
||||
Msgbox::Alert( "Failed to allocate memory needed to run pcsx2.\n\nError: " + ex.Message() );
|
||||
#endif
|
||||
SysShutdownMem();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Allocates memory for all recompilers,a nd force-disables any recs that fail to initialize.
|
||||
// This should be done asap, since the recompilers tend to demand a lot of system resources, and prefer
|
||||
// to have those resources at specific address ranges. The sooner memory is allocated, the better.
|
||||
// Returns FALSE on *critical* failure (GUI should issue a msg and exit).
|
||||
void SysAllocateDynarecs()
|
||||
{
|
||||
// Attempt to initialize the recompilers.
|
||||
// Most users want to use recs anyway, and if they are using interpreters I don't think the
|
||||
// extra few megs of allocation is going to be an issue.
|
||||
|
||||
try
|
||||
{
|
||||
// R5900 and R3000a must be rec-enabled together for now so if either fails they both fail.
|
||||
R5900::recCpu.Allocate();
|
||||
psxRec.Allocate();
|
||||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
Msgbox::Alert(
|
||||
"The EE/IOP recompiler failed to initialize with the following error:\n\n" + ex.Message() +
|
||||
"\n\nThe EE/IOP interpreter will be used instead (slow!)."
|
||||
);
|
||||
|
||||
g_Session.ForceDisableEErec = true;
|
||||
|
||||
R5900::recCpu.Shutdown();
|
||||
psxRec.Shutdown();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
recVU0.Allocate();
|
||||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
Msgbox::Alert(
|
||||
"The VU0 recompiler failed to initialize with the following error:\n\n" + ex.Message() +
|
||||
"\n\nThe VU0 interpreter will be used for this session (may slow down some games)."
|
||||
);
|
||||
|
||||
g_Session.ForceDisableVU0rec = true;
|
||||
recVU0.Shutdown();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
recVU1.Allocate();
|
||||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
Msgbox::Alert(
|
||||
"The VU1 recompiler failed to initialize with the following error:\n\n" + ex.Message() +
|
||||
"\n\nThe VU1 interpreter will be used for this session (will slow down most games)."
|
||||
);
|
||||
|
||||
g_Session.ForceDisableVU1rec = true;
|
||||
recVU1.Shutdown();
|
||||
}
|
||||
|
||||
// If both VUrecs failed, then make sure the SuperVU is totally closed out:
|
||||
if( !CHECK_VU0REC && !CHECK_VU1REC)
|
||||
Dynarec::SuperVUDestroy( -1 );
|
||||
}
|
||||
|
||||
// This should be called last thing before Pcsx2 exits.
|
||||
void SysShutdownMem()
|
||||
{
|
||||
R5900::cpuShutdown();
|
||||
|
||||
vuMicroMemShutdown();
|
||||
psxMemShutdown();
|
||||
memShutdown();
|
||||
}
|
||||
|
||||
// This should generally be called right before calling SysShutdownMem(), although you can optionally
|
||||
// use it in conjunction with SysAllocDynarecs to allocate/free the dynarec resources on the fly (as
|
||||
// risky as it might be, since dynarecs could very well fail on the second attempt).
|
||||
void SysShutdownDynarecs()
|
||||
{
|
||||
// Special SuperVU "complete" terminator.
|
||||
Dynarec::SuperVUDestroy( -1 );
|
||||
|
||||
psxRec.Shutdown();
|
||||
R5900::recCpu.Shutdown();
|
||||
}
|
|
@ -29,6 +29,12 @@ void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompile
|
|||
void SysUpdate(); // Called on VBlank (to update i.e. pads)
|
||||
void SysRunGui(); // Returns to the Gui
|
||||
void SysClose(); // Close mem and plugins
|
||||
|
||||
bool SysAllocateMem(); // allocates memory for all PS2 systems; returns FALSe on critical error.
|
||||
void SysAllocateDynarecs(); // allocates memory for all dynarecs, and force-disables any failures.
|
||||
void SysShutdownDynarecs();
|
||||
void SysShutdownMem();
|
||||
|
||||
void *SysLoadLibrary(const char *lib); // Loads Library
|
||||
void *SysLoadSym(void *lib, const char *sym); // Loads Symbol from Library
|
||||
const char *SysLibError(); // Gets previous error loading sysbols
|
||||
|
|
|
@ -46,7 +46,7 @@ enum VUStatus {
|
|||
VU_Stop = 2,
|
||||
};
|
||||
|
||||
typedef union {
|
||||
union VECTOR {
|
||||
struct {
|
||||
float x,y,z,w;
|
||||
} f;
|
||||
|
@ -64,9 +64,9 @@ typedef union {
|
|||
s16 SS[8];
|
||||
u8 UC[16];
|
||||
s8 SC[16];
|
||||
} VECTOR;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct REG_VI {
|
||||
union {
|
||||
float F;
|
||||
s32 SL;
|
||||
|
@ -78,7 +78,7 @@ typedef struct {
|
|||
};
|
||||
u32 padding[3]; // needs padding to make them 128bit; VU0 maps VU1's VI regs as 128bits to addr 0x4xx0 in
|
||||
// VU0 mem, with only lower 16 bits valid, and the upper 112bits are hardwired to 0 (cottonvibes)
|
||||
} REG_VI;
|
||||
};
|
||||
|
||||
#define VUFLAG_BREAKONMFLAG 0x00000001
|
||||
#define VUFLAG_MFLAGSET 0x00000002
|
||||
|
|
|
@ -65,6 +65,33 @@ void COP2_Unknown()
|
|||
CPU_LOG("Unknown COP2 opcode called\n");
|
||||
}
|
||||
|
||||
//****************************************************************************
|
||||
void _vu0WaitMicro() {
|
||||
int startcycle;
|
||||
|
||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
startcycle = VU0.cycle;
|
||||
|
||||
VU0.flags|= VUFLAG_BREAKONMFLAG;
|
||||
VU0.flags&= ~VUFLAG_MFLAGSET;
|
||||
|
||||
do {
|
||||
CpuVU0->ExecuteBlock();
|
||||
// knockout kings 2002 loops here
|
||||
if( VU0.cycle-startcycle > 0x1000 ) {
|
||||
Console::Notice("VU0 perma-stall, breaking execution..."); // (email zero if gfx are bad)
|
||||
break;
|
||||
}
|
||||
} while ((VU0.VI[REG_VPU_STAT].UL & 0x1) && (VU0.flags & VUFLAG_MFLAGSET) == 0);
|
||||
|
||||
//NEW
|
||||
cpuRegs.cycle += (VU0.cycle-startcycle)*2;
|
||||
VU0.flags&= ~VUFLAG_BREAKONMFLAG;
|
||||
}
|
||||
|
||||
namespace R5900 {
|
||||
namespace Interpreter{
|
||||
namespace OpcodeImpl
|
||||
|
@ -90,34 +117,6 @@ namespace OpcodeImpl
|
|||
}
|
||||
}}}
|
||||
|
||||
//****************************************************************************
|
||||
void _vu0WaitMicro() {
|
||||
int startcycle;
|
||||
|
||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) {
|
||||
return;
|
||||
}
|
||||
FreezeXMMRegs(1);
|
||||
startcycle = VU0.cycle;
|
||||
|
||||
VU0.flags|= VUFLAG_BREAKONMFLAG;
|
||||
VU0.flags&= ~VUFLAG_MFLAGSET;
|
||||
|
||||
do {
|
||||
Cpu->ExecuteVU0Block();
|
||||
// knockout kings 2002 loops here
|
||||
if( VU0.cycle-startcycle > 0x1000 ) {
|
||||
SysPrintf("VU0 wait stall.\n"); // (email zero if gfx are bad)
|
||||
break;
|
||||
}
|
||||
} while ((VU0.VI[REG_VPU_STAT].UL & 0x1) && (VU0.flags & VUFLAG_MFLAGSET) == 0);
|
||||
|
||||
FreezeXMMRegs(0);
|
||||
//NEW
|
||||
cpuRegs.cycle += (VU0.cycle-startcycle)*2;
|
||||
VU0.flags&= ~VUFLAG_BREAKONMFLAG;
|
||||
}
|
||||
|
||||
|
||||
void QMFC2() {
|
||||
if (cpuRegs.code & 1) {
|
||||
|
@ -163,14 +162,14 @@ void CTC2() {
|
|||
case REG_FBRST:
|
||||
VU0.VI[REG_FBRST].UL = cpuRegs.GPR.r[_Rt_].UL[0] & 0x0C0C;
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x1) { // VU0 Force Break
|
||||
SysPrintf("fixme: VU0 Force Break\n");
|
||||
Console::Error("fixme: VU0 Force Break");
|
||||
}
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x2) { // VU0 Reset
|
||||
//SysPrintf("fixme: VU0 Reset\n");
|
||||
vu0ResetRegs();
|
||||
}
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x100) { // VU1 Force Break
|
||||
SysPrintf("fixme: VU1 Force Break\n");
|
||||
Console::Error("fixme: VU1 Force Break");
|
||||
}
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x200) { // VU1 Reset
|
||||
// SysPrintf("fixme: VU1 Reset\n");
|
||||
|
@ -343,23 +342,22 @@ void VFCSET() { VU0.code = cpuRegs.code; _vuFCSET(&VU0); }
|
|||
void VFCGET() { VU0.code = cpuRegs.code; _vuFCGET(&VU0); }
|
||||
void VXITOP() { VU0.code = cpuRegs.code; _vuXITOP(&VU0); }
|
||||
|
||||
// fixme: Shouldn't anything calling this function be calling vu0WaitMicro instead?
|
||||
// Meaning that this function stalls, but doesn't increment the cpuRegs.cycle like
|
||||
// you would think it should.
|
||||
void vu0Finish()
|
||||
{
|
||||
if( (VU0.VI[REG_VPU_STAT].UL & 0x1) ) {
|
||||
int i = 0;
|
||||
|
||||
FreezeXMMRegs(1);
|
||||
while(i++ < 32) {
|
||||
Cpu->ExecuteVU0Block();
|
||||
CpuVU0->ExecuteBlock();
|
||||
if(!(VU0.VI[REG_VPU_STAT].UL & 0x1))
|
||||
break;
|
||||
}
|
||||
FreezeXMMRegs(0);
|
||||
if(VU0.VI[REG_VPU_STAT].UL & 0x1) {
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~1;
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
SysPrintf("VU0 stall\n");
|
||||
#endif
|
||||
Console::Notice("vu0Finish > stall aborted by force.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
// This module contains code shared by both the dynarec and interpreter versions
|
||||
// of the VU0 micro.
|
||||
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <cmath>
|
||||
|
@ -30,10 +34,7 @@
|
|||
|
||||
#include "iVUzerorec.h"
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
extern PSMEMORYBLOCK s_psVuMem;
|
||||
extern PSMEMORYMAP *memLUT;
|
||||
#endif
|
||||
using namespace R5900;
|
||||
|
||||
#define VF_VAL(x) ((x==0x80000000)?0:(x))
|
||||
|
||||
|
@ -57,90 +58,7 @@ void iDumpVU0Registers()
|
|||
#endif
|
||||
}
|
||||
|
||||
using namespace R5900;
|
||||
|
||||
int vu0Init()
|
||||
{
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
// unmap all vu0 pages
|
||||
SysMapUserPhysicalPages(PS2MEM_VU0MICRO, 16, NULL, 0);
|
||||
|
||||
// mirror 4 times
|
||||
VU0.Micro = PS2MEM_VU0MICRO;
|
||||
memLUT[0x11000].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11000].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
memLUT[0x11001].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11001].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
memLUT[0x11002].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11002].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
memLUT[0x11003].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11003].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
|
||||
// since vuregisters are mapped in vumem0, go to diff addr, but mapping to same physical addr
|
||||
//VirtualFree((void*)0x11000000, 0x10000, MEM_RELEASE); // free just in case
|
||||
if( VU0.Mem == NULL )
|
||||
VU0.Mem = (u8*)VirtualAlloc((void*)0x11000000, 0x10000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE);
|
||||
|
||||
if( VU0.Mem != (void*)0x11000000 ) {
|
||||
Console::WriteLn("Failed to alloc vu0mem 0x11000000 %d", params GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
memLUT[0x11004].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11004].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
memLUT[0x11005].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11005].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
memLUT[0x11006].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11006].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
memLUT[0x11007].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11007].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
|
||||
// map only registers
|
||||
SysMapUserPhysicalPages(VU0.Mem+0x4000, 1, s_psVuMem.aPFNs, 2);
|
||||
#else
|
||||
VU0.Mem = (u8*)_aligned_malloc(0x4000+sizeof(VURegs), 16); // for VU1
|
||||
VU0.Micro = (u8*)_aligned_malloc(4*1024, 16);
|
||||
memset(VU0.Mem, 0, 0x4000+sizeof(VURegs));
|
||||
memset(VU0.Micro, 0, 4*1024);
|
||||
#endif
|
||||
|
||||
|
||||
// VU0.VF = (VECTOR*)_aligned_malloc(32*sizeof(VECTOR), 16);
|
||||
// VU0.VI = (REG_VI*)_aligned_malloc(32*sizeof(REG_VI), 16);
|
||||
// if (VU0.VF == NULL || VU0.VI == NULL) {
|
||||
// Msgbox::Alert("Error allocating memory");
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
/* this is kinda tricky, maxmem is set to 0x4400 here,
|
||||
tho it's not 100% accurate, since the mem goes from
|
||||
0x0000 - 0x1000 (Mem) and 0x4000 - 0x4400 (VU1 Regs),
|
||||
i guess it shouldn't be a problem,
|
||||
at least hope so :) (linuz)
|
||||
*/
|
||||
VU0.maxmem = 0x4400-4;
|
||||
VU0.maxmicro = 4*1024-4;
|
||||
VU0.vuExec = vu0Exec;
|
||||
VU0.vifRegs = vif0Regs;
|
||||
|
||||
if( CHECK_VU0REC ) Dynarec::SuperVUInit(0);
|
||||
|
||||
vu0Reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vu0Shutdown()
|
||||
{
|
||||
if( CHECK_VU0REC ) Dynarec::SuperVUDestroy(0);
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
if( !SysMapUserPhysicalPages(VU0.Mem, 16, NULL, 0) )
|
||||
Console::Error("Error releasing vu0 memory %d", params GetLastError());
|
||||
|
||||
if( VirtualFree(VU0.Mem, 0, MEM_RELEASE) == 0 )
|
||||
Console::Error("Error freeing vu0 memory %d", params GetLastError());
|
||||
#else
|
||||
safe_aligned_free(VU0.Mem);
|
||||
safe_aligned_free(VU0.Micro);
|
||||
#endif
|
||||
|
||||
VU0.Mem = NULL;
|
||||
VU0.Micro = NULL;
|
||||
}
|
||||
|
||||
// This is called by the COP2 as per the CTC instruction
|
||||
void vu0ResetRegs()
|
||||
{
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~0xff; // stop vu0
|
||||
|
@ -150,30 +68,10 @@ void vu0ResetRegs()
|
|||
|
||||
void vu0Reset()
|
||||
{
|
||||
memset(&VU0.ACC, 0, sizeof(VECTOR));
|
||||
memset(VU0.VF, 0, sizeof(VECTOR)*32);
|
||||
memset(VU0.VI, 0, sizeof(REG_VI)*32);
|
||||
VU0.VF[0].f.x = 0.0f;
|
||||
VU0.VF[0].f.y = 0.0f;
|
||||
VU0.VF[0].f.z = 0.0f;
|
||||
VU0.VF[0].f.w = 1.0f;
|
||||
VU0.VI[0].UL = 0;
|
||||
memset(VU0.Mem, 0, 4*1024);
|
||||
memset(VU0.Micro, 0, 4*1024);
|
||||
|
||||
if( CHECK_VU0REC ) Dynarec::recResetVU0();
|
||||
CpuVU0 = CHECK_VU0REC ? &recVU0 : &intVU0;
|
||||
CpuVU0->Reset();
|
||||
}
|
||||
|
||||
void SaveState::vu0Freeze() {
|
||||
Freeze(VU0.ACC);
|
||||
Freeze(VU0.code);
|
||||
FreezeMem(VU0.Mem, 4*1024);
|
||||
FreezeMem(VU0.Micro, 4*1024);
|
||||
FreezeMem(VU0.VF, 32*sizeof(VECTOR));
|
||||
FreezeMem(VU0.VI, 32*sizeof(REG_VI));
|
||||
}
|
||||
|
||||
|
||||
void VU0MI_XGKICK() {
|
||||
}
|
||||
|
||||
|
@ -184,7 +82,7 @@ void vu0ExecMicro(u32 addr) {
|
|||
VUM_LOG("vu0ExecMicro %x\n", addr);
|
||||
|
||||
if(VU0.VI[REG_VPU_STAT].UL & 0x1) {
|
||||
SysPrintf("Previous Microprogram still running on VU0\n");
|
||||
DevCon::Notice("vu0ExecMicro > Stalling for previous microprogram to finish");
|
||||
vu0Finish();
|
||||
}
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x1;
|
||||
|
@ -192,187 +90,14 @@ void vu0ExecMicro(u32 addr) {
|
|||
|
||||
if (addr != -1) VU0.VI[REG_TPC].UL = addr;
|
||||
_vuExecMicroDebug(VU0);
|
||||
FreezeXMMRegs(1);
|
||||
Cpu->ExecuteVU0Block();
|
||||
FreezeXMMRegs(0);
|
||||
CpuVU0->ExecuteBlock();
|
||||
|
||||
// If the VU0 program didn't finish then we'll want to finish it up
|
||||
// pretty soon. This fixes vmhacks in some games (Naruto Ultimate Ninja 2)
|
||||
if(VU0.VI[REG_VPU_STAT].UL & 0x1)
|
||||
cpuSetNextBranchDelta( 128 );
|
||||
cpuSetNextBranchDelta( 192 ); // fixme : ideally this should be higher, like 512 or so.
|
||||
}
|
||||
|
||||
void _vu0ExecUpper(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[1];
|
||||
IdebugUPPER(VU0);
|
||||
VU0_UPPER_OPCODE[VU->code & 0x3f]();
|
||||
}
|
||||
|
||||
void _vu0ExecLower(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[0];
|
||||
IdebugLOWER(VU0);
|
||||
VU0_LOWER_OPCODE[VU->code >> 25]();
|
||||
}
|
||||
|
||||
extern void _vuFlushAll(VURegs* VU);
|
||||
int vu0branch = 0;
|
||||
void _vu0Exec(VURegs* VU) {
|
||||
_VURegsNum lregs;
|
||||
_VURegsNum uregs;
|
||||
VECTOR _VF;
|
||||
VECTOR _VFc;
|
||||
REG_VI _VI;
|
||||
REG_VI _VIc;
|
||||
u32 *ptr;
|
||||
int vfreg;
|
||||
int vireg;
|
||||
int discard=0;
|
||||
|
||||
if(VU0.VI[REG_TPC].UL >= VU0.maxmicro){
|
||||
#ifdef CPU_LOG
|
||||
SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL);
|
||||
#endif
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x1;
|
||||
VU->cycle++;
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL];
|
||||
VU->VI[REG_TPC].UL+=8;
|
||||
|
||||
if (ptr[1] & 0x40000000) {
|
||||
VU->ebit = 2;
|
||||
}
|
||||
if (ptr[1] & 0x20000000) { /* M flag */
|
||||
VU->flags|= VUFLAG_MFLAGSET;
|
||||
// SysPrintf("fixme: M flag set\n");
|
||||
}
|
||||
if (ptr[1] & 0x10000000) { /* D flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x4) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x2;
|
||||
hwIntcIrq(INTC_VU0);
|
||||
}
|
||||
}
|
||||
if (ptr[1] & 0x08000000) { /* T flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x8) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x4;
|
||||
hwIntcIrq(INTC_VU0);
|
||||
}
|
||||
}
|
||||
|
||||
VU->code = ptr[1];
|
||||
VU0regs_UPPER_OPCODE[VU->code & 0x3f](&uregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestUpperStalls(VU, &uregs);
|
||||
#endif
|
||||
|
||||
/* check upper flags */
|
||||
if (ptr[1] & 0x80000000) { /* I flag */
|
||||
_vu0ExecUpper(VU, ptr);
|
||||
|
||||
VU->VI[REG_I].UL = ptr[0];
|
||||
memset(&lregs, 0, sizeof(lregs));
|
||||
} else {
|
||||
VU->code = ptr[0];
|
||||
VU0regs_LOWER_OPCODE[VU->code >> 25](&lregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestLowerStalls(VU, &lregs);
|
||||
#endif
|
||||
|
||||
vu0branch = lregs.pipe == VUPIPE_BRANCH;
|
||||
|
||||
vfreg = 0; vireg = 0;
|
||||
if (uregs.VFwrite) {
|
||||
if (lregs.VFwrite == uregs.VFwrite) {
|
||||
// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VFread0 == uregs.VFwrite ||
|
||||
lregs.VFread1 == uregs.VFwrite) {
|
||||
// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL);
|
||||
_VF = VU->VF[uregs.VFwrite];
|
||||
vfreg = uregs.VFwrite;
|
||||
}
|
||||
}
|
||||
if (uregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) {
|
||||
SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
_VI = VU0.VI[REG_CLIP_FLAG];
|
||||
vireg = REG_CLIP_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
_vu0ExecUpper(VU, ptr);
|
||||
|
||||
if (discard == 0) {
|
||||
if (vfreg) {
|
||||
_VFc = VU->VF[vfreg];
|
||||
VU->VF[vfreg] = _VF;
|
||||
}
|
||||
if (vireg) {
|
||||
_VIc = VU->VI[vireg];
|
||||
VU->VI[vireg] = _VI;
|
||||
}
|
||||
|
||||
_vu0ExecLower(VU, ptr);
|
||||
|
||||
if (vfreg) {
|
||||
VU->VF[vfreg] = _VFc;
|
||||
}
|
||||
if (vireg) {
|
||||
VU->VI[vireg] = _VIc;
|
||||
}
|
||||
}
|
||||
}
|
||||
_vuAddUpperStalls(VU, &uregs);
|
||||
|
||||
if (!(ptr[1] & 0x80000000))
|
||||
_vuAddLowerStalls(VU, &lregs);
|
||||
|
||||
_vuTestPipes(VU);
|
||||
|
||||
if (VU->branch > 0) {
|
||||
VU->branch--;
|
||||
if (VU->branch == 0) {
|
||||
VU->VI[REG_TPC].UL = VU->branchpc;
|
||||
}
|
||||
}
|
||||
|
||||
if( VU->ebit > 0 ) {
|
||||
if( VU->ebit-- == 1 ) {
|
||||
_vuFlushAll(VU);
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x1; /* E flag */
|
||||
vif0Regs->stat&= ~0x4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vu0Exec(VURegs* VU) {
|
||||
// u32 *ptr;
|
||||
|
||||
if (VU->VI[REG_TPC].UL >= VU->maxmicro) {
|
||||
#ifdef CPU_LOG
|
||||
SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL);
|
||||
#endif
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x1;
|
||||
} else {
|
||||
_vu0Exec(VU);
|
||||
}
|
||||
VU->cycle++;
|
||||
|
||||
if (VU->VI[0].UL != 0) DbgCon::Error("VI[0] != 0!!!!\n");
|
||||
if (VU->VF[0].f.x != 0.0f) DbgCon::Error("VF[0].x != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.y != 0.0f) DbgCon::Error("VF[0].y != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.z != 0.0f) DbgCon::Error("VF[0].z != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.w != 1.0f) DbgCon::Error("VF[0].w != 1.0!!!!\n");
|
||||
}
|
||||
|
||||
_vuTables(VU0, VU0);
|
||||
_vuRegsTables(VU0, VU0regs);
|
||||
|
||||
void VU0unknown() {
|
||||
assert(0);
|
||||
|
||||
|
@ -385,6 +110,7 @@ void VU0regsunknown(_VURegsNum *VUregsn) {
|
|||
CPU_LOG("Unknown VU micromode opcode called\n");
|
||||
}
|
||||
|
||||
_vuRegsTables(VU0, VU0regs);
|
||||
|
||||
|
||||
/****************************************/
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
/* Pcsx2 - Pc Ps2 Emulator
|
||||
* Copyright (C) 2002-2008 Pcsx2 Team
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
extern void _vuFlushAll(VURegs* VU);
|
||||
|
||||
_vuTables(VU0, VU0);
|
||||
|
||||
void _vu0ExecUpper(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[1];
|
||||
IdebugUPPER(VU0);
|
||||
VU0_UPPER_OPCODE[VU->code & 0x3f]();
|
||||
}
|
||||
|
||||
void _vu0ExecLower(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[0];
|
||||
IdebugLOWER(VU0);
|
||||
VU0_LOWER_OPCODE[VU->code >> 25]();
|
||||
}
|
||||
|
||||
int vu0branch = 0;
|
||||
static void _vu0Exec(VURegs* VU)
|
||||
{
|
||||
_VURegsNum lregs;
|
||||
_VURegsNum uregs;
|
||||
VECTOR _VF;
|
||||
VECTOR _VFc;
|
||||
REG_VI _VI;
|
||||
REG_VI _VIc;
|
||||
u32 *ptr;
|
||||
int vfreg;
|
||||
int vireg;
|
||||
int discard=0;
|
||||
|
||||
if(VU0.VI[REG_TPC].UL >= VU0.maxmicro){
|
||||
#ifdef CPU_LOG
|
||||
SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL);
|
||||
#endif
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x1;
|
||||
VU->cycle++;
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL];
|
||||
VU->VI[REG_TPC].UL+=8;
|
||||
|
||||
if (ptr[1] & 0x40000000) {
|
||||
VU->ebit = 2;
|
||||
}
|
||||
if (ptr[1] & 0x20000000) { /* M flag */
|
||||
VU->flags|= VUFLAG_MFLAGSET;
|
||||
// SysPrintf("fixme: M flag set\n");
|
||||
}
|
||||
if (ptr[1] & 0x10000000) { /* D flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x4) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x2;
|
||||
hwIntcIrq(INTC_VU0);
|
||||
}
|
||||
}
|
||||
if (ptr[1] & 0x08000000) { /* T flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x8) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x4;
|
||||
hwIntcIrq(INTC_VU0);
|
||||
}
|
||||
}
|
||||
|
||||
VU->code = ptr[1];
|
||||
VU0regs_UPPER_OPCODE[VU->code & 0x3f](&uregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestUpperStalls(VU, &uregs);
|
||||
#endif
|
||||
|
||||
/* check upper flags */
|
||||
if (ptr[1] & 0x80000000) { /* I flag */
|
||||
_vu0ExecUpper(VU, ptr);
|
||||
|
||||
VU->VI[REG_I].UL = ptr[0];
|
||||
memset(&lregs, 0, sizeof(lregs));
|
||||
} else {
|
||||
VU->code = ptr[0];
|
||||
VU0regs_LOWER_OPCODE[VU->code >> 25](&lregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestLowerStalls(VU, &lregs);
|
||||
#endif
|
||||
|
||||
vu0branch = lregs.pipe == VUPIPE_BRANCH;
|
||||
|
||||
vfreg = 0; vireg = 0;
|
||||
if (uregs.VFwrite) {
|
||||
if (lregs.VFwrite == uregs.VFwrite) {
|
||||
// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VFread0 == uregs.VFwrite ||
|
||||
lregs.VFread1 == uregs.VFwrite) {
|
||||
// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL);
|
||||
_VF = VU->VF[uregs.VFwrite];
|
||||
vfreg = uregs.VFwrite;
|
||||
}
|
||||
}
|
||||
if (uregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) {
|
||||
SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
_VI = VU0.VI[REG_CLIP_FLAG];
|
||||
vireg = REG_CLIP_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
_vu0ExecUpper(VU, ptr);
|
||||
|
||||
if (discard == 0) {
|
||||
if (vfreg) {
|
||||
_VFc = VU->VF[vfreg];
|
||||
VU->VF[vfreg] = _VF;
|
||||
}
|
||||
if (vireg) {
|
||||
_VIc = VU->VI[vireg];
|
||||
VU->VI[vireg] = _VI;
|
||||
}
|
||||
|
||||
_vu0ExecLower(VU, ptr);
|
||||
|
||||
if (vfreg) {
|
||||
VU->VF[vfreg] = _VFc;
|
||||
}
|
||||
if (vireg) {
|
||||
VU->VI[vireg] = _VIc;
|
||||
}
|
||||
}
|
||||
}
|
||||
_vuAddUpperStalls(VU, &uregs);
|
||||
|
||||
if (!(ptr[1] & 0x80000000))
|
||||
_vuAddLowerStalls(VU, &lregs);
|
||||
|
||||
_vuTestPipes(VU);
|
||||
|
||||
if (VU->branch > 0) {
|
||||
VU->branch--;
|
||||
if (VU->branch == 0) {
|
||||
VU->VI[REG_TPC].UL = VU->branchpc;
|
||||
}
|
||||
}
|
||||
|
||||
if( VU->ebit > 0 ) {
|
||||
if( VU->ebit-- == 1 ) {
|
||||
_vuFlushAll(VU);
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x1; /* E flag */
|
||||
vif0Regs->stat&= ~0x4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vu0Exec(VURegs* VU)
|
||||
{
|
||||
if (VU->VI[REG_TPC].UL >= VU->maxmicro) {
|
||||
#ifdef CPU_LOG
|
||||
SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL);
|
||||
#endif
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x1;
|
||||
} else {
|
||||
_vu0Exec(VU);
|
||||
}
|
||||
VU->cycle++;
|
||||
|
||||
if (VU->VI[0].UL != 0) DbgCon::Error("VI[0] != 0!!!!\n");
|
||||
if (VU->VF[0].f.x != 0.0f) DbgCon::Error("VF[0].x != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.y != 0.0f) DbgCon::Error("VF[0].y != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.z != 0.0f) DbgCon::Error("VF[0].z != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.w != 1.0f) DbgCon::Error("VF[0].w != 1.0!!!!\n");
|
||||
}
|
||||
|
||||
static void intAlloc()
|
||||
{
|
||||
}
|
||||
|
||||
static void intReset()
|
||||
{
|
||||
}
|
||||
|
||||
static void intStep()
|
||||
{
|
||||
vu0Exec( &VU0 );
|
||||
}
|
||||
|
||||
static void intExecuteBlock()
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef _DEBUG
|
||||
int prevbranch;
|
||||
#endif
|
||||
|
||||
for (i = 128; i--;) {
|
||||
|
||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0)
|
||||
break;
|
||||
|
||||
#ifdef _DEBUG
|
||||
prevbranch = vu0branch;
|
||||
#endif
|
||||
vu0Exec(&VU0);
|
||||
}
|
||||
|
||||
if( i < 0 && (VU0.branch || VU0.ebit) ) {
|
||||
// execute one more
|
||||
vu0Exec(&VU0);
|
||||
}
|
||||
}
|
||||
|
||||
static void intClear(u32 Addr, u32 Size)
|
||||
{
|
||||
}
|
||||
|
||||
static void intShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
VUmicroCpu intVU0 =
|
||||
{
|
||||
intAlloc
|
||||
, intReset
|
||||
, intStep
|
||||
, intExecuteBlock
|
||||
, intClear
|
||||
, intShutdown
|
||||
};
|
|
@ -16,6 +16,9 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
// This module contains code shared by both the dynarec and interpreter versions
|
||||
// of the VU0 micro.
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <cmath>
|
||||
|
@ -60,43 +63,7 @@ void iDumpVU1Registers()
|
|||
#endif
|
||||
}
|
||||
|
||||
int vu1Init()
|
||||
{
|
||||
assert( VU0.Mem != NULL );
|
||||
g_pVU1 = (VURegs*)(VU0.Mem + 0x4000);
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
VU1.Mem = PS2MEM_VU1MEM;
|
||||
VU1.Micro = PS2MEM_VU1MICRO;
|
||||
#else
|
||||
VU1.Mem = (u8*)_aligned_malloc(16*1024, 16);
|
||||
VU1.Micro = (u8*)_aligned_malloc(16*1024, 16);
|
||||
if (VU1.Mem == NULL || VU1.Micro == NULL) {
|
||||
Msgbox::Alert("Error allocating memory");
|
||||
return -1;
|
||||
}
|
||||
memset(VU1.Mem, 0,16*1024);
|
||||
memset(VU1.Micro, 0,16*1024);
|
||||
#endif
|
||||
|
||||
VU1.maxmem = -1;//16*1024-4;
|
||||
VU1.maxmicro = 16*1024-4;
|
||||
// VU1.VF = (VECTOR*)(VU0.Mem + 0x4000);
|
||||
// VU1.VI = (REG_VI*)(VU0.Mem + 0x4200);
|
||||
VU1.vuExec = vu1Exec;
|
||||
VU1.vifRegs = vif1Regs;
|
||||
|
||||
if( CHECK_VU1REC ) Dynarec::recVU1Init();
|
||||
|
||||
vu1Reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vu1Shutdown() {
|
||||
if( CHECK_VU1REC ) Dynarec::recVU1Shutdown();
|
||||
}
|
||||
|
||||
// This is called by the COP2 as per the CTC instruction
|
||||
void vu1ResetRegs()
|
||||
{
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~0xff00; // stop vu1
|
||||
|
@ -104,41 +71,22 @@ void vu1ResetRegs()
|
|||
vif1Regs->stat &= ~4;
|
||||
}
|
||||
|
||||
void vu1Reset() {
|
||||
memset(&VU1.ACC, 0, sizeof(VECTOR));
|
||||
memset(VU1.VF, 0, sizeof(VECTOR)*32);
|
||||
memset(VU1.VI, 0, sizeof(REG_VI)*32);
|
||||
VU1.VF[0].f.x = 0.0f;
|
||||
VU1.VF[0].f.y = 0.0f;
|
||||
VU1.VF[0].f.z = 0.0f;
|
||||
VU1.VF[0].f.w = 1.0f;
|
||||
VU1.VI[0].UL = 0;
|
||||
memset(VU1.Mem, 0, 16*1024);
|
||||
memset(VU1.Micro, 0, 16*1024);
|
||||
|
||||
Dynarec::recResetVU1();
|
||||
}
|
||||
|
||||
void SaveState::vu1Freeze() {
|
||||
Freeze(VU1.ACC);
|
||||
Freeze(VU1.code);
|
||||
FreezeMem(VU1.Mem, 16*1024);
|
||||
FreezeMem(VU1.Micro, 16*1024);
|
||||
FreezeMem(VU1.VF, 32*sizeof(VECTOR));
|
||||
FreezeMem(VU1.VI, 32*sizeof(REG_VI));
|
||||
void vu1Reset()
|
||||
{
|
||||
CpuVU1 = CHECK_VU1REC ? &recVU1 : &intVU1;
|
||||
CpuVU1->Reset();
|
||||
}
|
||||
|
||||
static int count;
|
||||
|
||||
void vu1ExecMicro(u32 addr)
|
||||
{
|
||||
if(VU0.VI[REG_VPU_STAT].UL & 0x100) {
|
||||
SysPrintf("Previous Microprogram still running on VU1\n");
|
||||
|
||||
do {
|
||||
R5900::Cpu->ExecuteVU1Block();
|
||||
} while(VU0.VI[REG_VPU_STAT].UL & 0x100);
|
||||
while(VU0.VI[REG_VPU_STAT].UL & 0x100)
|
||||
{
|
||||
VUM_LOG("vu1ExecMicro > Stalling until current microprogram finishes");
|
||||
CpuVU1->ExecuteBlock();
|
||||
}
|
||||
|
||||
VUM_LOG("vu1ExecMicro %x\n", addr);
|
||||
VUM_LOG("vu1ExecMicro %x (count=%d)\n", addr, count++);
|
||||
|
||||
|
@ -148,176 +96,9 @@ void vu1ExecMicro(u32 addr)
|
|||
if (addr != -1) VU1.VI[REG_TPC].UL = addr;
|
||||
_vuExecMicroDebug(VU1);
|
||||
|
||||
//do {
|
||||
FreezeXMMRegs(1);
|
||||
R5900::Cpu->ExecuteVU1Block();
|
||||
FreezeXMMRegs(0);
|
||||
//} while(VU0.VI[REG_VPU_STAT].UL & 0x100);
|
||||
// rec can call vu1ExecMicro
|
||||
|
||||
// VU1 isn't handled by branch tests right now, so this isn't needed.
|
||||
// although maybe it should be? VU1 is updated in the intBranchTest, but not the
|
||||
// recompiler one. Why? No clue. (air)
|
||||
|
||||
//if( VU1.VI[REG_VPU_STAT].UL & 0x1 )
|
||||
// cpuSetNextBranchDelta( 256 );
|
||||
CpuVU1->ExecuteBlock();
|
||||
}
|
||||
|
||||
void _vu1ExecUpper(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[1];
|
||||
IdebugUPPER(VU1);
|
||||
VU1_UPPER_OPCODE[VU->code & 0x3f]();
|
||||
}
|
||||
|
||||
void _vu1ExecLower(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[0];
|
||||
IdebugLOWER(VU1);
|
||||
VU1_LOWER_OPCODE[VU->code >> 25]();
|
||||
}
|
||||
|
||||
extern void _vuFlushAll(VURegs* VU);
|
||||
|
||||
int vu1branch = 0;
|
||||
|
||||
void _vu1Exec(VURegs* VU) {
|
||||
_VURegsNum lregs;
|
||||
_VURegsNum uregs;
|
||||
VECTOR _VF;
|
||||
VECTOR _VFc;
|
||||
REG_VI _VI;
|
||||
REG_VI _VIc;
|
||||
u32 *ptr;
|
||||
int vfreg;
|
||||
int vireg;
|
||||
int discard=0;
|
||||
|
||||
if(VU->VI[REG_TPC].UL >= VU->maxmicro){
|
||||
CPU_LOG("VU1 memory overflow!!: %x\n", VU->VI[REG_TPC].UL);
|
||||
VU->VI[REG_TPC].UL &= 0x3FFF;
|
||||
/*VU0.VI[REG_VPU_STAT].UL&= ~0x100;
|
||||
VU->cycle++;
|
||||
return;*/
|
||||
}
|
||||
ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL];
|
||||
VU->VI[REG_TPC].UL+=8;
|
||||
|
||||
if (ptr[1] & 0x40000000) { /* E flag */
|
||||
VU->ebit = 2;
|
||||
}
|
||||
if (ptr[1] & 0x10000000) { /* D flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x400) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x200;
|
||||
hwIntcIrq(INTC_VU1);
|
||||
}
|
||||
}
|
||||
if (ptr[1] & 0x08000000) { /* T flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x800) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x400;
|
||||
hwIntcIrq(INTC_VU1);
|
||||
}
|
||||
}
|
||||
|
||||
VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)\n", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F);
|
||||
|
||||
VU->code = ptr[1];
|
||||
VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestUpperStalls(VU, &uregs);
|
||||
#endif
|
||||
|
||||
/* check upper flags */
|
||||
if (ptr[1] & 0x80000000) { /* I flag */
|
||||
_vu1ExecUpper(VU, ptr);
|
||||
|
||||
VU->VI[REG_I].UL = ptr[0];
|
||||
} else {
|
||||
VU->code = ptr[0];
|
||||
VU1regs_LOWER_OPCODE[VU->code >> 25](&lregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestLowerStalls(VU, &lregs);
|
||||
#endif
|
||||
|
||||
vu1branch = lregs.pipe == VUPIPE_BRANCH;
|
||||
|
||||
vfreg = 0; vireg = 0;
|
||||
if (uregs.VFwrite) {
|
||||
if (lregs.VFwrite == uregs.VFwrite) {
|
||||
// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VFread0 == uregs.VFwrite ||
|
||||
lregs.VFread1 == uregs.VFwrite) {
|
||||
// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL);
|
||||
_VF = VU->VF[uregs.VFwrite];
|
||||
vfreg = uregs.VFwrite;
|
||||
}
|
||||
}
|
||||
if (uregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) {
|
||||
SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
_VI = VU->VI[REG_CLIP_FLAG];
|
||||
vireg = REG_CLIP_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
_vu1ExecUpper(VU, ptr);
|
||||
|
||||
if (discard == 0) {
|
||||
if (vfreg) {
|
||||
_VFc = VU->VF[vfreg];
|
||||
VU->VF[vfreg] = _VF;
|
||||
}
|
||||
if (vireg) {
|
||||
_VIc = VU->VI[vireg];
|
||||
VU->VI[vireg] = _VI;
|
||||
}
|
||||
|
||||
_vu1ExecLower(VU, ptr);
|
||||
|
||||
if (vfreg) {
|
||||
VU->VF[vfreg] = _VFc;
|
||||
}
|
||||
if (vireg) {
|
||||
VU->VI[vireg] = _VIc;
|
||||
}
|
||||
}
|
||||
}
|
||||
_vuAddUpperStalls(VU, &uregs);
|
||||
_vuAddLowerStalls(VU, &lregs);
|
||||
|
||||
_vuTestPipes(VU);
|
||||
|
||||
if (VU->branch > 0) {
|
||||
if (VU->branch-- == 1) {
|
||||
VU->VI[REG_TPC].UL = VU->branchpc;
|
||||
}
|
||||
}
|
||||
|
||||
if( VU->ebit > 0 ) {
|
||||
if( VU->ebit-- == 1 ) {
|
||||
_vuFlushAll(VU);
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x100;
|
||||
vif1Regs->stat&= ~0x4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vu1Exec(VURegs* VU) {
|
||||
_vu1Exec(VU);
|
||||
VU->cycle++;
|
||||
#ifdef CPU_LOG
|
||||
if (VU->VI[0].UL != 0) CPU_LOG("VI[0] != 0!!!!\n");
|
||||
if (VU->VF[0].f.x != 0.0f) CPU_LOG("VF[0].x != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.y != 0.0f) CPU_LOG("VF[0].y != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.z != 0.0f) CPU_LOG("VF[0].z != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.w != 1.0f) CPU_LOG("VF[0].w != 1.0!!!!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
_vuTables(VU1, VU1);
|
||||
_vuRegsTables(VU1, VU1regs);
|
||||
|
||||
void VU1unknown() {
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
/* Pcsx2 - Pc Ps2 Emulator
|
||||
* Copyright (C) 2002-2008 Pcsx2 Team
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
extern void _vuFlushAll(VURegs* VU);
|
||||
|
||||
_vuTables(VU1, VU1);
|
||||
|
||||
void _vu1ExecUpper(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[1];
|
||||
IdebugUPPER(VU1);
|
||||
VU1_UPPER_OPCODE[VU->code & 0x3f]();
|
||||
}
|
||||
|
||||
void _vu1ExecLower(VURegs* VU, u32 *ptr) {
|
||||
VU->code = ptr[0];
|
||||
IdebugLOWER(VU1);
|
||||
VU1_LOWER_OPCODE[VU->code >> 25]();
|
||||
}
|
||||
|
||||
int vu1branch = 0;
|
||||
|
||||
static void _vu1Exec(VURegs* VU)
|
||||
{
|
||||
_VURegsNum lregs;
|
||||
_VURegsNum uregs;
|
||||
VECTOR _VF;
|
||||
VECTOR _VFc;
|
||||
REG_VI _VI;
|
||||
REG_VI _VIc;
|
||||
u32 *ptr;
|
||||
int vfreg;
|
||||
int vireg;
|
||||
int discard=0;
|
||||
|
||||
if(VU->VI[REG_TPC].UL >= VU->maxmicro){
|
||||
CPU_LOG("VU1 memory overflow!!: %x\n", VU->VI[REG_TPC].UL);
|
||||
VU->VI[REG_TPC].UL &= 0x3FFF;
|
||||
/*VU0.VI[REG_VPU_STAT].UL&= ~0x100;
|
||||
VU->cycle++;
|
||||
return;*/
|
||||
}
|
||||
ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL];
|
||||
VU->VI[REG_TPC].UL+=8;
|
||||
|
||||
if (ptr[1] & 0x40000000) { /* E flag */
|
||||
VU->ebit = 2;
|
||||
}
|
||||
if (ptr[1] & 0x10000000) { /* D flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x400) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x200;
|
||||
hwIntcIrq(INTC_VU1);
|
||||
}
|
||||
}
|
||||
if (ptr[1] & 0x08000000) { /* T flag */
|
||||
if (VU0.VI[REG_FBRST].UL & 0x800) {
|
||||
VU0.VI[REG_VPU_STAT].UL|= 0x400;
|
||||
hwIntcIrq(INTC_VU1);
|
||||
}
|
||||
}
|
||||
|
||||
VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)\n", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F);
|
||||
|
||||
VU->code = ptr[1];
|
||||
VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestUpperStalls(VU, &uregs);
|
||||
#endif
|
||||
|
||||
/* check upper flags */
|
||||
if (ptr[1] & 0x80000000) { /* I flag */
|
||||
_vu1ExecUpper(VU, ptr);
|
||||
|
||||
VU->VI[REG_I].UL = ptr[0];
|
||||
} else {
|
||||
VU->code = ptr[0];
|
||||
VU1regs_LOWER_OPCODE[VU->code >> 25](&lregs);
|
||||
#ifndef INT_VUSTALLHACK
|
||||
_vuTestLowerStalls(VU, &lregs);
|
||||
#endif
|
||||
|
||||
vu1branch = lregs.pipe == VUPIPE_BRANCH;
|
||||
|
||||
vfreg = 0; vireg = 0;
|
||||
if (uregs.VFwrite) {
|
||||
if (lregs.VFwrite == uregs.VFwrite) {
|
||||
// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VFread0 == uregs.VFwrite ||
|
||||
lregs.VFread1 == uregs.VFwrite) {
|
||||
// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL);
|
||||
_VF = VU->VF[uregs.VFwrite];
|
||||
vfreg = uregs.VFwrite;
|
||||
}
|
||||
}
|
||||
if (uregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) {
|
||||
SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n");
|
||||
discard = 1;
|
||||
}
|
||||
if (lregs.VIread & (1 << REG_CLIP_FLAG)) {
|
||||
_VI = VU->VI[REG_CLIP_FLAG];
|
||||
vireg = REG_CLIP_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
_vu1ExecUpper(VU, ptr);
|
||||
|
||||
if (discard == 0) {
|
||||
if (vfreg) {
|
||||
_VFc = VU->VF[vfreg];
|
||||
VU->VF[vfreg] = _VF;
|
||||
}
|
||||
if (vireg) {
|
||||
_VIc = VU->VI[vireg];
|
||||
VU->VI[vireg] = _VI;
|
||||
}
|
||||
|
||||
_vu1ExecLower(VU, ptr);
|
||||
|
||||
if (vfreg) {
|
||||
VU->VF[vfreg] = _VFc;
|
||||
}
|
||||
if (vireg) {
|
||||
VU->VI[vireg] = _VIc;
|
||||
}
|
||||
}
|
||||
}
|
||||
_vuAddUpperStalls(VU, &uregs);
|
||||
_vuAddLowerStalls(VU, &lregs);
|
||||
|
||||
_vuTestPipes(VU);
|
||||
|
||||
if (VU->branch > 0) {
|
||||
if (VU->branch-- == 1) {
|
||||
VU->VI[REG_TPC].UL = VU->branchpc;
|
||||
}
|
||||
}
|
||||
|
||||
if( VU->ebit > 0 ) {
|
||||
if( VU->ebit-- == 1 ) {
|
||||
_vuFlushAll(VU);
|
||||
VU0.VI[REG_VPU_STAT].UL&= ~0x100;
|
||||
vif1Regs->stat&= ~0x4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vu1Exec(VURegs* VU)
|
||||
{
|
||||
_vu1Exec(VU);
|
||||
VU->cycle++;
|
||||
|
||||
if (VU->VI[0].UL != 0) DbgCon::Error("VI[0] != 0!!!!\n");
|
||||
if (VU->VF[0].f.x != 0.0f) DbgCon::Error("VF[0].x != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.y != 0.0f) DbgCon::Error("VF[0].y != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.z != 0.0f) DbgCon::Error("VF[0].z != 0.0!!!!\n");
|
||||
if (VU->VF[0].f.w != 1.0f) DbgCon::Error("VF[0].w != 1.0!!!!\n");
|
||||
}
|
||||
|
||||
static void intAlloc()
|
||||
{
|
||||
}
|
||||
|
||||
static void intReset()
|
||||
{
|
||||
}
|
||||
|
||||
static void intStep()
|
||||
{
|
||||
vu1Exec( &VU1 );
|
||||
}
|
||||
|
||||
static void intExecuteBlock()
|
||||
{
|
||||
int i;
|
||||
#ifdef _DEBUG
|
||||
int prevbranch;
|
||||
#endif
|
||||
|
||||
for (i = 128; i--;) {
|
||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0)
|
||||
break;
|
||||
|
||||
#ifdef _DEBUG
|
||||
prevbranch = vu1branch;
|
||||
#endif
|
||||
vu1Exec(&VU1);
|
||||
}
|
||||
|
||||
if( i < 0 && (VU1.branch || VU1.ebit) ) {
|
||||
// execute one more
|
||||
vu1Exec(&VU1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void intClear(u32 Addr, u32 Size)
|
||||
{
|
||||
}
|
||||
|
||||
static void intShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
VUmicroCpu intVU1 =
|
||||
{
|
||||
intAlloc
|
||||
, intReset
|
||||
, intStep
|
||||
, intExecuteBlock
|
||||
, intClear
|
||||
, intShutdown
|
||||
};
|
|
@ -21,11 +21,38 @@
|
|||
|
||||
#include "VU.h"
|
||||
|
||||
struct VUmicroCpu
|
||||
{
|
||||
void (*Allocate)(); // throws exceptions on failure.
|
||||
void (*Reset)();
|
||||
void (*Step)();
|
||||
void (*ExecuteBlock)(); // VUs should support block-level execution only.
|
||||
void (*Clear)(u32 Addr, u32 Size);
|
||||
void (*Shutdown)(); // deallocates memory reserved by Allocate
|
||||
};
|
||||
|
||||
extern VUmicroCpu *CpuVU0;
|
||||
extern VUmicroCpu intVU0;
|
||||
extern VUmicroCpu recVU0;
|
||||
|
||||
extern VUmicroCpu *CpuVU1;
|
||||
extern VUmicroCpu intVU1;
|
||||
extern VUmicroCpu recVU1;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// These functions initialize memory for both VUs.
|
||||
//
|
||||
void vuMicroMemAlloc();
|
||||
void vuMicroMemShutdown();
|
||||
void vuMicroMemReset();
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Everything else does stuff on a per-VU basis.
|
||||
//
|
||||
void iDumpVU0Registers();
|
||||
void iDumpVU1Registers();
|
||||
|
||||
//both for VU0 VU1 micromode
|
||||
|
||||
extern void (*VU0_LOWER_OPCODE[128])();
|
||||
extern void (*VU0_UPPER_OPCODE[64])();
|
||||
|
||||
|
@ -59,20 +86,16 @@ extern void (*VU1regs_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn);
|
|||
extern void (*VU1regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn);
|
||||
|
||||
// VU0
|
||||
int vu0Init();
|
||||
void vu0Reset();
|
||||
void vu0ResetRegs();
|
||||
void vu0Shutdown();
|
||||
void vu0ExecMicro(u32 addr);
|
||||
void vu0Exec(VURegs* VU);
|
||||
void vu0Finish();
|
||||
void recResetVU0( void );
|
||||
|
||||
// VU1
|
||||
int vu1Init();
|
||||
void vu1Reset();
|
||||
void vu1ResetRegs();
|
||||
void vu1Shutdown();
|
||||
void vu1ExecMicro(u32 addr);
|
||||
void vu1Exec(VURegs* VU);
|
||||
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
/* Pcsx2 - Pc Ps2 Emulator
|
||||
* Copyright (C) 2002-2008 Pcsx2 Team
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Common.h"
|
||||
#include "R5900.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
#include "iVUzerorec.h"
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
extern PSMEMORYBLOCK s_psVuMem;
|
||||
extern PSMEMORYMAP *memLUT;
|
||||
#endif
|
||||
|
||||
VUmicroCpu *CpuVU0;
|
||||
VUmicroCpu *CpuVU1;
|
||||
|
||||
void vuMicroMemAlloc()
|
||||
{
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
jASSUME( memLUT != NULL ); // memAlloc() must always be called first, thanks.
|
||||
|
||||
// unmap all vu0 pages
|
||||
SysMapUserPhysicalPages(PS2MEM_VU0MICRO, 16, NULL, 0);
|
||||
|
||||
// mirror 4 times
|
||||
VU0.Micro = PS2MEM_VU0MICRO;
|
||||
memLUT[0x11000].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11000].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
memLUT[0x11001].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11001].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
memLUT[0x11002].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11002].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
memLUT[0x11003].aPFNs = &s_psVuMem.aPFNs[0]; memLUT[0x11003].aVFNs = &s_psVuMem.aVFNs[0];
|
||||
|
||||
// since vuregisters are mapped in vumem0, go to diff addr, but mapping to same physical addr
|
||||
//VirtualFree((void*)0x11000000, 0x10000, MEM_RELEASE); // free just in case
|
||||
bool vu1_reassign = false;
|
||||
if( VU0.Mem == NULL )
|
||||
{
|
||||
VU0.Mem = (u8*)VirtualAlloc((void*)0x11000000, 0x10000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE);
|
||||
vu1_reassign = true;
|
||||
}
|
||||
|
||||
if( VU0.Mem != (void*)0x11000000 )
|
||||
{
|
||||
VU0.Mem = NULL;
|
||||
throw Exception::OutOfMemory(
|
||||
fmt_string( "Failed to alloc vu0mem 0x11000000 %d", params GetLastError() )
|
||||
);
|
||||
}
|
||||
|
||||
memLUT[0x11004].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11004].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
memLUT[0x11005].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11005].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
memLUT[0x11006].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11006].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
memLUT[0x11007].aPFNs = &s_psVuMem.aPFNs[1]; memLUT[0x11007].aVFNs = &s_psVuMem.aVFNs[1];
|
||||
|
||||
// map only registers
|
||||
SysMapUserPhysicalPages(VU0.Mem+0x4000, 1, s_psVuMem.aPFNs, 2);
|
||||
|
||||
if( vu1_reassign )
|
||||
{
|
||||
// Initialize VU1 memory using VU0's allocations:
|
||||
// Important! VU1 is actually a macro to g_pVU1 (yes, awkward!) so we need to assign it first.
|
||||
g_pVU1 = (VURegs*)(VU0.Mem + 0x4000);
|
||||
|
||||
VU1.Mem = PS2MEM_VU1MEM;
|
||||
VU1.Micro = PS2MEM_VU1MICRO;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// -- VTLB Memory Allocation --
|
||||
|
||||
if( VU0.Mem == NULL )
|
||||
{
|
||||
VU0.Mem = (u8*)_aligned_malloc(0x4000+sizeof(VURegs), 16); // for VU1
|
||||
|
||||
if( VU0.Mem == NULL )
|
||||
throw Exception::OutOfMemory( "vu0init > Failed to allocate VUmicro memory." );
|
||||
|
||||
// Initialize VU1 memory using VU0's allocations:
|
||||
// Important! VU1 is actually a macro to g_pVU1 (yes, awkward!) so we need to assign it first.
|
||||
|
||||
g_pVU1 = (VURegs*)(VU0.Mem + 0x4000);
|
||||
|
||||
VU1.Mem = (u8*)_aligned_malloc(16*1024*2, 16);
|
||||
if (VU1.Mem == NULL )
|
||||
throw Exception::OutOfMemory( "vu1Init > Failed to allocate memory for the VU1micro." );
|
||||
VU1.Micro = VU1.Mem + 16*1024; //(u8*)_aligned_malloc(16*1024, 16);
|
||||
}
|
||||
|
||||
if( VU0.Micro == NULL )
|
||||
VU0.Micro = (u8*)_aligned_malloc(4*1024, 16);
|
||||
|
||||
if( VU0.Micro == NULL )
|
||||
throw Exception::OutOfMemory( "vu0init > Failed to allocate VUmicro memory." );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void vuMicroMemShutdown()
|
||||
{
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
|
||||
if( VU0.Mem != NULL )
|
||||
{
|
||||
if( !SysMapUserPhysicalPages(VU0.Mem, 16, NULL, 0) )
|
||||
Console::Error("Error releasing vu0 memory %d", params GetLastError());
|
||||
|
||||
if( VirtualFree(VU0.Mem, 0, MEM_RELEASE) == 0 )
|
||||
Console::Error("Error freeing vu0 memory %d", params GetLastError());
|
||||
}
|
||||
VU0.Mem = NULL;
|
||||
VU0.Micro = NULL;
|
||||
|
||||
#else
|
||||
|
||||
// -- VTLB Memory Allocation --
|
||||
|
||||
safe_aligned_free( VU1.Mem );
|
||||
safe_aligned_free( VU0.Mem );
|
||||
safe_aligned_free( VU0.Micro );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void vuMicroMemReset()
|
||||
{
|
||||
jASSUME( VU0.Mem != NULL );
|
||||
jASSUME( VU1.Mem != NULL );
|
||||
|
||||
// === VU0 Initialization ===
|
||||
memset(&VU0.ACC, 0, sizeof(VECTOR));
|
||||
memset(VU0.VF, 0, sizeof(VECTOR)*32);
|
||||
memset(VU0.VI, 0, sizeof(REG_VI)*32);
|
||||
VU0.VF[0].f.x = 0.0f;
|
||||
VU0.VF[0].f.y = 0.0f;
|
||||
VU0.VF[0].f.z = 0.0f;
|
||||
VU0.VF[0].f.w = 1.0f;
|
||||
VU0.VI[0].UL = 0;
|
||||
memset(VU0.Mem, 0, 4*1024);
|
||||
memset(VU0.Micro, 0, 4*1024);
|
||||
|
||||
/* this is kinda tricky, maxmem is set to 0x4400 here,
|
||||
tho it's not 100% accurate, since the mem goes from
|
||||
0x0000 - 0x1000 (Mem) and 0x4000 - 0x4400 (VU1 Regs),
|
||||
i guess it shouldn't be a problem,
|
||||
at least hope so :) (linuz)
|
||||
*/
|
||||
VU0.maxmem = 0x4400-4;
|
||||
VU0.maxmicro = 4*1024-4;
|
||||
VU0.vuExec = vu0Exec;
|
||||
VU0.vifRegs = vif0Regs;
|
||||
|
||||
// === VU1 Initialization ===
|
||||
memset(&VU1.ACC, 0, sizeof(VECTOR));
|
||||
memset(VU1.VF, 0, sizeof(VECTOR)*32);
|
||||
memset(VU1.VI, 0, sizeof(REG_VI)*32);
|
||||
VU1.VF[0].f.x = 0.0f;
|
||||
VU1.VF[0].f.y = 0.0f;
|
||||
VU1.VF[0].f.z = 0.0f;
|
||||
VU1.VF[0].f.w = 1.0f;
|
||||
VU1.VI[0].UL = 0;
|
||||
memset(VU1.Mem, 0, 16*1024);
|
||||
memset(VU1.Micro, 0, 16*1024);
|
||||
|
||||
VU1.maxmem = -1;//16*1024-4;
|
||||
VU1.maxmicro = 16*1024-4;
|
||||
// VU1.VF = (VECTOR*)(VU0.Mem + 0x4000);
|
||||
// VU1.VI = (REG_VI*)(VU0.Mem + 0x4200);
|
||||
VU1.vuExec = vu1Exec;
|
||||
VU1.vifRegs = vif1Regs;
|
||||
}
|
||||
|
||||
void SaveState::vuMicroFreeze()
|
||||
{
|
||||
jASSUME( VU0.Mem != NULL );
|
||||
jASSUME( VU1.Mem != NULL );
|
||||
|
||||
Freeze(VU0.ACC);
|
||||
Freeze(VU0.code);
|
||||
FreezeMem(VU0.Mem, 4*1024);
|
||||
FreezeMem(VU0.Micro, 4*1024);
|
||||
|
||||
Freeze(VU0.VF);
|
||||
if( GetVersion() >= 0x0012 )
|
||||
Freeze(VU0.VI);
|
||||
else
|
||||
{
|
||||
// Old versions stored the VIregs as 32 bit values...
|
||||
memset( VU0.VI, 0, sizeof( VU0.VI ) );
|
||||
for(int i=0; i<32; i++ )
|
||||
Freeze( VU0.VI[i].UL );
|
||||
}
|
||||
|
||||
Freeze(VU1.ACC);
|
||||
Freeze(VU1.code);
|
||||
FreezeMem(VU1.Mem, 16*1024);
|
||||
FreezeMem(VU1.Micro, 16*1024);
|
||||
|
||||
Freeze(VU1.VF);
|
||||
if( GetVersion() >= 0x0012 )
|
||||
Freeze(VU1.VI);
|
||||
else
|
||||
{
|
||||
// Old versions stored the VIregs as 32 bit values...
|
||||
memset( VU1.VI, 0, sizeof( VU1.VI ) );
|
||||
for(int i=0; i<32; i++ )
|
||||
Freeze( VU1.VI[i].UL );
|
||||
}
|
||||
|
||||
}
|
|
@ -207,6 +207,9 @@ __forceinline void vif0FLUSH() {
|
|||
int _cycles;
|
||||
_cycles = VU0.cycle;
|
||||
|
||||
// fixme: this code should call _vu0WaitMicro instead? I'm not sure if
|
||||
// it's purposefully ignoring ee cycles or not (see below for more)
|
||||
|
||||
vu0Finish();
|
||||
g_vifCycles+= (VU0.cycle - _cycles)*BIAS;
|
||||
}
|
||||
|
@ -215,9 +218,12 @@ __forceinline void vif1FLUSH() {
|
|||
int _cycles;
|
||||
_cycles = VU1.cycle;
|
||||
|
||||
// fixme: Same as above, is this a "stalling" offense? I think the cycles should
|
||||
// be added to cpuRegs.cycle instead of g_vifCycles, but not sure (air)
|
||||
|
||||
if( VU0.VI[REG_VPU_STAT].UL & 0x100 ) {
|
||||
do {
|
||||
Cpu->ExecuteVU1Block();
|
||||
CpuVU1->ExecuteBlock();
|
||||
} while(VU0.VI[REG_VPU_STAT].UL & 0x100);
|
||||
|
||||
g_vifCycles+= (VU1.cycle - _cycles)*BIAS;
|
||||
|
@ -359,7 +365,7 @@ static void VIFunpack(u32 *data, vifCode *v, int size, const unsigned int VIFdma
|
|||
assert( v->addr < memsize );
|
||||
//v->addr &= 0x3fff;
|
||||
|
||||
if( Cpu->ExecuteVU1Block == DummyExecuteVU1Block ) {
|
||||
if( CpuVU1->ExecuteBlock == DummyExecuteVU1Block ) {
|
||||
// don't process since the frame is dummy
|
||||
vif->tag.addr += (size / (VIFfuncTable[ vif->cmd & 0xf ].gsize* vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16);
|
||||
// unpacktotal += GetCPUTick()-basetick;
|
||||
|
@ -821,7 +827,7 @@ static __forceinline void _vif0mpgTransfer(u32 addr, u32 *data, int size) {
|
|||
FreezeMMXRegs(1);
|
||||
memcpy_fast(VU0.Micro + addr, data, size << 2);
|
||||
FreezeMMXRegs(0);
|
||||
Cpu->ClearVU0(addr, size);
|
||||
CpuVU1->Clear(addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1499,7 +1505,7 @@ static __forceinline void _vif1mpgTransfer(u32 addr, u32 *data, int size) {
|
|||
FreezeMMXRegs(1);
|
||||
memcpy_fast(VU1.Micro + addr, data, size << 2);
|
||||
FreezeMMXRegs(0);
|
||||
Cpu->ClearVU1(addr, size);
|
||||
CpuVU1->Clear(addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -429,14 +429,15 @@ void vtlb_VMapUnmap(u32 vaddr,u32 sz)
|
|||
sz-=VTLB_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
bool vtlb_Init()
|
||||
|
||||
void vtlb_Init()
|
||||
{
|
||||
//Reset all vars to default values
|
||||
vtlbHandlerCount=0;
|
||||
memset(RWFT,0,sizeof(RWFT));
|
||||
|
||||
//Register default handlers
|
||||
//Unmapped Virt handlers _MUST_ be registed frist.
|
||||
//Unmapped Virt handlers _MUST_ be registed first.
|
||||
//On address translation the top bit cannot be preserved.This is not normaly a problem since
|
||||
//the physical address space can be 'compressed' to just 29 bits.However, to properly handle exceptions
|
||||
//there must be a way to get the full address back.Thats why i use these 2 functions and encode the hi bit directly into em :)
|
||||
|
@ -467,8 +468,6 @@ bool vtlb_Init()
|
|||
vtlb_VMapUnmap(0,(VTLB_VMAP_ITEMS-1)*VTLB_PAGE_SIZE);
|
||||
//yeah i know, its stupid .. but this code has to be here for now ;p
|
||||
vtlb_VMapUnmap((VTLB_VMAP_ITEMS-1)*VTLB_PAGE_SIZE,VTLB_PAGE_SIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vtlb_Reset()
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef void __fastcall vltbMemW128FP(u32 addr,const mem128_t* data);
|
|||
|
||||
typedef u32 vtlbHandler;
|
||||
|
||||
bool vtlb_Init();
|
||||
void vtlb_Init();
|
||||
void vtlb_Reset();
|
||||
void vtlb_Term();
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
|
||||
#include "ix86/ix86.h"
|
||||
|
||||
static void EnableDlgItem( HWND hwndDlg, uint itemidx, bool enabled )
|
||||
{
|
||||
EnableWindow( GetDlgItem( hwndDlg, itemidx ), enabled );
|
||||
}
|
||||
|
||||
BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
char cpuspeedc[20];
|
||||
|
@ -81,9 +86,13 @@ BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
// if(cpucaps.hasAMD64BitArchitecture) strcat(features,",x86-64");
|
||||
SetDlgItemText(hW, IDC_FEATURESINPUT, features);
|
||||
|
||||
CheckDlgButton(hW, IDC_CPU_EEREC, !!CHECK_EEREC);
|
||||
CheckDlgButton(hW, IDC_CPU_VU0REC, !!CHECK_VU0REC);
|
||||
CheckDlgButton(hW, IDC_CPU_VU1REC, !!CHECK_VU1REC);
|
||||
CheckDlgButton(hW, IDC_CPU_EEREC, !!(Config.Options&PCSX2_EEREC));
|
||||
CheckDlgButton(hW, IDC_CPU_VU0REC, !!(Config.Options&CHECK_VU0REC));
|
||||
CheckDlgButton(hW, IDC_CPU_VU1REC, !!(Config.Options&CHECK_VU1REC));
|
||||
|
||||
EnableDlgItem( hW, IDC_CPU_EEREC, !g_Session.ForceDisableEErec );
|
||||
EnableDlgItem( hW, IDC_CPU_VU0REC, !g_Session.ForceDisableVU0rec );
|
||||
EnableDlgItem( hW, IDC_CPU_VU1REC, !g_Session.ForceDisableVU1rec );
|
||||
|
||||
CheckDlgButton(hW, IDC_CPU_GSMULTI, !!CHECK_MULTIGS);
|
||||
|
||||
|
|
|
@ -598,6 +598,10 @@
|
|||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
ExceptionHandling="0"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
|
@ -625,6 +629,10 @@
|
|||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
ExceptionHandling="0"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
|
@ -634,6 +642,10 @@
|
|||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
ExceptionHandling="0"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
|
@ -643,6 +655,10 @@
|
|||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
ExceptionHandling="0"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
|
@ -651,6 +667,54 @@
|
|||
<File
|
||||
RelativePath="..\WinSysExec.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Release vm (dev)|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release vtlb (dev)|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release vm (nondev)|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release vtlb (nondev)|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="2"
|
||||
OmitFramePointers="false"
|
||||
EnableFiberSafeOptimizations="false"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\WinVM.cpp"
|
||||
|
@ -3049,10 +3113,18 @@
|
|||
RelativePath="..\..\VU0micro.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\VU0microInterp.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\VU1micro.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\VU1microInterp.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\VUflags.cpp"
|
||||
>
|
||||
|
@ -3065,6 +3137,10 @@
|
|||
RelativePath="..\..\VUmicro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\VUmicroMem.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\VUops.cpp"
|
||||
>
|
||||
|
|
|
@ -35,16 +35,11 @@
|
|||
#include <ntsecapi.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "PsxCommon.h"
|
||||
#include "debugger.h"
|
||||
#include "rdebugger.h"
|
||||
#include "AboutDlg.h"
|
||||
#include "McdsDlg.h"
|
||||
|
||||
#include "VU.h"
|
||||
#include "iCore.h"
|
||||
#include "iVUzerorec.h"
|
||||
|
||||
#include "Patch.h"
|
||||
#include "cheats/cheats.h"
|
||||
|
||||
|
@ -196,6 +191,9 @@ void WinClose()
|
|||
|
||||
pthread_win32_process_detach_np();
|
||||
|
||||
SysShutdownDynarecs();
|
||||
SysShutdownMem();
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
VirtualFree(PS2MEM_BASE, 0, MEM_RELEASE);
|
||||
#endif
|
||||
|
@ -277,6 +275,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
Pcsx2Configure( NULL );
|
||||
}
|
||||
|
||||
// Important! Always allocate dynarecs before loading plugins, to give the dynarecs
|
||||
// the best possible chance of claiming ideal memory space!
|
||||
|
||||
if (Config.Lang[0] == 0) {
|
||||
strcpy(Config.Lang, "en_US");
|
||||
}
|
||||
|
@ -300,6 +301,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
// Console::WriteLn("-help to see arguments");
|
||||
}
|
||||
|
||||
if( !SysInit() )
|
||||
WinClose();
|
||||
|
||||
// Load the command line overrides for plugins.
|
||||
// Back up the user's preferences in winConfig.
|
||||
|
||||
|
@ -328,6 +332,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
ProfilerInit();
|
||||
#endif
|
||||
|
||||
while (LoadPlugins() == -1) {
|
||||
if (Pcsx2Configure(NULL) == FALSE) {
|
||||
WinClose(); // user cancelled.
|
||||
}
|
||||
}
|
||||
|
||||
// This makes sure the Windows Kernel is using high resolution
|
||||
// timeslices for Sleep calls.
|
||||
// (may not make much difference on most desktops but can improve performance
|
||||
|
@ -336,9 +346,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
timeBeginPeriod( 1 );
|
||||
InitCPUTicks();
|
||||
|
||||
if( !SysInit() )
|
||||
WinClose();
|
||||
|
||||
if( IsDevBuild && (g_TestRun.enabled || g_TestRun.ptitle != NULL) ) {
|
||||
// run without ui
|
||||
UseGui = 0;
|
||||
|
@ -372,9 +379,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
);
|
||||
|
||||
DevCon::WriteLn(
|
||||
"\tF10 - dump performance counters\n"
|
||||
//"\tF10 - dump performance counters\n"
|
||||
"\tF11 - save GS state\n"
|
||||
"\tF12 - dump hardware registers"
|
||||
//"\tF12 - dump hardware registers"
|
||||
);
|
||||
Console::ClearColor();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,8 @@ MemoryAlloc<u8>* g_gsRecoveryState = NULL;
|
|||
|
||||
|
||||
bool m_ReturnToGame = false; // set to exit the RunGui message pump
|
||||
bool g_GameInProgress = false; // Set TRUE if a game is actively running.
|
||||
bool g_GameInProgress = false; // Set TRUE if a game is actively running (set to false on reset)
|
||||
bool m_EmuStateActive = false; // Set TRUE when the GUI is running from the context of an emulation EventTest
|
||||
|
||||
// This instance is not modified by command line overrides so
|
||||
// that command line plugins and stuff won't be saved into the
|
||||
|
@ -194,8 +195,13 @@ void ExecuteCpu()
|
|||
gApp.hWnd = NULL;
|
||||
|
||||
g_GameInProgress = true;
|
||||
if( !m_EmuStateActive )
|
||||
{
|
||||
Cpu->Execute();
|
||||
g_GameInProgress = false;
|
||||
}
|
||||
else
|
||||
m_ReturnToGame = true;
|
||||
}
|
||||
|
||||
// Runs and ELF image directly (ISO or ELF program or BIN)
|
||||
|
@ -208,25 +214,31 @@ void RunExecute( const char* elf_file, bool use_bios )
|
|||
|
||||
g_GameInProgress = false;
|
||||
|
||||
if (OpenPlugins(g_TestRun.ptitle) == -1)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
cpuReset();
|
||||
}
|
||||
catch( std::exception& ex )
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
Msgbox::Alert( ex.what() );
|
||||
Msgbox::Alert( ex.Message() );
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenPlugins(g_TestRun.ptitle) == -1)
|
||||
return;
|
||||
|
||||
if( elf_file == NULL )
|
||||
{
|
||||
if(g_RecoveryState != NULL)
|
||||
{
|
||||
try
|
||||
{
|
||||
/*string Text;
|
||||
SaveState::GetFilename( Text, 9 );
|
||||
gzLoadingState joe( Text ); // throws exception on version mismatch
|
||||
R5900::cpuReset();
|
||||
joe.FreezeAll();*/
|
||||
|
||||
memLoadingState( *g_RecoveryState ).FreezeAll();
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
|
@ -249,6 +261,7 @@ void RunExecute( const char* elf_file, bool use_bios )
|
|||
// Note: if the elf_file is null we use the CDVD elf file.
|
||||
// But if the elf_file is an empty string then we boot the bios instead.
|
||||
|
||||
m_EmuStateActive = false; // make sure to start a new emu state when running cpuExecuteBios();
|
||||
cpuExecuteBios();
|
||||
char ename[g_MaxPath];
|
||||
ename[0] = 0;
|
||||
|
@ -262,10 +275,9 @@ void RunExecute( const char* elf_file, bool use_bios )
|
|||
// Custom ELF specified (not using CDVD).
|
||||
// Run the BIOS and load the ELF.
|
||||
|
||||
SetCursor( LoadCursor( gApp.hInstance, IDC_WAIT ) );
|
||||
m_EmuStateActive = false; // make sure to start a new emu state when running cpuExecuteBios();
|
||||
cpuExecuteBios();
|
||||
loadElfFile( elf_file );
|
||||
SetCursor( LoadCursor( gApp.hInstance, IDC_ARROW ) );
|
||||
}
|
||||
|
||||
// this needs to be called for every new game!
|
||||
|
@ -281,6 +293,8 @@ void RunGuiAndReturn() {
|
|||
MSG msg;
|
||||
|
||||
m_ReturnToGame = false;
|
||||
m_EmuStateActive = true;
|
||||
|
||||
while( !m_ReturnToGame )
|
||||
{
|
||||
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) {
|
||||
|
@ -297,8 +311,11 @@ void RunGuiAndReturn() {
|
|||
|
||||
if( g_gsRecoveryState != NULL )
|
||||
{
|
||||
s32 dummylen;
|
||||
|
||||
memLoadingState eddie( *g_gsRecoveryState );
|
||||
eddie.FreezePlugin( "GS", gsSafeFreeze );
|
||||
eddie.Freeze( dummylen ); // reads the length value recorded earlier.
|
||||
eddie.gsFreeze();
|
||||
|
||||
safe_delete( g_gsRecoveryState );
|
||||
|
@ -307,9 +324,13 @@ void RunGuiAndReturn() {
|
|||
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
||||
}
|
||||
|
||||
if( gApp.hWnd != NULL )
|
||||
{
|
||||
AccBreak = true;
|
||||
DestroyWindow(gApp.hWnd);
|
||||
gApp.hWnd = NULL;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class RecoveryMemSavingState : public memSavingState, Sealed
|
||||
|
@ -327,9 +348,9 @@ public:
|
|||
// just copy the data from src to dst.
|
||||
// the normal savestate doesn't expect a length prefix for internal structures,
|
||||
// so don't copy that part.
|
||||
u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr(0));
|
||||
u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr());
|
||||
u32& gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+4), gslen );
|
||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+8), gslen );
|
||||
m_idx += gslen;
|
||||
}
|
||||
else
|
||||
|
@ -602,9 +623,12 @@ public:
|
|||
int oldmidx = m_idx;
|
||||
m_idx += 4;
|
||||
memSavingState::gsFreeze();
|
||||
if( IsSaving() )
|
||||
{
|
||||
s32& len = *((s32*)m_memory.GetPtr( oldmidx ));
|
||||
len = (m_idx - oldmidx)-4;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static int shiftkey = 0;
|
||||
|
@ -641,6 +665,7 @@ void CALLBACK KeyEvent(keyEvent* ev)
|
|||
// Let's give the user a RunGui!
|
||||
|
||||
g_GameInProgress = false;
|
||||
m_EmuStateActive = false;
|
||||
CreateMainWindow( SW_SHOWNORMAL );
|
||||
RunGui(); // ah the beauty of perpetual stack recursion! (air)
|
||||
}
|
||||
|
@ -677,7 +702,7 @@ void CALLBACK KeyEvent(keyEvent* ev)
|
|||
PluginsResetGS();
|
||||
}
|
||||
|
||||
ClosePlugins();
|
||||
//ClosePlugins();
|
||||
|
||||
CreateMainWindow(SW_SHOWNORMAL);
|
||||
nDisableSC = 0;
|
||||
|
@ -705,7 +730,6 @@ void SysRestorableReset()
|
|||
g_RecoveryState = new MemoryAlloc<u8>( "Memory Savestate Recovery" );
|
||||
RecoveryMemSavingState().FreezeAll();
|
||||
safe_delete( g_gsRecoveryState );
|
||||
cpuShutdown();
|
||||
g_GameInProgress = false;
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
|
@ -751,15 +775,10 @@ bool SysInit()
|
|||
emuLog = fopen(LOGS_DIR "\\emuLog.txt","w");
|
||||
|
||||
SysDetect();
|
||||
if( !SysAllocateMem() )
|
||||
return false; // critical memory allocation failure;
|
||||
|
||||
while (LoadPlugins() == -1) {
|
||||
if (Pcsx2Configure(NULL) == FALSE) {
|
||||
return false; // user cancelled.
|
||||
}
|
||||
}
|
||||
|
||||
if( !cpuInit() )
|
||||
return false;
|
||||
SysAllocateDynarecs();
|
||||
|
||||
sinit = true;
|
||||
return true;
|
||||
|
|
|
@ -199,13 +199,15 @@ static void recCTC2(s32 info)
|
|||
// a lot of games have vu0 spinning on some integer
|
||||
// then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck)
|
||||
|
||||
MOV32ItoM((uptr)&VU0.VI[_Fs_].UL,g_cpuConstRegs[_Rt_].UL[0]);
|
||||
iFlushCall(FLUSH_NOCONST);
|
||||
CALLFunc((uptr)Cpu->ExecuteVU0Block);
|
||||
// Use vu0ExecMicro instead because it properly stalls for already-running micro
|
||||
// instructions, and also sets the nextBranchCycle as needed. (air)
|
||||
|
||||
// fixme: if the VU0 stat&1 is still enabled, then we should probably set a cpuBranchTest
|
||||
// for 128 cycles from now. It would be the safest thing to do to make sure the VU0
|
||||
// responds in a timely matter to the game's register write.
|
||||
MOV32ItoM((uptr)&VU0.VI[_Fs_].UL,g_cpuConstRegs[_Rt_].UL[0]);
|
||||
//PUSH32I( -1 );
|
||||
iFlushCall(FLUSH_NOCONST);
|
||||
CALLFunc((uptr)CpuVU0->ExecuteBlock);
|
||||
//CALLFunc((uptr)vu0ExecMicro);
|
||||
//ADD32ItoR( ESP, 4 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,7 @@ namespace Interp = R5900::Interpreter::OpcodeImpl::COP0;
|
|||
namespace Dynarec {
|
||||
namespace R5900 {
|
||||
namespace OpcodeImpl {
|
||||
namespace COP0
|
||||
{
|
||||
namespace COP0 {
|
||||
|
||||
/*********************************************************
|
||||
* COP0 opcodes *
|
||||
|
|
|
@ -1194,12 +1194,12 @@ EEINSTWRITEBACK* _recCheckWriteBack(int cycle)
|
|||
struct BASEBLOCKS
|
||||
{
|
||||
// 0 - ee, 1 - iop
|
||||
inline void Add(BASEBLOCKEX*);
|
||||
inline void Remove(BASEBLOCKEX*);
|
||||
inline int Get(u32 startpc);
|
||||
inline void Reset();
|
||||
void Add(BASEBLOCKEX*);
|
||||
void Remove(BASEBLOCKEX*);
|
||||
int Get(u32 startpc);
|
||||
void Reset();
|
||||
|
||||
inline BASEBLOCKEX** GetAll(int* pnum);
|
||||
BASEBLOCKEX** GetAll(int* pnum);
|
||||
|
||||
vector<BASEBLOCKEX*> blocks;
|
||||
};
|
||||
|
@ -1332,7 +1332,7 @@ extern int rdram_sdevid;
|
|||
|
||||
void iDumpRegisters(u32 startpc, u32 temp)
|
||||
{
|
||||
// [TODO] fixme : thie code is broken and has no labels. Needs a rewrite to be useful.
|
||||
// [TODO] fixme : this code is broken and has no labels. Needs a rewrite to be useful.
|
||||
|
||||
#if 0
|
||||
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
extern u8 *psH; // hw mem
|
||||
extern u16 *psHW;
|
||||
extern u32 *psHL;
|
||||
extern u64 *psHD;
|
||||
#endif
|
||||
|
||||
extern int rdram_devices; // put 8 for TOOL and 2 for PS2 and PSX
|
||||
|
|
|
@ -517,9 +517,14 @@ void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode,
|
|||
noconstcode(0);
|
||||
}
|
||||
|
||||
static int recInit() {
|
||||
int i;
|
||||
static u8* m_recBlockAlloc = NULL;
|
||||
|
||||
static const uint m_recBlockAllocSize =
|
||||
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK))
|
||||
+ (PSX_NUMBLOCKS*sizeof(BASEBLOCKEX)); // recBlocks
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
// can't have upper 4 bits nonzero!
|
||||
// ... we can't? (air)
|
||||
|
||||
|
@ -543,22 +548,26 @@ static int recInit() {
|
|||
}
|
||||
|
||||
if( recMem == NULL )
|
||||
{
|
||||
Console::Error( "Error > R3000A failed to allocate recompiler memory." );
|
||||
return 1;
|
||||
}
|
||||
throw Exception::OutOfMemory( "R3000a Init > failed to allocate memory for the recompiler." );
|
||||
|
||||
if( psxRecLUT == NULL )
|
||||
psxRecLUT = (uptr*) malloc(0x010000 * sizeof(uptr));
|
||||
|
||||
if( recRAM == NULL )
|
||||
recRAM = (BASEBLOCK*) _aligned_malloc(sizeof(BASEBLOCK)/4*0x200000, 16);
|
||||
if( recROM == NULL )
|
||||
recROM = (BASEBLOCK*) _aligned_malloc(sizeof(BASEBLOCK)/4*0x400000, 16);
|
||||
if( recROM1 == NULL )
|
||||
recROM1= (BASEBLOCK*) _aligned_malloc(sizeof(BASEBLOCK)/4*0x040000, 16);
|
||||
if( recBlocks == NULL )
|
||||
recBlocks = (BASEBLOCKEX*) _aligned_malloc( sizeof(BASEBLOCKEX)*PSX_NUMBLOCKS, 16);
|
||||
// Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory.
|
||||
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
||||
// always 4 bytes long).
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 );
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for baseblock lookup tables." );
|
||||
|
||||
u8* curpos = m_recBlockAlloc;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK);
|
||||
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
|
||||
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
|
||||
recBlocks = (BASEBLOCKEX*)curpos; // curpos += sizeof(BASEBLOCKEX)*EE_NUMBLOCKS;
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
{
|
||||
|
@ -566,45 +575,51 @@ static int recInit() {
|
|||
s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize );
|
||||
}
|
||||
|
||||
if( recRAM == NULL || recROM == NULL || recROM1 == NULL ||
|
||||
psxRecLUT == NULL || recBlocks == NULL || s_pInstCache == NULL )
|
||||
{
|
||||
Msgbox::Alert("Error allocating memory");
|
||||
return -1;
|
||||
}
|
||||
if( s_pInstCache == NULL )
|
||||
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for pInstCache." );
|
||||
|
||||
// No errors! Proceed with initialization...
|
||||
|
||||
memset(psxRecLUT, 0, 0x010000 * sizeof(uptr));
|
||||
ProfilerRegisterSource( "IOPRec", recMem, RECMEM_SIZE );
|
||||
|
||||
for (i=0; i<0x80; i++) psxRecLUT[i + 0x0000] = (uptr)&recRAM[(i & 0x1f) << 14];
|
||||
for (i=0; i<0x80; i++) psxRecLUT[i + 0x8000] = (uptr)&recRAM[(i & 0x1f) << 14];
|
||||
for (i=0; i<0x80; i++) psxRecLUT[i + 0xa000] = (uptr)&recRAM[(i & 0x1f) << 14];
|
||||
|
||||
for (i=0; i<0x40; i++) psxRecLUT[i + 0x1fc0] = (uptr)&recROM[i << 14];
|
||||
for (i=0; i<0x40; i++) psxRecLUT[i + 0x9fc0] = (uptr)&recROM[i << 14];
|
||||
for (i=0; i<0x40; i++) psxRecLUT[i + 0xbfc0] = (uptr)&recROM[i << 14];
|
||||
|
||||
for (i=0; i<0x40; i++) psxRecLUT[i + 0x1e00] = (uptr)&recROM1[i << 14];
|
||||
for (i=0; i<0x40; i++) psxRecLUT[i + 0x9e00] = (uptr)&recROM1[i << 14];
|
||||
for (i=0; i<0x40; i++) psxRecLUT[i + 0xbe00] = (uptr)&recROM1[i << 14];
|
||||
|
||||
memset(recMem, 0xcd, RECMEM_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void recReset()
|
||||
{
|
||||
DevCon::WriteLn("IOP Recompiler data reset");
|
||||
// calling recReset without first calling recInit is bad mojo.
|
||||
jASSUME( psxRecLUT != NULL );
|
||||
jASSUME( recMem != NULL );
|
||||
jASSUME( m_recBlockAlloc != NULL );
|
||||
|
||||
memset(recRAM, 0, sizeof(BASEBLOCK)/4*0x200000);
|
||||
memset(recROM, 0, sizeof(BASEBLOCK)/4*0x400000);
|
||||
memset(recROM1,0, sizeof(BASEBLOCK)/4*0x040000);
|
||||
DbgCon::Status( "iR3000A > Resetting recompiler memory and structures!" );
|
||||
|
||||
memset(psxRecLUT, 0, 0x010000 * sizeof(uptr));
|
||||
memset(recMem, 0xcd, RECMEM_SIZE);
|
||||
memset(m_recBlockAlloc, 0, m_recBlockAllocSize);
|
||||
|
||||
// We're only mapping 20 pages here in 4 places.
|
||||
// 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4
|
||||
for (int i=0; i<0x80; i++)
|
||||
{
|
||||
psxRecLUT[i + 0x0000] = (uptr)&recRAM[(i & 0x1f) << 14];
|
||||
psxRecLUT[i + 0x8000] = (uptr)&recRAM[(i & 0x1f) << 14];
|
||||
psxRecLUT[i + 0xa000] = (uptr)&recRAM[(i & 0x1f) << 14];
|
||||
}
|
||||
|
||||
for (int i=0; i<(Ps2MemSize::Rom / 0x10000); i++)
|
||||
{
|
||||
psxRecLUT[i + 0x1fc0] = (uptr)&recROM[i << 14];
|
||||
psxRecLUT[i + 0x9fc0] = (uptr)&recROM[i << 14];
|
||||
psxRecLUT[i + 0xbfc0] = (uptr)&recROM[i << 14];
|
||||
}
|
||||
|
||||
for (int i=0; i<(Ps2MemSize::Rom1 / 0x10000); i++)
|
||||
{
|
||||
psxRecLUT[i + 0x1e00] = (uptr)&recROM1[i << 14];
|
||||
psxRecLUT[i + 0x9e00] = (uptr)&recROM1[i << 14];
|
||||
psxRecLUT[i + 0xbe00] = (uptr)&recROM1[i << 14];
|
||||
}
|
||||
|
||||
if( s_pInstCache )
|
||||
memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
|
||||
|
||||
memset( recBlocks, 0, sizeof(BASEBLOCKEX)*PSX_NUMBLOCKS );
|
||||
if( s_pInstCache ) memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
|
||||
ResetBaseBlockEx(1);
|
||||
g_psxMaxRecMem = 0;
|
||||
|
||||
|
@ -617,12 +632,9 @@ static void recShutdown()
|
|||
ProfilerTerminateSource( "IOPRec" );
|
||||
|
||||
SafeSysMunmap(recMem, RECMEM_SIZE);
|
||||
safe_free(psxRecLUT);
|
||||
safe_aligned_free(recRAM);
|
||||
safe_aligned_free(recROM);
|
||||
safe_aligned_free(recROM1);
|
||||
safe_aligned_free( recBlocks );
|
||||
safe_aligned_free( m_recBlockAlloc );
|
||||
|
||||
safe_free(psxRecLUT);
|
||||
safe_free( s_pInstCache );
|
||||
s_nInstCacheSize = 0;
|
||||
|
||||
|
@ -644,8 +656,6 @@ static __forceinline void R3000AExecute()
|
|||
|
||||
BASEBLOCK* pblock;
|
||||
|
||||
//while (EEsCycle > 0)
|
||||
{
|
||||
pblock = PSX_GETBLOCK(psxRegs.pc);
|
||||
|
||||
if ( !pblock->pFnptr || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) {
|
||||
|
@ -687,7 +697,6 @@ static __forceinline void R3000AExecute()
|
|||
#else
|
||||
((R3000AFNPTR)pblock->pFnptr)();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
u32 g_psxlastpc = 0;
|
||||
|
@ -1274,8 +1283,10 @@ void psxRecRecompile(u32 startpc)
|
|||
assert( startpc );
|
||||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000))
|
||||
if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000)) {
|
||||
DevCon::WriteLn("IOP Recompiler data reset");
|
||||
recReset();
|
||||
}
|
||||
|
||||
s_pCurBlock = PSX_GETBLOCK(startpc);
|
||||
|
||||
|
@ -1300,7 +1311,7 @@ void psxRecRecompile(u32 startpc)
|
|||
}
|
||||
|
||||
if( s_pCurBlockEx == NULL ) {
|
||||
//SysPrintf("ee reset (blocks)\n");
|
||||
DevCon::WriteLn("IOP Recompiler data reset");
|
||||
recReset();
|
||||
s_nNextBlock = 0;
|
||||
s_pCurBlockEx = recBlocks;
|
||||
|
@ -1555,7 +1566,7 @@ StartRecomp:
|
|||
|
||||
using namespace Dynarec;
|
||||
R3000Acpu psxRec = {
|
||||
recInit,
|
||||
recAlloc,
|
||||
recReset,
|
||||
recExecute,
|
||||
recExecuteBlock,
|
||||
|
|
|
@ -19,48 +19,61 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "InterTables.h"
|
||||
#include "ix86/ix86.h"
|
||||
#include "iR5900.h"
|
||||
#include "iMMI.h"
|
||||
#include "iFPU.h"
|
||||
#include "iCP0.h"
|
||||
#include "VUmicro.h"
|
||||
#include "iVUmicro.h"
|
||||
#include "iVUops.h"
|
||||
#include "VUops.h"
|
||||
|
||||
#include "iVUzerorec.h"
|
||||
|
||||
namespace Dynarec
|
||||
{
|
||||
void recExecuteVU0Block( void )
|
||||
{
|
||||
if((VU0.VI[REG_VPU_STAT].UL & 1) == 0) {
|
||||
//SysPrintf("Execute block VU0, VU0 not busy\n");
|
||||
return;
|
||||
namespace Dynarec {
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
SuperVUAlloc(0);
|
||||
}
|
||||
|
||||
//while( (VU0.VI[ REG_VPU_STAT ].UL&1) ) {
|
||||
if( CHECK_VU0REC) {
|
||||
static void recReset()
|
||||
{
|
||||
SuperVUReset(0);
|
||||
|
||||
// these shouldn't be needed, but shouldn't hurt anythign either.
|
||||
x86FpuState = FPU_STATE;
|
||||
iCWstate = 0;
|
||||
}
|
||||
|
||||
static void recStep()
|
||||
{
|
||||
}
|
||||
|
||||
static void recExecuteBlock()
|
||||
{
|
||||
if((VU0.VI[REG_VPU_STAT].UL & 1) == 0)
|
||||
return;
|
||||
|
||||
FreezeXMMRegs(1);
|
||||
SuperVUExecuteProgram(VU0.VI[ REG_TPC ].UL & 0xfff, 0);
|
||||
FreezeXMMRegs(0);
|
||||
}
|
||||
else ::R5900::Interpreter::intExecuteVU0Block();
|
||||
//}
|
||||
}
|
||||
|
||||
void recClearVU0( u32 Addr, u32 Size )
|
||||
{
|
||||
if( CHECK_VU0REC ) {
|
||||
static void recClear(u32 Addr, u32 Size)
|
||||
{
|
||||
SuperVUClear(Addr, Size*4, 0);
|
||||
}
|
||||
|
||||
static void recShutdown()
|
||||
{
|
||||
SuperVUDestroy( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void recResetVU0( void )
|
||||
{
|
||||
SuperVUReset(0);
|
||||
}
|
||||
using namespace Dynarec;
|
||||
|
||||
VUmicroCpu recVU0 =
|
||||
{
|
||||
recAlloc
|
||||
, recReset
|
||||
, recStep
|
||||
, recExecuteBlock
|
||||
, recClear
|
||||
, recShutdown
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,93 +24,30 @@
|
|||
#include "InterTables.h"
|
||||
#include "ix86/ix86.h"
|
||||
#include "iR5900.h"
|
||||
#include "iMMI.h"
|
||||
#include "iFPU.h"
|
||||
#include "iCP0.h"
|
||||
#include "VU.h"
|
||||
#include "VUmicro.h"
|
||||
#include "iVUzerorec.h"
|
||||
#include "iVUops.h"
|
||||
#include "VUops.h"
|
||||
|
||||
// fixme - having the VUs share the branch/pc values of the R5900 is bad on so many levels... >_< (air)
|
||||
|
||||
using ::Dynarec::R5900::pc;
|
||||
using ::Dynarec::R5900::branch;
|
||||
|
||||
#ifdef _DEBUG
|
||||
extern u32 vudump;
|
||||
#endif
|
||||
|
||||
namespace Dynarec
|
||||
{
|
||||
namespace Dynarec {
|
||||
|
||||
#define VU ((VURegs*)&VU1)
|
||||
|
||||
//Lower/Upper instructions can use that..
|
||||
#define _Ft_ ((VU1.code >> 16) & 0x1F) // The rt part of the instruction register
|
||||
#define _Fs_ ((VU1.code >> 11) & 0x1F) // The rd part of the instruction register
|
||||
#define _Fd_ ((VU1.code >> 6) & 0x1F) // The sa part of the instruction register
|
||||
|
||||
#define _X ((VU1.code>>24) & 0x1)
|
||||
#define _Y ((VU1.code>>23) & 0x1)
|
||||
#define _Z ((VU1.code>>22) & 0x1)
|
||||
#define _W ((VU1.code>>21) & 0x1)
|
||||
|
||||
#define _Fsf_ ((VU1.code >> 21) & 0x03)
|
||||
#define _Ftf_ ((VU1.code >> 23) & 0x03)
|
||||
|
||||
|
||||
#define VU1_VFx_ADDR(x) (uptr)&VU1.VF[x].UL[0]
|
||||
#define VU1_VFy_ADDR(x) (uptr)&VU1.VF[x].UL[1]
|
||||
#define VU1_VFz_ADDR(x) (uptr)&VU1.VF[x].UL[2]
|
||||
#define VU1_VFw_ADDR(x) (uptr)&VU1.VF[x].UL[3]
|
||||
|
||||
#define VU1_REGR_ADDR (uptr)&VU1.VI[REG_R]
|
||||
#define VU1_REGI_ADDR (uptr)&VU1.VI[REG_I]
|
||||
#define VU1_REGQ_ADDR (uptr)&VU1.VI[REG_Q]
|
||||
#define VU1_REGMAC_ADDR (uptr)&VU1.VI[REG_MAC_FLAG]
|
||||
|
||||
#define VU1_VI_ADDR(x) (uptr)&VU1.VI[x].UL
|
||||
|
||||
#define VU1_ACCx_ADDR (uptr)&VU1.ACC.UL[0]
|
||||
#define VU1_ACCy_ADDR (uptr)&VU1.ACC.UL[1]
|
||||
#define VU1_ACCz_ADDR (uptr)&VU1.ACC.UL[2]
|
||||
#define VU1_ACCw_ADDR (uptr)&VU1.ACC.UL[3]
|
||||
|
||||
|
||||
void recVU1Init()
|
||||
{
|
||||
SuperVUInit(1);
|
||||
}
|
||||
|
||||
void recVU1Shutdown()
|
||||
{
|
||||
SuperVUDestroy(1);
|
||||
}
|
||||
|
||||
void recResetVU1( void ) {
|
||||
if( CHECK_VU1REC ) SuperVUReset(1);
|
||||
|
||||
x86FpuState = FPU_STATE;
|
||||
iCWstate = 0;
|
||||
branch = 0;
|
||||
}
|
||||
|
||||
static void iVU1DumpBlock()
|
||||
{
|
||||
// commented out because I'm not sure it actually works anymore with SuperVU (air)
|
||||
/*static void iVU1DumpBlock()
|
||||
{
|
||||
FILE *f;
|
||||
char filename[ g_MaxPath ];
|
||||
u32 *mem;
|
||||
u32 i;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
CreateDirectory("dumps", NULL);
|
||||
sprintf_s( filename, g_MaxPath, "dumps\\vu%.4X.txt", VU1.VI[ REG_TPC ].UL );
|
||||
#else
|
||||
#else
|
||||
mkdir("dumps", 0755);
|
||||
sprintf( filename, "dumps/vu%.4X.txt", VU1.VI[ REG_TPC ].UL );
|
||||
#endif
|
||||
#endif
|
||||
SysPrintf( "dump1 %x => %x (%s)\n", VU1.VI[ REG_TPC ].UL, pc, filename );
|
||||
|
||||
f = fopen( filename, "wb" );
|
||||
|
@ -125,28 +62,42 @@ static void iVU1DumpBlock()
|
|||
fprintf(f, "%s\n", pstr);
|
||||
}
|
||||
fclose( f );
|
||||
}
|
||||
}*/
|
||||
|
||||
#ifdef _DEBUG
|
||||
static u32 vuprogcount = 0;
|
||||
#endif
|
||||
static void recAlloc()
|
||||
{
|
||||
SuperVUAlloc(1);
|
||||
}
|
||||
|
||||
void recExecuteVU1Block(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
static void recReset()
|
||||
{
|
||||
SuperVUReset(1);
|
||||
|
||||
// these shouldn't be needed, but shouldn't hurt anythign either.
|
||||
x86FpuState = FPU_STATE;
|
||||
iCWstate = 0;
|
||||
}
|
||||
|
||||
static void recStep()
|
||||
{
|
||||
}
|
||||
|
||||
static void recExecuteBlock(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
static u32 vuprogcount = 0;
|
||||
vuprogcount++;
|
||||
if( vudump & 8 ) __Log("start vu1: %x %x\n", VU1.VI[ REG_TPC ].UL, vuprogcount);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0){
|
||||
//SysPrintf("Execute block VU1, VU1 not busy\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (CHECK_VU1REC)
|
||||
if (VU1.VI[REG_TPC].UL >= VU1.maxmicro)
|
||||
{
|
||||
if (VU1.VI[REG_TPC].UL >= VU1.maxmicro) {
|
||||
SysPrintf("VU1 memory overflow!!: %x\n", VU1.VI[REG_TPC].UL);
|
||||
Console::Error("VU1 memory overflow!!: %x", params VU1.VI[REG_TPC].UL);
|
||||
/*VU0.VI[REG_VPU_STAT].UL&= ~0x100;
|
||||
VU1.cycle++;
|
||||
return;*/
|
||||
|
@ -160,15 +111,28 @@ void recExecuteVU1Block(void)
|
|||
} while( VU0.VI[ REG_VPU_STAT ].UL&0x100 );
|
||||
FreezeXMMRegs(0);
|
||||
}
|
||||
else {
|
||||
while (VU0.VI[ REG_VPU_STAT ].UL&0x100) {
|
||||
::R5900::Interpreter::intExecuteVU1Block();
|
||||
|
||||
static void recClear( u32 Addr, u32 Size )
|
||||
{
|
||||
assert( (Addr&7) == 0 );
|
||||
SuperVUClear(Addr, Size*4, 1);
|
||||
}
|
||||
|
||||
static void recShutdown()
|
||||
{
|
||||
SuperVUDestroy( 1 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void recClearVU1( u32 Addr, u32 Size ) {
|
||||
assert( (Addr&7) == 0 );
|
||||
if( CHECK_VU1REC ) SuperVUClear(Addr, Size*4, 1);
|
||||
}
|
||||
}
|
||||
using namespace Dynarec;
|
||||
|
||||
VUmicroCpu recVU1 =
|
||||
{
|
||||
recAlloc
|
||||
, recReset
|
||||
, recStep
|
||||
, recExecuteBlock
|
||||
, recClear
|
||||
, recShutdown
|
||||
};
|
|
@ -325,12 +325,14 @@ static u32* SuperVUStaticAlloc(u32 size);
|
|||
static void SuperVURecompile();
|
||||
|
||||
// allocate VU resources
|
||||
void SuperVUInit(int vuindex)
|
||||
void SuperVUAlloc(int vuindex)
|
||||
{
|
||||
// The old -1 crap has been depreciated on this function. Please
|
||||
// specify either 0 or 1, thanks.
|
||||
jASSUME( vuindex >= 0 );
|
||||
|
||||
if( s_recVUMem == NULL )
|
||||
{
|
||||
jASSUME( vuindex < 0 );
|
||||
|
||||
// upper 4 bits must be zero!
|
||||
s_recVUMem = (u8*)SysMmap( 0x0c000000, VU_EXESIZE);
|
||||
|
||||
|
@ -352,20 +354,26 @@ void SuperVUInit(int vuindex)
|
|||
|
||||
if( s_recVUMem == NULL )
|
||||
{
|
||||
Console::Error( "SuperVU Error > failed to allocate recompiler memory (addr: 0x%x)", params (u32)s_recVUMem );
|
||||
throw Exception::OutOfMemory( "Could not reserve memory for the SuperVU." );
|
||||
throw Exception::OutOfMemory(
|
||||
fmt_string( "SuperVU Error > failed to allocate recompiler memory (addr: 0x%x)", params (u32)s_recVUMem )
|
||||
);
|
||||
}
|
||||
|
||||
ProfilerRegisterSource( "VURec", s_recVUMem, VU_EXESIZE);
|
||||
memset(s_recVUMem, 0xcd, VU_EXESIZE);
|
||||
s_recVUPtr = s_recVUMem;
|
||||
|
||||
if( recVUStack == NULL )
|
||||
recVUStack = new u8[SUPERVU_STACKSIZE * 4];
|
||||
}
|
||||
|
||||
if( vuindex >= 0 )
|
||||
{
|
||||
jASSUME( s_recVUMem != NULL );
|
||||
|
||||
if( recVUHeaders[vuindex] == NULL )
|
||||
recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex]/8];
|
||||
if( recVUBlocks[vuindex] == NULL )
|
||||
recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex]/8];
|
||||
if( s_plistCachedHeaders[vuindex] == NULL )
|
||||
s_plistCachedHeaders[vuindex] = new list<VuFunctionHeader*>[s_MemSize[vuindex]/8];
|
||||
}
|
||||
}
|
||||
|
@ -375,14 +383,16 @@ void SuperVUDestroy(int vuindex)
|
|||
{
|
||||
list<VuFunctionHeader*>::iterator it;
|
||||
|
||||
if( vuindex < 0 ) {
|
||||
if( vuindex < 0 )
|
||||
{
|
||||
SuperVUDestroy(0);
|
||||
SuperVUDestroy(1);
|
||||
ProfilerTerminateSource( "VURec" );
|
||||
SafeSysMunmap(s_recVUMem, VU_EXESIZE);
|
||||
safe_delete_array( recVUStack );
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
safe_delete_array( recVUHeaders[vuindex] );
|
||||
safe_delete_array( recVUBlocks[vuindex] );
|
||||
|
||||
|
@ -402,22 +412,27 @@ void SuperVUDestroy(int vuindex)
|
|||
// reset VU
|
||||
void SuperVUReset(int vuindex)
|
||||
{
|
||||
list<VuFunctionHeader*>::iterator it;
|
||||
|
||||
#ifdef _DEBUG
|
||||
s_vucount = 0;
|
||||
#endif
|
||||
|
||||
if( vuindex < 0 ) {
|
||||
SuperVUReset(0);
|
||||
SuperVUReset(1);
|
||||
if( s_recVUMem == NULL )
|
||||
return;
|
||||
|
||||
//memset(s_recVUMem, 0xcd, VU_EXESIZE);
|
||||
s_recVUPtr = s_recVUMem;
|
||||
//jASSUME( s_recVUMem != NULL );
|
||||
|
||||
if( vuindex < 0 )
|
||||
{
|
||||
DbgCon::Status( "SuperVU reset > Resetting recompiler memory and structures." );
|
||||
memset(s_recVUMem, 0xcd, VU_EXESIZE);
|
||||
memset(recVUStack, 0, SUPERVU_STACKSIZE);
|
||||
|
||||
s_recVUPtr = s_recVUMem;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
DbgCon::Status( "SuperVU reset [%d] > Resetting the recs and junk", params vuindex );
|
||||
list<VuFunctionHeader*>::iterator it;
|
||||
if( recVUHeaders[vuindex] ) memset( recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex]/8) );
|
||||
if( recVUBlocks[vuindex] ) memset( recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex]/8) );
|
||||
|
||||
|
@ -802,6 +817,8 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
|
|||
if ( ( (uptr)s_recVUPtr - (uptr)s_recVUMem ) >= VU_EXESIZE-0x40000 ) {
|
||||
//SysPrintf("SuperVU reset mem\n");
|
||||
SuperVUReset(-1);
|
||||
SuperVUReset(0);
|
||||
SuperVUReset(1);
|
||||
if( s_TotalVUCycles > 0 ) {
|
||||
// already executing, so return NULL
|
||||
return NULL;
|
||||
|
@ -1101,7 +1118,7 @@ static VuBaseBlock* SuperVUBuildBlocks(VuBaseBlock* parent, u32 startpc, const V
|
|||
break;
|
||||
|
||||
if( pc >= s_MemSize[s_vu] ) {
|
||||
SysPrintf("inf vu0 prog %x\n", startpc);
|
||||
Console::Error( "inf vu0 prog %x",params startpc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
namespace Dynarec
|
||||
{
|
||||
extern void SuperVUInit(int vuindex); // if vuindex is -1, inits the global VU resources
|
||||
extern void SuperVUAlloc(int vuindex); // global VU resources aare automatically allocated if necessary.
|
||||
extern void SuperVUDestroy(int vuindex); // if vuindex is -1, destroys everything
|
||||
extern void SuperVUReset(int vuindex); // if vuindex is -1, resets everything
|
||||
|
||||
|
|
|
@ -412,7 +412,15 @@ u32* recAllocStackMem(int size, int align)
|
|||
static const int REC_CACHEMEM = 0x01000000;
|
||||
static void __fastcall dyna_block_discard(u32 start,u32 sz);
|
||||
|
||||
static void recInit()
|
||||
// memory allocation handle for the entire BASEBLOCK and stack allocations.
|
||||
static u8* m_recBlockAlloc = NULL;
|
||||
|
||||
static const uint m_recBlockAllocSize =
|
||||
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK))
|
||||
+ (EE_NUMBLOCKS*sizeof(BASEBLOCKEX)) // recBlocks
|
||||
+ RECSTACK_SIZE; // recStack
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
// Hardware Requirements Check...
|
||||
|
||||
|
@ -425,9 +433,6 @@ static void recInit()
|
|||
if ( !( cpucaps.hasStreamingSIMD2Extensions ) )
|
||||
throw Exception::HardwareDeficiency( _( "Processor doesn't support SSE2" ) );
|
||||
|
||||
int i;
|
||||
const u8 macarr[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
|
||||
|
||||
if( recLUT == NULL )
|
||||
recLUT = (uptr*) _aligned_malloc( 0x010000 * sizeof(uptr), 16 );
|
||||
|
||||
|
@ -448,22 +453,27 @@ static void recInit()
|
|||
if( recMem == NULL || ((uptr)recMem > 0x80000000) )
|
||||
{
|
||||
SysMunmap( recMem, cachememsize );
|
||||
throw Exception::OutOfMemory( "R5900-32 failed to allocate recompiler memory." );
|
||||
throw Exception::OutOfMemory( "R5900-32 > failed to allocate recompiler memory." );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 32 alignment necessary
|
||||
if( recRAM == NULL )
|
||||
recRAM = (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*Ps2MemSize::Base , 4*sizeof(BASEBLOCK));
|
||||
if( recROM == NULL )
|
||||
recROM = (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*Ps2MemSize::Rom , 4*sizeof(BASEBLOCK));
|
||||
if( recROM1 == NULL )
|
||||
recROM1 = (BASEBLOCK*) _aligned_malloc( sizeof(BASEBLOCK)/4*Ps2MemSize::Rom1 , 4*sizeof(BASEBLOCK));
|
||||
if( recBlocks == NULL )
|
||||
recBlocks = (BASEBLOCKEX*) _aligned_malloc( sizeof(BASEBLOCKEX)*EE_NUMBLOCKS, 16);
|
||||
if( recStack == NULL )
|
||||
recStack = (u8*)malloc( RECSTACK_SIZE );
|
||||
// Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory.
|
||||
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
||||
// always 4 bytes long).
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
throw Exception::OutOfMemory( "R5900-32 Init > Failed to allocate memory for BASEBLOCK tables." );
|
||||
|
||||
u8* curpos = m_recBlockAlloc;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
|
||||
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
|
||||
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
|
||||
recBlocks = (BASEBLOCKEX*)curpos; curpos += sizeof(BASEBLOCKEX)*EE_NUMBLOCKS;
|
||||
recStack = (u8*)curpos;
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
{
|
||||
|
@ -471,70 +481,33 @@ static void recInit()
|
|||
s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize );
|
||||
}
|
||||
|
||||
if( recBlocks == NULL || recRAM == NULL || recROM == NULL ||
|
||||
recROM1 == NULL || recMem == NULL || recLUT == NULL ||
|
||||
recStack == NULL || s_pInstCache == NULL )
|
||||
{
|
||||
throw Exception::OutOfMemory("Heap-based memory allocation failed." );
|
||||
}
|
||||
if( s_pInstCache == NULL )
|
||||
throw Exception::OutOfMemory( "R5900-32 Init > failed to allocate memory for pInstCache." );
|
||||
|
||||
// No errors.. Proceed with initialization:
|
||||
|
||||
ProfilerRegisterSource( "EERec", recMem, REC_CACHEMEM+0x1000 );
|
||||
memset( recLUT, 0, 0x010000 * sizeof(uptr) );
|
||||
|
||||
for ( i = 0x0000; i < 0x0200; i++ )
|
||||
{
|
||||
recLUT[ i + 0x0000 ] = (uptr)&recRAM[ i << 14 ];
|
||||
recLUT[ i + 0x2000 ] = (uptr)&recRAM[ i << 14 ];
|
||||
recLUT[ i + 0x3000 ] = (uptr)&recRAM[ i << 14 ];
|
||||
}
|
||||
|
||||
for ( i = 0x0000; i < 0x0040; i++ )
|
||||
{
|
||||
recLUT[ i + 0x1fc0 ] = (uptr)&recROM[ i << 14 ];
|
||||
recLUT[ i + 0x9fc0 ] = (uptr)&recROM[ i << 14 ];
|
||||
recLUT[ i + 0xbfc0 ] = (uptr)&recROM[ i << 14 ];
|
||||
}
|
||||
|
||||
for ( i = 0x0000; i < 0x0004; i++ )
|
||||
{
|
||||
recLUT[ i + 0x1e00 ] = (uptr)&recROM1[ i << 14 ];
|
||||
recLUT[ i + 0x9e00 ] = (uptr)&recROM1[ i << 14 ];
|
||||
recLUT[ i + 0xbe00 ] = (uptr)&recROM1[ i << 14 ];
|
||||
}
|
||||
|
||||
memcpy( recLUT + 0x8000, recLUT, 0x2000 * sizeof(uptr) );
|
||||
memcpy( recLUT + 0xa000, recLUT, 0x2000 * sizeof(uptr) );
|
||||
// Clear remMem here but not in Reset. Unfortunately the GUI requires recMem to beintact
|
||||
// in order to "return" execution even after a reset of the emulator.
|
||||
|
||||
memset(recMem, 0xcd, REC_CACHEMEM);
|
||||
memset(recStack, 0, RECSTACK_SIZE);
|
||||
|
||||
x86SetPtr(recMem+REC_CACHEMEM);
|
||||
dyna_block_discard_recmem=(u8*)x86Ptr;
|
||||
JMP32( (uptr)&dyna_block_discard - ( (u32)x86Ptr + 5 ));
|
||||
|
||||
x86FpuState = FPU_STATE;
|
||||
|
||||
SuperVUInit(-1);
|
||||
|
||||
//Msgbox::Alert("recInit: Config.sseMXCSR = %x; Config.sseVUMXCSR = %x \n", Config.sseMXCSR, Config.sseVUMXCSR);
|
||||
SetCPUState(Config.sseMXCSR, Config.sseVUMXCSR);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
static void recReset( void ) {
|
||||
|
||||
DevCon::WriteLn( "EE Recompiler data reset" );
|
||||
static void recReset( void )
|
||||
{
|
||||
DbgCon::Status( "iR5900-32 > Resetting recompiler memory and structures." );
|
||||
|
||||
s_nNextBlock = 0;
|
||||
maxrecmem = 0;
|
||||
memset( recRAM, 0, sizeof(BASEBLOCK)/4*Ps2MemSize::Base );
|
||||
memset( recROM, 0, sizeof(BASEBLOCK)/4*Ps2MemSize::Rom );
|
||||
memset( recROM1, 0, sizeof(BASEBLOCK)/4*Ps2MemSize::Rom1 );
|
||||
memset( recBlocks, 0, sizeof(BASEBLOCKEX)*EE_NUMBLOCKS );
|
||||
memset( m_recBlockAlloc, 0, m_recBlockAllocSize );
|
||||
if( s_pInstCache ) memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
|
||||
|
||||
ResetBaseBlockEx(0);
|
||||
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
mmap_ResetBlockTracking();
|
||||
#endif
|
||||
|
@ -545,10 +518,40 @@ static void recReset( void ) {
|
|||
__asm__("emms");
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
// don't clear since save states won't work
|
||||
//memset(recMem, 0xcd, REC_CACHEMEM);
|
||||
#endif
|
||||
memset( recLUT, 0, 0x010000 * sizeof(uptr) );
|
||||
|
||||
for ( int i = 0x0000; i < 0x0200; i++ )
|
||||
{
|
||||
recLUT[ i + 0x0000 ] = (uptr)&recRAM[ i << 14 ];
|
||||
recLUT[ i + 0x2000 ] = (uptr)&recRAM[ i << 14 ];
|
||||
recLUT[ i + 0x3000 ] = (uptr)&recRAM[ i << 14 ];
|
||||
}
|
||||
|
||||
for ( int i = 0x0000; i < 0x0040; i++ )
|
||||
{
|
||||
recLUT[ i + 0x1fc0 ] = (uptr)&recROM[ i << 14 ];
|
||||
recLUT[ i + 0x9fc0 ] = (uptr)&recROM[ i << 14 ];
|
||||
recLUT[ i + 0xbfc0 ] = (uptr)&recROM[ i << 14 ];
|
||||
}
|
||||
|
||||
for ( int i = 0x0000; i < 0x0004; i++ )
|
||||
{
|
||||
recLUT[ i + 0x1e00 ] = (uptr)&recROM1[ i << 14 ];
|
||||
recLUT[ i + 0x9e00 ] = (uptr)&recROM1[ i << 14 ];
|
||||
recLUT[ i + 0xbe00 ] = (uptr)&recROM1[ i << 14 ];
|
||||
}
|
||||
|
||||
memcpy( recLUT + 0x8000, recLUT, 0x2000 * sizeof(uptr) );
|
||||
memcpy( recLUT + 0xa000, recLUT, 0x2000 * sizeof(uptr) );
|
||||
|
||||
//memset(recStack, 0, RECSTACK_SIZE);
|
||||
|
||||
// This may or may not be needed anymore...
|
||||
x86SetPtr(recMem+REC_CACHEMEM);
|
||||
dyna_block_discard_recmem=(u8*)x86Ptr;
|
||||
JMP32( (uptr)&dyna_block_discard - ( (u32)x86Ptr + 5 ));
|
||||
|
||||
x86SetPtr(recMem);
|
||||
|
||||
recPtr = recMem;
|
||||
recStackPtr = recStack;
|
||||
|
@ -556,34 +559,27 @@ static void recReset( void ) {
|
|||
iCWstate = 0;
|
||||
|
||||
branch = 0;
|
||||
SetCPUState(Config.sseMXCSR, Config.sseVUMXCSR);
|
||||
}
|
||||
|
||||
void recShutdown( void )
|
||||
static void recShutdown( void )
|
||||
{
|
||||
ProfilerTerminateSource( "EERec" );
|
||||
ResetBaseBlockEx(0);
|
||||
|
||||
SafeSysMunmap(recMem, REC_CACHEMEM);
|
||||
|
||||
SafeSysMunmap( recMem, REC_CACHEMEM );
|
||||
safe_aligned_free( recLUT );
|
||||
safe_aligned_free( recRAM );
|
||||
safe_aligned_free( recROM );
|
||||
safe_aligned_free( recROM1 );
|
||||
safe_aligned_free( recBlocks );
|
||||
safe_aligned_free( m_recBlockAlloc );
|
||||
recRAM = recROM = recROM1 = NULL;
|
||||
recBlocks = NULL;
|
||||
recStack = NULL;
|
||||
|
||||
safe_free( s_pInstCache );
|
||||
s_nInstCacheSize = 0;
|
||||
|
||||
SuperVUDestroy(-1);
|
||||
|
||||
x86Shutdown();
|
||||
}
|
||||
|
||||
void recEnableVU0micro(int enable) {
|
||||
}
|
||||
|
||||
void recEnableVU1micro(int enable) {
|
||||
}
|
||||
|
||||
#pragma warning(disable:4731) // frame pointer register 'ebp' modified by inline assembly code
|
||||
static u32 s_uSaveESP = 0, s_uSaveEBP;
|
||||
|
||||
|
@ -1633,10 +1629,11 @@ void recRecompile( u32 startpc )
|
|||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) {
|
||||
DevCon::WriteLn( "EE Recompiler data reset" );
|
||||
recReset();
|
||||
}
|
||||
if ( ( (uptr)recStackPtr - (uptr)recStack ) >= RECSTACK_SIZE-0x100 ) {
|
||||
DevCon::WriteLn("stack reset");
|
||||
DevCon::WriteLn("EE recompiler stack reset");
|
||||
recReset();
|
||||
}
|
||||
|
||||
|
@ -2179,20 +2176,14 @@ using namespace Dynarec::R5900;
|
|||
namespace R5900
|
||||
{
|
||||
|
||||
R5900cpu recCpu = {
|
||||
recInit,
|
||||
R5900cpu recCpu = {
|
||||
recAlloc,
|
||||
recReset,
|
||||
recStep,
|
||||
recExecute,
|
||||
recExecuteBlock,
|
||||
recExecuteVU0Block,
|
||||
recExecuteVU1Block,
|
||||
recEnableVU0micro,
|
||||
recEnableVU1micro,
|
||||
recClear,
|
||||
recClearVU0,
|
||||
recClearVU1,
|
||||
recShutdown
|
||||
};
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue