/[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 401 - (hide annotations) (download)
Fri Feb 25 17:31:09 2011 UTC (9 years, 4 months ago) by william
File size: 14172 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4358 local: v0.9.7.313-latest) in ./trunk
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 william 401 int wmId;
375 william 62
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     // Parse the menu selections:
389     switch (wmId)
390     {
391     case IDOK:
392     case IDCANCEL:
393     debugDialogOpen=false;
394     EndDialog(hWnd,0);
395     break;
396     default:
397     return FALSE;
398     }
399     break;
400    
401     default:
402     return FALSE;
403     }
404     return TRUE;
405     }
406     #endif
407 william 31 uptr gsWindowHandle = 0;
408    
409     EXPORT_C_(s32) SPU2open(void *pDsp)
410     {
411     if( IsOpened ) return 0;
412    
413     FileLog("[%10d] SPU2 Open\n",Cycles);
414    
415     if( pDsp != NULL )
416     gsWindowHandle = *(uptr*)pDsp;
417     else
418     gsWindowHandle = 0;
419    
420 william 401 #ifdef _MSC_VER
421     #ifdef PCSX2_DEVBUILD // Define may not be needed but not tested yet. Better make sure.
422     if( IsDevBuild && VisualDebug() )
423 william 31 {
424 william 401 if(debugDialogOpen==0)
425     {
426     hDebugDialog = CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD_DEBUG),0,DebugProc,0);
427     ShowWindow(hDebugDialog,SW_SHOWNORMAL);
428     debugDialogOpen=1;
429     }
430     }
431     else if(debugDialogOpen)
432     {
433     DestroyWindow(hDebugDialog);
434     debugDialogOpen=0;
435     }
436     #endif
437     #endif
438 william 31
439     IsOpened = true;
440     lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
441    
442     try
443     {
444     SndBuffer::Init();
445 william 273
446 william 31 #ifndef __LINUX__
447     DspLoadLibrary(dspPlugin,dspPluginModule);
448     #endif
449     WaveDump::Open();
450     }
451     catch( std::exception& ex )
452     {
453     fprintf( stderr, "SPU2-X Error: Could not initialize device, or something.\nReason: %s", ex.what() );
454     SPU2close();
455     return -1;
456     }
457     return 0;
458     }
459    
460     EXPORT_C_(void) SPU2close()
461     {
462     if( !IsOpened ) return;
463     IsOpened = false;
464    
465     FileLog("[%10d] SPU2 Close\n",Cycles);
466    
467     #ifndef __LINUX__
468     DspCloseLibrary();
469     #endif
470 william 62
471 william 31 SndBuffer::Cleanup();
472     }
473    
474     EXPORT_C_(void) SPU2shutdown()
475     {
476     if(!IsInitialized) return;
477     IsInitialized = false;
478    
479 william 62 ConLog( "* SPU2-X: Shutting down.\n" );
480 william 31
481     SPU2close();
482    
483     #ifdef S2R_ENABLE
484     if(!replay_mode)
485     s2r_close();
486     #endif
487    
488     DoFullDump();
489     #ifdef STREAM_DUMP
490     fclose(il0);
491     fclose(il1);
492     #endif
493     #ifdef EFFECTS_DUMP
494     fclose(el0);
495     fclose(el1);
496     #endif
497     WaveDump::Close();
498    
499     DMALogClose();
500    
501     safe_free(spu2regs);
502     safe_free(_spu2mem);
503     safe_free( pcm_cache_data );
504    
505 william 62
506 william 31 #ifdef SPU2_LOG
507     if(!AccessLog()) return;
508     FileLog("[%10d] SPU2shutdown\n",Cycles);
509     if(spu2Log) fclose(spu2Log);
510     #endif
511     }
512    
513     EXPORT_C_(void) SPU2setClockPtr(u32 *ptr)
514     {
515     cyclePtr = ptr;
516     }
517    
518     static bool numpad_plus = false, numpad_plus_old = false;
519    
520     #ifdef DEBUG_KEYS
521     static u32 lastTicks;
522 william 280 static bool lState[6];
523 william 31 #endif
524    
525     EXPORT_C_(void) SPU2async(u32 cycles)
526     {
527     DspUpdate();
528    
529     if(cyclePtr != NULL)
530     {
531     TimeUpdate( *cyclePtr );
532     }
533     else
534     {
535     pClocks += cycles;
536     TimeUpdate( pClocks );
537     }
538    
539     #ifdef DEBUG_KEYS
540     u32 curTicks = GetTickCount();
541 william 280 if((curTicks - lastTicks) >= 50)
542 william 31 {
543     int oldI = Interpolation;
544 william 280 bool cState[6];
545     for(int i=0;i<6;i++)
546 william 31 {
547     cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0+i)&0x8000);
548    
549 william 280 if((cState[i] && !lState[i]) && i != 5)
550 william 31 Interpolation = i;
551    
552 william 280 if((cState[i] && !lState[i]) && i == 5)
553     {
554     postprocess_filter_enabled = !postprocess_filter_enabled;
555     printf("Post process filters %s \n", postprocess_filter_enabled? "enabled" : "disabled");
556     }
557    
558 william 31 lState[i] = cState[i];
559     }
560    
561     if(Interpolation != oldI)
562     {
563     printf("Interpolation set to %d", Interpolation);
564     switch(Interpolation)
565     {
566     case 0: printf(" - Nearest.\n"); break;
567     case 1: printf(" - Linear.\n"); break;
568     case 2: printf(" - Cubic.\n"); break;
569     case 3: printf(" - Hermite.\n"); break;
570     case 4: printf(" - Catmull-Rom.\n"); break;
571     default: printf(" (unknown).\n"); break;
572     }
573     }
574    
575     lastTicks = curTicks;
576     }
577     #endif
578     }
579    
580     EXPORT_C_(u16) SPU2read(u32 rmem)
581     {
582     // if(!replay_mode)
583     // s2r_readreg(Cycles,rmem);
584    
585     u16 ret=0xDEAD; u32 core=0, mem=rmem&0xFFFF, omem=mem;
586     if (mem & 0x400) { omem^=0x400; core=1; }
587    
588     if(rmem==0x1f9001AC)
589     {
590     ret = Cores[core].DmaRead();
591     }
592     else
593     {
594     if( cyclePtr != NULL )
595     TimeUpdate( *cyclePtr );
596    
597     if (rmem>>16 == 0x1f80)
598     {
599     ret = Cores[0].ReadRegPS1(rmem);
600     }
601     else if( (mem&0xFFFF) >= 0x800 )
602     {
603     ret = spu2Ru16(mem);
604 william 62 ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n",mem,ret);
605 william 31 }
606     else
607     {
608     ret = *(regtable[(mem>>1)]);
609     //FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret);
610     SPU2writeLog( "read", rmem, ret );
611     }
612     }
613    
614     return ret;
615     }
616    
617     EXPORT_C_(void) SPU2write(u32 rmem, u16 value)
618     {
619     #ifdef S2R_ENABLE
620     if(!replay_mode)
621     s2r_writereg(Cycles,rmem,value);
622     #endif
623    
624     // Note: Reverb/Effects are very sensitive to having precise update timings.
625     // If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
626     // incorrect pitches and loop lengths.
627    
628     if( cyclePtr != NULL )
629     TimeUpdate( *cyclePtr );
630    
631     if (rmem>>16 == 0x1f80)
632     Cores[0].WriteRegPS1(rmem,value);
633     else
634     {
635     SPU2writeLog( "write", rmem, value );
636     SPU2_FastWrite( rmem, value );
637     }
638     }
639    
640     // if start is 1, starts recording spu2 data, else stops
641     // returns a non zero value if successful
642     // for now, pData is not used
643     EXPORT_C_(int) SPU2setupRecording(int start, void* pData)
644     {
645     if(start==0)
646     RecordStop();
647     else if(start==1)
648     RecordStart();
649    
650     return 0;
651     }
652    
653     EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
654     {
655     if( mode == FREEZE_SIZE )
656     {
657     data->size = Savestate::SizeIt();
658     return 0;
659     }
660    
661     jASSUME( mode == FREEZE_LOAD || mode == FREEZE_SAVE );
662     jASSUME( data != NULL );
663    
664     if( data->data == NULL ) return -1;
665     Savestate::DataBlock& spud = (Savestate::DataBlock&)*(data->data);
666    
667     switch( mode )
668     {
669     case FREEZE_LOAD: return Savestate::ThawIt( spud );
670     case FREEZE_SAVE: return Savestate::FreezeIt( spud );
671    
672     jNO_DEFAULT;
673     }
674    
675     // technically unreachable, but kills a warning:
676     return 0;
677     }

  ViewVC Help
Powered by ViewVC 1.1.22