/[pcsx2_0.9.7]/trunk/plugins/spu2-x/src/PS2E-spu2.cpp
ViewVC logotype

Annotation of /trunk/plugins/spu2-x/src/PS2E-spu2.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (hide annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 6 months ago) by william
File size: 14032 byte(s)
re-commit (had local access denied errors when committing)
1 william 31 /* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
2     * Developed and maintained by the Pcsx2 Development Team.
3     *
4     * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
5     *
6     * SPU2-X is free software: you can redistribute it and/or modify it under the terms
7     * of the GNU Lesser General Public License as published by the Free Software Found-
8     * ation, either version 3 of the License, or (at your option) any later version.
9     *
10     * SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12     * PURPOSE. See the GNU Lesser General Public License for more details.
13     *
14     * You should have received a copy of the GNU Lesser General Public License
15     * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
16     */
17    
18     #include "Global.h"
19     #include "PS2E-spu2.h"
20     #include "Dma.h"
21     #include "Dialogs.h"
22    
23     #include "x86emitter/tools.h"
24    
25     #ifdef _MSC_VER
26     # include "svnrev.h"
27     #endif
28    
29    
30     // PCSX2 expects ASNI, not unicode, so this MUST always be char...
31     static char libraryName[256];
32    
33    
34     static bool IsOpened = false;
35     static bool IsInitialized = false;
36    
37     static u32 pClocks = 0;
38    
39     u32* cyclePtr = NULL;
40     u32 lClocks = 0;
41    
42     #ifdef _MSC_VER
43     HINSTANCE hInstance;
44     BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
45     {
46     if( dwReason == DLL_PROCESS_ATTACH )
47     {
48     hInstance = hinstDLL;
49     }
50     else if( dwReason == DLL_PROCESS_DETACH )
51     {
52     // TODO : perform shutdown procedure, just in case PCSX2 itself failed
53     // to for some reason..
54     }
55     return TRUE;
56     }
57     #endif
58    
59     static void InitLibraryName()
60     {
61     #ifdef SPU2X_PUBLIC_RELEASE
62    
63     // Public Release!
64     // Output a simplified string that's just our name:
65    
66     strcpy( libraryName, "SPU2-X" );
67    
68     #else
69     #ifdef SVN_REV_UNKNOWN
70    
71     // Unknown revision.
72     // Output a name that includes devbuild status but not
73     // subversion revision tags:
74    
75     strcpy( libraryName, "SPU2-X"
76     #ifdef DEBUG_FAST
77     "-Debug"
78     #elif defined( PCSX2_DEBUG )
79     "-Debug/Strict" // strict debugging is slow!
80     #elif defined( PCSX2_DEVBUILD )
81     "-Dev"
82     #else
83     ""
84     #endif
85     );
86    
87     #else
88    
89     // Use TortoiseSVN's SubWCRev utility's output
90     // to label the specific revision:
91    
92     sprintf_s( libraryName, "SPU2-X r%d%s"
93     #ifdef DEBUG_FAST
94     "-Debug"
95     #elif defined( PCSX2_DEBUG )
96     "-Debug/Strict" // strict debugging is slow!
97     #elif defined( PCSX2_DEVBUILD )
98     "-Dev"
99     #else
100     ""
101     #endif
102     ,SVN_REV,
103     SVN_MODS ? "m" : ""
104     );
105     #endif
106     #endif
107    
108     }
109    
110     static bool cpu_detected = false;
111    
112     static bool CheckSSE()
113     {
114 william 62 return true;
115    
116     #if 0
117 william 31 if( !cpu_detected )
118     {
119     cpudetectInit();
120     cpu_detected = true;
121     }
122     if( !x86caps.hasStreamingSIMDExtensions || !x86caps.hasStreamingSIMD2Extensions )
123     {
124     SysMessage( "Your CPU does not support SSE2 instructions.\nThe SPU2-X plugin requires SSE2 to run." );
125     return false;
126     }
127     return true;
128 william 62 #endif
129 william 31 }
130    
131     EXPORT_C_(u32) PS2EgetLibType()
132     {
133     return PS2E_LT_SPU2;
134     }
135    
136     EXPORT_C_(char*) PS2EgetLibName()
137     {
138     InitLibraryName();
139     return libraryName;
140     }
141    
142     EXPORT_C_(u32) PS2EgetLibVersion2(u32 type)
143     {
144     return (PS2E_SPU2_VERSION<<16) | (VersionInfo::Release<<8) | VersionInfo::Revision;
145     }
146    
147     EXPORT_C_(void) SPU2configure()
148     {
149     if( !CheckSSE() ) return;
150     configure();
151     }
152    
153     EXPORT_C_(void) SPU2about()
154     {
155     AboutBox();
156     }
157    
158     EXPORT_C_(s32) SPU2test()
159     {
160     if( !CheckSSE() ) return -1;
161    
162     ReadSettings();
163     if( SndBuffer::Test() != 0 )
164     {
165     // TODO : Implement a proper dialog that allows the user to test different audio out drivers.
166     const wchar_t* wtf = mods[OutputModule]->GetIdent();
167     SysMessage( L"The '%s' driver test failed. Please configure\na different SoundOut module and try again.", wtf );
168     return -1;
169     }
170    
171     return 0;
172     }
173    
174     // --------------------------------------------------------------------------------------
175     // DMA 4/7 Callbacks from Core Emulator
176     // --------------------------------------------------------------------------------------
177    
178     u16* DMABaseAddr;
179     void (* _irqcallback)();
180     void (* dma4callback)();
181     void (* dma7callback)();
182    
183     EXPORT_C_(u32) CALLBACK SPU2ReadMemAddr(int core)
184     {
185     return Cores[core].MADR;
186     }
187     EXPORT_C_(void) CALLBACK SPU2WriteMemAddr(int core,u32 value)
188     {
189     Cores[core].MADR = value;
190     }
191    
192     EXPORT_C_(void) CALLBACK SPU2setDMABaseAddr(uptr baseaddr)
193     {
194     DMABaseAddr = (u16*)baseaddr;
195     }
196    
197     EXPORT_C_(void) CALLBACK SPU2setSettingsDir(const char* dir)
198     {
199     CfgSetSettingsDir( dir );
200     }
201    
202 william 62 EXPORT_C_(void) CALLBACK SPU2setLogDir(const char* dir)
203     {
204     CfgSetLogDir( dir );
205     }
206    
207 william 31 EXPORT_C_(s32) SPU2dmaRead(s32 channel, u32* data, u32 bytesLeft, u32* bytesProcessed)
208     {
209     if(channel==4)
210     return Cores[0].NewDmaRead(data,bytesLeft, bytesProcessed);
211     else
212     return Cores[1].NewDmaRead(data,bytesLeft, bytesProcessed);
213     }
214    
215     EXPORT_C_(s32) SPU2dmaWrite(s32 channel, u32* data, u32 bytesLeft, u32* bytesProcessed)
216     {
217     if(channel==4)
218     return Cores[0].NewDmaWrite(data,bytesLeft, bytesProcessed);
219     else
220     return Cores[1].NewDmaWrite(data,bytesLeft, bytesProcessed);
221     }
222    
223     EXPORT_C_(void) SPU2dmaInterrupt(s32 channel)
224     {
225     if(channel==4)
226     return Cores[0].NewDmaInterrupt();
227     else
228     return Cores[1].NewDmaInterrupt();
229     }
230    
231     #ifdef ENABLE_NEW_IOPDMA_SPU2
232     EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)())
233     {
234     _irqcallback = SPU2callback;
235     }
236     #else
237     EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)())
238     {
239     _irqcallback = SPU2callback;
240     dma4callback = DMA4callback;
241     dma7callback = DMA7callback;
242     }
243     #endif
244    
245     EXPORT_C_(void) CALLBACK SPU2readDMA4Mem(u16 *pMem, u32 size) // size now in 16bit units
246     {
247     if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
248    
249     FileLog("[%10d] SPU2 readDMA4Mem size %x\n",Cycles, size<<1);
250     Cores[0].DoDMAread(pMem, size);
251     }
252    
253     EXPORT_C_(void) CALLBACK SPU2writeDMA4Mem(u16* pMem, u32 size) // size now in 16bit units
254     {
255     if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
256    
257     FileLog("[%10d] SPU2 writeDMA4Mem size %x at address %x\n",Cycles, size<<1, Cores[0].TSA);
258     #ifdef S2R_ENABLE
259     if(!replay_mode)
260     s2r_writedma4(Cycles,pMem,size);
261     #endif
262     Cores[0].DoDMAwrite(pMem,size);
263     }
264    
265     EXPORT_C_(void) CALLBACK SPU2interruptDMA4()
266     {
267     FileLog("[%10d] SPU2 interruptDMA4\n",Cycles);
268     Cores[0].Regs.STATX |= 0x80;
269     //Cores[0].Regs.ATTR &= ~0x30;
270     }
271    
272     EXPORT_C_(void) CALLBACK SPU2interruptDMA7()
273     {
274     FileLog("[%10d] SPU2 interruptDMA7\n",Cycles);
275     Cores[1].Regs.STATX |= 0x80;
276     //Cores[1].Regs.ATTR &= ~0x30;
277     }
278    
279     EXPORT_C_(void) CALLBACK SPU2readDMA7Mem(u16* pMem, u32 size)
280     {
281     if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
282    
283     FileLog("[%10d] SPU2 readDMA7Mem size %x\n",Cycles, size<<1);
284     Cores[1].DoDMAread(pMem,size);
285     }
286    
287     EXPORT_C_(void) CALLBACK SPU2writeDMA7Mem(u16* pMem, u32 size)
288     {
289     if( cyclePtr != NULL ) TimeUpdate( *cyclePtr );
290    
291     FileLog("[%10d] SPU2 writeDMA7Mem size %x at address %x\n",Cycles, size<<1, Cores[1].TSA);
292     #ifdef S2R_ENABLE
293     if(!replay_mode)
294     s2r_writedma7(Cycles,pMem,size);
295     #endif
296     Cores[1].DoDMAwrite(pMem,size);
297     }
298    
299     EXPORT_C_(s32) SPU2init()
300     {
301     assert( regtable[0x400] == NULL );
302    
303 william 62 if (IsInitialized)
304     {
305     printf( " * SPU2-X: Already initialized - Ignoring SPU2init signal." );
306     return 0;
307     }
308    
309     IsInitialized = true;
310    
311 william 31 ReadSettings();
312    
313     #ifdef SPU2_LOG
314     if(AccessLog())
315     {
316 william 62 spu2Log = OpenLog( AccessLogFileName );
317 william 31 setvbuf(spu2Log, NULL, _IONBF, 0);
318     FileLog("SPU2init\n");
319     }
320     #endif
321     srand((unsigned)time(NULL));
322    
323     spu2regs = (s16*)malloc(0x010000);
324     _spu2mem = (s16*)malloc(0x200000);
325    
326     // adpcm decoder cache:
327     // the cache data size is determined by taking the number of adpcm blocks
328     // (2MB / 16) and multiplying it by the decoded block size (28 samples).
329     // Thus: pcm_cache_data = 7,340,032 bytes (ouch!)
330     // Expanded: 16 bytes expands to 56 bytes [3.5:1 ratio]
331     // Resulting in 2MB * 3.5.
332    
333     pcm_cache_data = (PcmCacheEntry*)calloc( pcm_BlockCount, sizeof(PcmCacheEntry) );
334    
335     if( (spu2regs == NULL) || (_spu2mem == NULL) || (pcm_cache_data == NULL) )
336     {
337 william 62 SysMessage("SPU2-X: Error allocating Memory\n"); return -1;
338 william 31 }
339    
340     // Patch up a copy of regtable that directly maps "NULLs" to SPU2 memory.
341    
342     memcpy(regtable, regtable_original, sizeof(regtable));
343    
344 william 62 for(uint mem=0;mem<0x800;mem++)
345 william 31 {
346     u16 *ptr = regtable[mem>>1];
347     if(!ptr) {
348     regtable[mem>>1] = &(spu2Ru16(mem));
349     }
350     }
351    
352     memset(spu2regs, 0, 0x010000);
353     memset(_spu2mem, 0, 0x200000);
354 william 62 Cores[0].Init(0);
355     Cores[1].Init(1);
356 william 31
357     DMALogOpen();
358     InitADSR();
359    
360     #ifdef S2R_ENABLE
361     if(!replay_mode)
362     s2r_open("replay_dump.s2r");
363     #endif
364     return 0;
365     }
366    
367 william 62 #ifdef _MSC_VER
368     // Bit ugly to have this here instead of in RealttimeDebugger.cpp, but meh :p
369     extern bool debugDialogOpen;
370     extern HWND hDebugDialog;
371    
372     static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
373     {
374     int wmId,wmEvent;
375    
376     switch(uMsg)
377     {
378     case WM_PAINT:
379     return FALSE;
380     case WM_INITDIALOG:
381     {
382     debugDialogOpen=true;
383     }
384     break;
385    
386     case WM_COMMAND:
387     wmId = LOWORD(wParam);
388     wmEvent = HIWORD(wParam);
389     // Parse the menu selections:
390     switch (wmId)
391     {
392     case IDOK:
393     case IDCANCEL:
394     debugDialogOpen=false;
395     EndDialog(hWnd,0);
396     break;
397     default:
398     return FALSE;
399     }
400     break;
401    
402     default:
403     return FALSE;
404     }
405     return TRUE;
406     }
407     #endif
408 william 31 uptr gsWindowHandle = 0;
409    
410     EXPORT_C_(s32) SPU2open(void *pDsp)
411     {
412     if( IsOpened ) return 0;
413    
414     FileLog("[%10d] SPU2 Open\n",Cycles);
415    
416     if( pDsp != NULL )
417     gsWindowHandle = *(uptr*)pDsp;
418     else
419     gsWindowHandle = 0;
420    
421 william 62 // uncomment for a visual debug display showing all core's activity!
422     /*if(debugDialogOpen==0)
423 william 31 {
424 william 62 hDebugDialog = CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD_DEBUG),0,DebugProc,0);
425     ShowWindow(hDebugDialog,SW_SHOWNORMAL);
426     debugDialogOpen=1;
427 william 31 }*/
428    
429     IsOpened = true;
430     lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
431    
432     try
433     {
434     SndBuffer::Init();
435 william 273
436 william 31 #ifndef __LINUX__
437     DspLoadLibrary(dspPlugin,dspPluginModule);
438     #endif
439     WaveDump::Open();
440     }
441     catch( std::exception& ex )
442     {
443     fprintf( stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what() );
444     SPU2close();
445     return -1;
446     }
447     return 0;
448     }
449    
450     EXPORT_C_(void) SPU2close()
451     {
452     if( !IsOpened ) return;
453     IsOpened = false;
454    
455     FileLog("[%10d] SPU2 Close\n",Cycles);
456    
457     #ifndef __LINUX__
458     DspCloseLibrary();
459     #endif
460 william 62
461 william 31 SndBuffer::Cleanup();
462     }
463    
464     EXPORT_C_(void) SPU2shutdown()
465     {
466     if(!IsInitialized) return;
467     IsInitialized = false;
468    
469 william 62 ConLog( "* SPU2-X: Shutting down.\n" );
470 william 31
471     SPU2close();
472    
473     #ifdef S2R_ENABLE
474     if(!replay_mode)
475     s2r_close();
476     #endif
477    
478     DoFullDump();
479     #ifdef STREAM_DUMP
480     fclose(il0);
481     fclose(il1);
482     #endif
483     #ifdef EFFECTS_DUMP
484     fclose(el0);
485     fclose(el1);
486     #endif
487     WaveDump::Close();
488    
489     DMALogClose();
490    
491     safe_free(spu2regs);
492     safe_free(_spu2mem);
493     safe_free( pcm_cache_data );
494    
495 william 62
496 william 31 #ifdef SPU2_LOG
497     if(!AccessLog()) return;
498     FileLog("[%10d] SPU2shutdown\n",Cycles);
499     if(spu2Log) fclose(spu2Log);
500     #endif
501     }
502    
503     EXPORT_C_(void) SPU2setClockPtr(u32 *ptr)
504     {
505     cyclePtr = ptr;
506     }
507    
508     static bool numpad_plus = false, numpad_plus_old = false;
509    
510     #ifdef DEBUG_KEYS
511     static u32 lastTicks;
512 william 280 static bool lState[6];
513 william 31 #endif
514    
515     EXPORT_C_(void) SPU2async(u32 cycles)
516     {
517     DspUpdate();
518    
519     if(cyclePtr != NULL)
520     {
521     TimeUpdate( *cyclePtr );
522     }
523     else
524     {
525     pClocks += cycles;
526     TimeUpdate( pClocks );
527     }
528    
529     #ifdef DEBUG_KEYS
530     u32 curTicks = GetTickCount();
531 william 280 if((curTicks - lastTicks) >= 50)
532 william 31 {
533     int oldI = Interpolation;
534 william 280 bool cState[6];
535     for(int i=0;i<6;i++)
536 william 31 {
537     cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0+i)&0x8000);
538    
539 william 280 if((cState[i] && !lState[i]) && i != 5)
540 william 31 Interpolation = i;
541    
542 william 280 if((cState[i] && !lState[i]) && i == 5)
543     {
544     postprocess_filter_enabled = !postprocess_filter_enabled;
545     printf("Post process filters %s \n", postprocess_filter_enabled? "enabled" : "disabled");
546     }
547    
548 william 31 lState[i] = cState[i];
549     }
550    
551     if(Interpolation != oldI)
552     {
553     printf("Interpolation set to %d", Interpolation);
554     switch(Interpolation)
555     {
556     case 0: printf(" - Nearest.\n"); break;
557     case 1: printf(" - Linear.\n"); break;
558     case 2: printf(" - Cubic.\n"); break;
559     case 3: printf(" - Hermite.\n"); break;
560     case 4: printf(" - Catmull-Rom.\n"); break;
561     default: printf(" (unknown).\n"); break;
562     }
563     }
564    
565     lastTicks = curTicks;
566     }
567     #endif
568     }
569    
570     EXPORT_C_(u16) SPU2read(u32 rmem)
571     {
572     // if(!replay_mode)
573     // s2r_readreg(Cycles,rmem);
574    
575     u16 ret=0xDEAD; u32 core=0, mem=rmem&0xFFFF, omem=mem;
576     if (mem & 0x400) { omem^=0x400; core=1; }
577    
578     if(rmem==0x1f9001AC)
579     {
580     ret = Cores[core].DmaRead();
581     }
582     else
583     {
584     if( cyclePtr != NULL )
585     TimeUpdate( *cyclePtr );
586    
587     if (rmem>>16 == 0x1f80)
588     {
589     ret = Cores[0].ReadRegPS1(rmem);
590     }
591     else if( (mem&0xFFFF) >= 0x800 )
592     {
593     ret = spu2Ru16(mem);
594 william 62 ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n",mem,ret);
595 william 31 }
596     else
597     {
598     ret = *(regtable[(mem>>1)]);
599     //FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret);
600     SPU2writeLog( "read", rmem, ret );
601     }
602     }
603    
604     return ret;
605     }
606    
607     EXPORT_C_(void) SPU2write(u32 rmem, u16 value)
608     {
609     #ifdef S2R_ENABLE
610     if(!replay_mode)
611     s2r_writereg(Cycles,rmem,value);
612     #endif
613    
614     // Note: Reverb/Effects are very sensitive to having precise update timings.
615     // If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
616     // incorrect pitches and loop lengths.
617    
618     if( cyclePtr != NULL )
619     TimeUpdate( *cyclePtr );
620    
621     if (rmem>>16 == 0x1f80)
622     Cores[0].WriteRegPS1(rmem,value);
623     else
624     {
625     SPU2writeLog( "write", rmem, value );
626     SPU2_FastWrite( rmem, value );
627     }
628     }
629    
630     // if start is 1, starts recording spu2 data, else stops
631     // returns a non zero value if successful
632     // for now, pData is not used
633     EXPORT_C_(int) SPU2setupRecording(int start, void* pData)
634     {
635     if(start==0)
636     RecordStop();
637     else if(start==1)
638     RecordStart();
639    
640     return 0;
641     }
642    
643     EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
644     {
645     if( mode == FREEZE_SIZE )
646     {
647     data->size = Savestate::SizeIt();
648     return 0;
649     }
650    
651     jASSUME( mode == FREEZE_LOAD || mode == FREEZE_SAVE );
652     jASSUME( data != NULL );
653    
654     if( data->data == NULL ) return -1;
655     Savestate::DataBlock& spud = (Savestate::DataBlock&)*(data->data);
656    
657     switch( mode )
658     {
659     case FREEZE_LOAD: return Savestate::ThawIt( spud );
660     case FREEZE_SAVE: return Savestate::FreezeIt( spud );
661    
662     jNO_DEFAULT;
663     }
664    
665     // technically unreachable, but kills a warning:
666     return 0;
667     }

  ViewVC Help
Powered by ViewVC 1.1.22