/[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 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 10 months ago) by william
File size: 13898 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug 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 // 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 return true;
117
118 #if 0
119 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 #endif
131 }
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 EXPORT_C_(void) CALLBACK SPU2setLogDir(const char* dir)
205 {
206 CfgSetLogDir( dir );
207 }
208
209 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 if (IsInitialized)
306 {
307 printf( " * SPU2-X: Already initialized - Ignoring SPU2init signal." );
308 return 0;
309 }
310
311 IsInitialized = true;
312
313 ReadSettings();
314
315 #ifdef SPU2_LOG
316 if(AccessLog())
317 {
318 spu2Log = OpenLog( AccessLogFileName );
319 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 SysMessage("SPU2-X: Error allocating Memory\n"); return -1;
340 }
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 for(uint mem=0;mem<0x800;mem++)
347 {
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 Cores[0].Init(0);
357 Cores[1].Init(1);
358
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 #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 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 // uncomment for a visual debug display showing all core's activity!
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 IsOpened = true;
432 lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
433
434 try
435 {
436 SndBuffer::Init();
437 spdif_init();
438 #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
463 spdif_shutdown();
464 SndBuffer::Cleanup();
465 }
466
467 EXPORT_C_(void) SPU2shutdown()
468 {
469 if(!IsInitialized) return;
470 IsInitialized = false;
471
472 ConLog( "* SPU2-X: Shutting down.\n" );
473
474 SPU2close();
475
476 #ifdef S2R_ENABLE
477 if(!replay_mode)
478 s2r_close();
479 #endif
480
481 DoFullDump();
482 #ifdef STREAM_DUMP
483 fclose(il0);
484 fclose(il1);
485 #endif
486 #ifdef EFFECTS_DUMP
487 fclose(el0);
488 fclose(el1);
489 #endif
490 WaveDump::Close();
491
492 DMALogClose();
493
494 safe_free(spu2regs);
495 safe_free(_spu2mem);
496 safe_free( pcm_cache_data );
497
498
499 #ifdef SPU2_LOG
500 if(!AccessLog()) return;
501 FileLog("[%10d] SPU2shutdown\n",Cycles);
502 if(spu2Log) fclose(spu2Log);
503 #endif
504 }
505
506 EXPORT_C_(void) SPU2setClockPtr(u32 *ptr)
507 {
508 cyclePtr = ptr;
509 }
510
511 static bool numpad_plus = false, numpad_plus_old = false;
512
513 #ifdef DEBUG_KEYS
514 static u32 lastTicks;
515 static bool lState[5];
516 #endif
517
518 EXPORT_C_(void) SPU2async(u32 cycles)
519 {
520 DspUpdate();
521
522 if(cyclePtr != NULL)
523 {
524 TimeUpdate( *cyclePtr );
525 }
526 else
527 {
528 pClocks += cycles;
529 TimeUpdate( pClocks );
530 }
531
532 #ifdef DEBUG_KEYS
533 u32 curTicks = GetTickCount();
534 if((curTicks - lastTicks) >= 100)
535 {
536 int oldI = Interpolation;
537 bool cState[5];
538 for(int i=0;i<5;i++)
539 {
540 cState[i] = !!(GetAsyncKeyState(VK_NUMPAD0+i)&0x8000);
541
542 if(cState[i] && !lState[i])
543 Interpolation = i;
544
545 lState[i] = cState[i];
546 }
547
548 if(Interpolation != oldI)
549 {
550 printf("Interpolation set to %d", Interpolation);
551 switch(Interpolation)
552 {
553 case 0: printf(" - Nearest.\n"); break;
554 case 1: printf(" - Linear.\n"); break;
555 case 2: printf(" - Cubic.\n"); break;
556 case 3: printf(" - Hermite.\n"); break;
557 case 4: printf(" - Catmull-Rom.\n"); break;
558 default: printf(" (unknown).\n"); break;
559 }
560 }
561
562 lastTicks = curTicks;
563 }
564 #endif
565 }
566
567 EXPORT_C_(u16) SPU2read(u32 rmem)
568 {
569 // if(!replay_mode)
570 // s2r_readreg(Cycles,rmem);
571
572 u16 ret=0xDEAD; u32 core=0, mem=rmem&0xFFFF, omem=mem;
573 if (mem & 0x400) { omem^=0x400; core=1; }
574
575 if(rmem==0x1f9001AC)
576 {
577 ret = Cores[core].DmaRead();
578 }
579 else
580 {
581 if( cyclePtr != NULL )
582 TimeUpdate( *cyclePtr );
583
584 if (rmem>>16 == 0x1f80)
585 {
586 ret = Cores[0].ReadRegPS1(rmem);
587 }
588 else if( (mem&0xFFFF) >= 0x800 )
589 {
590 ret = spu2Ru16(mem);
591 ConLog("* SPU2-X: Read from reg>=0x800: %x value %x\n",mem,ret);
592 }
593 else
594 {
595 ret = *(regtable[(mem>>1)]);
596 //FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret);
597 SPU2writeLog( "read", rmem, ret );
598 }
599 }
600
601 return ret;
602 }
603
604 EXPORT_C_(void) SPU2write(u32 rmem, u16 value)
605 {
606 #ifdef S2R_ENABLE
607 if(!replay_mode)
608 s2r_writereg(Cycles,rmem,value);
609 #endif
610
611 // Note: Reverb/Effects are very sensitive to having precise update timings.
612 // If the SPU2 isn't in in sync with the IOP, samples can end up playing at rather
613 // incorrect pitches and loop lengths.
614
615 if( cyclePtr != NULL )
616 TimeUpdate( *cyclePtr );
617
618 if (rmem>>16 == 0x1f80)
619 Cores[0].WriteRegPS1(rmem,value);
620 else
621 {
622 SPU2writeLog( "write", rmem, value );
623 SPU2_FastWrite( rmem, value );
624 }
625 }
626
627 // if start is 1, starts recording spu2 data, else stops
628 // returns a non zero value if successful
629 // for now, pData is not used
630 EXPORT_C_(int) SPU2setupRecording(int start, void* pData)
631 {
632 if(start==0)
633 RecordStop();
634 else if(start==1)
635 RecordStart();
636
637 return 0;
638 }
639
640 EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
641 {
642 if( mode == FREEZE_SIZE )
643 {
644 data->size = Savestate::SizeIt();
645 return 0;
646 }
647
648 jASSUME( mode == FREEZE_LOAD || mode == FREEZE_SAVE );
649 jASSUME( data != NULL );
650
651 if( data->data == NULL ) return -1;
652 Savestate::DataBlock& spud = (Savestate::DataBlock&)*(data->data);
653
654 switch( mode )
655 {
656 case FREEZE_LOAD: return Savestate::ThawIt( spud );
657 case FREEZE_SAVE: return Savestate::FreezeIt( spud );
658
659 jNO_DEFAULT;
660 }
661
662 // technically unreachable, but kills a warning:
663 return 0;
664 }

  ViewVC Help
Powered by ViewVC 1.1.22