pcsx2/pcsx2/HwRead.cpp

395 lines
11 KiB
C++

/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2009 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 "iR5900.h"
#include "VUmicro.h"
#include "IopMem.h"
// The full suite of hardware APIs:
#include "IPU/IPU.h"
#include "GS.h"
#include "Counters.h"
#include "Vif.h"
#include "VifDma.h"
#include "SPR.h"
#include "Sif.h"
using namespace R5900;
static __forceinline void IntCHackCheck()
{
cpuRegs.cycle = g_nextBranchCycle;
// Threshold method, might fix games that have problems with the simple
// implementation above (none known that break yet)
/*if( ( g_nextBranchCycle - cpuRegs.cycle ) > 500 )
cpuRegs.cycle += 498;
else
cpuRegs.cycle = g_nextBranchCycle - 2;*/
}
/////////////////////////////////////////////////////////////////////////
// Hardware READ 8 bit
__forceinline u8 hwRead8(u32 mem)
{
u8 ret;
if( mem >= 0x10002000 && mem < 0x10008000 )
DevCon::Notice("Unexpected hwRead8 from 0x%x", params mem);
switch (mem)
{
case 0x10000000: ret = (u8)rcntRcount(0); break;
case 0x10000010: ret = (u8)counters[0].modeval; break;
case 0x10000020: ret = (u8)counters[0].target; break;
case 0x10000030: ret = (u8)counters[0].hold; break;
case 0x10000001: ret = (u8)(rcntRcount(0)>>8); break;
case 0x10000011: ret = (u8)(counters[0].modeval>>8); break;
case 0x10000021: ret = (u8)(counters[0].target>>8); break;
case 0x10000031: ret = (u8)(counters[0].hold>>8); break;
case 0x10000800: ret = (u8)rcntRcount(1); break;
case 0x10000810: ret = (u8)counters[1].modeval; break;
case 0x10000820: ret = (u8)counters[1].target; break;
case 0x10000830: ret = (u8)counters[1].hold; break;
case 0x10000801: ret = (u8)(rcntRcount(1)>>8); break;
case 0x10000811: ret = (u8)(counters[1].modeval>>8); break;
case 0x10000821: ret = (u8)(counters[1].target>>8); break;
case 0x10000831: ret = (u8)(counters[1].hold>>8); break;
case 0x10001000: ret = (u8)rcntRcount(2); break;
case 0x10001010: ret = (u8)counters[2].modeval; break;
case 0x10001020: ret = (u8)counters[2].target; break;
case 0x10001001: ret = (u8)(rcntRcount(2)>>8); break;
case 0x10001011: ret = (u8)(counters[2].modeval>>8); break;
case 0x10001021: ret = (u8)(counters[2].target>>8); break;
case 0x10001800: ret = (u8)rcntRcount(3); break;
case 0x10001810: ret = (u8)counters[3].modeval; break;
case 0x10001820: ret = (u8)counters[3].target; break;
case 0x10001801: ret = (u8)(rcntRcount(3)>>8); break;
case 0x10001811: ret = (u8)(counters[3].modeval>>8); break;
case 0x10001821: ret = (u8)(counters[3].target>>8); break;
default:
if ((mem & 0xffffff0f) == 0x1000f200)
{
if(mem == 0x1000f260) ret = 0;
else if(mem == 0x1000F240) {
ret = psHu32(mem);
//psHu32(mem) &= ~0x4000;
}
else ret = psHu32(mem);
return (u8)ret;
}
ret = psHu8(mem);
HW_LOG("Unknown Hardware Read 8 from 0x%x = 0x%x\n", mem, ret);
break;
}
return ret;
}
/////////////////////////////////////////////////////////////////////////
// Hardware READ 16 bit
__forceinline u16 hwRead16(u32 mem)
{
u16 ret;
if( mem >= 0x10002000 && mem < 0x10008000 )
Console::Notice("Unexpected hwRead16 from 0x%x", params mem);
switch (mem)
{
case 0x10000000: ret = (u16)rcntRcount(0); break;
case 0x10000010: ret = (u16)counters[0].modeval; break;
case 0x10000020: ret = (u16)counters[0].target; break;
case 0x10000030: ret = (u16)counters[0].hold; break;
case 0x10000800: ret = (u16)rcntRcount(1); break;
case 0x10000810: ret = (u16)counters[1].modeval; break;
case 0x10000820: ret = (u16)counters[1].target; break;
case 0x10000830: ret = (u16)counters[1].hold; break;
case 0x10001000: ret = (u16)rcntRcount(2); break;
case 0x10001010: ret = (u16)counters[2].modeval; break;
case 0x10001020: ret = (u16)counters[2].target; break;
case 0x10001800: ret = (u16)rcntRcount(3); break;
case 0x10001810: ret = (u16)counters[3].modeval; break;
case 0x10001820: ret = (u16)counters[3].target; break;
default:
if ((mem & 0xffffff0f) == 0x1000f200)
{
if(mem == 0x1000f260) ret = 0;
else if(mem == 0x1000F240) {
ret = psHu16(mem) | 0x0102;
psHu32(mem) &= ~0x4000;
}
else
ret = psHu32(mem);
return (u16)ret;
}
ret = psHu16(mem);
HW_LOG("Hardware Read16 at 0x%x, value= 0x%x\n", ret, mem);
break;
}
return ret;
}
/////////////////////////////////////////////////////////////////////////
// Hardware READ 32 bit
// Reads hardware registers for page 0 (counters 0 and 1)
mem32_t __fastcall hwRead32_page_00(u32 mem)
{
mem &= 0xffff;
switch( mem )
{
case 0x00: return (u16)rcntRcount(0);
case 0x10: return (u16)counters[0].modeval;
case 0x20: return (u16)counters[0].target;
case 0x30: return (u16)counters[0].hold;
case 0x800: return (u16)rcntRcount(1);
case 0x810: return (u16)counters[1].modeval;
case 0x820: return (u16)counters[1].target;
case 0x830: return (u16)counters[1].hold;
}
return *((u32*)&PS2MEM_HW[mem]);
}
// Reads hardware registers for page 1 (counters 2 and 3)
mem32_t __fastcall hwRead32_page_01(u32 mem)
{
mem &= 0xffff;
switch( mem )
{
case 0x1000: return (u16)rcntRcount(2);
case 0x1010: return (u16)counters[2].modeval;
case 0x1020: return (u16)counters[2].target;
case 0x1800: return (u16)rcntRcount(3);
case 0x1810: return (u16)counters[3].modeval;
case 0x1820: return (u16)counters[3].target;
}
return *((u32*)&PS2MEM_HW[mem]);
}
// Reads hardware registers for page 15 (0x0F).
// This is used internally to produce two inline versions, one with INTC_HACK, and one without.
static __forceinline mem32_t __hwRead32_page_0F( u32 mem, bool intchack )
{
// *Performance Warning* This function is called -A-LOT. Be weary when making changes. It
// could impact FPS significantly.
mem &= 0xffff;
switch( mem )
{
case 0xf000:
if( intchack ) IntCHackCheck();
// This one is checked alot, so leave it commented out unless you love 600 meg logfiles.
//HW_LOG("INTC_STAT Read 32bit %x\n", psHu32(0xf010));
break;
case 0xf010:
HW_LOG("INTC_MASK Read32, value=0x%x\n", psHu32(INTC_MASK));
break;
case 0xf130: // 0x1000f130
case 0xf260: // 0x1000f260 SBUS?
case 0xf410: // 0x1000f410
case 0xf430: // MCH_RICM
return 0;
case 0xf240: // 0x1000f240: SBUS
return psHu32(0xf240) | 0xF0000102;
case 0xf440: // 0x1000f440: MCH_DRD
if( !((psHu32(0xf430) >> 6) & 0xF) )
{
switch ((psHu32(0xf430)>>16) & 0xFFF)
{
//MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5
case 0x21://INIT
if(rdram_sdevid < rdram_devices)
{
rdram_sdevid++;
return 0x1F;
}
return 0;
case 0x23://CNFGA
return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5
case 0x24://CNFGB
//0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0
return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0
case 0x40://DEVID
return psHu32(0xf430) & 0x1F; // =SDEV
}
}
return 0;
}
return *((u32*)&PS2MEM_HW[mem]);
}
mem32_t __fastcall hwRead32_page_0F(u32 mem)
{
return __hwRead32_page_0F( mem, false );
}
mem32_t __fastcall hwRead32_page_0F_INTC_HACK(u32 mem)
{
return __hwRead32_page_0F( mem, true );
}
mem32_t __fastcall hwRead32_page_02(u32 mem)
{
return ipuRead32( mem );
}
// Used for all pages not explicitly specified above.
mem32_t __fastcall hwRead32_generic(u32 mem)
{
const u16 masked_mem = mem & 0xffff;
switch( masked_mem>>12 ) // switch out as according to the 4k page of the access.
{
///////////////////////////////////////////////////////
// Most of the following case handlers are for developer builds only (logging).
// It'll all optimize to ziltch in public release builds.
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0a:
case 0x0d:
{
const char* regName = "Unknown";
switch( mem )
{
case D2_CHCR: regName = "DMA2_CHCR"; break;
case D2_MADR: regName = "DMA2_MADR"; break;
case D2_QWC: regName = "DMA2_QWC"; break;
case D2_TADR: regName = "DMA2_TADDR"; break;
case D2_ASR0: regName = "DMA2_ASR0"; break;
case D2_ASR1: regName = "DMA2_ASR1"; break;
case D2_SADR: regName = "DMA2_SADDR"; break;
}
HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", mem, regName, psHu32(mem) );
}
break;
case 0x0b:
if( mem == D4_CHCR )
HW_LOG("Hardware Read32 at 0x%x (IPU1:DMA4_CHCR), value=0x%x\n", mem, psHu32(mem));
break;
case 0x0c:
case 0x0e:
if( mem == DMAC_STAT)
HW_LOG("DMAC_STAT Read32, value=0x%x\n", psHu32(DMAC_STAT));
break;
jNO_DEFAULT;
}
return *((u32*)&PS2MEM_HW[masked_mem]);
}
/////////////////////////////////////////////////////////////////////////
// Hardware READ 64 bit
void __fastcall hwRead64_page_00(u32 mem, mem64_t* result )
{
*result = hwRead32_page_00( mem );
}
void __fastcall hwRead64_page_01(u32 mem, mem64_t* result )
{
*result = hwRead32_page_01( mem );
}
void __fastcall hwRead64_page_02(u32 mem, mem64_t* result )
{
*result = ipuRead64(mem);
}
void __fastcall hwRead64_generic_INTC_HACK(u32 mem, mem64_t* result )
{
if( mem == INTC_STAT ) IntCHackCheck();
*result = psHu64(mem);
HW_LOG("Unknown Hardware Read 64 at %x\n",mem);
}
void __fastcall hwRead64_generic(u32 mem, mem64_t* result )
{
*result = psHu64(mem);
HW_LOG("Unknown Hardware Read 64 at %x\n",mem);
}
/////////////////////////////////////////////////////////////////////////
// Hardware READ 128 bit
void __fastcall hwRead128_page_00(u32 mem, mem128_t* result )
{
result[0] = hwRead32_page_00( mem );
result[1] = 0;
}
void __fastcall hwRead128_page_01(u32 mem, mem128_t* result )
{
result[0] = hwRead32_page_01( mem );
result[1] = 0;
}
void __fastcall hwRead128_page_02(u32 mem, mem128_t* result )
{
// IPU is currently unhandled in 128 bit mode.
HW_LOG("Unknown Hardware Read 128 at %x (IPU)\n",mem);
}
void __fastcall hwRead128_generic(u32 mem, mem128_t* out)
{
out[0] = psHu64(mem);
out[1] = psHu64(mem+8);
HW_LOG("Unknown Hardware Read 128 at %x\n",mem);
}