From 8d07e78b867d2346f4f2e9033a930bb906f876fd Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Thu, 22 Jul 2010 13:25:48 +0000 Subject: [PATCH] Unified the three DmaExec functions into one. :) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3550 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/Dmac.h | 33 ++++--- pcsx2/HwWrite.cpp | 220 +++++++++------------------------------------- 2 files changed, 63 insertions(+), 190 deletions(-) diff --git a/pcsx2/Dmac.h b/pcsx2/Dmac.h index 67cdbbc573..138cdbf7a5 100644 --- a/pcsx2/Dmac.h +++ b/pcsx2/Dmac.h @@ -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 { diff --git a/pcsx2/HwWrite.cpp b/pcsx2/HwWrite.cpp index b1bbf3e191..29cf919e55 100644 --- a/pcsx2/HwWrite.cpp +++ b/pcsx2/HwWrite.cpp @@ -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