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

  ViewVC Help
Powered by ViewVC 1.1.22