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:
Jake.Stine 2009-01-12 06:37:56 +00:00 committed by Gregory Hainaut
parent d6383a4a04
commit 7488e930d4
56 changed files with 1964 additions and 1651 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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()

View File

@ -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,27 +47,24 @@ 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;
// i guess this is kinda a version, it's used by some bioses
psHu32(0xf590) = 0x1201;
gsReset();
ipuReset();
}

View File

@ -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();

View File

@ -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
};

View File

@ -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()

View File

@ -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
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;
memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(PSMEMORYMAP), 16);
if( memLUT == NULL )
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);

View File

@ -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();

View File

@ -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(

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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:

View File

@ -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();

View File

@ -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) {

View File

@ -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);

View File

@ -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();
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. -_-

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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()
{

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -88,7 +88,7 @@ extern _sio sio;
#define RTS 0x0020
#define SIO_RESET 0x0040
int sioInit();
void sioInit();
void sioShutdown();
void psxSIOShutdown();
u8 sioRead8();

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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.");
}
}
}

View File

@ -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);
/****************************************/

250
pcsx2/VU0microInterp.cpp Normal file
View File

@ -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
};

View File

@ -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() {

235
pcsx2/VU1microInterp.cpp Normal file
View File

@ -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
};

View File

@ -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);

229
pcsx2/VUmicroMem.cpp Normal file
View File

@ -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 );
}
}

View File

@ -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);
}
}

View File

@ -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()

View File

@ -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();

View File

@ -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);

View File

@ -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"
>

View File

@ -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
@ -335,9 +345,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
@ -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();
}

View File

@ -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;
Cpu->Execute();
g_GameInProgress = false;
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);
}
AccBreak = true;
DestroyWindow(gApp.hWnd);
gApp.hWnd = NULL;
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,8 +623,11 @@ public:
int oldmidx = m_idx;
m_idx += 4;
memSavingState::gsFreeze();
s32& len = *((s32*)m_memory.GetPtr( oldmidx ));
len = (m_idx - oldmidx)-4;
if( IsSaving() )
{
s32& len = *((s32*)m_memory.GetPtr( oldmidx ));
len = (m_idx - oldmidx)-4;
}
}
};
@ -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;

View File

@ -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;
}
}

View File

@ -35,8 +35,7 @@ namespace Interp = R5900::Interpreter::OpcodeImpl::COP0;
namespace Dynarec {
namespace R5900 {
namespace OpcodeImpl {
namespace COP0
{
namespace COP0 {
/*********************************************************
* COP0 opcodes *

View File

@ -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

View File

@ -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

View File

@ -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,50 +656,47 @@ static __forceinline void R3000AExecute()
BASEBLOCK* pblock;
//while (EEsCycle > 0)
{
pblock = PSX_GETBLOCK(psxRegs.pc);
pblock = PSX_GETBLOCK(psxRegs.pc);
if ( !pblock->pFnptr || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) {
psxRecRecompile(psxRegs.pc);
}
if ( !pblock->pFnptr || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) {
psxRecRecompile(psxRegs.pc);
}
assert( pblock->pFnptr != 0 );
assert( pblock->pFnptr != 0 );
#ifdef _DEBUG
fnptr = (u8*)pblock->pFnptr;
fnptr = (u8*)pblock->pFnptr;
#ifdef _MSC_VER
__asm {
// save data
mov oldesi, esi;
mov s_uSaveESP, esp;
sub s_uSaveESP, 8;
push ebp;
call fnptr; // jump into function
// restore data
pop ebp;
mov esi, oldesi;
}
__asm {
// save data
mov oldesi, esi;
mov s_uSaveESP, esp;
sub s_uSaveESP, 8;
push ebp;
call fnptr; // jump into function
// restore data
pop ebp;
mov esi, oldesi;
}
#else // linux
__asm__("movl %%esi, %0\n"
"movl %%esp, %1\n"
"sub $8, %%esp\n"
"push %%ebp\n"
"call *%2\n"
"pop %%ebp\n"
"movl %0, %%esi\n" : "=m"(oldesi), "=m"(s_uSaveESP) : "c"(fnptr) : );
__asm__("movl %%esi, %0\n"
"movl %%esp, %1\n"
"sub $8, %%esp\n"
"push %%ebp\n"
"call *%2\n"
"pop %%ebp\n"
"movl %0, %%esi\n" : "=m"(oldesi), "=m"(s_uSaveESP) : "c"(fnptr) : );
#endif // _MSC_VER
#else
((R3000AFNPTR)pblock->pFnptr)();
((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,

View File

@ -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) {
FreezeXMMRegs(1);
SuperVUExecuteProgram(VU0.VI[ REG_TPC ].UL & 0xfff, 0);
FreezeXMMRegs(0);
}
else ::R5900::Interpreter::intExecuteVU0Block();
//}
}
static void recReset()
{
SuperVUReset(0);
void recClearVU0( u32 Addr, u32 Size )
{
if( CHECK_VU0REC ) {
// 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);
}
static void recClear(u32 Addr, u32 Size)
{
SuperVUClear(Addr, Size*4, 0);
}
static void recShutdown()
{
SuperVUDestroy( 0 );
}
}
void recResetVU0( void )
using namespace Dynarec;
VUmicroCpu recVU0 =
{
SuperVUReset(0);
}
recAlloc
, recReset
, recStep
, recExecuteBlock
, recClear
, recShutdown
};
}

View File

@ -24,129 +24,80 @@
#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()
{
FILE *f;
char filename[ g_MaxPath ];
u32 *mem;
u32 i;
#ifdef _WIN32
CreateDirectory("dumps", NULL);
sprintf_s( filename, g_MaxPath, "dumps\\vu%.4X.txt", VU1.VI[ REG_TPC ].UL );
#else
mkdir("dumps", 0755);
sprintf( filename, "dumps/vu%.4X.txt", VU1.VI[ REG_TPC ].UL );
#endif
SysPrintf( "dump1 %x => %x (%s)\n", VU1.VI[ REG_TPC ].UL, pc, filename );
f = fopen( filename, "wb" );
for ( i = VU1.VI[REG_TPC].UL; i < pc; i += 8 ) {
char* pstr;
mem = (u32*)&VU1.Micro[i];
pstr = disVU1MicroUF( mem[1], i+4 );
fprintf(f, "%x: %-40s ", i, pstr);
pstr = disVU1MicroLF( mem[0], i );
fprintf(f, "%s\n", pstr);
}
fclose( f );
}
#ifdef _DEBUG
static u32 vuprogcount = 0;
#endif
void recExecuteVU1Block(void)
{
#ifdef _DEBUG
vuprogcount++;
if( vudump & 8 ) __Log("start vu1: %x %x\n", VU1.VI[ REG_TPC ].UL, vuprogcount);
#endif
if((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0){
//SysPrintf("Execute block VU1, VU1 not busy\n");
return;
}
if (CHECK_VU1REC)
// commented out because I'm not sure it actually works anymore with SuperVU (air)
/*static void iVU1DumpBlock()
{
if (VU1.VI[REG_TPC].UL >= VU1.maxmicro) {
SysPrintf("VU1 memory overflow!!: %x\n", VU1.VI[REG_TPC].UL);
FILE *f;
char filename[ g_MaxPath ];
u32 *mem;
u32 i;
#ifdef _WIN32
CreateDirectory("dumps", NULL);
sprintf_s( filename, g_MaxPath, "dumps\\vu%.4X.txt", VU1.VI[ REG_TPC ].UL );
#else
mkdir("dumps", 0755);
sprintf( filename, "dumps/vu%.4X.txt", VU1.VI[ REG_TPC ].UL );
#endif
SysPrintf( "dump1 %x => %x (%s)\n", VU1.VI[ REG_TPC ].UL, pc, filename );
f = fopen( filename, "wb" );
for ( i = VU1.VI[REG_TPC].UL; i < pc; i += 8 ) {
char* pstr;
mem = (u32*)&VU1.Micro[i];
pstr = disVU1MicroUF( mem[1], i+4 );
fprintf(f, "%x: %-40s ", i, pstr);
pstr = disVU1MicroLF( mem[0], i );
fprintf(f, "%s\n", pstr);
}
fclose( f );
}*/
static void recAlloc()
{
SuperVUAlloc(1);
}
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
if((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0){
//SysPrintf("Execute block VU1, VU1 not busy\n");
return;
}
if (VU1.VI[REG_TPC].UL >= VU1.maxmicro)
{
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
};

View File

@ -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,21 +354,27 @@ 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;
recVUStack = new u8[SUPERVU_STACKSIZE * 4];
if( recVUStack == NULL )
recVUStack = new u8[SUPERVU_STACKSIZE * 4];
}
if( vuindex >= 0 )
{
recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex]/8];
recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex]/8];
s_plistCachedHeaders[vuindex] = new list<VuFunctionHeader*>[s_MemSize[vuindex]/8];
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;
}
}

View File

@ -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

View File

@ -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 ];
}
// 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.
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) );
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,
recReset,
recStep,
recExecute,
recExecuteBlock,
recExecuteVU0Block,
recExecuteVU1Block,
recEnableVU0micro,
recEnableVU1micro,
recClear,
recClearVU0,
recClearVU1,
recShutdown
};
R5900cpu recCpu = {
recAlloc,
recReset,
recStep,
recExecute,
recExecuteBlock,
recClear,
recShutdown
};
}