More changes to the IOP's memory model. Some of these are experimental and might cause problems (needs testing). Quick rundown:

* The R3000 does not have a TLB, and has no valid addresses mapped above page 0x2000 in physical memory [lower 512M].  Thus all addresses can have the top 6 bits masked off and still retain full validity.  For example, address 0xbfc0 is simply a mirror of physical address 0x1fc0.  Technically speaking, a full emulation of the IOP memory model would raise bus error exceptions for accesses between 0x2000 to 0x8000 segments (instead of treating them as mirrors of the lower 0x2000 segment), but buss errors are generally fatal (unrecoverable) program errors that would never happen within the context of game emulation.

* The IOP's SIF register space is only 256 bytes, and then mirrored repeatedly through it's 64k page at 0x1d00.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@814 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-03-19 03:59:25 +00:00
parent f2477537f9
commit a51b407cdb
2 changed files with 144 additions and 429 deletions

View File

@ -24,309 +24,10 @@
#include "Hw.h"
#include "iR3000A.h"
#ifdef PCSX2_VIRTUAL_MEM
void psxMemAlloc()
{
// In VirtualMemory land all mem taken care by memAlloc
}
void psxMemReset()
{
memzero_ptr<Ps2MemSize::IopRam>(psxM);
}
void psxMemShutdown()
{
}
u8 iopMemRead8(u32 mem)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
mem&= 0x1fffffff;
if (mem < 0x1f801000)
return psxHu8(mem);
else
return psxHwRead8(mem);
break;
#ifdef _DEBUG
case 0x1d00: assert(0);
#endif
case 0x1f40:
mem &= 0x1fffffff;
return psxHw4Read8(mem);
case 0x1000: return DEV9read8(mem & 0x1FFFFFFF);
default:
assert( g_psxWriteOk );
return *(u8*)PSXM(mem);
}
}
u16 iopMemRead16(u32 mem)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
mem&= 0x1fffffff;
if (mem < 0x1f801000)
return psxHu16(mem);
else
return psxHwRead16(mem);
break;
case 0x1d00:
SIF_LOG("Sif reg read %x value %x\n", mem, psxHu16(mem));
switch(mem & 0xF0)
{
case 0x40: return psHu16(0x1000F240) | 0x0002;
case 0x60: return 0;
default: return *(u16*)(PS2MEM_HW+0xf200+(mem&0xf0));
}
break;
case 0x1f90:
return SPU2read(mem & 0x1FFFFFFF);
case 0x1000:
return DEV9read16(mem & 0x1FFFFFFF);
default:
assert( g_psxWriteOk );
return *(u16*)PSXM(mem);
}
}
u32 iopMemRead32(u32 mem)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
mem&= 0x1fffffff;
if (mem < 0x1f801000)
return psxHu32(mem);
else
return psxHwRead32(mem);
break;
case 0x1d00:
SIF_LOG("Sif reg read %x value %x\n", mem, psxHu32(mem));
switch(mem & 0xF0)
{
case 0x40: return psHu32(0x1000F240) | 0xF0000002;
case 0x60: return 0;
default: return *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0));
}
break;
case 0x1fff: return g_psxWriteOk;
case 0x1000:
return DEV9read32(mem & 0x1FFFFFFF);
default:
//assert(g_psxWriteOk);
if( mem == 0xfffe0130 )
return writectrl;
else if( mem == 0xffffffff )
return writectrl;
else if( g_psxWriteOk )
return *(u32*)PSXM(mem);
else return 0;
}
}
void iopMemWrite8(u32 mem, u8 value)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
mem&= 0x1fffffff;
if (mem < 0x1f801000)
psxHu8(mem) = value;
else
psxHwWrite8(mem, value);
break;
case 0x1f40:
mem&= 0x1fffffff;
psxHw4Write8(mem, value);
break;
case 0x1d00:
SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value);
*(u8*)(PS2MEM_HW+0xf200+(mem&0xff)) = value;
break;
case 0x1000:
DEV9write8(mem & 0x1fffffff, value);
return;
default:
assert(g_psxWriteOk);
*(u8 *)PSXM(mem) = value;
psxCpu->Clear(mem&~3, 1);
break;
}
}
void iopMemWrite16(u32 mem, u16 value)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1600:
//HACK: DEV9 VM crash fix
break;
case 0x1f80:
mem&= 0x1fffffff;
if (mem < 0x1f801000)
psxHu16(mem) = value;
else
psxHwWrite16(mem, value);
break;
case 0x1d00:
switch (mem & 0xf0) {
case 0x10:
// write to ps2 mem
psHu16(0x1000F210) = value;
return;
case 0x40:
{
u32 temp = value & 0xF0;
// write to ps2 mem
if(value & 0x20 || value & 0x80)
{
psHu16(0x1000F240) &= ~0xF000;
psHu16(0x1000F240) |= 0x2000;
}
if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp;
else psHu16(0x1000F240) |= temp;
return;
}
case 0x60:
psHu32(0x1000F260) = 0;
return;
default:
assert(0);
}
return;
case 0x1f90:
SPU2write(mem & 0x1FFFFFFF, value); return;
case 0x1000:
DEV9write16(mem & 0x1fffffff, value); return;
default:
assert( g_psxWriteOk );
*(u16 *)PSXM(mem) = value;
psxCpu->Clear(mem&~3, 1);
break;
}
}
void iopMemWrite32(u32 mem, u32 value)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
mem&= 0x1fffffff;
if (mem < 0x1f801000)
psxHu32(mem) = value;
else
psxHwWrite32(mem, value);
break;
case 0x1d00:
switch (mem & 0xf0) {
case 0x10:
// write to ps2 mem
psHu32(0x1000F210) = value;
return;
case 0x20:
// write to ps2 mem
psHu32(0x1000F220) &= ~value;
return;
case 0x30:
// write to ps2 mem
psHu32(0x1000F230) |= value;
return;
case 0x40:
{
u32 temp = value & 0xF0;
// write to ps2 mem
if(value & 0x20 || value & 0x80)
{
psHu32(0x1000F240) &= ~0xF000;
psHu32(0x1000F240) |= 0x2000;
}
if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp;
else psHu32(0x1000F240) |= temp;
return;
}
case 0x60:
psHu32(0x1000F260) = 0;
return;
default:
*(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value;
}
return;
case 0x1000:
DEV9write32(mem & 0x1fffffff, value);
return;
case 0x1ffe:
if( mem == 0xfffe0130 ) {
writectrl = value;
switch (value) {
case 0x800: case 0x804:
case 0xc00: case 0xc04:
case 0xcc0: case 0xcc4:
case 0x0c4:
g_psxWriteOk = 0;
//PSXMEM_LOG("writectrl: writenot ok\n");
break;
case 0x1e988:
case 0x1edd8:
g_psxWriteOk = 1;
//PSXMEM_LOG("writectrl: write ok\n");
break;
default:
PSXMEM_LOG("unk %8.8lx = %x\n", mem, value);
break;
}
}
break;
default:
if( g_psxWriteOk ) {
*(u32 *)PSXM(mem) = value;
psxCpu->Clear(mem&~3, 1);
}
break;
}
}
#else
u8 *psxM = NULL;
u8 *psxP = NULL;
u8 *psxH = NULL;
u8 *psxS = NULL;
u8 *psxH = NULL; // standard hardware registers (0x000->0x3ff is the scratchpad)
u8 *psxS = NULL; // 'undocumented' SIF communication registers
uptr *psxMemWLUT = NULL;
const uptr *psxMemRLUT = NULL;
@ -336,7 +37,7 @@ static const uint m_psxMemSize =
Ps2MemSize::IopRam +
Ps2MemSize::IopHardware +
0x00010000 + // psxP
0x00010000 ; // psxS
0x00000100 ; // psxS
void psxMemAlloc()
{
@ -352,8 +53,8 @@ void psxMemAlloc()
psxH = curpos; curpos += Ps2MemSize::IopHardware;
psxS = curpos; //curpos += 0x00010000;
psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr) * 2, 16);
psxMemRLUT = psxMemWLUT + 0x10000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
}
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
@ -365,53 +66,53 @@ void psxMemReset()
DbgCon::Status( "psxMemReset > Resetting core memory!" );
memzero_ptr<0x10000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT
memzero_ptr<0x2000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT
memzero_ptr<m_psxMemSize>( m_psxAllMem );
// 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.
// So the ones with a 0x2000 prefixed are RLUT tables.
// Map IOP main memory, which is Read/Write, and mirrored three times
// at 0x0, 0x8000, and 0xa000:
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];
//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];
psxMemWLUT[i + 0x2000] = (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 for things we store in special locations.
psxMemWLUT[0x11f00] = (uptr)psxP;
psxMemWLUT[0x11f80] = (uptr)psxH;
psxMemWLUT[0x1bf80] = (uptr)psxH;
psxMemWLUT[0x2000 + 0x1f00] = (uptr)psxP;
psxMemWLUT[0x2000 + 0x1f80] = (uptr)psxH;
//psxMemWLUT[0x1bf80] = (uptr)psxH;
psxMemWLUT[0x1f00] = (uptr)psxP;
psxMemWLUT[0x1f80] = (uptr)psxH;
psxMemWLUT[0xbf80] = (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];
psxMemWLUT[i + 0x2000 + 0x1fc0] = (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];
psxMemWLUT[i + 0x2000 + 0x1e00] = (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;
// sif!! (which is read only? (air))
psxMemWLUT[0x2000 + 0x1d00] = (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];
@ -433,50 +134,58 @@ void psxMemShutdown()
psxMemRLUT = NULL;
}
u8 iopMemRead8(u32 mem) {
const u8* p;
u32 t;
u8 iopMemRead8(u32 mem)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (t == 0x1f80)
{
if (mem < 0x1f801000)
return psxHu8(mem);
else
return psxHwRead8(mem);
} else
if (t == 0x1f40) {
mem&= 0x1fffffff;
return psxHw4Read8(mem);
} else
}
else if (t == 0x1f40)
{
p = (const u8*)(psxMemRLUT[mem >> 16]);
if (p != NULL) {
return ( psxRegs.CP0.n.Status & 0x10000 ) ? 0 : *(const u8 *)(p + (mem & 0xffff));
} else {
if (t == 0x1000) return DEV9read8(mem & 0x1FFFFFFF);
return psxHw4Read8(mem);
}
else
{
const u8* p = (const u8*)(psxMemRLUT[mem >> 16]);
if (p != NULL)
{
return *(const u8 *)(p + (mem & 0xffff));
}
else
{
if (t == 0x1000)
return DEV9read8(mem);
PSXMEM_LOG("err lb %8.8lx\n", mem);
return 0;
}
}
}
u16 iopMemRead16(u32 mem) {
const u8* p;
u32 t;
u16 iopMemRead16(u32 mem)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (t == 0x1f80)
{
if (mem < 0x1f801000)
return psxHu16(mem);
else
return psxHwRead16(mem);
} else
}
else
{
p = (const u8*)(psxMemRLUT[mem >> 16]);
if (p != NULL) {
if (t == 0x1d00) {
const u8* p = (const u8*)(psxMemRLUT[mem >> 16]);
if (p != NULL)
{
if (t == 0x1d00)
{
u16 ret;
switch(mem & 0xF0)
{
@ -493,32 +202,33 @@ u16 iopMemRead16(u32 mem) {
ret = 0;
break;
default:
if( !(psxRegs.CP0.n.Status & 0x10000) )
ret = psxHu16(mem);
else
ret = 0;
ret = psxHu16(mem);
break;
}
SIF_LOG("Sif reg read %x value %x\n", mem, ret);
return ret;
}
return *(const u16 *)(p + (mem & 0xffff));
} else {
}
else
{
if (t == 0x1F90)
return SPU2read(mem & 0x1FFFFFFF);
if (t == 0x1000) return DEV9read16(mem & 0x1FFFFFFF);
return SPU2read(mem);
if (t == 0x1000)
return DEV9read16(mem);
PSXMEM_LOG("err lh %8.8lx\n", mem);
return 0;
}
}
}
u32 iopMemRead32(u32 mem) {
const u8* p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
u32 iopMemRead32(u32 mem)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
if (t == 0x1f80)
{
if (mem < 0x1f801000)
return psxHu32(mem);
else
@ -526,9 +236,11 @@ u32 iopMemRead32(u32 mem) {
} else
{
//see also Hw.c
p = (const u8*)(psxMemRLUT[mem >> 16]);
if (p != NULL) {
if (t == 0x1d00) {
const u8* p = (const u8*)(psxMemRLUT[mem >> 16]);
if (p != NULL)
{
if (t == 0x1d00)
{
u32 ret;
switch(mem & 0xF0)
{
@ -551,42 +263,42 @@ u32 iopMemRead32(u32 mem) {
ret = 0;
break;
default:
if( !(psxRegs.CP0.n.Status & 0x10000) )
ret = psxHu32(mem);
else
ret = 0;
ret = psxHu32(mem);
break;
}
SIF_LOG("Sif reg read %x value %x\n", mem, ret);
return ret;
}
return *(const u32 *)(p + (mem & 0xffff));
} else {
if (t == 0x1000) return DEV9read32(mem & 0x1FFFFFFF);
}
else
{
if (t == 0x1000)
return DEV9read32(mem);
return 0;
}
}
}
void iopMemWrite8(u32 mem, u8 value) {
char *p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
void iopMemWrite8(u32 mem, u8 value)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
if (t == 0x1f80)
{
if (mem < 0x1f801000)
psxHu8(mem) = value;
else
psxHwWrite8(mem, value);
} else
if (t == 0x1f40) {
mem&= 0x1fffffff;
psxHw4Write8(mem, value);
} else
}
else if (t == 0x1f40)
{
p = (char *)(psxMemWLUT[mem >> 16]);
psxHw4Write8(mem, value);
}
else
{
u8* p = (u8 *)(psxMemWLUT[mem >> 16]);
if (p != NULL && !(psxRegs.CP0.n.Status & 0x10000) )
{
*(u8 *)(p + (mem & 0xffff)) = value;
@ -594,35 +306,35 @@ void iopMemWrite8(u32 mem, u8 value) {
}
else
{
if ((t & 0x1FFF)==0x1D00) SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value);
if (t == 0x1D00) SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value);
if (t == 0x1d00) {
psxSu8(mem) = value; return;
}
if (t == 0x1000) {
DEV9write8(mem & 0x1fffffff, value); return;
DEV9write8(mem, value); return;
}
PSXMEM_LOG("err sb %8.8lx = %x\n", mem, value);
}
}
}
void iopMemWrite16(u32 mem, u16 value) {
char *p;
u32 t;
void iopMemWrite16(u32 mem, u16 value)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (t == 0x1f80)
{
if (mem < 0x1f801000)
psxHu16(mem) = value;
else
psxHwWrite16(mem, value);
} else
{
p = (char *)(psxMemWLUT[mem >> 16]);
u8* p = (u8 *)(psxMemWLUT[mem >> 16]);
if (p != NULL && !(psxRegs.CP0.n.Status & 0x10000) )
{
if ((t & 0x1FFF)==0x1D00) SysPrintf("sw16 [0x%08X]=0x%08X\n", mem, value);
if( t==0x1D00 ) SysPrintf("sw16 [0x%08X]=0x%08X\n", mem, value);
*(u16 *)(p + (mem & 0xffff)) = value;
psxCpu->Clear(mem&~3, 1);
}
@ -659,23 +371,23 @@ void iopMemWrite16(u32 mem, u16 value) {
psxSu16(mem) = value; return;
}
if (t == 0x1F90) {
SPU2write(mem & 0x1FFFFFFF, value); return;
SPU2write(mem, value); return;
}
if (t == 0x1000) {
DEV9write16(mem & 0x1fffffff, value); return;
DEV9write16(mem, value); return;
}
PSXMEM_LOG("err sh %8.8lx = %x\n", mem, value);
}
}
}
void iopMemWrite32(u32 mem, u32 value) {
char *p;
u32 t;
void iopMemWrite32(u32 mem, u32 value)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (t == 0x1f80)
{
if (mem < 0x1f801000)
psxHu32(mem) = value;
else
@ -683,7 +395,7 @@ void iopMemWrite32(u32 mem, u32 value) {
} else
{
//see also Hw.c
p = (char *)(psxMemWLUT[mem >> 16]);
u8* p = (u8 *)(psxMemWLUT[mem >> 16]);
if( p != NULL && !(psxRegs.CP0.n.Status & 0x10000) )
{
*(u32 *)(p + (mem & 0xffff)) = value;
@ -696,22 +408,24 @@ void iopMemWrite32(u32 mem, u32 value) {
MEM_LOG("iop Sif reg write %x value %x\n", mem, value);
switch (mem & 0xf0)
{
case 0x10:
// write to ps2 mem
case 0x00: // EE write path (EE/IOP readable)
return; // this is the IOP, so read-only (do nothing)
case 0x10: // IOP write path (EE/IOP readable)
psHu32(0x1000F210) = value;
return;
case 0x20:
// write to ps2 mem
case 0x20: // Bits cleared when written from IOP.
psHu32(0x1000F220) &= ~value;
return;
case 0x30:
// write to ps2 mem
case 0x30: // bits set when written from IOP
psHu32(0x1000F230) |= value;
return;
case 0x40:
case 0x40: // Control Register
{
u32 temp = value & 0xF0;
// write to ps2 mem
if(value & 0x20 || value & 0x80)
{
psHu32(0x1000F240) &= ~0xF000;
@ -719,28 +433,28 @@ void iopMemWrite32(u32 mem, u32 value) {
}
if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp;
else psHu32(0x1000F240) |= temp;
if(psHu32(0x1000F240) & temp)
psHu32(0x1000F240) &= ~temp;
else
psHu32(0x1000F240) |= temp;
return;
}
case 0x60:
psHu32(0x1000F260) = 0;
return;
return;
}
psxSu32(mem) = value;
// write to ps2 mem
if( (mem & 0xf0) != 0x60 )
*(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value;
// wtf? why were we writing to the EE's sif space? Commenting this out doesn't
// break any of my games, and should be more correct, but I guess we'll see. --air
//*(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value;
return;
}
else if (t == 0x1000)
{
DEV9write32(mem & 0x1fffffff, value); return;
DEV9write32(mem, value); return;
}
}
}
}
#endif

View File

@ -46,7 +46,8 @@ static __forceinline T* iopVirtMemW( u32 mem )
template<typename T>
static __forceinline const T* iopVirtMemR( u32 mem )
{
return (psxMemRLUT[(mem) >> 16] == 0) ? NULL : (const T*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff));
mem &= 0x1fffffff;
return (psxMemRLUT[mem >> 16] == 0) ? NULL : (const T*)(psxMemRLUT[mem >> 16] + (mem & 0xffff));
}
// Obtains a pointer to the IOP's physical mapping (bypasses the TLB)
@ -56,11 +57,11 @@ static __forceinline u8* iopPhysMem( u32 addr )
}
#define psxSs8(mem) psxS[(mem) & 0xffff]
#define psxSs16(mem) (*(s16*)&psxS[(mem) & 0xffff])
#define psxSs32(mem) (*(s32*)&psxS[(mem) & 0xffff])
#define psxSu8(mem) (*(u8*) &psxS[(mem) & 0xffff])
#define psxSu16(mem) (*(u16*)&psxS[(mem) & 0xffff])
#define psxSu32(mem) (*(u32*)&psxS[(mem) & 0xffff])
#define psxSs16(mem) (*(s16*)&psxS[(mem) & 0x00ff])
#define psxSs32(mem) (*(s32*)&psxS[(mem) & 0x00ff])
#define psxSu8(mem) (*(u8*) &psxS[(mem) & 0x00ff])
#define psxSu16(mem) (*(u16*)&psxS[(mem) & 0x00ff])
#define psxSu32(mem) (*(u32*)&psxS[(mem) & 0x00ff])
#define psxPs8(mem) psxP[(mem) & 0xffff]
#define psxPs16(mem) (*(s16*)&psxP[(mem) & 0xffff])