pcsx2/PsxMem.c

1605 lines
31 KiB
C

/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "PsxCommon.h"
#include "VU.h"
#include "iCore.h"
#include "ir3000A.h"
extern u32 g_psxMaxRecMem;
int g_psxWriteOk=1;
static u32 writectrl;
#ifdef WIN32_VIRTUAL_MEM
int psxMemInit()
{
// all mem taken care by memInit
return 0;
}
void psxMemReset()
{
memset(psxM, 0, 0x00200000);
}
void psxMemShutdown()
{
}
#ifdef _DEBUG
#define ASSERT_WRITEOK \
{ \
__asm cmp g_psxWriteOk, 1 \
__asm je WriteOk \
__asm int 10 \
} \
WriteOk: \
#else
#define ASSERT_WRITEOK
#endif
u8 psxMemRead8(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);
}
}
__declspec(naked) void psxRecMemRead8()
{
__asm {
mov edx, ecx
shr edx, 16
cmp dx, 0x1f80
je hwread
cmp dx, 0x1f40
je hw4read
cmp dx, 0x1000
je devread
cmp dx, 0x1f00
je spuread
}
ASSERT_WRITEOK
__asm {
memread:
// rom reads, has to be PS2MEM_BASE_
mov eax, dword ptr [ecx+PS2MEM_BASE_]
ret
hwread:
cmp cx, 0x1000
jb memread
push ecx
call psxHwRead8
add esp, 4
ret
hw4read:
push ecx
call psxHw4Read8
add esp, 4
ret
devread:
push ecx
call DEV9read8
// stack already incremented
ret
spuread:
push ecx
call SPU2read
// stack already incremented
ret
}
}
int psxRecMemConstRead8(u32 x86reg, u32 mem, u32 sign)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
return psxHwConstRead8(x86reg, mem&0x1fffffff, sign);
#ifdef _DEBUG
case 0x1d00: assert(0);
#endif
case 0x1f40:
return psxHw4ConstRead8(x86reg, mem&0x1fffffff, sign);
case 0x1000:
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)DEV9read8);
if( sign ) MOVSX32R8toR(x86reg, EAX);
else MOVZX32R8toR(x86reg, EAX);
return 0;
default:
_eeReadConstMem8(x86reg, (u32)PSXM(mem), sign);
return 0;
}
}
u16 psxMemRead16(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:
#ifdef SIF_LOG
SIF_LOG("Sif reg read %x value %x\n", mem, psxHu16(mem));
#endif
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);
}
}
__declspec(naked) void psxRecMemRead16()
{
__asm {
mov edx, ecx
shr edx, 16
cmp dx, 0x1f80
je hwread
cmp dx, 0x1f90
je spuread
cmp dx, 0x1d00
je sifread
cmp dx, 0x1000
je devread
}
ASSERT_WRITEOK
__asm {
memread:
// rom reads, has to be PS2MEM_BASE_
mov eax, dword ptr [ecx+PS2MEM_BASE_]
ret
hwread:
cmp cx, 0x1000
jb memread
push ecx
call psxHwRead16
add esp, 4
ret
sifread:
mov edx, ecx
and edx, 0xf0
cmp dl, 0x60
je Sif60
mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200]
cmp dl, 0x40
jne End
// 0x40
or eax, 2
jmp End
Sif60:
xor eax, eax
jmp End
spuread:
push ecx
call SPU2read
// stack already incremented
End:
ret
devread:
push ecx
call DEV9read16
// stack already incremented
ret
}
}
int psxRecMemConstRead16(u32 x86reg, u32 mem, u32 sign)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80: return psxHwConstRead16(x86reg, mem&0x1fffffff, sign);
case 0x1d00:
switch(mem & 0xF0)
{
case 0x40:
_eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xF240, sign);
OR32ItoR(x86reg, 0x0002);
break;
case 0x60:
XOR32RtoR(x86reg, x86reg);
break;
default:
_eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0), sign);
break;
}
return 0;
case 0x1f90:
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)SPU2read);
if( sign ) MOVSX32R16toR(x86reg, EAX);
else MOVZX32R16toR(x86reg, EAX);
return 0;
case 0x1000:
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)DEV9read16);
if( sign ) MOVSX32R16toR(x86reg, EAX);
else MOVZX32R16toR(x86reg, EAX);
return 0;
default:
assert( g_psxWriteOk );
_eeReadConstMem16(x86reg, (u32)PSXM(mem), sign);
return 0;
}
return 0;
}
u32 psxMemRead32(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:
#ifdef SIF_LOG
SIF_LOG("Sif reg read %x value %x\n", mem, psxHu32(mem));
#endif
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;
}
}
__declspec(naked) void psxRecMemRead32()
{
__asm {
mov edx, ecx
shr edx, 16
cmp dx, 0x1f80
je hwread
cmp dx, 0x1d00
je sifread
cmp dx, 0x1000
je devread
cmp ecx, 0x1ffe0130
je WriteCtrlRead
}
ASSERT_WRITEOK
__asm {
memread:
// rom reads, has to be PS2MEM_BASE_
mov eax, dword ptr [ecx+PS2MEM_BASE_]
ret
hwread:
cmp cx, 0x1000
jb memread
push ecx
call psxHwRead32
add esp, 4
ret
sifread:
mov edx, ecx
and edx, 0xf0
cmp dl, 0x60
je Sif60
// do the read from ps2 mem
mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200]
cmp dl, 0x40
jne End
// 0x40
or eax, 0xf0000002
jmp End
Sif60:
xor eax, eax
End:
ret
devread:
push ecx
call DEV9read32
// stack already incremented
ret
WriteCtrlRead:
mov eax, writectrl
ret
}
}
int psxRecMemConstRead32(u32 x86reg, u32 mem)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80: return psxHwConstRead32(x86reg, mem&0x1fffffff);
case 0x1d00:
switch(mem & 0xF0)
{
case 0x40:
_eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xF240);
OR32ItoR(x86reg, 0xf0000002);
break;
case 0x60:
XOR32RtoR(x86reg, x86reg);
break;
default:
_eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0));
break;
}
return 0;
case 0x1000:
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)DEV9read32);
return 1;
default:
if( mem == 0xfffe0130 )
MOV32MtoR(x86reg, (u32)&writectrl);
else {
XOR32RtoR(x86reg, x86reg);
CMP32ItoM((u32)&g_psxWriteOk, 0);
CMOVNE32MtoR(x86reg, (u32)PSXM(mem));
}
return 0;
}
}
void psxMemWrite8(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;
}
}
__declspec(naked) void psxRecMemWrite8()
{
__asm {
mov edx, ecx
shr edx, 16
cmp dx, 0x1f80
je hwwrite
cmp dx, 0x1f40
je hw4write
cmp dx, 0x1000
je devwrite
}
ASSERT_WRITEOK
__asm {
memwrite:
// rom writes, has to be PS2MEM_BASE_
mov byte ptr [ecx+PS2MEM_BASE_], al
ret
hwwrite:
cmp cx, 0x1000
jb memwrite
push eax
push ecx
call psxHwWrite8
add esp, 8
ret
hw4write:
push eax
push ecx
call psxHw4Write8
add esp, 8
ret
devwrite:
push eax
push ecx
call DEV9write8
// stack alwritey incremented
ret
}
}
int psxRecMemConstWrite8(u32 mem, int mmreg)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
psxHwConstWrite8(mem&0x1fffffff, mmreg);
return 0;
case 0x1f40:
psxHw4ConstWrite8(mem&0x1fffffff, mmreg);
return 0;
case 0x1d00:
assert(0);
_eeWriteConstMem8((u32)(PS2MEM_HW+0xf200+(mem&0xff)), mmreg);
return 0;
case 0x1000:
_recPushReg(mmreg);
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)DEV9write8);
return 0;
default:
_eeWriteConstMem8((u32)PSXM(mem), mmreg);
return 1;
}
}
void psxMemWrite16(u32 mem, u16 value)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
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;
}
}
__declspec(naked) void psxRecMemWrite16()
{
__asm {
mov edx, ecx
shr edx, 16
cmp dx, 0x1f80
je hwwrite
cmp dx, 0x1f90
je spuwrite
cmp dx, 0x1d00
je sifwrite
cmp dx, 0x1000
je devwrite
}
ASSERT_WRITEOK
__asm {
memwrite:
// rom writes, has to be PS2MEM_BASE_
mov word ptr [ecx+PS2MEM_BASE_], ax
ret
hwwrite:
cmp cx, 0x1000
jb memwrite
push eax
push ecx
call psxHwWrite16
add esp, 8
ret
sifwrite:
mov edx, ecx
and edx, 0xf0
cmp dl, 0x60
je Sif60
cmp dl, 0x40
je Sif40
mov word ptr [edx+PS2MEM_BASE_+0x1000f200], ax
ret
Sif40:
mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200]
test ax, 0xa0
jz Sif40_2
// psHu16(0x1000F240) &= ~0xF000;
// psHu16(0x1000F240) |= 0x2000;
and bx, 0x0fff
or bx, 0x2000
Sif40_2:
// if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp;
// else psHu16(0x1000F240) |= temp;
and ax, 0xf0
test bx, ax
jz Sif40_3
not ax
and bx, ax
jmp Sif40_4
Sif40_3:
or bx, ax
Sif40_4:
mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx
ret
Sif60:
mov word ptr [edx+PS2MEM_BASE_+0x1000f200], 0
ret
spuwrite:
push eax
push ecx
call SPU2write
// stack alwritey incremented
ret
devwrite:
push eax
push ecx
call DEV9write16
// stack alwritey incremented
ret
}
}
int psxRecMemConstWrite16(u32 mem, int mmreg)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
psxHwConstWrite16(mem&0x1fffffff, mmreg);
return 0;
case 0x1d00:
switch (mem & 0xf0) {
case 0x10:
// write to ps2 mem
_eeWriteConstMem16((u32)(PS2MEM_HW+0xf210), mmreg);
return 0;
case 0x40:
{
// delete x86reg
_eeMoveMMREGtoR(EAX, mmreg);
assert( mmreg != EBX );
MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240);
TEST16ItoR(EAX, 0xa0);
j8Ptr[0] = JZ8(0);
AND16ItoR(EBX, 0x0fff);
OR16ItoR(EBX, 0x2000);
x86SetJ8(j8Ptr[0]);
AND16ItoR(EAX, 0xf0);
TEST16RtoR(EAX, 0xf0);
j8Ptr[0] = JZ8(0);
NOT32R(EAX);
AND16RtoR(EBX, EAX);
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
OR16RtoR(EBX, EAX);
x86SetJ8(j8Ptr[1]);
MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX);
return 0;
}
case 0x60:
MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0);
return 0;
default:
assert(0);
}
return 0;
case 0x1f90:
_recPushReg(mmreg);
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)SPU2write);
return 0;
case 0x1000:
_recPushReg(mmreg);
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)DEV9write16);
return 0;
default:
_eeWriteConstMem16((u32)PSXM(mem), mmreg);
return 1;
}
}
void psxMemWrite32(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;
#ifdef PSXMEM_LOG
// PSXMEM_LOG("writectrl: writenot ok\n");
#endif
break;
case 0x1e988:
case 0x1edd8:
g_psxWriteOk = 1;
#ifdef PSXMEM_LOG
// PSXMEM_LOG("writectrl: write ok\n");
#endif
break;
default:
#ifdef PSXMEM_LOG
PSXMEM_LOG("unk %8.8lx = %x\n", mem, value);
#endif
break;
}
}
break;
default:
if( g_psxWriteOk ) {
*(u32 *)PSXM(mem) = value;
psxCpu->Clear(mem&~3, 1);
}
break;
}
}
__declspec(naked) void psxRecMemWrite32()
{
__asm {
mov edx, ecx
shr edx, 16
cmp dx, 0x1f80
je hwwrite
cmp dx, 0x1d00
je sifwrite
cmp dx, 0x1000
je devwrite
cmp dx, 0x1ffe
je WriteCtrl
}
__asm {
// rom writes, has to be PS2MEM_BASE_
test g_psxWriteOk, 1
jz endwrite
memwrite:
mov dword ptr [ecx+PS2MEM_BASE_], eax
endwrite:
ret
hwwrite:
cmp cx, 0x1000
jb memwrite
push eax
push ecx
call psxHwWrite32
add esp, 8
ret
sifwrite:
mov edx, ecx
and edx, 0xf0
cmp dl, 0x60
je Sif60
cmp dl, 0x40
je Sif40
cmp dl, 0x30
je Sif30
cmp dl, 0x20
je Sif20
mov word ptr [edx+PS2MEM_BASE_+0x1000f200], ax
ret
Sif40:
mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200]
test ax, 0xa0
jz Sif40_2
// psHu16(0x1000F240) &= ~0xF000;
// psHu16(0x1000F240) |= 0x2000;
and bx, 0x0fff
or bx, 0x2000
Sif40_2:
// if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp;
// else psHu16(0x1000F240) |= temp;
and ax, 0xf0
test bx, ax
jz Sif40_3
not ax
and bx, ax
jmp Sif40_4
Sif40_3:
or bx, ax
Sif40_4:
mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx
ret
Sif30:
or dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax
ret
Sif20:
not eax
and dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax
ret
Sif60:
mov dword ptr [edx+PS2MEM_BASE_+0x1000f200], 0
ret
devwrite:
push eax
push ecx
call DEV9write32
// stack alwritey incremented
ret
WriteCtrl:
cmp ecx, 0x1ffe0130
jne End
mov writectrl, eax
cmp eax, 0x800
je SetWriteNotOk
cmp eax, 0x804
je SetWriteNotOk
cmp eax, 0xc00
je SetWriteNotOk
cmp eax, 0xc04
je SetWriteNotOk
cmp eax, 0xcc0
je SetWriteNotOk
cmp eax, 0xcc4
je SetWriteNotOk
cmp eax, 0x0c4
je SetWriteNotOk
// test ok
cmp eax, 0x1e988
je SetWriteOk
cmp eax, 0x1edd8
je SetWriteOk
End:
ret
SetWriteNotOk:
mov g_psxWriteOk, 0
ret
SetWriteOk:
mov g_psxWriteOk, 1
ret
}
}
int psxRecMemConstWrite32(u32 mem, int mmreg)
{
u32 t = (mem >> 16) & 0x1fff;
switch(t) {
case 0x1f80:
psxHwConstWrite32(mem&0x1fffffff, mmreg);
return 0;
case 0x1d00:
switch (mem & 0xf0) {
case 0x10:
// write to ps2 mem
_eeWriteConstMem32((u32)PS2MEM_HW+0xf210, mmreg);
return 0;
case 0x20:
// write to ps2 mem
// delete x86reg
if( IS_PSXCONSTREG(mmreg) ) {
AND32ItoM((u32)PS2MEM_HW+0xf220, ~g_psxConstRegs[(mmreg>>16)&0x1f]);
}
else {
NOT32R(mmreg);
AND32RtoM((u32)PS2MEM_HW+0xf220, mmreg);
}
return 0;
case 0x30:
// write to ps2 mem
_eeWriteConstMem32OP((u32)PS2MEM_HW+0xf230, mmreg, 1);
return 0;
case 0x40:
{
// delete x86reg
assert( mmreg != EBX );
_eeMoveMMREGtoR(EAX, mmreg);
MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240);
TEST16ItoR(EAX, 0xa0);
j8Ptr[0] = JZ8(0);
AND16ItoR(EBX, 0x0fff);
OR16ItoR(EBX, 0x2000);
x86SetJ8(j8Ptr[0]);
AND16ItoR(EAX, 0xf0);
TEST16RtoR(EAX, 0xf0);
j8Ptr[0] = JZ8(0);
NOT32R(EAX);
AND16RtoR(EBX, EAX);
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
OR16RtoR(EBX, EAX);
x86SetJ8(j8Ptr[1]);
MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX);
return 0;
}
case 0x60:
MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0);
return 0;
default:
assert(0);
}
return 0;
case 0x1000:
_recPushReg(mmreg);
PUSH32I(mem&0x1fffffff);
CALLFunc((u32)DEV9write32);
return 0;
case 0x1ffe:
if( mem == 0xfffe0130 ) {
u8* ptrs[9];
_eeWriteConstMem32((u32)&writectrl, mmreg);
if( IS_PSXCONSTREG(mmreg) ) {
switch (g_psxConstRegs[(mmreg>>16)&0x1f]) {
case 0x800: case 0x804:
case 0xc00: case 0xc04:
case 0xcc0: case 0xcc4:
case 0x0c4:
MOV32ItoM((u32)&g_psxWriteOk, 0);
break;
case 0x1e988:
case 0x1edd8:
MOV32ItoM((u32)&g_psxWriteOk, 1);
break;
default:
assert(0);
}
}
else {
// not ok
CMP32ItoR(mmreg, 0x800);
ptrs[0] = JE8(0);
CMP32ItoR(mmreg, 0x804);
ptrs[1] = JE8(0);
CMP32ItoR(mmreg, 0xc00);
ptrs[2] = JE8(0);
CMP32ItoR(mmreg, 0xc04);
ptrs[3] = JE8(0);
CMP32ItoR(mmreg, 0xcc0);
ptrs[4] = JE8(0);
CMP32ItoR(mmreg, 0xcc4);
ptrs[5] = JE8(0);
CMP32ItoR(mmreg, 0x0c4);
ptrs[6] = JE8(0);
// ok
CMP32ItoR(mmreg, 0x1e988);
ptrs[7] = JE8(0);
CMP32ItoR(mmreg, 0x1edd8);
ptrs[8] = JE8(0);
x86SetJ8(ptrs[0]);
x86SetJ8(ptrs[1]);
x86SetJ8(ptrs[2]);
x86SetJ8(ptrs[3]);
x86SetJ8(ptrs[4]);
x86SetJ8(ptrs[5]);
x86SetJ8(ptrs[6]);
MOV32ItoM((u32)&g_psxWriteOk, 0);
ptrs[0] = JMP8(0);
x86SetJ8(ptrs[7]);
x86SetJ8(ptrs[8]);
MOV32ItoM((u32)&g_psxWriteOk, 1);
x86SetJ8(ptrs[0]);
}
}
return 0;
default:
TEST8ItoM((u32)&g_psxWriteOk, 1);
j8Ptr[0] = JZ8(0);
_eeWriteConstMem32((u32)PSXM(mem), mmreg);
x86SetJ8(j8Ptr[0]);
return 1;
}
}
#else
// TLB functions
s8 *psxM;
s8 *psxP;
s8 *psxH;
s8 *psxS;
uptr *psxMemWLUT;
uptr *psxMemRLUT;
int psxMemInit()
{
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));
psxM = (char*)_aligned_malloc(0x00200000,16);
psxP = (char*)_aligned_malloc(0x00010000,16);
psxH = (char*)_aligned_malloc(0x00010000,16);
psxS = (char*)_aligned_malloc(0x00010000,16);
if (psxMemRLUT == NULL || psxMemWLUT == NULL ||
psxM == NULL || psxP == NULL || psxH == NULL) {
SysMessage(_("Error allocating memory")); return -1;
}
memset(psxM, 0, 0x00200000);
memset(psxP, 0, 0x00010000);
memset(psxH, 0, 0x00010000);
memset(psxS, 0, 0x00010000);
// 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);
}
void psxMemShutdown()
{
_aligned_free(psxM);
_aligned_free(psxP);
_aligned_free(psxH);
_aligned_free(psxMemRLUT);
_aligned_free(psxMemWLUT);
}
u8 psxMemRead8(u32 mem) {
char *p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (mem < 0x1f801000)
return psxHu8(mem);
else
return psxHwRead8(mem);
} else
if (t == 0x1f40) {
mem&= 0x1fffffff;
return psxHw4Read8(mem);
} else {
p = (char *)(psxMemRLUT[mem >> 16]);
if (p != NULL) {
return *(u8 *)(p + (mem & 0xffff));
} else {
if (t == 0x1000) return DEV9read8(mem & 0x1FFFFFFF);
#ifdef PSXMEM_LOG
PSXMEM_LOG("err lb %8.8lx\n", mem);
#endif
return 0;
}
}
}
u16 psxMemRead16(u32 mem) {
char *p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (mem < 0x1f801000)
return psxHu16(mem);
else
return psxHwRead16(mem);
} else {
p = (char *)(psxMemRLUT[mem >> 16]);
if (p != NULL) {
if (t == 0x1d00) {
u16 ret;
switch(mem & 0xF0)
{
case 0x00:
ret= psHu16(0x1000F200);
break;
case 0x10:
ret= psHu16(0x1000F210);
break;
case 0x40:
ret= psHu16(0x1000F240) | 0x0002;
break;
case 0x60:
ret = 0;
break;
default:
ret = psxHu16(mem);
break;
}
#ifdef SIF_LOG
SIF_LOG("Sif reg read %x value %x\n", mem, ret);
#endif
return ret;
}
return *(u16 *)(p + (mem & 0xffff));
} else {
if (t == 0x1F90)
return SPU2read(mem & 0x1FFFFFFF);
if (t == 0x1000) return DEV9read16(mem & 0x1FFFFFFF);
#ifdef PSXMEM_LOG
PSXMEM_LOG("err lh %8.8lx\n", mem);
#endif
return 0;
}
}
}
u32 psxMemRead32(u32 mem) {
char *p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (mem < 0x1f801000)
return psxHu32(mem);
else
return psxHwRead32(mem);
} else {
//see also Hw.c
p = (char *)(psxMemRLUT[mem >> 16]);
if (p != NULL) {
if (t == 0x1d00) {
u32 ret;
switch(mem & 0xF0)
{
case 0x00:
ret= psHu32(0x1000F200);
break;
case 0x10:
ret= psHu32(0x1000F210);
break;
case 0x20:
ret= psHu32(0x1000F220);
break;
case 0x30: // EE Side
ret= psHu32(0x1000F230);
break;
case 0x40:
ret= psHu32(0x1000F240) | 0xF0000002;
break;
case 0x60:
ret = 0;
break;
default:
ret = psxHu32(mem);
break;
}
#ifdef SIF_LOG
SIF_LOG("Sif reg read %x value %x\n", mem, ret);
#endif
return ret;
}
return *(u32 *)(p + (mem & 0xffff));
} else {
if (t == 0x1000) return DEV9read32(mem & 0x1FFFFFFF);
if (mem != 0xfffe0130) {
#ifdef PSXMEM_LOG
if (g_psxWriteOk) PSXMEM_LOG("err lw %8.8lx\n", mem);
#endif
} else {
return writectrl;
}
return 0;
}
}
}
void psxMemWrite8(u32 mem, u8 value) {
char *p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (mem < 0x1f801000)
psxHu8(mem) = value;
else
psxHwWrite8(mem, value);
} else
if (t == 0x1f40) {
mem&= 0x1fffffff;
psxHw4Write8(mem, value);
} else {
p = (char *)(psxMemWLUT[mem >> 16]);
if (p != NULL) {
*(u8 *)(p + (mem & 0xffff)) = value;
psxCpu->Clear(mem&~3, 1);
} else {
if ((t & 0x1FFF)==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;
}
#ifdef PSXMEM_LOG
PSXMEM_LOG("err sb %8.8lx = %x\n", mem, value);
#endif
}
}
}
void psxMemWrite16(u32 mem, u16 value) {
char *p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (mem < 0x1f801000)
psxHu16(mem) = value;
else
psxHwWrite16(mem, value);
} else {
p = (char *)(psxMemWLUT[mem >> 16]);
if (p != NULL) {
if ((t & 0x1FFF)==0x1D00) SysPrintf("sw16 [0x%08X]=0x%08X\n", mem, value);
*(u16 *)(p + (mem & 0xffff)) = value;
psxCpu->Clear(mem&~3, 1);
} else {
if (t == 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;
}
psxSu16(mem) = value; return;
}
if (t == 0x1F90) {
SPU2write(mem & 0x1FFFFFFF, value); return;
}
if (t == 0x1000) {
DEV9write16(mem & 0x1fffffff, value); return;
}
#ifdef PSXMEM_LOG
PSXMEM_LOG("err sh %8.8lx = %x\n", mem, value);
#endif
}
}
}
void psxMemWrite32(u32 mem, u32 value) {
char *p;
u32 t;
t = (mem >> 16) & 0x1fff;
if (t == 0x1f80) {
mem&= 0x1fffffff;
if (mem < 0x1f801000)
psxHu32(mem) = value;
else
psxHwWrite32(mem, value);
} else {
//see also Hw.c
p = (char *)(psxMemWLUT[mem >> 16]);
if (p != NULL) {
*(u32 *)(p + (mem & 0xffff)) = value;
psxCpu->Clear(mem&~3, 1);
} else {
if (mem != 0xfffe0130) {
if (t == 0x1d00) {
#ifdef MEM_LOG
MEM_LOG("iop Sif reg write %x value %x\n", mem, value);
#endif
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;
}
psxSu32(mem) = value;
// write to ps2 mem
if( (mem & 0xf0) != 0x60 )
*(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value;
return;
}
if (t == 0x1000) {
DEV9write32(mem & 0x1fffffff, value); return;
}
//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:
case 0xc00: case 0xc04:
case 0xcc0: case 0xcc4:
case 0x0c4:
if (g_psxWriteOk == 0) break;
g_psxWriteOk = 0;
memset(psxMemWLUT + 0x0000, 0, 0x80 * sizeof(uptr));
memset(psxMemWLUT + 0x8000, 0, 0x80 * sizeof(uptr));
memset(psxMemWLUT + 0xa000, 0, 0x80 * sizeof(uptr));
#ifdef PSXMEM_LOG
// PSXMEM_LOG("writectrl: writenot ok\n");
#endif
break;
case 0x1e988:
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];
#ifdef PSXMEM_LOG
// PSXMEM_LOG("writectrl: write ok\n");
#endif
break;
default:
#ifdef PSXMEM_LOG
PSXMEM_LOG("unk %8.8lx = %x\n", mem, value);
#endif
break;
}
}
}
}
}
#endif