/[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 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 2 months ago) by william
File size: 14032 byte(s)
re-commit (had local access denied errors when committing)
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,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 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 // uncomment for a visual debug display showing all core's activity!
422 /*if(debugDialogOpen==0)
423 {
424 hDebugDialog = CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD_DEBUG),0,DebugProc,0);
425 ShowWindow(hDebugDialog,SW_SHOWNORMAL);
426 debugDialogOpen=1;
427 }*/
428
429 IsOpened = true;
430 lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
431
432 try
433 {
434 SndBuffer::Init();
435
436 #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
461 SndBuffer::Cleanup();
462 }
463
464 EXPORT_C_(void) SPU2shutdown()
465 {
466 if(!IsInitialized) return;
467 IsInitialized = false;
468
469 ConLog( "* SPU2-X: Shutting down.\n" );
470
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
496 #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 static bool lState[6];
513 #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 if((curTicks - lastTicks) >= 50)
532 {
533 int oldI = Interpolation;
534 bool cState[6];
535 for(int i=0;i<6;i++)
536 {
537 cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0+i)&0x8000);
538
539 if((cState[i] && !lState[i]) && i != 5)
540 Interpolation = i;
541
542 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 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 ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n",mem,ret);
595 }
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