From 1ec70f1df35ccdd12a43bea20dac85c243d21f3a Mon Sep 17 00:00:00 2001 From: Robert Neumann Date: Sun, 9 Oct 2016 00:11:50 +0200 Subject: [PATCH] psxmode: Spu2x now working correctly. Kudos to pseudonym. Took him 30 minutes to fix this! --- plugins/spu2-x/src/Mixer.cpp | 35 +++--- plugins/spu2-x/src/defs.h | 22 ---- plugins/spu2-x/src/spu2sys.cpp | 203 ++++++++++++++------------------- 3 files changed, 101 insertions(+), 159 deletions(-) diff --git a/plugins/spu2-x/src/Mixer.cpp b/plugins/spu2-x/src/Mixer.cpp index 414da0ba53..b4c96cfb38 100644 --- a/plugins/spu2-x/src/Mixer.cpp +++ b/plugins/spu2-x/src/Mixer.cpp @@ -128,8 +128,7 @@ static void __forceinline IncrementNextA(V_Core& thiscore, uint voiceidx) } vc.NextA++; - if (psxmode) vc.NextA &= 0x7FFFF; - else vc.NextA&=0xFFFFF; + vc.NextA&=0xFFFFF; } // decoded pcm data, used to cache the decoded data so that it needn't be decoded @@ -589,10 +588,8 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx ) // Write-back of raw voice data (post ADSR applied) - 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); - } + 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 @@ -611,10 +608,8 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx ) } // Write-back of raw voice data (some zeros since the voice is "dead") - 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); - } + 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 ); } } @@ -645,13 +640,11 @@ 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 ) ); - 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 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) @@ -838,11 +831,9 @@ void Mix() Ext = clamp_mix( ApplyVolume( Ext, Cores[0].MasterVol ) ); } - if (!psxmode) { - // Commit Core 0 output to ram before mixing Core 1: - spu2M_WriteFast(0x800 + OutPos, Ext.Left); - spu2M_WriteFast(0xA00 + OutPos, Ext.Right); - } + // Commit Core 0 output to ram before mixing Core 1: + spu2M_WriteFast(0x800 + OutPos, Ext.Left); + spu2M_WriteFast(0xA00 + OutPos, Ext.Right); WaveDump::WriteCore( 0, CoreSrc_External, Ext ); diff --git a/plugins/spu2-x/src/defs.h b/plugins/spu2-x/src/defs.h index be28eec75d..2056686151 100644 --- a/plugins/spu2-x/src/defs.h +++ b/plugins/spu2-x/src/defs.h @@ -28,7 +28,6 @@ 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 ); @@ -155,10 +154,6 @@ 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) @@ -447,12 +442,8 @@ 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]; @@ -519,25 +510,12 @@ 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 8a410cd10c..9bf76ce866 100644 --- a/plugins/spu2-x/src/spu2sys.cpp +++ b/plugins/spu2-x/src/spu2sys.cpp @@ -44,6 +44,7 @@ bool has_to_call_irq=false; bool psxmode = false; +#define PSXUNLIKELYHACKS 1 void SetIrqCall(int core) { // reset by an irq disable/enable cycle, behaviour found by @@ -69,11 +70,6 @@ __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 ) @@ -409,7 +405,7 @@ __forceinline void TimeUpdate(u32 cClocks) Cores[0].DMAICounter-=TickInterval; if(Cores[0].DMAICounter<=0) { - ConLog("counter set and callback!\n"); + //ConLog("counter set and callback!\n"); Cores[0].MADR=Cores[0].TADR; Cores[0].DMAICounter=0; if(dma4callback) dma4callback(); @@ -519,6 +515,17 @@ static __forceinline u16 GetLoWord(u32& src) return ((u16*)&src)[0]; } +static u32 map_spu1to2(u32 addr) +{ + return addr * 4 + (addr >= 0x100 ? 0xc0000 : 0); +} + +static u32 map_spu2to1(u32 addr) +{ + // if (addr >= 0x800 && addr < 0x80000) oh dear + return (addr - (addr >= 0xc0000 ? 0xc0000 : 0)) / 4; +} + void V_Core::WriteRegPS1( u32 mem, u16 value ) { pxAssume( Index == 0 ); // Valid on Core 0 only! @@ -535,33 +542,9 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) switch(vval) { case 0x0: //VOLL (Volume L) - { - 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) { - V_VolumeSlide& thisvol = Voices[voice].Volume.Right; + V_VolumeSlide& thisvol = vval == 0 ? Voices[voice].Volume.Left : Voices[voice].Volume.Right; thisvol.Reg_VOL = value; if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp @@ -581,7 +564,7 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) thisvol.Mode = 0; thisvol.Increment = 0; } - ConLog("voice %x VOLR write: %x\n", voice, value); + //ConLog("voice %x VOL%c write: %x\n", voice, vval == 0 ? 'L' : 'R', value); break; } case 0x4: @@ -590,8 +573,7 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) //ConLog("voice %x Pitch write: %x\n", voice, Voices[voice].Pitch); break; case 0x6: - Voices[voice].StartA = value * 8; - Voices[voice].psxStartA = value; + Voices[voice].StartA = map_spu1to2(value); //ConLog("voice %x StartA write: %x\n", voice, Voices[voice].StartA); break; @@ -606,12 +588,11 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) break; case 0xc: // Voice 0..23 ADSR Current Volume // not commonly set by games - Voices[voice].ADSR.Value = (value << 16) | value; + Voices[voice].ADSR.Value = value * 0x10001U; 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; + Voices[voice].LoopStartA = map_spu1to2(value); //ConLog("voice %x LoopStartA write: %x\n", voice, Voices[voice].LoopStartA); break; @@ -713,89 +694,87 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) case 0x1da2:// Reverb work area start { - EffectsStartA = value * 8; - EffectsEndA = 0x7FFFF; // fixed EndA in psx mode - psxReverbStartA = value; + EffectsStartA = map_spu1to2(value); + EffectsEndA = 0xFFFFF; // fixed EndA in psx mode Cores[0].RevBuffers.NeedsUpdated = true; } break; case 0x1da4: - IRQA = value * 8; - psxIRQA = value; - ConLog("SPU2-X Setting IRQA to %x \n", IRQA); + IRQA = map_spu1to2(value); + //ConLog("SPU2-X Setting IRQA to %x \n", IRQA); break; case 0x1da6: - TSA = value * 8; - psxTSA = value; - ConLog("SPU2-X Setting TSA to %x \n", TSA); + TSA = map_spu1to2(value); + //ConLog("SPU2-X Setting TSA to %x \n", TSA); break; case 0x1da8: // Spu Write to Memory - ConLog("SPU direct DMA Write. Current TSA = %x\n", TSA); + //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); - //DmaWrite(value); + DmaWrite(value); show = false; break; case 0x1daa: { - 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; + V_Core& thiscore = Cores[0]; + bool irqe = thiscore.IRQEnable; + int bit0 = thiscore.AttrBit0; + bool fxenable = thiscore.FxEnable; + u8 oldDmaMode = thiscore.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.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 - Cores[0].Mute = 0; + thiscore.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; + thiscore.Regs.STATX = 0; + thiscore.Regs.ATTR = value & 0x7fff; - if (fxenable && !Cores[0].FxEnable) + if (fxenable && !thiscore.FxEnable + && (thiscore.EffectsStartA != thiscore.ExtEffectsStartA + || thiscore.EffectsEndA != thiscore.ExtEffectsEndA)) { - Cores[0].ReverbX = 0; - Cores[0].RevBuffers.NeedsUpdated = true; + thiscore.EffectsStartA = thiscore.ExtEffectsStartA; + thiscore.EffectsEndA = thiscore.ExtEffectsEndA; + thiscore.ReverbX = 0; + thiscore.RevBuffers.NeedsUpdated = true; } - if (oldDmaMode != Cores[0].DmaMode) + if (oldDmaMode != thiscore.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 + thiscore.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 (MsgToConsole()) ConLog("* SPU2-X: Core 0 ATTR unknown bits SET! value=%04x\n", value); } - if (Cores[0].AttrBit0 != bit0) + if (thiscore.AttrBit0 != bit0) { - if (MsgToConsole()) ConLog("* SPU2-X: ATTR bit 0 set to %d\n", Cores[0].AttrBit0); + if (MsgToConsole()) ConLog("* SPU2-X: ATTR bit 0 set to %d\n", thiscore.AttrBit0); } - if (Cores[0].IRQEnable != irqe) + if (thiscore.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); + //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 (!Cores[0].IRQEnable) - Spdif.Info &= ~(4 << Cores[0].Index); + if (!thiscore.IRQEnable) + Spdif.Info &= ~(4 << thiscore.Index); } } break; @@ -869,7 +848,7 @@ u16 V_Core::ReadRegPS1(u32 mem) //ConLog("voice %d read pitch result = %x\n", voice, value); break; case 0x6: - value = Voices[voice].psxStartA; + value = map_spu2to1(Voices[voice].StartA); //ConLog("voice %d read StartA result = %x\n", voice, value); break; case 0x8: @@ -883,7 +862,7 @@ u16 V_Core::ReadRegPS1(u32 mem) //if (value != 0) ConLog("voice %d read ADSR.Value result = %x\n", voice, value); break; case 0xe: - value = Voices[voice].psxLoopStartA; + value = map_spu2to1(Voices[voice].LoopStartA); //ConLog("voice %d read LoopStartA result = %x\n", voice, value); break; @@ -916,32 +895,30 @@ u16 V_Core::ReadRegPS1(u32 mem) case 0x1d9e: value = Regs.ENDX >> 16; case 0x1da2: - value = psxReverbStartA; + value = map_spu2to1(EffectsStartA); break; case 0x1da4: - value = psxIRQA; - ConLog("SPU2-X IRQA read: 0x1da4 = %x , (IRQA = %x)\n", value, IRQA); + value = map_spu2to1(IRQA); + //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); + value = map_spu2to1(TSA); + //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); + //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); + value = Cores[0].Regs.STATX; + //ConLog("SPU2-X ps1 reg REG_P_STATX read return value: %x\n", value); break; } @@ -1114,16 +1091,14 @@ static void __fastcall RegWrite_Core( u16 value ) thiscore.Regs.STATX = 0; thiscore.Regs.ATTR = value & 0x7fff; - 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 (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) { @@ -1320,24 +1295,22 @@ static void __fastcall RegWrite_Core( u16 value ) case REG_S_ADMAS: if ( MsgToConsole() ) ConLog("* SPU2-X: Core %d AutoDMAControl set to %d (at cycle %d)\n",core,value, Cycles); + + if (psxmode) ConLog("* SPU2-X: Writing to REG_S_ADMAS while in PSX mode! value: %x",value); // hack for ps1driver which writes -1 (and never turns the adma off after psxlogo). // adma isn't available in psx mode either - if (value == 32767) { + if (value == 32767 && PSXUNLIKELYHACKS) { psxmode = true; - //memset(spu2regs, 0, 0x010000); - memset(_spu2mem, 0, 0x200000); - Cores[0].EffectsStartA = 0x7FFF8; - Cores[0].EffectsEndA = 0x7FFFF; - Cores[0].ReverbX = 0; - Cores[0].RevBuffers.NeedsUpdated = true; - Cores[1].EffectsStartA = 0xFFFF8; // park core1 effect area in high mem - Cores[1].EffectsEndA = 0xFFFFF; + //memset(_spu2mem, 0, 0x200000); Cores[1].FxEnable = 0; - Cores[1].ExtEffectsStartA = 0xFFFF8; // park core1 ext effect area in high mem - Cores[1].ExtEffectsStartA = 0xFFFFF; + Cores[1].EffectsStartA = 0x7FFF8; // park core1 effect area in inaccessible mem + Cores[1].EffectsEndA = 0x7FFFF; + Cores[1].ExtEffectsStartA = 0x7FFF8; // park core1 ext effect area in high mem + Cores[1].ExtEffectsStartA = 0x7FFFF; Cores[1].ReverbX = 0; Cores[1].RevBuffers.NeedsUpdated = true; - Cores[1].Mute = 1; // silence core1 in psxmode + Cores[0].ReverbX = 0; + Cores[0].RevBuffers.NeedsUpdated = true; for (uint v = 0; v < 24; ++v) { Cores[1].Voices[v].Volume = V_VolumeSlideLR(0, 0); // V_VolumeSlideLR::Max; @@ -1346,9 +1319,9 @@ static void __fastcall RegWrite_Core( u16 value ) Cores[1].Voices[v].ADSR.Value = 0; Cores[1].Voices[v].ADSR.Phase = 0; Cores[1].Voices[v].Pitch = 0x0; - Cores[1].Voices[v].NextA = 0xBFFFF; - Cores[1].Voices[v].StartA = 0xBFFFF; - Cores[1].Voices[v].LoopStartA = 0xBFFFF; + Cores[1].Voices[v].NextA = 0x6FFFF; + Cores[1].Voices[v].StartA = 0x6FFFF; + Cores[1].Voices[v].LoopStartA = 0x6FFFF; Cores[1].Voices[v].Modulated = 0; } return;