diff --git a/plugins/spu2-x/src/Debug.cpp b/plugins/spu2-x/src/Debug.cpp index 114f728ff1..0ae0751025 100644 --- a/plugins/spu2-x/src/Debug.cpp +++ b/plugins/spu2-x/src/Debug.cpp @@ -177,8 +177,8 @@ void DoFullDump() " - Rm: %x\n" " - Phase: %x\n" " - Value: %x\n", - Cores[c].Voices[v].ADSR.Reg_ADSR1, - Cores[c].Voices[v].ADSR.Reg_ADSR2, + Cores[c].Voices[v].ADSR.regADSR1, + Cores[c].Voices[v].ADSR.regADSR2, Cores[c].Voices[v].ADSR.AttackRate, Cores[c].Voices[v].ADSR.AttackMode, Cores[c].Voices[v].ADSR.DecayRate, diff --git a/plugins/spu2-x/src/PS2E-spu2.cpp b/plugins/spu2-x/src/PS2E-spu2.cpp index ab3f80c959..42bd93d4ba 100644 --- a/plugins/spu2-x/src/PS2E-spu2.cpp +++ b/plugins/spu2-x/src/PS2E-spu2.cpp @@ -19,7 +19,6 @@ #include "PS2E-spu2.h" #include "dma.h" #include "Dialogs.h" -#include "RegTable.h" #ifdef _MSC_VER # include "svnrev.h" @@ -216,11 +215,7 @@ EXPORT_C_(void) CALLBACK SPU2interruptDMA7() EXPORT_C_(s32) SPU2init() { -#define MAKESURE(a,b) \ - /*fprintf(stderr,"%08p: %08p == %08p\n",&(regtable[a>>1]),regtable[a>>1],U16P(b));*/ \ - assert(regtable[(a)>>1]==U16P(b)) - - MAKESURE(0x800,zero); + assert( regtable[0x400] == NULL ); s32 c=0,v=0; ReadSettings(); @@ -271,6 +266,8 @@ EXPORT_C_(s32) SPU2init() memset(spu2regs, 0, 0x010000); memset(_spu2mem, 0, 0x200000); + Cores[0].Index = 0; + Cores[1].Index = 1; Cores[0].Reset(); Cores[1].Reset(); diff --git a/plugins/spu2-x/src/RegLog.cpp b/plugins/spu2-x/src/RegLog.cpp index 26b24bdafc..bc95c398f2 100644 --- a/plugins/spu2-x/src/RegLog.cpp +++ b/plugins/spu2-x/src/RegLog.cpp @@ -16,7 +16,6 @@ */ #include "Global.h" -#include "RegTable.h" const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"}; const char *AddressNames[6]={"SSAH","SSAL","LSAH","LSAL","NAXH","NAXL"}; @@ -89,8 +88,8 @@ void SPU2writeLog( const char* action, u32 rmem, u16 value ) case SPDIF_OUT: RegLog(2,"SPDIF_OUT",rmem,-1,value); break; - case IRQINFO: - RegLog(2,"IRQINFO",rmem,-1,value); + case SPDIF_IRQINFO: + RegLog(2,"SPDIF_IRQINFO",rmem,-1,value); break; case 0x7c4: if(Spdif.Unknown1 != value) ConLog(" * SPU2: SPDIF Unknown Register 1 set to %04x\n",value); diff --git a/plugins/spu2-x/src/RegTable.cpp b/plugins/spu2-x/src/RegTable.cpp index 9f01381d12..3028204f0c 100644 --- a/plugins/spu2-x/src/RegTable.cpp +++ b/plugins/spu2-x/src/RegTable.cpp @@ -16,12 +16,6 @@ */ #include "Global.h" -#include "RegTable.h" - -// This var is used to confirm that our lookup table is "correct" -// If the assertion in DllMain fails, it means the table has too too few entries. -// (it can't have too many because that would generate a compiler error). -const u16 zero = 0; #define PCORE(c,p) \ U16P(Cores[c].p) @@ -33,8 +27,8 @@ const u16 zero = 0; PVCP(c,v,Volume.Left.Reg_VOL), \ PVCP(c,v,Volume.Right.Reg_VOL), \ PVCP(c,v,Pitch), \ - PVCP(c,v,ADSR.Reg_ADSR1), \ - PVCP(c,v,ADSR.Reg_ADSR2), \ + PVCP(c,v,ADSR.regADSR1), \ + PVCP(c,v,ADSR.regADSR2), \ PVCP(c,v,ADSR.Value)+1, \ PVCP(c,v,Volume.Left.Value)+1, \ PVCP(c,v,Volume.Right.Value)+1 @@ -54,8 +48,7 @@ const u16 zero = 0; PCORE(c,Revb.n)+1, \ PCORE(c,Revb.n) -#pragma pack(1) -u16* regtable[0x800] = +u16* regtable[0x401] = { // Voice Params: 8 params, 24 voices = 0x180 bytes PVC(0, 0),PVC(0, 1),PVC(0, 2),PVC(0, 3),PVC(0, 4),PVC(0, 5), @@ -75,22 +68,20 @@ u16* regtable[0x800] = PCORE(0,Regs.VMIXR)+1, PCORE(0,Regs.VMIXER), PCORE(0,Regs.VMIXER)+1, - PCORE(0,Regs.MMIX), + PCORE(0,Regs.MMIX), PCORE(0,Regs.ATTR), PCORE(0,IRQA)+1, PCORE(0,IRQA), - U16P(zero), - U16P(zero), - U16P(zero), - U16P(zero), + NULL, NULL, + NULL, NULL, PCORE(0,TSA)+1, PCORE(0,TSA), - PRAW(0x1ac), PRAW(0x1ae), + PRAW(REG__1AC), PRAW(REG__1AE), PCORE(0,AutoDMACtrl), @@ -129,7 +120,7 @@ u16* regtable[0x800] = PREVB_REG(0,MIX_DEST_B1), PCORE(0,EffectsEndA)+1, - U16P(zero), + NULL, PCORE(0,Regs.ENDX), PCORE(0,Regs.ENDX)+1, @@ -187,10 +178,8 @@ u16* regtable[0x800] = PCORE(1,IRQA)+1, PCORE(1,IRQA), - U16P(zero), - U16P(zero), - U16P(zero), - U16P(zero), + NULL, NULL, + NULL, NULL, PCORE(1,TSA)+1, PCORE(1,TSA), @@ -234,7 +223,7 @@ u16* regtable[0x800] = PREVB_REG(1,MIX_DEST_B1), PCORE(1,EffectsEndA)+1, - U16P(zero), + NULL, PCORE(1,Regs.ENDX), PCORE(1,Regs.ENDX)+1, @@ -308,6 +297,5 @@ u16* regtable[0x800] = PRAW(0x7F0),PRAW(0x7F2),PRAW(0x7F4),PRAW(0x7F6), PRAW(0x7F8),PRAW(0x7FA),PRAW(0x7FC),PRAW(0x7FE), - U16P(zero) + NULL }; -#pragma pack() \ No newline at end of file diff --git a/plugins/spu2-x/src/RegTable.h b/plugins/spu2-x/src/RegTable.h deleted file mode 100644 index e9a94ceccc..0000000000 --- a/plugins/spu2-x/src/RegTable.h +++ /dev/null @@ -1,32 +0,0 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library 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 Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#ifndef _REGTABLE_H_ -#define _REGTABLE_H_ - -#define U16P(x) ( (u16*)&(x) ) - -// Returns the hiword of a 32 bit integer. -#define U16P_HI(x) ( ((u16*)&(x))+1 ) - -// Yay! Global namespace pollution 101! -extern const u16 zero; - -extern u16* regtable[0x800]; - -#endif \ No newline at end of file diff --git a/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp b/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp index bfcf05904c..d4a9e2ab4d 100644 --- a/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp +++ b/plugins/spu2-x/src/Windows/RealtimeDebugger.cpp @@ -18,7 +18,6 @@ #include "Global.h" #include "Dialogs.h" -#include "../RegTable.h" static bool debugDialogOpen=false; diff --git a/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj b/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj index fe52c0d5ad..d0da354d3c 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj +++ b/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj @@ -990,10 +990,6 @@ RelativePath="..\RegTable.cpp" > - - diff --git a/plugins/spu2-x/src/defs.h b/plugins/spu2-x/src/defs.h index 7df50a66ec..c113aca54a 100644 --- a/plugins/spu2-x/src/defs.h +++ b/plugins/spu2-x/src/defs.h @@ -99,24 +99,35 @@ public: void DebugDump( FILE* dump, const char* title ); }; - struct V_ADSR { - u16 Reg_ADSR1; - u16 Reg_ADSR2; + union + { + u32 reg32; + + struct + { + u16 regADSR1; + u16 regADSR2; + }; + + struct + { + u32 SustainLevel:4, + DecayRate:4, + AttackRate:7, + AttackMode:1, // 0 for linear (+lin), 1 for pseudo exponential (+exp) - s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0) [Reg_ENVX] - u8 Phase; - u8 AttackRate; // Ar - u8 AttackMode; // Am - u8 DecayRate; // Dr - u8 SustainLevel; // Sl - u8 SustainRate; // Sr - u8 SustainMode; // Sm - u8 ReleaseRate; // Rr - u8 ReleaseMode; // Rm + ReleaseRate:5, + ReleaseMode:1, // 0 for linear (-lin), 1 for exponential (-exp) + SustainRate:7, + SustainMode:3; // 0 = +lin, 1 = -lin, 2 = +exp, 3 = -exp + }; + }; - bool Releasing; // Ready To Release, triggered by Voice.Stop(); + s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0) [Reg_ENVX] + u8 Phase; // monitors current phase of ADSR envelope + bool Releasing; // Ready To Release, triggered by Voice.Stop(); public: bool Calculate(); @@ -133,10 +144,6 @@ struct V_Voice V_ADSR ADSR; // Pitch (also Reg_PITCH) s16 Pitch; -// Pitch Modulated by previous voice - s8 Modulated; -// Source (Wave/Noise) - s8 Noise; // Loop Start address (also Reg_LSAH/L) u32 LoopStartA; // Sound Start address (also Reg_SSAH/L) @@ -147,15 +154,14 @@ struct V_Voice s32 Prev1; s32 Prev2; + // Pitch Modulated by previous voice + bool Modulated; + // Source (Wave/Noise) + bool Noise; + s8 LoopMode; s8 LoopFlags; -// [Air] : Replaced loop flags read from the ADPCM header with -// a single LoopFlags value (above) -- more cache-friendly. - //s8 LoopStart; - //s8 Loop; - //s8 LoopEnd; - // Sample pointer (19:12 bit fixed point) s32 SP; @@ -303,8 +309,9 @@ struct V_CoreRegs u32 VMIXR; u32 VMIXEL; u32 VMIXER; - u16 MMIX; u32 ENDX; + + u16 MMIX; u16 STATX; u16 ATTR; u16 _1AC; @@ -374,17 +381,18 @@ struct V_Core u32 TSA; // DMA Transfer Start Address u32 TDA; // DMA Transfer Data Address (Internal...) - s8 IRQEnable; // Interrupt Enable + bool IRQEnable; // Interrupt Enable + bool FxEnable; // Effect Enable + bool Mute; // Mute + bool AdmaInProgress; + s8 DMABits; // DMA related? - s8 FxEnable; // Effect Enable s8 NoiseClk; // Noise Clock u16 AutoDMACtrl; // AutoDMA Status s32 DMAICounter; // DMA Interrupt Counter - s8 Mute; // Mute u32 InputDataLeft; // Input Buffer u32 InputPos; u32 InputDataProgress; - u8 AdmaInProgress; V_Reverb Revb; // Reverb Registers V_ReverbBuffers RevBuffers; // buffer pointers for reverb, pre-calculated and pre-clipped. diff --git a/plugins/spu2-x/src/regs.h b/plugins/spu2-x/src/regs.h index 7b1f92c7aa..38d11cd1b9 100644 --- a/plugins/spu2-x/src/regs.h +++ b/plugins/spu2-x/src/regs.h @@ -127,10 +127,10 @@ // SPDIF interface #define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass -#define IRQINFO 0x07C2 +#define SPDIF_IRQINFO 0x07C2 #define SPDIF_MODE 0x07C6 #define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD -#define SPDIF_PROTECT 0x07CC // SPDIF Copy Protection +#define SPDIF_PROTECT 0x07CC // SPDIF Copy Protection /********************************************************************* @@ -180,3 +180,16 @@ Core attributes (SD_C) #define VOICE_ADDR_LSAX 0x4 // Loop point address #define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next + + +// -------------------------------------------------------------------------------------- +// SPU2-X Register Table LUT +// -------------------------------------------------------------------------------------- + +#define U16P(x) ( (u16*)&(x) ) + +// Returns the hiword of a 32 bit integer. +#define U16P_HI(x) ( ((u16*)&(x))+1 ) + +extern u16* regtable[0x401]; + diff --git a/plugins/spu2-x/src/spu2sys.cpp b/plugins/spu2-x/src/spu2sys.cpp index 9798ed1fc0..9e082c836e 100644 --- a/plugins/spu2-x/src/spu2sys.cpp +++ b/plugins/spu2-x/src/spu2sys.cpp @@ -23,7 +23,6 @@ #include "Global.h" -#include "RegTable.h" #include "dma.h" #include "PS2E-spu2.h" // needed until I figure out a nice solution for irqcallback dependencies. @@ -274,65 +273,6 @@ static const int SanityInterval = 4800; u32 TicksCore = 0; u32 TicksThread = 0; -PCSX2_ALIGNED16( static u64 g_globalMMXData[8] ); - -static __forceinline void SaveMMXRegs() -{ -#ifdef _MSC_VER - __asm { - movntq mmword ptr [g_globalMMXData + 0], mm0 - movntq mmword ptr [g_globalMMXData + 8], mm1 - movntq mmword ptr [g_globalMMXData + 16], mm2 - movntq mmword ptr [g_globalMMXData + 24], mm3 - movntq mmword ptr [g_globalMMXData + 32], mm4 - movntq mmword ptr [g_globalMMXData + 40], mm5 - movntq mmword ptr [g_globalMMXData + 48], mm6 - movntq mmword ptr [g_globalMMXData + 56], mm7 - emms - } -#else - __asm__(".intel_syntax\n" - "movq [%0+0x00], %%mm0\n" - "movq [%0+0x08], %%mm1\n" - "movq [%0+0x10], %%mm2\n" - "movq [%0+0x18], %%mm3\n" - "movq [%0+0x20], %%mm4\n" - "movq [%0+0x28], %%mm5\n" - "movq [%0+0x30], %%mm6\n" - "movq [%0+0x38], %%mm7\n" - "emms\n" - ".att_syntax\n" : : "r"(g_globalMMXData) ); -#endif -} - -static __forceinline void RestoreMMXRegs() -{ -#ifdef _MSC_VER - __asm { - movq mm0, mmword ptr [g_globalMMXData + 0] - movq mm1, mmword ptr [g_globalMMXData + 8] - movq mm2, mmword ptr [g_globalMMXData + 16] - movq mm3, mmword ptr [g_globalMMXData + 24] - movq mm4, mmword ptr [g_globalMMXData + 32] - movq mm5, mmword ptr [g_globalMMXData + 40] - movq mm6, mmword ptr [g_globalMMXData + 48] - movq mm7, mmword ptr [g_globalMMXData + 56] - emms - } -#else - __asm__(".intel_syntax\n" - "movq %%mm0, [%0+0x00]\n" - "movq %%mm1, [%0+0x08]\n" - "movq %%mm2, [%0+0x10]\n" - "movq %%mm3, [%0+0x18]\n" - "movq %%mm4, [%0+0x20]\n" - "movq %%mm5, [%0+0x28]\n" - "movq %%mm6, [%0+0x30]\n" - "movq %%mm7, [%0+0x38]\n" - "emms\n" - ".att_syntax\n" : : "r"(g_globalMMXData) ); -#endif -} __forceinline void TimeUpdate(u32 cClocks) { @@ -423,7 +363,7 @@ __forceinline void TimeUpdate(u32 cClocks) static u16 mask = 0xFFFF; -void UpdateSpdifMode() +__forceinline void UpdateSpdifMode() { int OPM=PlayMode; u16 last = 0; @@ -504,19 +444,11 @@ void V_Core::WriteRegPS1( u32 mem, u16 value ) case 3: Voices[voice].StartA = (u32)value<<8; break; case 4: // ADSR1 (Envelope) - Voices[voice].ADSR.AttackMode = (value & 0x8000)>>15; - Voices[voice].ADSR.AttackRate = (value & 0x7F00)>>8; - Voices[voice].ADSR.DecayRate = (value & 0xF0)>>4; - Voices[voice].ADSR.SustainLevel = (value & 0xF); - Voices[voice].ADSR.Reg_ADSR1 = value; + Voices[voice].ADSR.regADSR1 = value; break; case 5: // ADSR2 (Envelope) - Voices[voice].ADSR.SustainMode = (value & 0xE000)>>13; - Voices[voice].ADSR.SustainRate = (value & 0x1FC0)>>6; - Voices[voice].ADSR.ReleaseMode = (value & 0x20)>>5; - Voices[voice].ADSR.ReleaseRate = (value & 0x1F); - Voices[voice].ADSR.Reg_ADSR2 = value; + Voices[voice].ADSR.regADSR2 = value; break; case 6: @@ -667,8 +599,8 @@ u16 V_Core::ReadRegPS1(u32 mem) case 2: value = Voices[voice].Pitch; break; case 3: value = Voices[voice].StartA; break; - case 4: value = Voices[voice].ADSR.Reg_ADSR1; break; - case 5: value = Voices[voice].ADSR.Reg_ADSR2; 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; @@ -766,415 +698,721 @@ static __forceinline u16 GetLoWord( s32& src ) return ((u16*)&src)[0]; } -#ifndef __LINUX__ -__forceinline -#endif -void SPU2_FastWrite( u32 rmem, u16 value ) +template< int CoreIdx, int VoiceIdx, int param > +static void __fastcall RegWrite_VoiceParams( u16 value ) { - u32 vx=0, vc=0, core=0, omem, mem; - omem=mem=rmem & 0x7FF; //FFFF; - if (mem & 0x400) { omem^=0x400; core=1; } + const int core = CoreIdx; + const int voice = VoiceIdx; - if (omem < 0x0180) // Voice Params + V_Voice& thisvoice = Cores[core].Voices[voice]; + + switch (param) { - const u32 voice = (omem & 0x1F0) >> 4; - const u32 param = (omem & 0xF) >> 1; - V_Voice& thisvoice = Cores[core].Voices[voice]; - - switch (param) + case 0: //VOLL (Volume L) + case 1: //VOLR (Volume R) { - case 0: //VOLL (Volume L) - case 1: //VOLR (Volume R) - { - V_VolumeSlide& thisvol = (param==0) ? thisvoice.Volume.Left : thisvoice.Volume.Right; - thisvol.Reg_VOL = value; + V_VolumeSlide& thisvol = (param==0) ? thisvoice.Volume.Left : thisvoice.Volume.Right; + thisvol.Reg_VOL = value; - if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp + if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp + { + thisvol.Mode = (value & 0xF000)>>12; + thisvol.Increment = (value & 0x3F); + } + 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; + } + } + break; + + case 2: + thisvoice.Pitch = value; + break; + + case 3: // ADSR1 (Envelope) + thisvoice.ADSR.regADSR1 = value; + break; + + case 4: // ADSR2 (Envelope) + thisvoice.ADSR.regADSR2 = value; + break; + + case 5: + // [Air] : Mysterious ADSR set code. Too bad none of my games ever use it. + // (as usual... ) + thisvoice.ADSR.Value = (value << 16) | value; + ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); + break; + + case 6: thisvoice.Volume.Left.RegSet( value ); break; + case 7: thisvoice.Volume.Right.RegSet( value ); break; + + jNO_DEFAULT; + } +} + +template< int CoreIdx, int VoiceIdx, int address > +static void __fastcall RegWrite_VoiceAddr( u16 value ) +{ + const int core = CoreIdx; + const int voice = VoiceIdx; + + V_Voice& thisvoice = Cores[core].Voices[voice]; + + switch (address) + { + case 0: // SSA (Waveform Start Addr) (hiword, 4 bits only) + thisvoice.StartA = ((value & 0x0F) << 16) | (thisvoice.StartA & 0xFFF8); + if( IsDevBuild ) + DebugCores[core].Voices[voice].lastSetStartA = thisvoice.StartA; + break; + + case 1: // SSA (loword) + thisvoice.StartA = (thisvoice.StartA & 0x0F0000) | (value & 0xFFF8); + if( IsDevBuild ) + DebugCores[core].Voices[voice].lastSetStartA = thisvoice.StartA; + break; + + case 2: + thisvoice.LoopStartA = ((value & 0x0F) << 16) | (thisvoice.LoopStartA & 0xFFF8); + thisvoice.LoopMode = 3; + break; + + case 3: + thisvoice.LoopStartA = (thisvoice.LoopStartA & 0x0F0000) | (value & 0xFFF8); + thisvoice.LoopMode = 3; + break; + + case 4: + thisvoice.NextA = ((value & 0x0F) << 16) | (thisvoice.NextA & 0xFFF8); + break; + + case 5: + thisvoice.NextA = (thisvoice.NextA & 0x0F0000) | (value & 0xFFF8); + break; + } +} + +template< int CoreIdx, int cAddr > +static void __fastcall RegWrite_Core( u16 value ) +{ + const int omem = cAddr; + const int core = CoreIdx; + V_Core& thiscore = Cores[core]; + + switch(omem) + { + case REG__1AC: + // ---------------------------------------------------------------------------- + // 0x1ac / 0x5ac : direct-write to DMA address : special register (undocumented) + // ---------------------------------------------------------------------------- + // On the GS, DMAs are actually pushed through a hardware register. Chances are the + // SPU works the same way, and "technically" *all* DMA data actually passes through + // the HW registers at 0x1ac (core0) and 0x5ac (core1). We handle normal DMAs in + // optimized block copy fashion elsewhere, but some games will write this register + // directly, so handle those here: + + // Performance Note: The PS2 Bios uses this extensively right before booting games, + // causing massive slowdown if we don't shortcut it here. + + for( int i=0; i<2; i++ ) + { + if(Cores[i].IRQEnable && (Cores[i].IRQA == Cores[i].TSA)) { - thisvol.Mode = (value & 0xF000)>>12; - thisvol.Increment = (value & 0x3F); + Spdif.Info = 4 << i; + SetIrqCall(); + } + } + thiscore.DmaWrite( value ); + break; + + case REG_C_ATTR: + { + bool irqe = thiscore.IRQEnable; + int bit0 = thiscore.AttrBit0; + int bit4 = thiscore.AttrBit4; + + if( ((value>>15)&1) && (!thiscore.CoreEnabled) && (thiscore.InitDelay==0) ) // on init/reset + { + // When we have exact cycle update info from the Pcsx2 IOP unit, then use + // the more accurate delayed initialization system. + + if(cyclePtr != NULL) + { + thiscore.InitDelay = 1; + thiscore.Regs.STATX = 0; } 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; + thiscore.Reset(); } } - break; - case 2: thisvoice.Pitch=value; break; - case 3: // ADSR1 (Envelope) - thisvoice.ADSR.AttackMode = (value & 0x8000)>>15; - thisvoice.ADSR.AttackRate = (value & 0x7F00)>>8; - thisvoice.ADSR.DecayRate = (value & 0xF0)>>4; - thisvoice.ADSR.SustainLevel = (value & 0xF); - thisvoice.ADSR.Reg_ADSR1 = value; break; - case 4: // ADSR2 (Envelope) - thisvoice.ADSR.SustainMode = (value & 0xE000)>>13; - thisvoice.ADSR.SustainRate = (value & 0x1FC0)>>6; - thisvoice.ADSR.ReleaseMode = (value & 0x20)>>5; - thisvoice.ADSR.ReleaseRate = (value & 0x1F); - thisvoice.ADSR.Reg_ADSR2 = value; break; - case 5: - // [Air] : Mysterious ADSR set code. Too bad none of my games ever use it. - // (as usual... ) - thisvoice.ADSR.Value = (value << 16) | value; - ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); - break; + thiscore.AttrBit0 =(value>> 0) & 0x01; //1 bit + thiscore.DMABits =(value>> 1) & 0x07; //3 bits + thiscore.AttrBit4 =(value>> 4) & 0x01; //1 bit + thiscore.AttrBit5 =(value>> 5) & 0x01; //1 bit + 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.CoreEnabled=(value>>15) & 0x01; //1 bit + thiscore.Regs.ATTR =value&0x7fff; - case 6: thisvoice.Volume.Left.RegSet( value ); break; - case 7: thisvoice.Volume.Right.RegSet( value ); break; - - jNO_DEFAULT; - } - } - else if ((omem >= 0x01C0) && (omem < 0x02DE)) - { - const u32 voice = ((omem-0x01C0) / 12); - const u32 address = ((omem-0x01C0) % 12) >> 1; - V_Voice& thisvoice = Cores[core].Voices[voice]; - - switch (address) - { - case 0: // SSA (Waveform Start Addr) (hiword, 4 bits only) - thisvoice.StartA = ((value & 0x0F) << 16) | (thisvoice.StartA & 0xFFF8); - if( IsDevBuild ) - DebugCores[core].Voices[voice].lastSetStartA = thisvoice.StartA; - break; - - case 1: // SSA (loword) - thisvoice.StartA = (thisvoice.StartA & 0x0F0000) | (value & 0xFFF8); - if( IsDevBuild ) - DebugCores[core].Voices[voice].lastSetStartA = thisvoice.StartA; - break; - - case 2: - thisvoice.LoopStartA = ((value & 0x0F) << 16) | (thisvoice.LoopStartA & 0xFFF8); - thisvoice.LoopMode = 3; - break; - - case 3: - thisvoice.LoopStartA = (thisvoice.LoopStartA & 0x0F0000) | (value & 0xFFF8); - thisvoice.LoopMode = 3; - break; - - case 4: - thisvoice.NextA = ((value & 0x0F) << 16) | (thisvoice.NextA & 0xFFF8); - break; - - case 5: - thisvoice.NextA = (thisvoice.NextA & 0x0F0000) | (value & 0xFFF8); - break; - } - } - else if((mem>=0x07C0) && (mem<0x07CE)) - { - *(regtable[mem>>1]) = value; - UpdateSpdifMode(); - } - else if( mem >= R_FB_SRC_A && mem < REG_A_EEA ) - { - // Signal to the Reverb code that the effects buffers need to be re-aligned. - // This is both simple, efficient, and safe, since we only want to re-align - // buffers after both hi and lo words have been written. - - *(regtable[mem>>1]) = value; - Cores[core].RevBuffers.NeedsUpdated = true; - } - else - { - V_Core& thiscore = Cores[core]; - switch(omem) - { - case 0x1ac: - // ---------------------------------------------------------------------------- - // 0x1ac / 0x5ac : direct-write to DMA address : special register (undocumented) - // ---------------------------------------------------------------------------- - // On the GS, DMAs are actually pushed through a hardware register. Chances are the - // SPU works the same way, and "technically" *all* DMA data actually passes through - // the HW registers at 0x1ac (core0) and 0x5ac (core1). We handle normal DMAs in - // optimized block copy fashion elsewhere, but some games will write this register - // directly, so handle those here: - - // Performance Note: If a game uses this extensively, it *will* be slow. I plan to - // fix that using a proper paged LUT someday. - - for( int i=0; i<2; i++ ) - { - if(Cores[i].IRQEnable && (Cores[i].IRQA == Cores[i].TSA)) - { - Spdif.Info = 4 << i; - SetIrqCall(); - } - } - thiscore.DmaWrite( value ); - break; - - case REG_C_ATTR: + if(value&0x000E) { - int irqe = thiscore.IRQEnable; - int bit0 = thiscore.AttrBit0; - int bit4 = thiscore.AttrBit4; - - if( ((value>>15)&1) && (!thiscore.CoreEnabled) && (thiscore.InitDelay==0) ) // on init/reset - { - // When we have exact cycle update info from the Pcsx2 IOP unit, then use - // the more accurate delayed initialization system. - - if(cyclePtr != NULL) - { - thiscore.InitDelay = 1; - thiscore.Regs.STATX = 0; - } - else - { - thiscore.Reset(); - } - } - - thiscore.AttrBit0 =(value>> 0) & 0x01; //1 bit - thiscore.DMABits =(value>> 1) & 0x07; //3 bits - thiscore.AttrBit4 =(value>> 4) & 0x01; //1 bit - thiscore.AttrBit5 =(value>> 5) & 0x01; //1 bit - 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.CoreEnabled=(value>>15) & 0x01; //1 bit - thiscore.Regs.ATTR =value&0x7fff; - - if(value&0x000E) - { - ConLog(" * SPU2: Core %d ATTR unknown bits SET! value=%04x\n",core,value); - } - - if(thiscore.AttrBit0!=bit0) - { - ConLog(" * SPU2: ATTR bit 0 set to %d\n",thiscore.AttrBit0); - } - if(thiscore.IRQEnable!=irqe) - { - ConLog(" * SPU2: IRQ %s\n",((thiscore.IRQEnable==0)?"disabled":"enabled")); - if(!thiscore.IRQEnable) - Spdif.Info=0; - } - + ConLog(" * SPU2: Core %d ATTR unknown bits SET! value=%04x\n",core,value); } - break; - case REG_S_PMON: - vx=2; for (vc=1;vc<16;vc++) { thiscore.Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } - SetLoWord( thiscore.Regs.PMON, value ); - break; + if(thiscore.AttrBit0!=bit0) + { + ConLog(" * SPU2: ATTR bit 0 set to %d\n",thiscore.AttrBit0); + } + if(thiscore.IRQEnable!=irqe) + { + ConLog(" * SPU2: IRQ %s\n",((thiscore.IRQEnable==0)?"disabled":"enabled")); + if(!thiscore.IRQEnable) + Spdif.Info=0; + } - case (REG_S_PMON + 2): - vx=1; for (vc=16;vc<24;vc++) { thiscore.Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } - SetHiWord( thiscore.Regs.PMON, value ); - break; + } + break; - case REG_S_NON: - vx=1; for (vc=0;vc<16;vc++) { thiscore.Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } - SetLoWord( thiscore.Regs.NON, value ); - break; + case REG_S_PMON: + for( int vc=1; vc<16; ++vc ) + thiscore.Voices[vc].Modulated = (value >> vc) & 1; + SetLoWord( thiscore.Regs.PMON, value ); + break; - case (REG_S_NON + 2): - vx=1; for (vc=16;vc<24;vc++) { thiscore.Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } - SetHiWord( thiscore.Regs.NON, value ); - break; + case (REG_S_PMON + 2): + for( int vc=0; vc<8; ++vc ) + thiscore.Voices[vc+16].Modulated = (value >> vc) & 1; + SetHiWord( thiscore.Regs.PMON, value ); + break; + + case REG_S_NON: + for( int vc=0; vc<16; ++vc) + thiscore.Voices[vc].Noise = (value >> vc) & 1; + SetLoWord( thiscore.Regs.NON, value ); + break; + + case (REG_S_NON + 2): + for( int vc=0; vc<8; ++vc ) + thiscore.Voices[vc+16].Noise = (value >> vc) & 1; + SetHiWord( thiscore.Regs.NON, value ); + break; // Games like to repeatedly write these regs over and over with the same value, hence // the shortcut that skips the bitloop if the values are equal. #define vx_SetSomeBits( reg_out, mask_out, hiword ) \ { \ - const u32 result = thiscore.Regs.reg_out; \ + const u32 result = thiscore.Regs.reg_out; \ if( hiword ) \ SetHiWord( thiscore.Regs.reg_out, value ); \ else \ 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; \ for (uint vc=start_bit, vx=1; vc>1]) = value; - break; + const int vx = value & ((core==0) ? 0xFF0 : 0xFFF); + thiscore.WetGate.ExtR = (vx & 0x001) ? -1 : 0; + thiscore.WetGate.ExtL = (vx & 0x002) ? -1 : 0; + thiscore.DryGate.ExtR = (vx & 0x004) ? -1 : 0; + thiscore.DryGate.ExtL = (vx & 0x008) ? -1 : 0; + thiscore.WetGate.InpR = (vx & 0x010) ? -1 : 0; + thiscore.WetGate.InpL = (vx & 0x020) ? -1 : 0; + thiscore.DryGate.InpR = (vx & 0x040) ? -1 : 0; + thiscore.DryGate.InpL = (vx & 0x080) ? -1 : 0; + thiscore.WetGate.SndR = (vx & 0x100) ? -1 : 0; + thiscore.WetGate.SndL = (vx & 0x200) ? -1 : 0; + thiscore.DryGate.SndR = (vx & 0x400) ? -1 : 0; + thiscore.DryGate.SndL = (vx & 0x800) ? -1 : 0; + thiscore.Regs.MMIX = value; } + break; + + case (REG_S_KON + 2): + StartVoices(core,((u32)value)<<16); + break; + + case REG_S_KON: + StartVoices(core,((u32)value)); + break; + + case (REG_S_KOFF + 2): + StopVoices(core,((u32)value)<<16); + break; + + case REG_S_KOFF: + StopVoices(core,((u32)value)); + break; + + case REG_S_ENDX: + thiscore.Regs.ENDX&=0x00FF0000; + break; + + case (REG_S_ENDX + 2): + thiscore.Regs.ENDX&=0xFFFF; + break; + + // Reverb Start and End Address Writes! + // * Yes, these are backwards from all the volumes -- the hiword comes FIRST (wtf!) + // * End position is a hiword only! Loword is always ffff. + // * The Reverb buffer position resets on writes to StartA. It probably resets + // on writes to End too. Docs don't say, but they're for PSX, which couldn't + // change the end address anyway. + + case REG_A_ESA: + SetHiWord( thiscore.EffectsStartA, value ); + thiscore.UpdateEffectsBufferSize(); + thiscore.ReverbX = 0; + break; + + case (REG_A_ESA + 2): + SetLoWord( thiscore.EffectsStartA, value ); + thiscore.UpdateEffectsBufferSize(); + thiscore.ReverbX = 0; + break; + + case REG_A_EEA: + thiscore.EffectsEndA = ((u32)value<<16) | 0xFFFF; + thiscore.UpdateEffectsBufferSize(); + thiscore.ReverbX = 0; + break; + + case REG_S_ADMAS: + //ConLog(" * SPU2: Core %d AutoDMAControl set to %d (%d)\n",core,value, Cycles); + thiscore.AutoDMACtrl=value; + + if(value==0) + { + thiscore.AdmaInProgress=0; + } + break; + + default: + { + const int addr = omem | ( (core == 1) ? 0x400 : 0 ); + *(regtable[addr>>1]) = value; + } + break; } } +template< int CoreIdx, int addr > +static void __fastcall RegWrite_CoreExt( u16 value ) +{ + V_Core& thiscore = Cores[CoreIdx]; + const int core = CoreIdx; + + switch(addr) + { + // Master Volume Address Write! + + case REG_P_MVOLL: + case REG_P_MVOLR: + { + V_VolumeSlide& thisvol = (addr==REG_P_MVOLL) ? thiscore.MasterVol.Left : thiscore.MasterVol.Right; + + if( value & 0x8000 ) // +Lin/-Lin/+Exp/-Exp + { + thisvol.Mode = (value & 0xE000) / 0x2000; + thisvol.Increment = (value & 0x7F); // | ((value & 0x800)/0x10); + } + 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.Value = GetVol32( value<<1 ); + thisvol.Mode = 0; + thisvol.Increment = 0; + } + thisvol.Reg_VOL = value; + } + break; + + case REG_P_EVOLL: + thiscore.FxVol.Left = GetVol32( value ); + break; + + case REG_P_EVOLR: + thiscore.FxVol.Right = GetVol32( value ); + break; + + case REG_P_AVOLL: + thiscore.ExtVol.Left = GetVol32( value ); + break; + + case REG_P_AVOLR: + thiscore.ExtVol.Right = GetVol32( value ); + break; + + case REG_P_BVOLL: + thiscore.InpVol.Left = GetVol32( value ); + break; + + case REG_P_BVOLR: + thiscore.InpVol.Right = GetVol32( value ); + break; + + default: + { + const int raddr = addr + ((core==1) ? 0x28 : 0 ); + *(regtable[raddr>>1]) = value; + } + break; + } +} + + +template< int core, int addr > +static void __fastcall RegWrite_Reverb( u16 value ) +{ + // Signal to the Reverb code that the effects buffers need to be re-aligned. + // This is both simple, efficient, and safe, since we only want to re-align + // buffers after both hi and lo words have been written. + + *(regtable[addr>>1]) = value; + Cores[core].RevBuffers.NeedsUpdated = true; +} + +template< int addr > +static void __fastcall RegWrite_SPDIF( u16 value ) +{ + *(regtable[addr>>1]) = value; + UpdateSpdifMode(); +} + +template< int addr > +static void __fastcall RegWrite_Raw( u16 value ) +{ + *(regtable[addr>>1]) = value; +} + +// -------------------------------------------------------------------------------------- +// Macros for tbl_reg_writes +// -------------------------------------------------------------------------------------- +#define VoiceParamsSet( core, voice ) \ + RegWrite_VoiceParams, RegWrite_VoiceParams, \ + RegWrite_VoiceParams, RegWrite_VoiceParams, \ + RegWrite_VoiceParams, RegWrite_VoiceParams, \ + RegWrite_VoiceParams, RegWrite_VoiceParams + +#define VoiceParamsCore( core ) \ + VoiceParamsSet(core, 0), VoiceParamsSet(core, 1), VoiceParamsSet(core, 2), VoiceParamsSet(core, 3 ), \ + VoiceParamsSet(core, 4), VoiceParamsSet(core, 5), VoiceParamsSet(core, 6), VoiceParamsSet(core, 7 ), \ + VoiceParamsSet(core, 8), VoiceParamsSet(core, 9), VoiceParamsSet(core, 10),VoiceParamsSet(core, 11 ), \ + VoiceParamsSet(core, 12),VoiceParamsSet(core, 13),VoiceParamsSet(core, 14),VoiceParamsSet(core, 15 ), \ + VoiceParamsSet(core, 16),VoiceParamsSet(core, 17),VoiceParamsSet(core, 18),VoiceParamsSet(core, 19 ), \ + VoiceParamsSet(core, 20),VoiceParamsSet(core, 21),VoiceParamsSet(core, 22),VoiceParamsSet(core, 23 ) + +#define VoiceAddrSet( core, voice ) \ + RegWrite_VoiceAddr, RegWrite_VoiceAddr, \ + RegWrite_VoiceAddr, RegWrite_VoiceAddr, \ + RegWrite_VoiceAddr, RegWrite_VoiceAddr + + +#define CoreParamsPair( core, omem ) \ + RegWrite_Core, RegWrite_Core + +#define ReverbPair( core, mem ) \ + RegWrite_Reverb, RegWrite_Core + +#define REGRAW(addr) RegWrite_Raw + +// -------------------------------------------------------------------------------------- +// tbl_reg_writes - Register Write Function Invocation LUT +// -------------------------------------------------------------------------------------- + +typedef void __fastcall RegWriteHandler( u16 value ); +static RegWriteHandler * const tbl_reg_writes[0x401] = +{ + VoiceParamsCore(0), // 0x000 -> 0x180 + CoreParamsPair(0,REG_S_PMON), + CoreParamsPair(0,REG_S_NON), + CoreParamsPair(0,REG_S_VMIXL), + CoreParamsPair(0,REG_S_VMIXEL), + CoreParamsPair(0,REG_S_VMIXR), + CoreParamsPair(0,REG_S_VMIXER), + + RegWrite_Core<0,REG_P_MMIX>, + RegWrite_Core<0,REG_C_ATTR>, + + CoreParamsPair(0,REG_A_IRQA), + CoreParamsPair(0,REG_S_KON), + CoreParamsPair(0,REG_S_KOFF), + CoreParamsPair(0,REG_A_TSA), + CoreParamsPair(0,REG__1AC), + + RegWrite_Core<0,REG_S_ADMAS>, + REGRAW(0x1b2), + + REGRAW(0x1b4), REGRAW(0x1b6), + REGRAW(0x1b8), REGRAW(0x1ba), + REGRAW(0x1bc), REGRAW(0x1be), + + // 0x1c0! + + VoiceAddrSet(0, 0),VoiceAddrSet(0, 1),VoiceAddrSet(0, 2),VoiceAddrSet(0, 3),VoiceAddrSet(0, 4),VoiceAddrSet(0, 5), + VoiceAddrSet(0, 6),VoiceAddrSet(0, 7),VoiceAddrSet(0, 8),VoiceAddrSet(0, 9),VoiceAddrSet(0,10),VoiceAddrSet(0,11), + VoiceAddrSet(0,12),VoiceAddrSet(0,13),VoiceAddrSet(0,14),VoiceAddrSet(0,15),VoiceAddrSet(0,16),VoiceAddrSet(0,17), + VoiceAddrSet(0,18),VoiceAddrSet(0,19),VoiceAddrSet(0,20),VoiceAddrSet(0,21),VoiceAddrSet(0,22),VoiceAddrSet(0,23), + + CoreParamsPair(0,REG_A_ESA), + + ReverbPair(0,R_FB_SRC_A), // 0x02E4 // Feedback Source A + ReverbPair(0,R_FB_SRC_B), // 0x02E8 // Feedback Source B + ReverbPair(0,R_IIR_DEST_A0), // 0x02EC + ReverbPair(0,R_IIR_DEST_A1), // 0x02F0 + ReverbPair(0,R_ACC_SRC_A0), // 0x02F4 + ReverbPair(0,R_ACC_SRC_A1), // 0x02F8 + ReverbPair(0,R_ACC_SRC_B0), // 0x02FC + ReverbPair(0,R_ACC_SRC_B1), // 0x0300 + ReverbPair(0,R_IIR_SRC_A0), // 0x0304 + ReverbPair(0,R_IIR_SRC_A1), // 0x0308 + ReverbPair(0,R_IIR_DEST_B0), // 0x030C + ReverbPair(0,R_IIR_DEST_B1), // 0x0310 + ReverbPair(0,R_ACC_SRC_C0), // 0x0314 + ReverbPair(0,R_ACC_SRC_C1), // 0x0318 + ReverbPair(0,R_ACC_SRC_D0), // 0x031C + ReverbPair(0,R_ACC_SRC_D1), // 0x0320 + ReverbPair(0,R_IIR_SRC_B1), // 0x0324 + ReverbPair(0,R_IIR_SRC_B0), // 0x0328 + ReverbPair(0,R_MIX_DEST_A0), // 0x032C + ReverbPair(0,R_MIX_DEST_A1), // 0x0330 + ReverbPair(0,R_MIX_DEST_B0), // 0x0334 + ReverbPair(0,R_MIX_DEST_B1), // 0x0338 + + RegWrite_Core<0,REG_A_EEA>, NULL, + + CoreParamsPair(0,REG_S_ENDX), // 0x0340 // End Point passed flag + RegWrite_Core<0,REG_P_STATX>, // 0x0344 // Status register? + + //0x346 here + REGRAW(0x346), + REGRAW(0x348),REGRAW(0x34A),REGRAW(0x34C),REGRAW(0x34E), + REGRAW(0x350),REGRAW(0x352),REGRAW(0x354),REGRAW(0x356), + REGRAW(0x358),REGRAW(0x35A),REGRAW(0x35C),REGRAW(0x35E), + REGRAW(0x360),REGRAW(0x362),REGRAW(0x364),REGRAW(0x366), + REGRAW(0x368),REGRAW(0x36A),REGRAW(0x36C),REGRAW(0x36E), + REGRAW(0x370),REGRAW(0x372),REGRAW(0x374),REGRAW(0x376), + REGRAW(0x378),REGRAW(0x37A),REGRAW(0x37C),REGRAW(0x37E), + REGRAW(0x380),REGRAW(0x382),REGRAW(0x384),REGRAW(0x386), + REGRAW(0x388),REGRAW(0x38A),REGRAW(0x38C),REGRAW(0x38E), + REGRAW(0x390),REGRAW(0x392),REGRAW(0x394),REGRAW(0x396), + REGRAW(0x398),REGRAW(0x39A),REGRAW(0x39C),REGRAW(0x39E), + REGRAW(0x3A0),REGRAW(0x3A2),REGRAW(0x3A4),REGRAW(0x3A6), + REGRAW(0x3A8),REGRAW(0x3AA),REGRAW(0x3AC),REGRAW(0x3AE), + REGRAW(0x3B0),REGRAW(0x3B2),REGRAW(0x3B4),REGRAW(0x3B6), + REGRAW(0x3B8),REGRAW(0x3BA),REGRAW(0x3BC),REGRAW(0x3BE), + REGRAW(0x3C0),REGRAW(0x3C2),REGRAW(0x3C4),REGRAW(0x3C6), + REGRAW(0x3C8),REGRAW(0x3CA),REGRAW(0x3CC),REGRAW(0x3CE), + REGRAW(0x3D0),REGRAW(0x3D2),REGRAW(0x3D4),REGRAW(0x3D6), + REGRAW(0x3D8),REGRAW(0x3DA),REGRAW(0x3DC),REGRAW(0x3DE), + REGRAW(0x3E0),REGRAW(0x3E2),REGRAW(0x3E4),REGRAW(0x3E6), + REGRAW(0x3E8),REGRAW(0x3EA),REGRAW(0x3EC),REGRAW(0x3EE), + REGRAW(0x3F0),REGRAW(0x3F2),REGRAW(0x3F4),REGRAW(0x3F6), + REGRAW(0x3F8),REGRAW(0x3FA),REGRAW(0x3FC),REGRAW(0x3FE), + + // AND... we reached 0x400! + // Last verse, same as the first: + + VoiceParamsCore(1), // 0x000 -> 0x180 + CoreParamsPair(1,REG_S_PMON), + CoreParamsPair(1,REG_S_NON), + CoreParamsPair(1,REG_S_VMIXL), + CoreParamsPair(1,REG_S_VMIXEL), + CoreParamsPair(1,REG_S_VMIXR), + CoreParamsPair(1,REG_S_VMIXER), + + RegWrite_Core<1,REG_P_MMIX>, + RegWrite_Core<1,REG_C_ATTR>, + + CoreParamsPair(1,REG_A_IRQA), + CoreParamsPair(1,REG_S_KON), + CoreParamsPair(1,REG_S_KOFF), + CoreParamsPair(1,REG_A_TSA), + CoreParamsPair(1,REG__1AC), + + RegWrite_Core<1,REG_S_ADMAS>, + REGRAW(0x5b2), + + REGRAW(0x5b4), REGRAW(0x5b6), + REGRAW(0x5b8), REGRAW(0x5ba), + REGRAW(0x5bc), REGRAW(0x5be), + + // 0x1c0! + + VoiceAddrSet(1, 0),VoiceAddrSet(1, 1),VoiceAddrSet(1, 2),VoiceAddrSet(1, 3),VoiceAddrSet(1, 4),VoiceAddrSet(1, 5), + VoiceAddrSet(1, 6),VoiceAddrSet(1, 7),VoiceAddrSet(1, 8),VoiceAddrSet(1, 9),VoiceAddrSet(1,10),VoiceAddrSet(1,11), + VoiceAddrSet(1,12),VoiceAddrSet(1,13),VoiceAddrSet(1,14),VoiceAddrSet(1,15),VoiceAddrSet(1,16),VoiceAddrSet(1,17), + VoiceAddrSet(1,18),VoiceAddrSet(1,19),VoiceAddrSet(1,20),VoiceAddrSet(1,21),VoiceAddrSet(1,22),VoiceAddrSet(1,23), + + CoreParamsPair(1,REG_A_ESA), + + ReverbPair(1,R_FB_SRC_A), // 0x02E4 // Feedback Source A + ReverbPair(1,R_FB_SRC_B), // 0x02E8 // Feedback Source B + ReverbPair(1,R_IIR_DEST_A0), // 0x02EC + ReverbPair(1,R_IIR_DEST_A1), // 0x02F0 + ReverbPair(1,R_ACC_SRC_A0), // 0x02F4 + ReverbPair(1,R_ACC_SRC_A1), // 0x02F8 + ReverbPair(1,R_ACC_SRC_B0), // 0x02FC + ReverbPair(1,R_ACC_SRC_B1), // 0x0300 + ReverbPair(1,R_IIR_SRC_A0), // 0x0304 + ReverbPair(1,R_IIR_SRC_A1), // 0x0308 + ReverbPair(1,R_IIR_DEST_B0), // 0x030C + ReverbPair(1,R_IIR_DEST_B1), // 0x0310 + ReverbPair(1,R_ACC_SRC_C0), // 0x0314 + ReverbPair(1,R_ACC_SRC_C1), // 0x0318 + ReverbPair(1,R_ACC_SRC_D0), // 0x031C + ReverbPair(1,R_ACC_SRC_D1), // 0x0320 + ReverbPair(1,R_IIR_SRC_B1), // 0x0324 + ReverbPair(1,R_IIR_SRC_B0), // 0x0328 + ReverbPair(1,R_MIX_DEST_A0), // 0x032C + ReverbPair(1,R_MIX_DEST_A1), // 0x0330 + ReverbPair(1,R_MIX_DEST_B0), // 0x0334 + ReverbPair(1,R_MIX_DEST_B1), // 0x0338 + + RegWrite_Core<1,REG_A_EEA>, NULL, + + CoreParamsPair(1,REG_S_ENDX), // 0x0340 // End Point passed flag + RegWrite_Core<1,REG_P_STATX>, // 0x0344 // Status register? + + REGRAW(0x746), + REGRAW(0x748),REGRAW(0x74A),REGRAW(0x74C),REGRAW(0x74E), + REGRAW(0x750),REGRAW(0x752),REGRAW(0x754),REGRAW(0x756), + REGRAW(0x758),REGRAW(0x75A),REGRAW(0x75C),REGRAW(0x75E), + + // ------ ------- + + RegWrite_CoreExt<0,REG_P_MVOLL>, // 0x0760 // Master Volume Left + RegWrite_CoreExt<0,REG_P_MVOLR>, // 0x0762 // Master Volume Right + RegWrite_CoreExt<0,REG_P_EVOLL>, // 0x0764 // Effect Volume Left + RegWrite_CoreExt<0,REG_P_EVOLR>, // 0x0766 // Effect Volume Right + RegWrite_CoreExt<0,REG_P_AVOLL>, // 0x0768 // Core External Input Volume Left (Only Core 1) + RegWrite_CoreExt<0,REG_P_AVOLR>, // 0x076A // Core External Input Volume Right (Only Core 1) + RegWrite_CoreExt<0,REG_P_BVOLL>, // 0x076C // Sound Data Volume Left + RegWrite_CoreExt<0,REG_P_BVOLR>, // 0x076E // Sound Data Volume Right + RegWrite_CoreExt<0,REG_P_MVOLXL>, // 0x0770 // Current Master Volume Left + RegWrite_CoreExt<0,REG_P_MVOLXR>, // 0x0772 // Current Master Volume Right + + RegWrite_CoreExt<0,R_IIR_ALPHA>, // 0x0774 //IIR alpha (% used) + RegWrite_CoreExt<0,R_ACC_COEF_A>, // 0x0776 + RegWrite_CoreExt<0,R_ACC_COEF_B>, // 0x0778 + RegWrite_CoreExt<0,R_ACC_COEF_C>, // 0x077A + RegWrite_CoreExt<0,R_ACC_COEF_D>, // 0x077C + RegWrite_CoreExt<0,R_IIR_COEF>, // 0x077E + RegWrite_CoreExt<0,R_FB_ALPHA>, // 0x0780 //feedback alpha (% used) + RegWrite_CoreExt<0,R_FB_X>, // 0x0782 //feedback + RegWrite_CoreExt<0,R_IN_COEF_L>, // 0x0784 + RegWrite_CoreExt<0,R_IN_COEF_R>, // 0x0786 + + // ------ ------- + + RegWrite_CoreExt<1,REG_P_MVOLL>, // 0x0788 // Master Volume Left + RegWrite_CoreExt<1,REG_P_MVOLR>, // 0x078A // Master Volume Right + RegWrite_CoreExt<1,REG_P_EVOLL>, // 0x0764 // Effect Volume Left + RegWrite_CoreExt<1,REG_P_EVOLR>, // 0x0766 // Effect Volume Right + RegWrite_CoreExt<1,REG_P_AVOLL>, // 0x0768 // Core External Input Volume Left (Only Core 1) + RegWrite_CoreExt<1,REG_P_AVOLR>, // 0x076A // Core External Input Volume Right (Only Core 1) + RegWrite_CoreExt<1,REG_P_BVOLL>, // 0x076C // Sound Data Volume Left + RegWrite_CoreExt<1,REG_P_BVOLR>, // 0x076E // Sound Data Volume Right + RegWrite_CoreExt<1,REG_P_MVOLXL>, // 0x0770 // Current Master Volume Left + RegWrite_CoreExt<1,REG_P_MVOLXR>, // 0x0772 // Current Master Volume Right + + RegWrite_CoreExt<1,R_IIR_ALPHA>, // 0x0774 //IIR alpha (% used) + RegWrite_CoreExt<1,R_ACC_COEF_A>, // 0x0776 + RegWrite_CoreExt<1,R_ACC_COEF_B>, // 0x0778 + RegWrite_CoreExt<1,R_ACC_COEF_C>, // 0x077A + RegWrite_CoreExt<1,R_ACC_COEF_D>, // 0x077C + RegWrite_CoreExt<1,R_IIR_COEF>, // 0x077E + RegWrite_CoreExt<1,R_FB_ALPHA>, // 0x0780 //feedback alpha (% used) + RegWrite_CoreExt<1,R_FB_X>, // 0x0782 //feedback + RegWrite_CoreExt<1,R_IN_COEF_L>, // 0x0784 + RegWrite_CoreExt<1,R_IN_COEF_R>, // 0x0786 + + REGRAW(0x7B0),REGRAW(0x7B2),REGRAW(0x7B4),REGRAW(0x7B6), + REGRAW(0x7B8),REGRAW(0x7BA),REGRAW(0x7BC),REGRAW(0x7BE), + + // SPDIF interface + + RegWrite_SPDIF, // 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass + RegWrite_SPDIF, // 0x07C2 + REGRAW(0x7C4), + RegWrite_SPDIF, // 0x07C6 + RegWrite_SPDIF, // 0x07C8 // SPDIF Media: 'CD'/DVD + REGRAW(0x7CA), + RegWrite_SPDIF, // 0x07CC // SPDIF Copy Protection + + REGRAW(0x7CE), + REGRAW(0x7D0),REGRAW(0x7D2),REGRAW(0x7D4),REGRAW(0x7D6), + REGRAW(0x7D8),REGRAW(0x7DA),REGRAW(0x7DC),REGRAW(0x7DE), + REGRAW(0x7E0),REGRAW(0x7E2),REGRAW(0x7E4),REGRAW(0x7E6), + REGRAW(0x7E8),REGRAW(0x7EA),REGRAW(0x7EC),REGRAW(0x7EE), + REGRAW(0x7F0),REGRAW(0x7F2),REGRAW(0x7F4),REGRAW(0x7F6), + REGRAW(0x7F8),REGRAW(0x7FA),REGRAW(0x7FC),REGRAW(0x7FE), + + NULL // should be at 0x400! (we assert check it on startup) +}; + + +__forceinline void SPU2_FastWrite( u32 rmem, u16 value ) +{ + tbl_reg_writes[(rmem&0x7ff)/2]( value ); +} + void StartVoices(int core, u32 value) { @@ -1202,7 +1440,7 @@ void StartVoices(int core, u32 value) *(u8*)GetMemPtr(thisvc.StartA),*(u8 *)GetMemPtr((thisvc.StartA)+1), thisvc.Pitch, thisvc.Volume.Left.Value>>16,thisvc.Volume.Right.Value>>16, - thisvc.ADSR.Reg_ADSR1,thisvc.ADSR.Reg_ADSR2); + thisvc.ADSR.regADSR1,thisvc.ADSR.regADSR2); } } }