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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 401 - (show 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 /* 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 return true;
115
116 #if 0
117 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 #endif
129 }
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 EXPORT_C_(void) CALLBACK SPU2setLogDir(const char* dir)
203 {
204 CfgSetLogDir( dir );
205 }
206
207 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 if (IsInitialized)
304 {
305 printf( " * SPU2-X: Already initialized - Ignoring SPU2init signal." );
306 return 0;
307 }
308
309 IsInitialized = true;
310
311 ReadSettings();
312
313 #ifdef SPU2_LOG
314 if(AccessLog())
315 {
316 spu2Log = OpenLog( AccessLogFileName );
317 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 SysMessage("SPU2-X: Error allocating Memory\n"); return -1;
338 }
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 for(uint mem=0;mem<0x800;mem++)
345 {
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 Cores[0].Init(0);
355 Cores[1].Init(1);
356
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 #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;
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 // 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 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 #ifdef _MSC_VER
421 #ifdef PCSX2_DEVBUILD // Define may not be needed but not tested yet. Better make sure.
422 if( IsDevBuild && VisualDebug() )
423 {
424 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
439 IsOpened = true;
440 lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
441
442 try
443 {
444 SndBuffer::Init();
445
446 #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
471 SndBuffer::Cleanup();
472 }
473
474 EXPORT_C_(void) SPU2shutdown()
475 {
476 if(!IsInitialized) return;
477 IsInitialized = false;
478
479 ConLog( "* SPU2-X: Shutting down.\n" );
480
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
506 #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 static bool lState[6];
523 #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 if((curTicks - lastTicks) >= 50)
542 {
543 int oldI = Interpolation;
544 bool cState[6];
545 for(int i=0;i<6;i++)
546 {
547 cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0+i)&0x8000);
548
549 if((cState[i] && !lState[i]) && i != 5)
550 Interpolation = i;
551
552 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 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 ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n",mem,ret);
605 }
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