beetle-psx-libretro/pgxp/pgxp_mem.c

238 lines
5.0 KiB
C

#include <string.h>
#include "pgxp_mem.h"
#include "pgxp_cpu.h"
#include "pgxp_gte.h"
#include "pgxp_value.h"
PGXP_value Mem[3 * 2048 * 1024 / 4]; // mirror 2MB in 32-bit words * 3
const u32 UserMemOffset = 0;
const u32 ScratchOffset = 2048 * 1024 / 4;
const u32 RegisterOffset = 2 * 2048 * 1024 / 4;
const u32 InvalidAddress = 3 * 2048 * 1024 / 4;
void PGXP_InitMem()
{
memset(Mem, 0, sizeof(Mem));
}
char* PGXP_GetMem()
{
return (char*)(Mem); // Config.PGXP_GTE ? (char*)(Mem) : NULL;
}
/* Playstation Memory Map (from Playstation doc by Joshua Walker)
0x0000_0000-0x0000_ffff Kernel (64K)
0x0001_0000-0x001f_ffff User Memory (1.9 Meg)
0x1f00_0000-0x1f00_ffff Parallel Port (64K)
0x1f80_0000-0x1f80_03ff Scratch Pad (1024 bytes)
0x1f80_1000-0x1f80_2fff Hardware Registers (8K)
0x1fc0_0000-0x1fc7_ffff BIOS (512K)
0x8000_0000-0x801f_ffff Kernel and User Memory Mirror (2 Meg) Cached
0x9fc0_0000-0x9fc7_ffff BIOS Mirror (512K) Cached
0xa000_0000-0xa01f_ffff Kernel and User Memory Mirror (2 Meg) Uncached
0xbfc0_0000-0xbfc7_ffff BIOS Mirror (512K) Uncached
*/
void ValidateAddress(u32 addr)
{
int* pi = NULL;
if ((addr >= 0x00000000) && (addr <= 0x007fffff)) {} // Kernel + User Memory x 8
else if ((addr >= 0x1f000000) && (addr <= 0x1f00ffff)) {} // Parallel Port
else if ((addr >= 0x1f800000) && (addr <= 0x1f8003ff)) {} // Scratch Pad
else if ((addr >= 0x1f801000) && (addr <= 0x1f802fff)) {} // Hardware Registers
else if ((addr >= 0x1fc00000) && (addr <= 0x1fc7ffff)) {} // Bios
else if ((addr >= 0x80000000) && (addr <= 0x807fffff)) {} // Kernel + User Memory x 8 Cached mirror
else if ((addr >= 0x9fc00000) && (addr <= 0x9fc7ffff)) {} // Bios Cached Mirror
else if ((addr >= 0xa0000000) && (addr <= 0xa07fffff)) {} // Kernel + User Memory x 8 Uncached mirror
else if ((addr >= 0xbfc00000) && (addr <= 0xbfc7ffff)) {} // Bios Uncached Mirror
else if (addr == 0xfffe0130) {} // Used for cache flushing
else
{
// *pi = 5;
}
}
u32 PGXP_ConvertAddress(u32 addr)
{
u32 memOffs = 0;
u32 paddr = addr;
// ValidateAddress(addr);
switch (paddr >> 24)
{
case 0x80:
case 0xa0:
case 0x00:
// RAM further mirrored over 8MB
paddr = ((paddr & 0x7FFFFF) % 0x200000) >> 2;
paddr = UserMemOffset + paddr;
break;
default:
if ((paddr >> 20) == 0x1f8)
{
if (paddr >= 0x1f801000)
{
// paddr = ((paddr & 0xFFFF) - 0x1000);
// paddr = (paddr % 0x2000) >> 2;
paddr = ((paddr & 0xFFFF) - 0x1000) >> 2;
paddr = RegisterOffset + paddr;
break;
}
else
{
//paddr = ((paddr & 0xFFF) % 0x400) >> 2;
paddr = (paddr & 0x3FF) >> 2;
paddr = ScratchOffset + paddr;
break;
}
}
paddr = InvalidAddress;
break;
}
#ifdef GTE_LOG
//GTE_LOG("PGXP_Read %x [%x] |", addr, paddr);
#endif
return paddr;
}
PGXP_value* GetPtr(u32 addr)
{
addr = PGXP_ConvertAddress(addr);
if (addr != InvalidAddress)
return &Mem[addr];
return NULL;
}
PGXP_value* ReadMem(u32 addr)
{
return GetPtr(addr);
}
void ValidateAndCopyMem(PGXP_value* dest, u32 addr, u32 value)
{
PGXP_value* pMem = GetPtr(addr);
if (pMem != NULL)
{
Validate(pMem, value);
*dest = *pMem;
return;
}
*dest = PGXP_value_invalid_address;
}
void ValidateAndCopyMem16(PGXP_value* dest, u32 addr, u32 value, int sign)
{
u32 validMask = 0;
psx_value val, mask;
PGXP_value* pMem = GetPtr(addr);
if (pMem != NULL)
{
mask.d = val.d = 0;
// determine if high or low word
if ((addr % 4) == 2)
{
val.w.h = value;
mask.w.h = 0xFFFF;
validMask = VALID_1;
}
else
{
val.w.l = value;
mask.w.l = 0xFFFF;
validMask = VALID_0;
}
// validate and copy whole value
MaskValidate(pMem, val.d, mask.d, validMask);
*dest = *pMem;
// if high word then shift
if ((addr % 4) == 2)
{
dest->x = dest->y;
dest->lFlags = dest->hFlags;
dest->compFlags[0] = dest->compFlags[1];
}
// truncate value
dest->y = (dest->x < 0) ? -1.f * sign : 0.f;// 0.f;
dest->hFlags = 0;
dest->value = value;
dest->compFlags[1] = VALID; // iCB: High word is valid, just 0
return;
}
*dest = PGXP_value_invalid_address;
}
void WriteMem(PGXP_value* value, u32 addr)
{
PGXP_value* pMem = GetPtr(addr);
if (pMem)
*pMem = *value;
}
void WriteMem16(PGXP_value* src, u32 addr)
{
PGXP_value* dest = GetPtr(addr);
psx_value* pVal = NULL;
if (dest)
{
pVal = (psx_value*)&dest->value;
// determine if high or low word
if ((addr % 4) == 2)
{
dest->y = src->x;
dest->hFlags = src->lFlags;
dest->compFlags[1] = src->compFlags[0];
pVal->w.h = (u16)src->value;
}
else
{
dest->x = src->x;
dest->lFlags = src->lFlags;
dest->compFlags[0] = src->compFlags[0];
pVal->w.l = (u16)src->value;
}
// overwrite z/w if valid
if (src->compFlags[2] == VALID)
{
dest->z = src->z;
dest->compFlags[2] = src->compFlags[2];
}
//dest->valid = dest->valid && src->valid;
dest->gFlags |= src->gFlags; // inherit flags from both values (?)
}
}
u32 lastDMAAddr = 0;
void PGXP_SetLastDMA(u32 addr)
{
lastDMAAddr = PGXP_ConvertAddress(addr);
}
u32 PGXP_GetLastDMA()
{
return lastDMAAddr;
}