Unified the three DmaExec functions into one. :)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3550 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-07-22 13:25:48 +00:00
parent bc849cc042
commit 8d07e78b86
2 changed files with 63 additions and 190 deletions

View File

@ -438,18 +438,24 @@ union tDMAC_CTRL {
union tDMAC_STAT {
struct {
u32 CIS : 10;
u32 _reserved1 : 3;
u32 SIS : 1;
u32 MEIS : 1;
u32 BEIS : 1;
u32 CIM : 10;
u32 _reserved2 : 3;
u32 SIM : 1;
u32 MEIM : 1;
u32 _reserved3 : 1;
struct {
u32 CIS : 10;
u32 _reserved1 : 3;
u32 SIS : 1;
u32 MEIS : 1;
u32 BEIS : 1;
u32 CIM : 10;
u32 _reserved2 : 3;
u32 SIM : 1;
u32 MEIM : 1;
u32 _reserved3 : 1;
};
u32 _u32;
};
struct {
u16 _u16lo;
u16 _u16hi;
};
u32 _u32;
tDMAC_STAT(u32 val) { _u32 = val; }
@ -458,6 +464,11 @@ union tDMAC_STAT {
void clear_flags(u32 flags) { _u32 &= ~flags; }
void reset() { _u32 = 0; }
wxString desc() const { return wxsFormat(L"Stat: 0x%x", _u32); }
bool TestForInterrupt() const
{
return ((_u16lo & _u16hi) != 0) || BEIS;
}
};
union tDMAC_PCR {

View File

@ -24,6 +24,8 @@ using namespace R5900;
/////////////////////////////////////////////////////////////////////////
// DMA Execution Interfaces
// Returns true if the DMA is enabled and executed successfully. Returns false if execution
// was blocked (DMAE or master DMA enabler).
static bool QuickDmaExec( void (*func)(), u32 mem)
{
bool ret = false;
@ -35,7 +37,6 @@ static bool QuickDmaExec( void (*func)(), u32 mem)
ret = true;
}
return ret;
}
@ -43,205 +44,49 @@ static bool QuickDmaExec( void (*func)(), u32 mem)
tDMAC_QUEUE QueuedDMA(0);
u32 oldvalue = 0;
void __fastcall StartQueuedDMA()
static void StartQueuedDMA()
{
if (QueuedDMA.VIF0) { DMA_LOG("Resuming DMA for VIF0"); if(QuickDmaExec(dmaVIF0, D0_CHCR) == true) QueuedDMA.VIF0 = false; }
if (QueuedDMA.VIF1) { DMA_LOG("Resuming DMA for VIF1"); if(QuickDmaExec(dmaVIF1, D1_CHCR) == true) QueuedDMA.VIF1 = false; }
if (QueuedDMA.GIF ) { DMA_LOG("Resuming DMA for GIF" ); if(QuickDmaExec(dmaGIF , D2_CHCR) == true) QueuedDMA.GIF = false; }
if (QueuedDMA.IPU0) { DMA_LOG("Resuming DMA for IPU0"); if(QuickDmaExec(dmaIPU0, D3_CHCR) == true) QueuedDMA.IPU0 = false; }
if (QueuedDMA.IPU1) { DMA_LOG("Resuming DMA for IPU1"); if(QuickDmaExec(dmaIPU1, D4_CHCR) == true) QueuedDMA.IPU1 = false; }
if (QueuedDMA.SIF0) { DMA_LOG("Resuming DMA for SIF0"); if(QuickDmaExec(dmaSIF0, D5_CHCR) == true) QueuedDMA.SIF0 = false; }
if (QueuedDMA.SIF1) { DMA_LOG("Resuming DMA for SIF1"); if(QuickDmaExec(dmaSIF1, D6_CHCR) == true) QueuedDMA.SIF1 = false; }
if (QueuedDMA.SIF2) { DMA_LOG("Resuming DMA for SIF2"); if(QuickDmaExec(dmaSIF2, D7_CHCR) == true) QueuedDMA.SIF2 = false; }
if (QueuedDMA.SPR0) { DMA_LOG("Resuming DMA for SPR0"); if(QuickDmaExec(dmaSPR0, D8_CHCR) == true) QueuedDMA.SPR0 = false; }
if (QueuedDMA.SPR1) { DMA_LOG("Resuming DMA for SPR1"); if(QuickDmaExec(dmaSPR1, D9_CHCR) == true) QueuedDMA.SPR1 = false; }
if (QueuedDMA.VIF0) { DMA_LOG("Resuming DMA for VIF0"); QueuedDMA.VIF0 = !QuickDmaExec(dmaVIF0, D0_CHCR); }
if (QueuedDMA.VIF1) { DMA_LOG("Resuming DMA for VIF1"); QueuedDMA.VIF1 = !QuickDmaExec(dmaVIF1, D1_CHCR); }
if (QueuedDMA.GIF ) { DMA_LOG("Resuming DMA for GIF" ); QueuedDMA.GIF = !QuickDmaExec(dmaGIF , D2_CHCR); }
if (QueuedDMA.IPU0) { DMA_LOG("Resuming DMA for IPU0"); QueuedDMA.IPU0 = !QuickDmaExec(dmaIPU0, D3_CHCR); }
if (QueuedDMA.IPU1) { DMA_LOG("Resuming DMA for IPU1"); QueuedDMA.IPU1 = !QuickDmaExec(dmaIPU1, D4_CHCR); }
if (QueuedDMA.SIF0) { DMA_LOG("Resuming DMA for SIF0"); QueuedDMA.SIF0 = !QuickDmaExec(dmaSIF0, D5_CHCR); }
if (QueuedDMA.SIF1) { DMA_LOG("Resuming DMA for SIF1"); QueuedDMA.SIF1 = !QuickDmaExec(dmaSIF1, D6_CHCR); }
if (QueuedDMA.SIF2) { DMA_LOG("Resuming DMA for SIF2"); QueuedDMA.SIF2 = !QuickDmaExec(dmaSIF2, D7_CHCR); }
if (QueuedDMA.SPR0) { DMA_LOG("Resuming DMA for SPR0"); QueuedDMA.SPR0 = !QuickDmaExec(dmaSPR0, D8_CHCR); }
if (QueuedDMA.SPR1) { DMA_LOG("Resuming DMA for SPR1"); QueuedDMA.SPR1 = !QuickDmaExec(dmaSPR1, D9_CHCR); }
}
// dark cloud2 uses 8 bit DMAs register writes
static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value )
static _f void DmaExec( void (*func)(), u32 mem, u32 value )
{
DMACh *reg = &psH_DMACh(mem & ~0xf);
//The only thing we can do in an 8bit write is set the CHCR, so lets just do checks for that
//It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC
if (reg->chcr.STR)
{
if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything
{
//If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue.
if(value == 0)
{
//DevCon.Warning(L"8bit %s DMA Stopped on Suspend", ChcrName(mem & ~0xf));
if(ChannelNumber(mem & ~0xf) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem & ~0xf) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem & ~0xf) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem & ~0xf)); //Clear any queued DMA requests for this channel;
}
//Here we update the CHCR STR (Busy) bit, we don't touch anything else.
reg->chcr.STR = value;
return;
}
else //Else the DMA is running (Not Suspended), so we cant touch it!
{
//As the manual states "Fields other than STR can only be written to when the DMA is stopped"
//Also "The DMA may not stop properly just by writing 0 to STR"
//So the presumption is that STR can be written to (ala force stop the DMA) but nothing else
if(value == 0)
{
//DevCon.Warning(L"8bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem & ~0xf), reg->chcr._u32, value);
reg->chcr.STR = value;
//We need to clear any existing DMA loops that are in progress else they will continue!
if(ChannelNumber(mem & ~0xf) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem & ~0xf) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem & ~0xf) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem & ~0xf)); //Clear any queued DMA requests for this channel
}
//else DevCon.Warning(L"8bit Attempted to stop %s DMA without suspend, ignoring", ChcrName(mem & ~0xf));
return;
}
}
reg->chcr.STR = value;
if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
{
func();
}
else if(reg->chcr.STR)
{
//DevCon.Warning(L"8bit %s DMA Start while DMAC Disabled\n",ChcrName(mem));
QueuedDMA._u16 |= (1 << ChannelNumber(mem & ~0xf)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted
}
}
static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value )
{
DMACh *reg = &psH_DMACh(mem);
tDMA_CHCR chcr(value);
//It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC
if (reg->chcr.STR)
{
if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything
{
//If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue.
if(chcr.STR == 0)
{
//DevCon.Warning(L"16bit %s DMA Stopped on Suspend", ChcrName(mem));
if(ChannelNumber(mem) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
}
//Here we update the lower part of the CHCR, we dont touch the tag as it is only a 16bit value
reg->chcr.set((reg->chcr.TAG << 16) | chcr.lower());
return;
}
else //Else the DMA is running (Not Suspended), so we cant touch it!
{
//As the manual states "Fields other than STR can only be written to when the DMA is stopped"
//Also "The DMA may not stop properly just by writing 0 to STR"
//So the presumption is that STR can be written to (ala force stop the DMA) but nothing else
if(chcr.STR == 0)
{
//DevCon.Warning(L"16bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg->chcr._u32, chcr._u32);
reg->chcr.STR = 0;
//We need to clear any existing DMA loops that are in progress else they will continue!
if(ChannelNumber(mem) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
}
//else DevCon.Warning(L"16bit Attempted to change %s modes while DMA active, ignoring", ChcrName(mem));
return;
}
}
reg->chcr.set((reg->chcr.TAG << 16) | chcr.lower());
if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
{
func();
}
else if(reg->chcr.STR)
{
//DevCon.Warning(L"16bit %s DMA Start while DMAC Disabled\n",ChcrName(mem));
QueuedDMA._u16 |= (1 << ChannelNumber(mem)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted
}
}
static void DmaExec( void (*func)(), u32 mem, u32 value )
{
DMACh *reg = &psH_DMACh(mem);
tDMA_CHCR chcr(value);
//It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC
if (reg->chcr.STR)
{
const uint channel = ChannelNumber(mem);
if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything
{
//If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue.
if(chcr.STR == 0)
{
//DevCon.Warning(L"32bit %s DMA Stopped on Suspend", ChcrName(mem));
if(ChannelNumber(mem) == 1)
if(channel == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
else if(channel == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
cpuClearInt( channel );
QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel
}
//Sanity Check for possible future bug fix0rs ;p
//Spams on Persona 4 opening.
@ -263,19 +108,19 @@ static void DmaExec( void (*func)(), u32 mem, u32 value )
reg->chcr.STR = 0;
//We need to clear any existing DMA loops that are in progress else they will continue!
if(ChannelNumber(mem) == 1)
if(channel == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
else if(channel == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
cpuClearInt( channel );
QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel
}
//else DevCon.Warning(L"32bit Attempted to change %s CHCR (Currently %x) with %x while DMA active, ignoring QWC = %x", ChcrName(mem), reg->chcr._u32, chcr._u32, reg->qwc);
return;
@ -298,6 +143,23 @@ static void DmaExec( void (*func)(), u32 mem, u32 value )
} //else QueuedDMA._u16 &~= (1 << ChannelNumber(mem)); //
}
// DmaExec8 should only be called for the second byte of CHCR.
// Testing Note: dark cloud 2 uses 8 bit DMAs register writes.
static _f void DmaExec8( void (*func)(), u32 mem, u8 value )
{
pxAssumeMsg( (mem & 0xf) == 1, "DmaExec8 should only be called for the second byte of CHCR" );
// The calling function calls this when the second byte (bits 8->15) is written. Only bit 8
// is effective, and it is the STR (start) bit. :)
DmaExec( func, mem & ~0xf, (u32)value<<8 );
}
static _f void DmaExec16( void (*func)(), u32 mem, u16 value )
{
DmaExec( func, mem, (u32)value );
}
/////////////////////////////////////////////////////////////////////////
// Hardware WRITE 8 bit