Files
archived-pcsx2/pcsx2/Hw.cpp
Jake.Stine bda94b16cd General emulator memory work, regarding my new policy that most (or all) cpu and hardware registers should be standard globals, as it makes our lives a lot easier in general (and their memory footprint is small so it won't adversely affect the virtual memory availability of the host operating systems). Details:
* Removed the hacky g_pVU1 pointer, which required VU1 cpu registers to be part of VU0.  Replaced it with a standard VU1 variable (mimics all other CPU registers, which are standard static vars).  We were using translation functions/tables for all VU0 memory operations anyway, so this was a no-brainer.
 * Removed code from microVU that was only there to help deal with the fact that g_pVU1 was annoying.
 * Turned eeMem->HW into a static global array eeHw [64k].

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3692 96395faa-99c1-11dd-bbfe-3dabce05a288
2010-08-27 03:21:16 +00:00

305 lines
8.9 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Common.h"
#include "Hardware.h"
#include "newVif.h"
using namespace R5900;
const int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX
int rdram_sdevid = 0;
static bool hwInitialized = false;
void hwInit()
{
// [TODO] / FIXME: PCSX2 no longer works on an Init system. It assumes that the
// static global vars for the process will be initialized when the process is created, and
// then issues *resets only* from then on. (reset code for various S2 components should do
// NULL checks and allocate memory and such if the pointers are NULL only).
if( hwInitialized ) return;
VifUnpackSSE_Init();
gsInit();
sifInit();
sprInit();
ipuInit();
hwInitialized = true;
}
/*void hwShutdown()
{
ipuShutdown();
}*/
void hwReset()
{
hwInit();
memzero_ptr<Ps2MemSize::Hardware>( eeHw );
//memset(eeHw+0x2000, 0, 0x0000e000);
psHu32(SBUS_F260) = 0x1D000060;
// i guess this is kinda a version, it's used by some bioses
psHu32(DMAC_ENABLEW) = 0x1201;
psHu32(DMAC_ENABLER) = 0x1201;
SPU2reset();
sifInit();
sprInit();
gsReset();
ipuReset();
vif0Reset();
vif1Reset();
}
__fi void intcInterrupt()
{
if ((psHu32(INTC_STAT)) == 0) {
//DevCon.Warning("*PCSX2*: intcInterrupt already cleared");
return;
}
if ((psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0)
{
//DevCon.Warning("*PCSX2*: No valid interrupt INTC_MASK: %x INTC_STAT: %x", psHu32(INTC_MASK), psHu32(INTC_STAT));
return;
}
HW_LOG("intcInterrupt %x", psHu32(INTC_STAT) & psHu32(INTC_MASK));
if(psHu32(INTC_STAT) & 0x2){
counters[0].hold = rcntRcount(0);
counters[1].hold = rcntRcount(1);
}
cpuException(0x400, cpuRegs.branch);
}
__fi void dmacInterrupt()
{
if( ((psHu16(DMAC_STAT + 2) & psHu16(DMAC_STAT)) == 0 ) &&
( psHu16(DMAC_STAT) & 0x8000) == 0 )
{
//DevCon.Warning("No valid DMAC interrupt MASK %x STAT %x", psHu16(DMAC_STAT+2), psHu16(DMAC_STAT));
return;
}
if (!(dmacRegs->ctrl.DMAE) || psHu8(DMAC_ENABLER+2) == 1)
{
//DevCon.Warning("DMAC Suspended or Disabled on interrupt");
return;
}
HW_LOG("dmacInterrupt %x", (psHu16(DMAC_STAT + 2) & psHu16(DMAC_STAT) |
psHu16(DMAC_STAT) & 0x8000));
cpuException(0x800, cpuRegs.branch);
}
void hwIntcIrq(int n)
{
psHu32(INTC_STAT) |= 1<<n;
if(psHu32(INTC_MASK) & (1<<n))cpuTestINTCInts();
}
void hwDmacIrq(int n)
{
psHu32(DMAC_STAT) |= 1<<n;
if(psHu16(DMAC_STAT+2) & (1<<n))cpuTestDMACInts();
}
// Write 'size' bytes to memory address 'addr' from 'data'.
__ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc)
{
// all FIFO addresses should always be QWC-aligned.
pxAssume((dmacRegs->rbor.ADDR & 15) == 0);
pxAssume((addr & 15) == 0);
// DMAC Address resolution: FIFO can be placed anywhere in the *physical* memory map
// for the PS2. Its probably a serious error for a PS2 app to have the buffer cross
// valid/invalid page areas of ram, so realistically we only need to test the base address
// of the FIFO for address validity.
if (u128* dst = (u128*)PSM(dmacRegs->rbor.ADDR))
{
const u32 ringsize = (dmacRegs->rbsr.RMSK / 16) + 1;
pxAssertMsg( PSM(dmacRegs->rbor.ADDR+ringsize-1) != NULL, "Scratchpad/MFIFO ringbuffer spans into invalid (unmapped) physical memory!" );
uint startpos = (addr & dmacRegs->rbsr.RMSK)/16;
MemCopy_WrappedDest( data, dst, startpos, ringsize, qwc );
}
else
{
SPR_LOG( "Scratchpad/MFIFO: invalid base physical address: 0x%08x", dmacRegs->rbor.ADDR );
pxFailDev( wxsFormat( L"Scratchpad/MFIFO: Invalid base physical address: 0x%08x", dmacRegs->rbor.ADDR) );
return false;
}
return true;
}
__ri bool hwDmacSrcChainWithStack(DMACh *dma, int id) {
switch (id) {
case TAG_REFE: // Refe - Transfer Packet According to ADDR field
//End Transfer
return true;
case TAG_CNT: // CNT - Transfer QWC following the tag.
// Set MADR to QW afer tag, and set TADR to QW following the data.
dma->madr = dma->tadr + 16;
dma->tadr = dma->madr + (dma->qwc << 4);
return false;
case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
{
// Set MADR to QW following the tag, and set TADR to the address formerly in MADR.
u32 temp = dma->madr;
dma->madr = dma->tadr + 16;
dma->tadr = temp;
return false;
}
case TAG_REF: // Ref - Transfer QWC from ADDR field
case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control)
//Set TADR to next tag
dma->tadr += 16;
return false;
case TAG_CALL: // Call - Transfer QWC following the tag, save succeeding tag
{
// Store the address in MADR in temp, and set MADR to the data following the tag.
u32 temp = dma->madr;
dma->madr = dma->tadr + 16;
if(temp == 0)
{
DevCon.Warning("DMA Chain CALL next tag error. Tag Addr = 0");
dma->tadr = dma->madr + (dma->qwc << 4);
return false;
}
// Stash an address on the address stack pointer.
switch(dma->chcr.ASP)
{
case 0: //Check if ASR0 is empty
// Store the succeeding tag in asr0, and mark chcr as having 1 address.
dma->asr0 = dma->madr + (dma->qwc << 4);
dma->chcr.ASP++;
break;
case 1:
// Store the succeeding tag in asr1, and mark chcr as having 2 addresses.
dma->asr1 = dma->madr + (dma->qwc << 4);
dma->chcr.ASP++;
break;
default:
Console.Warning("Call Stack Overflow (report if it fixes/breaks anything)");
return true;
}
// Set TADR to the address from MADR we stored in temp.
dma->tadr = temp;
return false;
}
case TAG_RET: // Ret - Transfer QWC following the tag, load next tag
//Set MADR to data following the tag.
dma->madr = dma->tadr + 16;
// Snag an address from the address stack pointer.
switch(dma->chcr.ASP)
{
case 2:
// Pull asr1 from the stack, give it to TADR, and decrease the # of addresses.
dma->tadr = dma->asr1;
dma->asr1 = 0;
dma->chcr.ASP--;
break;
case 1:
// Pull asr0 from the stack, give it to TADR, and decrease the # of addresses.
dma->tadr = dma->asr0;
dma->asr0 = 0;
dma->chcr.ASP--;
break;
case 0:
// There aren't any addresses to pull, so end the transfer.
//dma->tadr += 16; //Clear tag address - Kills Klonoa 2
return true;
default:
// If ASR1 and ASR0 are messed up, end the transfer.
//Console.Error("TAG_RET: ASR 1 & 0 == 1. This shouldn't happen!");
//dma->tadr += 16; //Clear tag address - Kills Klonoa 2
return true;
}
return false;
case TAG_END: // End - Transfer QWC following the tag
//Set MADR to data following the tag, and end the transfer.
dma->madr = dma->tadr + 16;
//Don't Increment tadr; breaks Soul Calibur II and III
return true;
}
return false;
}
bool hwDmacSrcChain(DMACh *dma, int id)
{
u32 temp;
switch (id)
{
case TAG_REFE: // Refe - Transfer Packet According to ADDR field
// End the transfer.
return true;
case TAG_CNT: // CNT - Transfer QWC following the tag.
// Set MADR to QW after the tag, and TADR to QW following the data.
dma->madr = dma->tadr + 16;
dma->tadr = dma->madr + (dma->qwc << 4);
return false;
case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
// Set MADR to QW following the tag, and set TADR to the address formerly in MADR.
temp = dma->madr;
dma->madr = dma->tadr + 16;
dma->tadr = temp;
return false;
case TAG_REF: // Ref - Transfer QWC from ADDR field
case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control)
//Set TADR to next tag
dma->tadr += 16;
return false;
case TAG_END: // End - Transfer QWC following the tag
//Set MADR to data following the tag, and end the transfer.
dma->madr = dma->tadr + 16;
//Don't Increment tadr; breaks Soul Calibur II and III
return true;
}
return false;
}