diff --git a/pcsx2/Sio.h b/pcsx2/Sio.h index 6153f9bc55..00ffbd38b5 100644 --- a/pcsx2/Sio.h +++ b/pcsx2/Sio.h @@ -17,7 +17,7 @@ // Let's enable this to free the IOP event handler of some considerable load. // Games are highly unlikely to need timed IRQ's for PAD and MemoryCard handling anyway (rama). -#define SIO_INLINE_IRQS +//#define SIO_INLINE_IRQS #include "MemoryCardFile.h" @@ -30,8 +30,8 @@ struct _mcd u32 transferAddr; // Transfer address u8 FLAG; // for PSX; - - u8 port; // port + + u8 port; // port u8 slot; // and slot for this memcard // Auto Eject @@ -55,13 +55,13 @@ struct _mcd } // Read from memorycard to dest - void Read(u8 *dest, int size) + void Read(u8 *dest, int size) { SysPlugins.McdRead(port, slot, dest, transferAddr, size); } // Write to memorycard from src - void Write(u8 *src, int size) + void Write(u8 *src, int size) { SysPlugins.McdSave(port, slot, src,transferAddr, size); } diff --git a/plugins/spu2-x/src/Dma.cpp b/plugins/spu2-x/src/Dma.cpp index 766816c5f1..4b5c82407d 100644 --- a/plugins/spu2-x/src/Dma.cpp +++ b/plugins/spu2-x/src/Dma.cpp @@ -214,7 +214,10 @@ void V_Core::PlainDMAWrite(u16 *pMem, u32 size) else DMA7LogWrite(pMem,size<<1); - TSA &= 0xfffff; + if (psxmode) + TSA &= 0x7ffff; + else + TSA &= 0xfffff; u32 buff1end = TSA + size; u32 buff2end=0; @@ -235,14 +238,11 @@ void V_Core::PlainDMAWrite(u16 *pMem, u32 size) cacheLine++; } while ( cacheLine != &cacheEnd ); - //ConLog( "* SPU2-X: Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n", - // TSA, buff1end, flagTSA, flagTDA, clearLen ); - - // First Branch needs cleared: // It starts at TSA and goes to buff1end. const u32 buff1size = (buff1end-TSA); + ConLog("* SPU2-X: DMA exec! TSA = %x buff1size*2 = %x\n", TSA, buff1size*2); memcpy( GetMemPtr( TSA ), pMem, buff1size*2 ); u32 TDA; @@ -261,7 +261,8 @@ void V_Core::PlainDMAWrite(u16 *pMem, u32 size) // 0x2800? Hard to know for sure (almost no games depend on this) memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); - TDA = (buff2end+1) & 0xfffff; + if (psxmode) TDA = (buff2end + 1) & 0x7ffff; + else TDA = (buff2end+1) & 0xfffff; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! @@ -297,7 +298,8 @@ void V_Core::PlainDMAWrite(u16 *pMem, u32 size) // Buffer doesn't wrap/overflow! // Just set the TDA and check for an IRQ... - TDA = (buff1end + 1) & 0xfffff; + if (psxmode) TDA = (buff1end + 1) & 0x7ffff; + else TDA = (buff1end + 1) & 0xfffff; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! @@ -402,6 +404,7 @@ void V_Core::DoDMAwrite(u16* pMem, u32 size) if(size<2) { //if(dma7callback) dma7callback(); + ConLog("* SPU2-X: Warning DMA Transfer of 0 bytes? size is %x\n", size); Regs.STATX &= ~0x80; //Regs.ATTR |= 0x30; DMAICounter=1; @@ -422,11 +425,12 @@ void V_Core::DoDMAwrite(u16* pMem, u32 size) } } - TSA &= 0xfffff; + if (psxmode) TSA &= 0x7ffff; + else TSA &= 0xfffff; bool adma_enable = ((AutoDMACtrl&(Index+1))==(Index+1)); - if(adma_enable) + if(adma_enable && !psxmode) // no adma in psx mode { TSA&=0x1fff; StartADMAWrite(pMem,size); diff --git a/plugins/spu2-x/src/Global.h b/plugins/spu2-x/src/Global.h index b8eda4d429..e79d2b520d 100644 --- a/plugins/spu2-x/src/Global.h +++ b/plugins/spu2-x/src/Global.h @@ -20,6 +20,8 @@ #define NOMINMAX +extern bool psxmode; + struct StereoOut16; struct StereoOut32; struct StereoOutFloat; diff --git a/plugins/spu2-x/src/Mixer.cpp b/plugins/spu2-x/src/Mixer.cpp index 4ddb8f3beb..414da0ba53 100644 --- a/plugins/spu2-x/src/Mixer.cpp +++ b/plugins/spu2-x/src/Mixer.cpp @@ -128,7 +128,8 @@ static void __forceinline IncrementNextA(V_Core& thiscore, uint voiceidx) } vc.NextA++; - vc.NextA&=0xFFFFF; + if (psxmode) vc.NextA &= 0x7FFFF; + else vc.NextA&=0xFFFFF; } // decoded pcm data, used to cache the decoded data so that it needn't be decoded @@ -588,9 +589,10 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx ) // Write-back of raw voice data (post ADSR applied) - if (voiceidx==1) spu2M_WriteFast( ( (0==coreidx) ? 0x400 : 0xc00 ) + OutPos, vc.OutX ); - else if (voiceidx==3) spu2M_WriteFast( ( (0==coreidx) ? 0x600 : 0xe00 ) + OutPos, vc.OutX ); - + if (!psxmode) { // i'm not sure if this is correct for psxmode. it doesn't seem to hurt to have it off so i assume it is bad. + if (voiceidx == 1) spu2M_WriteFast(((0 == coreidx) ? 0x400 : 0xc00) + OutPos, vc.OutX); + else if (voiceidx == 3) spu2M_WriteFast(((0 == coreidx) ? 0x600 : 0xe00) + OutPos, vc.OutX); + } return ApplyVolume( StereoOut32( Value, Value ), vc.Volume ); } else @@ -609,9 +611,10 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx ) } // Write-back of raw voice data (some zeros since the voice is "dead") - if (voiceidx==1) spu2M_WriteFast( ( (0==coreidx) ? 0x400 : 0xc00 ) + OutPos, 0 ); - else if (voiceidx==3) spu2M_WriteFast( ( (0==coreidx) ? 0x600 : 0xe00 ) + OutPos, 0 ); - + if (!psxmode) { // i'm not sure if this is correct for psxmode. it doesn't seem to hurt to have it off so i assume it is bad. + if (voiceidx == 1) spu2M_WriteFast(((0 == coreidx) ? 0x400 : 0xc00) + OutPos, 0); + else if (voiceidx == 3) spu2M_WriteFast(((0 == coreidx) ? 0x600 : 0xe00) + OutPos, 0); + } return StereoOut32( 0, 0 ); } } @@ -642,11 +645,13 @@ StereoOut32 V_Core::Mix( const VoiceMixSet& inVoices, const StereoOut32& Input, // Saturate final result to standard 16 bit range. const VoiceMixSet Voices( clamp_mix( inVoices.Dry ), clamp_mix( inVoices.Wet ) ); - // Write Mixed results To Output Area - spu2M_WriteFast( ( (0==Index) ? 0x1000 : 0x1800 ) + OutPos, Voices.Dry.Left ); - spu2M_WriteFast( ( (0==Index) ? 0x1200 : 0x1A00 ) + OutPos, Voices.Dry.Right ); - spu2M_WriteFast( ( (0==Index) ? 0x1400 : 0x1C00 ) + OutPos, Voices.Wet.Left ); - spu2M_WriteFast( ( (0==Index) ? 0x1600 : 0x1E00 ) + OutPos, Voices.Wet.Right ); + if (!psxmode) { + // Write Mixed results To Output Area + spu2M_WriteFast(((0 == Index) ? 0x1000 : 0x1800) + OutPos, Voices.Dry.Left); + spu2M_WriteFast(((0 == Index) ? 0x1200 : 0x1A00) + OutPos, Voices.Dry.Right); + spu2M_WriteFast(((0 == Index) ? 0x1400 : 0x1C00) + OutPos, Voices.Wet.Left); + spu2M_WriteFast(((0 == Index) ? 0x1600 : 0x1E00) + OutPos, Voices.Wet.Right); + } // Write mixed results to logfile (if enabled) @@ -833,10 +838,12 @@ void Mix() Ext = clamp_mix( ApplyVolume( Ext, Cores[0].MasterVol ) ); } - // Commit Core 0 output to ram before mixing Core 1: + if (!psxmode) { + // Commit Core 0 output to ram before mixing Core 1: + spu2M_WriteFast(0x800 + OutPos, Ext.Left); + spu2M_WriteFast(0xA00 + OutPos, Ext.Right); + } - spu2M_WriteFast( 0x800 + OutPos, Ext.Left ); - spu2M_WriteFast( 0xA00 + OutPos, Ext.Right ); WaveDump::WriteCore( 0, CoreSrc_External, Ext ); Ext = ApplyVolume( Ext, Cores[1].ExtVol ); diff --git a/plugins/spu2-x/src/ReadInput.cpp b/plugins/spu2-x/src/ReadInput.cpp index 9326a97004..78a3b81a21 100644 --- a/plugins/spu2-x/src/ReadInput.cpp +++ b/plugins/spu2-x/src/ReadInput.cpp @@ -31,6 +31,7 @@ // StereoOut32 V_Core::ReadInput_HiFi() { + if (psxmode)ConLog("ReadInput_HiFi!!!!!\n"); InputPosRead &= ~1; // //#ifdef PCM24_S1_INTERLEAVE diff --git a/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp b/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp index d1bf7aceda..64be714416 100644 --- a/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp +++ b/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp @@ -164,13 +164,6 @@ void UpdateDebugDialog() TextOut(hdc,IX+4,IY+32,t,6); vcd.displayPeak = 0; - - if(vcd.lastSetStartA != vc.StartA) - { - printf(" *** Warning! Core %d Voice %d: StartA should be %06x, and is %06x.\n", - c,v,vcd.lastSetStartA,vc.StartA); - vcd.lastSetStartA = vc.StartA; - } } // top now: 400 diff --git a/plugins/spu2-x/src/defs.h b/plugins/spu2-x/src/defs.h index 0306b6c478..be28eec75d 100644 --- a/plugins/spu2-x/src/defs.h +++ b/plugins/spu2-x/src/defs.h @@ -28,6 +28,7 @@ extern s16* GetMemPtr(u32 addr); extern s16 spu2M_Read( u32 addr ); +extern s16 spu2M_ReadPSX(u32 addr); extern void spu2M_Write( u32 addr, s16 value ); extern void spu2M_Write( u32 addr, u16 value ); @@ -154,6 +155,10 @@ struct V_Voice s32 Prev1; s32 Prev2; + // psx caches + u16 psxPitch; + u16 psxLoopStartA; + u16 psxStartA; // Pitch Modulated by previous voice bool Modulated; // Source (Wave/Noise) @@ -441,6 +446,15 @@ struct V_Core u32 KeyOn; // not the KON register (though maybe it is) + // psxmode caches + u16 psxIRQA; + u16 psxTSA; + u16 psxSPUCNT; + u16 psxSoundDataTransferControl; + u16 psxSPUSTAT; + u16 psxReverbStartA; + + StereoOut32 downbuf[8]; StereoOut32 upbuf[8]; int dbpos, ubpos; @@ -505,12 +519,25 @@ struct V_Core return ret; } + __forceinline u16 DmaReadPSX() + { + const u16 ret = (u16)spu2M_ReadPSX(TSA); + ++TSA; TSA &= 0x7ffff; + return ret; + } + __forceinline void DmaWrite(u16 value) { spu2M_Write( TSA, value ); ++TSA; TSA &= 0xfffff; } + __forceinline void DmaWritePSX(u16 value) + { + spu2M_Write(TSA, value); + ++TSA; TSA &= 0x7ffff; + } + void LogAutoDMA( FILE* fp ); s32 NewDmaRead(u32* data, u32 bytesLeft, u32* bytesProcessed); diff --git a/plugins/spu2-x/src/spu2sys.cpp b/plugins/spu2-x/src/spu2sys.cpp index db12e90124..c52478c7eb 100644 --- a/plugins/spu2-x/src/spu2sys.cpp +++ b/plugins/spu2-x/src/spu2sys.cpp @@ -42,6 +42,8 @@ int PlayMode; bool has_to_call_irq=false; +bool psxmode = false; + void SetIrqCall(int core) { // reset by an irq disable/enable cycle, behaviour found by @@ -67,6 +69,11 @@ __forceinline s16 spu2M_Read( u32 addr ) return *GetMemPtr( addr & 0xfffff ); } +__forceinline s16 spu2M_ReadPSX(u32 addr) +{ + return *GetMemPtr(addr & 0x7ffff); +} + // writes a signed value to the SPU2 ram // Invalidates the ADPCM cache in the process. __forceinline void spu2M_Write( u32 addr, s16 value ) @@ -116,6 +123,7 @@ void V_Core::Init( int index ) { ConLog( "* SPU2-X: Init SPU2 core %d \n", index ); memset( this, 0, sizeof(V_Core) ); + psxmode = false; const int c = Index = index; @@ -191,32 +199,32 @@ void V_Core::AnalyzeReverbPreset() { ConLog("Reverb Parameter Update for Core %d:\n", Index); ConLog("----------------------------------------------------------\n"); - + ConLog(" IN_COEF_L, IN_COEF_R 0x%08x, 0x%08x\n", Revb.IN_COEF_L, Revb.IN_COEF_R); ConLog(" FB_SRC_A, FB_SRC_B 0x%08x, 0x%08x\n", Revb.FB_SRC_A, Revb.FB_SRC_B); ConLog(" FB_ALPHA, FB_X 0x%08x, 0x%08x\n", Revb.FB_ALPHA, Revb.FB_X); - + ConLog(" ACC_COEF_A 0x%08x\n", Revb.ACC_COEF_A); ConLog(" ACC_COEF_B 0x%08x\n", Revb.ACC_COEF_B); ConLog(" ACC_COEF_C 0x%08x\n", Revb.ACC_COEF_C); ConLog(" ACC_COEF_D 0x%08x\n", Revb.ACC_COEF_D); - + ConLog(" ACC_SRC_A0, ACC_SRC_A1 0x%08x, 0x%08x\n", Revb.ACC_SRC_A0, Revb.ACC_SRC_A1); ConLog(" ACC_SRC_B0, ACC_SRC_B1 0x%08x, 0x%08x\n", Revb.ACC_SRC_B0, Revb.ACC_SRC_B1); ConLog(" ACC_SRC_C0, ACC_SRC_C1 0x%08x, 0x%08x\n", Revb.ACC_SRC_C0, Revb.ACC_SRC_C1); ConLog(" ACC_SRC_D0, ACC_SRC_D1 0x%08x, 0x%08x\n", Revb.ACC_SRC_D0, Revb.ACC_SRC_D1); - + ConLog(" IIR_SRC_A0, IIR_SRC_A1 0x%08x, 0x%08x\n", Revb.IIR_SRC_A0, Revb.IIR_SRC_A1); ConLog(" IIR_SRC_B0, IIR_SRC_B1 0x%08x, 0x%08x\n", Revb.IIR_SRC_B0, Revb.IIR_SRC_B1); ConLog(" IIR_DEST_A0, IIR_DEST_A1 0x%08x, 0x%08x\n", Revb.IIR_DEST_A0, Revb.IIR_DEST_A1); - ConLog(" IIR_DEST_B0, IIR_DEST_B1 0x%08x, 0x%08x\n", Revb.IIR_DEST_B0, Revb.IIR_DEST_B1); + ConLog(" IIR_DEST_B0, IIR_DEST_B1 0x%08x, 0x%08x\n", Revb.IIR_DEST_B0, Revb.IIR_DEST_B1); ConLog(" IIR_ALPHA, IIR_COEF 0x%08x, 0x%08x\n", Revb.IIR_ALPHA, Revb.IIR_COEF); ConLog(" MIX_DEST_A0 0x%08x\n", Revb.MIX_DEST_A0); ConLog(" MIX_DEST_A1 0x%08x\n", Revb.MIX_DEST_A1); ConLog(" MIX_DEST_B0 0x%08x\n", Revb.MIX_DEST_B0); ConLog(" MIX_DEST_B1 0x%08x\n", Revb.MIX_DEST_B1); - + ConLog(" EffectsBufferSize 0x%x\n", EffectsBufferSize); ConLog("----------------------------------------------------------\n"); } @@ -226,7 +234,7 @@ s32 V_Core::EffectsBufferIndexer( s32 offset ) const // that it *4's all addresses before upping them to the SPU2 -- so our buffers are // already x4'd. It doesn't really make sense that we should x4 them again, and this // seems to work. (feedback-free in bios and DDS) --air - + u32 pos = EffectsStartA + offset; // Need to use modulus here, because games can and will drop the buffer size @@ -261,12 +269,12 @@ void V_Core::UpdateEffectsBufferSize() //printf("Rvb Area change: ESA = %x, EEA = %x, Size(dec) = %d, Size(hex) = %x FxEnable = %d\n", EffectsStartA, EffectsEndA, newbufsize * 2, newbufsize * 2, FxEnable); if( (newbufsize*2) > 0x20000 ) // max 128kb per core - { + { //printf("too big, returning\n"); //return; } if (newbufsize == EffectsBufferSize && EffectsStartA == EffectsBufferStart) return; - + RevBuffers.NeedsUpdated = false; EffectsBufferSize = newbufsize; EffectsBufferStart = EffectsStartA; @@ -274,7 +282,7 @@ void V_Core::UpdateEffectsBufferSize() if( EffectsBufferSize <= 0 ) return; //AnalyzeReverbPreset(); - + // Rebuild buffer indexers. RevBuffers.ACC_SRC_A0 = EffectsBufferIndexer( Revb.ACC_SRC_A0 ); RevBuffers.ACC_SRC_A1 = EffectsBufferIndexer( Revb.ACC_SRC_A1 ); @@ -401,6 +409,7 @@ __forceinline void TimeUpdate(u32 cClocks) Cores[0].DMAICounter-=TickInterval; if(Cores[0].DMAICounter<=0) { + ConLog("counter set and callback!\n"); Cores[0].MADR=Cores[0].TADR; Cores[0].DMAICounter=0; if(dma4callback) dma4callback(); @@ -489,6 +498,27 @@ void V_VolumeSlide::RegSet( u16 src ) Value = GetVol32( src ); } +// Ah the joys of endian-specific code! :D +static __forceinline void SetHiWord(u32& src, u16 value) +{ + ((u16*)&src)[1] = value; +} + +static __forceinline void SetLoWord(u32& src, u16 value) +{ + ((u16*)&src)[0] = value; +} + +static __forceinline u16 GetHiWord(u32& src) +{ + return ((u16*)&src)[1]; +} + +static __forceinline u16 GetLoWord(u32& src) +{ + return ((u16*)&src)[0]; +} + void V_Core::WriteRegPS1( u32 mem, u16 value ) { pxAssume( Index == 0 ); // Valid on Core 0 only! @@ -501,32 +531,89 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) //voice values u8 voice = ((reg-0x1c00)>>4); u8 vval = reg&0xf; + switch(vval) { case 0x0: //VOLL (Volume L) - Voices[voice].Volume.Left.Mode = 0; - Voices[voice].Volume.Left.RegSet( value << 1 ); - Voices[voice].Volume.Left.Reg_VOL = value; - break; + { + V_VolumeSlide& thisvol = Voices[voice].Volume.Left; + thisvol.Reg_VOL = value; + if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp + { + thisvol.Mode = (value & 0xF000) >> 12; + thisvol.Increment = (value & 0x7F); + // We're not sure slides work 100% + if (IsDevBuild) ConLog("* SPU2: Voice uses Slides in Mode = %x, Increment = %x\n", thisvol.Mode, thisvol.Increment); + } + else + { + // Constant Volume mode (no slides or envelopes) + // Volumes range from 0x3fff to 0x7fff, with 0x4000 serving as + // the "sign" bit, so a simple bitwise extension will do the trick: + + thisvol.RegSet(value << 1); + thisvol.Mode = 0; + thisvol.Increment = 0; + } + //ConLog("voice %x VOLL write: %x\n", voice, value); + break; + } case 0x2: //VOLR (Volume R) - Voices[voice].Volume.Right.Mode = 0; - Voices[voice].Volume.Right.RegSet( value << 1 ); - Voices[voice].Volume.Right.Reg_VOL = value; - break; + { + V_VolumeSlide& thisvol = Voices[voice].Volume.Right; + thisvol.Reg_VOL = value; - case 0x4: Voices[voice].Pitch = value; break; - case 0x6: Voices[voice].StartA = (u32)value << 8; break; + if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp + { + thisvol.Mode = (value & 0xF000) >> 12; + thisvol.Increment = (value & 0x7F); + // We're not sure slides work 100% + if (IsDevBuild) ConLog("* SPU2: Voice uses Slides in Mode = %x, Increment = %x\n", thisvol.Mode, thisvol.Increment); + } + else + { + // Constant Volume mode (no slides or envelopes) + // Volumes range from 0x3fff to 0x7fff, with 0x4000 serving as + // the "sign" bit, so a simple bitwise extension will do the trick: + + thisvol.RegSet(value << 1); + thisvol.Mode = 0; + thisvol.Increment = 0; + } + //ConLog("voice %x VOLR write: %x\n", voice, value); + break; + } + case 0x4: + if (value > 0x3fff) ConLog("* SPU2: Pitch setting too big: 0x%x\n", value); + Voices[voice].Pitch = value & 0x3fff; + //ConLog("voice %x Pitch write: %x\n", voice, Voices[voice].Pitch); + break; + case 0x6: + Voices[voice].StartA = value * 8; + Voices[voice].psxStartA = value; + //ConLog("voice %x StartA write: %x\n", voice, Voices[voice].StartA); + break; case 0x8: // ADSR1 (Envelope) Voices[voice].ADSR.regADSR1 = value; + //ConLog("voice %x regADSR1 write: %x\n", voice, Voices[voice].ADSR.regADSR1); break; case 0xa: // ADSR2 (Envelope) Voices[voice].ADSR.regADSR2 = value; + //ConLog("voice %x regADSR2 write: %x\n", voice, Voices[voice].ADSR.regADSR2); + break; + case 0xc: // Voice 0..23 ADSR Current Volume + // not commonly set by games + Voices[voice].ADSR.Value = (value << 16) | value; + //ConLog("voice %x ADSR.Value write: %x\n", voice, Voices[voice].ADSR.Value); + break; + case 0xe: + Voices[voice].LoopStartA = value * 8; + Voices[voice].psxLoopStartA = value; + //ConLog("voice %x LoopStartA write: %x\n", voice, Voices[voice].LoopStartA); break; - - case 0xe: Voices[voice].LoopStartA = (u32)value << 8; break; jNO_DEFAULT; } @@ -553,85 +640,193 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) break; case 0x1d88:// Voice ON (0-15) - SPU2_FastWrite(REG_S_KON,value); + StartVoices(0, (u32)value); break; case 0x1d8a:// Voice ON (16-23) - SPU2_FastWrite(REG_S_KON+2,value); + StartVoices(0, ((u32)value) << 16); break; case 0x1d8c:// Voice OFF (0-15) - SPU2_FastWrite(REG_S_KOFF,value); + StopVoices(0, (u32)value); break; case 0x1d8e:// Voice OFF (16-23) - SPU2_FastWrite(REG_S_KOFF+2,value); + StopVoices(0, ((u32)value) << 16); break; case 0x1d90:// Channel FM (pitch lfo) mode (0-15) - SPU2_FastWrite(REG_S_PMON,value); + Regs.PMON = value & 0xFFFF; + for (int vc = 1; vc<16; ++vc) + Voices[vc].Modulated = (value >> vc) & 1; + if (value != 0) ConLog("spu2x warning: wants to set Pitch Modulation reg1 to %x \n", value); break; case 0x1d92:// Channel FM (pitch lfo) mode (16-23) - SPU2_FastWrite(REG_S_PMON+2,value); + Regs.PMON = value << 16; + for (int vc = 0; vc<8; ++vc) + Voices[vc + 16].Modulated = (value >> vc) & 1; break; case 0x1d94:// Channel Noise mode (0-15) - SPU2_FastWrite(REG_S_NON,value); + SetLoWord(Regs.NON, value); + for (int vc = 0; vc<16; ++vc) + Voices[vc].Noise = (value >> vc) & 1; + if (value != 0) ConLog("spu2x warning: wants to set Channel Noise mode reg1 to %x\n", value); break; case 0x1d96:// Channel Noise mode (16-23) - SPU2_FastWrite(REG_S_NON+2,value); + SetHiWord(Regs.NON, value); + for (int vc = 0; vc<8; ++vc) + Voices[vc + 16].Noise = (value >> vc) & 1; + //ConLog("spu2x warning: wants to set Channel Noise mode reg2 to %x (ignored)\n", value); break; - case 0x1d98:// Channel Reverb mode (0-15) - SPU2_FastWrite(REG_S_VMIXEL,value); - SPU2_FastWrite(REG_S_VMIXER,value); + case 0x1d98:// 1F801D98h - Voice 0..23 Reverb mode aka Echo On (EON) (R/W) + //Regs.VMIXEL = value & 0xFFFF; + //ConLog("spu2x warning: setting reverb mode reg1 to %x \n", Regs.VMIXEL); break; - case 0x1d9a:// Channel Reverb mode (16-23) - SPU2_FastWrite(REG_S_VMIXEL+2,value); - SPU2_FastWrite(REG_S_VMIXER+2,value); + case 0x1d9a:// 1F801D98h + 2 - Voice 0..23 Reverb mode aka Echo On (EON) (R/W) + //Regs.VMIXEL = value << 16; + //ConLog("spu2x warning: setting reverb mode reg2 to %x \n", Regs.VMIXEL); break; - case 0x1d9c:// Channel Reverb mode (0-15) - SPU2_FastWrite(REG_S_VMIXL,value); - SPU2_FastWrite(REG_S_VMIXR,value); + // this was wrong? // edit: appears so! + //case 0x1d9c:// Channel Reverb mode (0-15) + // SPU2_FastWrite(REG_S_VMIXL,value); + // SPU2_FastWrite(REG_S_VMIXR,value); + //break; + + //case 0x1d9e:// Channel Reverb mode (16-23) + // SPU2_FastWrite(REG_S_VMIXL+2,value); + // SPU2_FastWrite(REG_S_VMIXR+2,value); + //break; + case 0x1d9c: // Voice 0..15 ON/OFF (status) (ENDX) (R) // writeable but hw overrides it shortly after + Regs.ENDX &= 0xff0000; + ConLog("spu2x warning: wants to set ENDX reg1 to %x \n", value); break; - case 0x1d9e:// Channel Reverb mode (16-23) - SPU2_FastWrite(REG_S_VMIXL+2,value); - SPU2_FastWrite(REG_S_VMIXR+2,value); + case 0x1d9e:// // Voice 15..23 ON/OFF (status) (ENDX) (R) // writeable but hw overrides it shortly after + Regs.ENDX &= 0xffff; + ConLog("spu2x warning: wants to set ENDX reg2 to %x \n", value); break; case 0x1da2:// Reverb work area start { - u32 val = (u32)value << 8; - - SPU2_FastWrite(REG_A_ESA, val&0xFFFF); - SPU2_FastWrite(REG_A_ESA+2,val>>16); + EffectsStartA = value * 8; + EffectsEndA = 0x7FFFF; // fixed EndA in psx mode + psxReverbStartA = value; + Cores[0].RevBuffers.NeedsUpdated = true; } break; case 0x1da4: - IRQA = (u32)value<<8; + IRQA = value * 8; + psxIRQA = value; + ConLog("SPU2-X Setting IRQA to %x value was %x \n", IRQA, value); break; case 0x1da6: - TSA = (u32)value<<8; + TSA = value * 8; + psxTSA = value; + ConLog("SPU2-X Setting TSA to %x value was %x \n", TSA, value); + break; + + case 0x1da8: // Spu Write to Memory + ConLog("SPU direct DMA Write. Current TSA = %x\n", TSA); + if (Cores[0].IRQEnable && (Cores[0].IRQA <= Cores[0].TSA)) + { + SetIrqCall(0); + _irqcallback(); + } + DmaWritePSX(value); + show = false; break; case 0x1daa: - SPU2_FastWrite(REG_C_ATTR,value); + { + psxSPUCNT = value; + ConLog("SPU Control register write with %x\n", value); + bool irqe = Cores[0].IRQEnable; + int bit0 = Cores[0].AttrBit0; + bool fxenable = Cores[0].FxEnable; + u8 oldDmaMode = Cores[0].DmaMode; + + Cores[0].AttrBit0 = (value >> 0) & 0x01; //1 bit + Cores[0].DMABits = (value >> 1) & 0x07; //3 bits + Cores[0].DmaMode = (value >> 4) & 0x03; //2 bit (not necessary, we get the direction from the iop) + Cores[0].IRQEnable = (value >> 6) & 0x01; //1 bit + Cores[0].FxEnable = (value >> 7) & 0x01; //1 bit + Cores[0].NoiseClk = (value >> 8) & 0x3f; //6 bits + //thiscore.Mute =(value>>14) & 0x01; //1 bit + Cores[0].Mute = 0; + //thiscore.CoreEnabled=(value>>15) & 0x01; //1 bit + // no clue + if (value >> 15) + Cores[0].Regs.STATX = 0; + Cores[0].Regs.ATTR = value & 0x7fff; + + if (fxenable && !Cores[0].FxEnable) + { + Cores[0].ReverbX = 0; + Cores[0].RevBuffers.NeedsUpdated = true; + } + + if (oldDmaMode != Cores[0].DmaMode) + { + // FIXME... maybe: if this mode was cleared in the middle of a DMA, should we interrupt it? + ConLog("* SPU2-X: DMA mode changed. oldDmaMode = %x , newDmaMode = %x \n", oldDmaMode,Cores[0].DmaMode); + Cores[0].Regs.STATX &= ~0x400; // ready to transfer + } + + if (value & 0x000E) + { + if (MsgToConsole()) ConLog("* SPU2-X: Core 0 ATTR unknown bits SET! value=%x\n", value); + } + + if (Cores[0].AttrBit0 != bit0) + { + if (MsgToConsole()) ConLog("* SPU2-X: ATTR bit 0 set to %d\n", Cores[0].AttrBit0); + } + if (Cores[0].IRQEnable != irqe) + { + ConLog("* SPU2-X: write reg psx Core%d IRQ %s at cycle %d. Current IRQA = %x Current TSA = %x\n", + 0, ((Cores[0].IRQEnable==0)?"disabled":"enabled"), Cycles, Cores[0].IRQA, Cores[0].TSA); + + if (!Cores[0].IRQEnable) + Spdif.Info &= ~(4 << Cores[0].Index); + } + } break; - case 0x1dae: - SPU2_FastWrite(REG_P_STATX,value); - break; + case 0x1dac: // 1F801DACh - Sound RAM Data Transfer Control (should be 0004h) + ConLog("SPU Sound RAM Data Transfer Control (should be 0004h) : value = %x \n", value); + psxSoundDataTransferControl = value; + break; + + case 0x1dae: // 1F801DAEh - SPU Status Register (SPUSTAT) (R) + // The SPUSTAT register should be treated read-only (writing is possible in so far that the written + // value can be read-back for a short moment, however, thereafter the hardware is overwriting that value). + //Regs.STATX = value; + break; + + case 0x1DB0: // 1F801DB0h 4 CD Volume Left/Right + break; // cd left? + case 0x1DB2: + break;// cd right? + case 0x1DB4: // 1F801DB4h 4 Extern Volume Left / Right + break; // Extern left? + case 0x1DB6: + break; // Extern right? + case 0x1DB8: // 1F801DB8h 4 Current Main Volume Left/Right + break; // Current left? + case 0x1DBA: + break; // Current right? + case 0x1DBC: // 1F801DBCh 4 Unknown? (R/W) + break; + case 0x1DBE: + break; - case 0x1da8:// Spu Write to Memory - DmaWrite(value); - show=false; - break; } if(show) FileLog("[%10d] (!) SPU write mem %08x value %04x\n",Cycles,mem,value); @@ -641,6 +836,7 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) u16 V_Core::ReadRegPS1(u32 mem) { + //ConLog("ReadRegPS1 from %x on core %d\n", mem, Index); pxAssume( Index == 0 ); // Valid on Core 0 only! bool show=true; @@ -655,24 +851,40 @@ u16 V_Core::ReadRegPS1(u32 mem) u8 vval = reg&0xf; switch(vval) { - case 0: //VOLL (Volume L) + case 0x0: //VOLL (Volume L) //value=Voices[voice].VolumeL.Mode; //value=Voices[voice].VolumeL.Value; value = Voices[voice].Volume.Left.Reg_VOL; - break; + break; - case 1: //VOLR (Volume R) + case 0x2: //VOLR (Volume R) //value=Voices[voice].VolumeR.Mode; //value=Voices[voice].VolumeR.Value; value = Voices[voice].Volume.Right.Reg_VOL; - break; + break; - case 2: value = Voices[voice].Pitch; break; - case 3: value = Voices[voice].StartA; break; - case 4: value = Voices[voice].ADSR.regADSR1; break; - case 5: value = Voices[voice].ADSR.regADSR2; break; - case 6: value = Voices[voice].ADSR.Value >> 16; break; - case 7: value = Voices[voice].LoopStartA; break; + case 0x4: + value = Voices[voice].Pitch; + //ConLog("voice %d read pitch result = %x\n", voice, value); + break; + case 0x6: + value = Voices[voice].psxStartA; + //ConLog("voice %d read StartA result = %x\n", voice, value); + break; + case 0x8: + value = Voices[voice].ADSR.regADSR1; + break; + case 0xa: + value = Voices[voice].ADSR.regADSR2; + break; + case 0xc: // Voice 0..23 ADSR Current Volume + value = Voices[voice].ADSR.Value >> 16; // no clue + //if (value != 0) ConLog("voice %d read ADSR.Value result = %x\n", voice, value); + break; + case 0xe: + value = Voices[voice].psxLoopStartA; + //ConLog("voice %d read LoopStartA result = %x\n", voice, value); + break; jNO_DEFAULT; } @@ -684,75 +896,58 @@ u16 V_Core::ReadRegPS1(u32 mem) case 0x1d84: value = FxVol.Left >> 16; break; case 0x1d86: value = FxVol.Right >> 16; break; - case 0x1d88: value = 0; break; + case 0x1d88: value = 0; break; // Voice 0..23 Key ON(Start Attack / Decay / Sustain) (W) case 0x1d8a: value = 0; break; - case 0x1d8c: value = 0; break; + case 0x1d8c: value = 0; break; // Voice 0..23 Key OFF (Start Release) (W) case 0x1d8e: value = 0; break; - case 0x1d90: value = Regs.PMON&0xFFFF; break; + case 0x1d90: value = Regs.PMON&0xFFFF; break; // Voice 0..23 Channel FM(pitch lfo) mode(R / W) case 0x1d92: value = Regs.PMON>>16; break; - case 0x1d94: value = Regs.NON&0xFFFF; break; + case 0x1d94: value = Regs.NON&0xFFFF; break; // Voice 0..23 Channel Noise mode (R/W) case 0x1d96: value = Regs.NON>>16; break; - case 0x1d98: value = Regs.VMIXEL&0xFFFF; break; + case 0x1d98: value = Regs.VMIXEL&0xFFFF; break; // Voice 0..23 Channel Reverb mode (R/W) case 0x1d9a: value = Regs.VMIXEL>>16; break; - case 0x1d9c: value = Regs.VMIXL&0xFFFF; break; - case 0x1d9e: value = Regs.VMIXL>>16; break; + /*case 0x1d9c: value = Regs.VMIXL&0xFFFF; break;*/ // this is wrong? + /*case 0x1d9e: value = Regs.VMIXL >> 16; break;*/ + case 0x1d9c: value = Regs.ENDX & 0xFFFF; break;// Voice 0..23 Channel ON / OFF(status) (R) (ENDX) + case 0x1d9e: value = Regs.ENDX >> 16; case 0x1da2: -#if 0 - // This smells of old hack - if( value != EffectsStartA>>3 ) - { - value = EffectsStartA>>3; - UpdateEffectsBufferSize(); - ReverbX = 0; - } -#else - value = EffectsStartA >> 3; -#endif - break; - case 0x1da4: value = IRQA>>3; break; - case 0x1da6: value = TSA>>3; break; - - case 0x1daa: - value = SPU2read(REG_C_ATTR); + value = psxReverbStartA; break; - case 0x1dae: - value = 0; //SPU2read(REG_P_STATX)<<3; + case 0x1da4: + value = psxIRQA; + ConLog("SPU2-X IRQA read: 0x1da4 = %x , (IRQA = %x)\n", value, IRQA); + break; + case 0x1da6: + value = psxTSA; + ConLog("SPU2-X TSA read: 0x1da6 = %x , (TSA = %x)\n", value, TSA); break; case 0x1da8: value = DmaRead(); show=false; break; + case 0x1daa: + //value = psxSPUCNT; + value = Cores[0].Regs.ATTR; + ConLog("SPU2-X ps1 reg psxSPUCNT read return value: %x\n", value); + break; + case 0x1dac: // 1F801DACh - Sound RAM Data Transfer Control (should be 0004h) + value = psxSoundDataTransferControl; + break; + case 0x1dae: + value = Regs.STATX; + //value = Cores[0].Regs.STATX; + ConLog("SPU2-X ps1 reg REG_P_STATX read return value: %x\n", value); + break; } if(show) FileLog("[%10d] (!) SPU read mem %08x value %04x\n",Cycles,mem,value); return value; } -// Ah the joys of endian-specific code! :D -static __forceinline void SetHiWord( u32& src, u16 value ) -{ - ((u16*)&src)[1] = value; -} - -static __forceinline void SetLoWord( u32& src, u16 value ) -{ - ((u16*)&src)[0] = value; -} - -static __forceinline u16 GetHiWord( u32& src ) -{ - return ((u16*)&src)[1]; -} - -static __forceinline u16 GetLoWord( u32& src ) -{ - return ((u16*)&src)[0]; -} - template< int CoreIdx, int VoiceIdx, int param > static void __fastcall RegWrite_VoiceParams( u16 value ) { @@ -871,7 +1066,7 @@ static void __fastcall RegWrite_Core( u16 value ) const int omem = cAddr; const int core = CoreIdx; V_Core& thiscore = Cores[core]; - + //ConLog("RegWrite_Core #%d addr: %x value %x \n", core, omem, value); switch(omem) { case REG__1AC: @@ -899,35 +1094,36 @@ static void __fastcall RegWrite_Core( u16 value ) case REG_C_ATTR: { - bool irqe = thiscore.IRQEnable; - int bit0 = thiscore.AttrBit0; - bool fxenable = thiscore.FxEnable; - u8 oldDmaMode = thiscore.DmaMode; - - thiscore.AttrBit0 =(value>> 0) & 0x01; //1 bit - thiscore.DMABits =(value>> 1) & 0x07; //3 bits - thiscore.DmaMode =(value>> 4) & 0x03; //2 bit (not necessary, we get the direction from the iop) - thiscore.IRQEnable =(value>> 6) & 0x01; //1 bit - thiscore.FxEnable =(value>> 7) & 0x01; //1 bit - thiscore.NoiseClk =(value>> 8) & 0x3f; //6 bits + bool irqe = thiscore.IRQEnable; + int bit0 = thiscore.AttrBit0; + bool fxenable = thiscore.FxEnable; + u8 oldDmaMode = thiscore.DmaMode; + + thiscore.AttrBit0 = (value >> 0) & 0x01; //1 bit + thiscore.DMABits = (value >> 1) & 0x07; //3 bits + thiscore.DmaMode = (value >> 4) & 0x03; //2 bit (not necessary, we get the direction from the iop) + thiscore.IRQEnable = (value >> 6) & 0x01; //1 bit + thiscore.FxEnable = (value >> 7) & 0x01; //1 bit + thiscore.NoiseClk = (value >> 8) & 0x3f; //6 bits //thiscore.Mute =(value>>14) & 0x01; //1 bit - thiscore.Mute =0; + thiscore.Mute = 0; //thiscore.CoreEnabled=(value>>15) & 0x01; //1 bit // no clue - if (value>>15) + if (value >> 15) thiscore.Regs.STATX = 0; - thiscore.Regs.ATTR =value&0x7fff; + thiscore.Regs.ATTR = value & 0x7fff; - if (fxenable && !thiscore.FxEnable - && (thiscore.EffectsStartA != thiscore.ExtEffectsStartA - || thiscore.EffectsEndA != thiscore.ExtEffectsEndA)) - { - thiscore.EffectsStartA = thiscore.ExtEffectsStartA; - thiscore.EffectsEndA = thiscore.ExtEffectsEndA; - thiscore.ReverbX = 0; - thiscore.RevBuffers.NeedsUpdated = true; + if (!psxmode) { + if (fxenable && !thiscore.FxEnable + && (thiscore.EffectsStartA != thiscore.ExtEffectsStartA + || thiscore.EffectsEndA != thiscore.ExtEffectsEndA)) + { + thiscore.EffectsStartA = thiscore.ExtEffectsStartA; + thiscore.EffectsEndA = thiscore.ExtEffectsEndA; + thiscore.ReverbX = 0; + thiscore.RevBuffers.NeedsUpdated = true; + } } - if(oldDmaMode != thiscore.DmaMode) { // FIXME... maybe: if this mode was cleared in the middle of a DMA, should we interrupt it? @@ -947,7 +1143,7 @@ static void __fastcall RegWrite_Core( u16 value ) { //ConLog("* SPU2-X: Core%d IRQ %s at cycle %d. Current IRQA = %x Current EffectA = %x\n", // core, ((thiscore.IRQEnable==0)?"disabled":"enabled"), Cycles, thiscore.IRQA, thiscore.EffectsStartA); - + if(!thiscore.IRQEnable) Spdif.Info &= ~(4 << thiscore.Index); } @@ -990,8 +1186,8 @@ static void __fastcall RegWrite_Core( u16 value ) SetLoWord( thiscore.Regs.reg_out, value ); \ if( result == thiscore.Regs.reg_out ) break; \ \ - const uint start_bit = (hiword) ? 16 : 0; \ - const uint end_bit = (hiword) ? 24 : 16; \ + const uint start_bit = hiword ? 16 : 0; \ + const uint end_bit = hiword ? 24 : 16; \ for (uint vc=start_bit, vx=1; vc, RegWrite_Core + RegWrite_Core, RegWrite_Core #define ReverbPair( core, mem ) \ - RegWrite_Reverb, RegWrite_Core + RegWrite_Reverb, RegWrite_Core #define REGRAW(addr) RegWrite_Raw