2009-02-15 05:15:39 +00:00
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
2010-07-04 22:49:00 +00:00
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
2009-02-15 05:15:39 +00:00
//
2009-09-29 19:18:50 +00:00
# include "Global.h"
# include "PS2E-spu2.h"
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
# ifdef _MSC_VER
# include "Windows.h"
# endif
2009-02-15 05:15:39 +00:00
FILE * s2rfile ;
void s2r_write16 ( s16 data )
{
fwrite ( & data , 2 , 1 , s2rfile ) ;
}
void s2r_write32 ( u32 data )
{
fwrite ( & data , 4 , 1 , s2rfile ) ;
}
2011-06-25 23:45:58 +00:00
# define EMITC(i,a) s2r_write32(((u32)(i&0x7)<<29)|(a&0x1FFFFFFF))
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
int s2r_open ( u32 ticks , char * filename )
2009-02-15 05:15:39 +00:00
{
s2rfile = fopen ( filename , " wb " ) ;
2011-06-25 23:45:58 +00:00
if ( s2rfile )
s2r_write32 ( ticks ) ;
2009-02-15 05:15:39 +00:00
return s2rfile ? 0 : - 1 ;
}
void s2r_readreg ( u32 ticks , u32 addr )
{
if ( ! s2rfile ) return ;
s2r_write32 ( ticks ) ;
EMITC ( 0 , addr ) ;
}
void s2r_writereg ( u32 ticks , u32 addr , s16 value )
{
if ( ! s2rfile ) return ;
s2r_write32 ( ticks ) ;
EMITC ( 1 , addr ) ;
s2r_write16 ( value ) ;
}
void s2r_writedma4 ( u32 ticks , u16 * data , u32 len )
{
u32 i ;
if ( ! s2rfile ) return ;
s2r_write32 ( ticks ) ;
EMITC ( 2 , len ) ;
for ( i = 0 ; i < len ; i + + , data + + )
s2r_write16 ( * data ) ;
}
void s2r_writedma7 ( u32 ticks , u16 * data , u32 len )
{
u32 i ;
if ( ! s2rfile ) return ;
s2r_write32 ( ticks ) ;
EMITC ( 3 , len ) ;
for ( i = 0 ; i < len ; i + + , data + + )
s2r_write16 ( * data ) ;
}
void s2r_close ( )
{
if ( ! s2rfile ) return ;
fclose ( s2rfile ) ;
}
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// replay code
bool replay_mode = false ;
u16 dmabuffer [ 0xFFFFF ] ;
2011-06-25 23:45:58 +00:00
const u32 IOP_CLK = 768 * 48000 ;
const u32 IOPCiclesPerMS = 768 * 48 ;
u32 CurrentIOPCycle = 0 ;
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
u64 HighResFreq ;
u64 HighResPrev ;
double HighResScale ;
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
bool Running = false ;
2009-02-15 05:15:39 +00:00
2011-04-23 08:11:40 +00:00
# ifdef _MSC_VER
2011-06-25 23:45:58 +00:00
int conprintf ( const char * fmt , . . . )
{
# ifdef WIN32
char s [ 1024 ] ;
va_list list ;
va_start ( list , fmt ) ;
vsprintf ( s , fmt , list ) ;
va_end ( list ) ;
HANDLE handle = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
if ( handle = = INVALID_HANDLE_VALUE )
return 0 ;
DWORD written = 0 ;
WriteConsoleA ( handle , s , strlen ( s ) , & written , 0 ) ;
FlushFileBuffers ( handle ) ;
return written ;
# else
va_list list ;
va_start ( list , fmt ) ;
int ret = vsprintf ( stderr , fmt , list ) ;
va_end ( list ) ;
return ret ;
# endif
}
2009-02-15 05:15:39 +00:00
void dummy1 ( )
{
}
void dummy4 ( )
{
2010-02-03 03:37:55 +00:00
# ifndef ENABLE_NEW_IOPDMA_SPU2
2009-02-15 05:15:39 +00:00
SPU2interruptDMA4 ( ) ;
2010-02-03 03:37:55 +00:00
# endif
2009-02-15 05:15:39 +00:00
}
void dummy7 ( )
{
2010-02-03 03:37:55 +00:00
# ifndef ENABLE_NEW_IOPDMA_SPU2
2009-02-15 05:15:39 +00:00
SPU2interruptDMA7 ( ) ;
2010-02-03 03:37:55 +00:00
# endif
2009-02-15 05:15:39 +00:00
}
2011-06-25 23:45:58 +00:00
u64 HighResFrequency ( )
{
u64 freq ;
# ifdef WIN32
QueryPerformanceFrequency ( ( LARGE_INTEGER * ) & freq ) ;
# else
// TODO
# endif
return freq ;
}
u64 HighResCounter ( )
{
u64 time ;
# ifdef WIN32
QueryPerformanceCounter ( ( LARGE_INTEGER * ) & time ) ;
# else
// TODO
# endif
return time ;
}
void InitWaitSync ( ) // not extremely accurate but enough.
{
HighResFreq = HighResFrequency ( ) ;
HighResPrev = HighResCounter ( ) ;
HighResScale = ( double ) HighResFreq / ( double ) IOP_CLK ;
}
u32 WaitSync ( u32 TargetCycle )
{
u32 WaitCycles = ( TargetCycle - CurrentIOPCycle ) ;
u32 WaitTime = WaitCycles / IOPCiclesPerMS ;
if ( WaitTime > 10 )
WaitTime = 10 ;
2011-08-12 14:47:36 +00:00
if ( WaitTime = = 0 )
2011-06-25 23:45:58 +00:00
WaitTime = 1 ;
SleepEx ( WaitTime , TRUE ) ;
// Refresh current time after sleeping
u64 Current = HighResCounter ( ) ;
u32 delta = ( u32 ) floor ( ( Current - HighResPrev ) / HighResScale + 0.5 ) ; // We lose some precision here, cycles might drift away over long periods of time ;P
// Calculate time delta
CurrentIOPCycle + = delta ;
HighResPrev + = ( u64 ) floor ( delta * HighResScale + 0.5 ) ; // Trying to compensate drifting mentioned above, not necessarily useful.
return delta ;
}
# ifdef WIN32
BOOL WINAPI HandlerRoutine ( DWORD dwCtrlType )
{
Running = false ;
return TRUE ;
}
# endif
2009-02-15 05:15:39 +00:00
2009-09-29 19:18:50 +00:00
# include "Windows/Dialogs.h"
2009-03-02 06:41:02 +00:00
EXPORT_C_ ( void ) s2r_replay ( HWND hwnd , HINSTANCE hinst , LPSTR filename , int nCmdShow )
2009-02-15 05:15:39 +00:00
{
2010-02-03 03:37:55 +00:00
# ifndef ENABLE_NEW_IOPDMA_SPU2
2011-06-25 23:45:58 +00:00
int events = 0 ;
Running = true ;
# ifdef WIN32
AllocConsole ( ) ;
SetConsoleCtrlHandler ( HandlerRoutine , TRUE ) ;
conprintf ( " Playing %s file on %x... " , filename , hwnd ) ;
# endif
2009-02-15 05:15:39 +00:00
// load file
FILE * file = fopen ( filename , " rb " ) ;
2011-06-25 23:45:58 +00:00
if ( ! file )
{
conprintf ( " Could not open the replay file. " ) ;
return ;
}
2009-02-15 05:15:39 +00:00
// if successful, init the plugin
2011-06-25 23:45:58 +00:00
# define TryRead(dest,size,count,file) if(fread(dest,size,count,file)<count) { conprintf("Error reading from file."); goto Finish; /* Need to exit the while() loop and maybe also the switch */ }
TryRead ( & CurrentIOPCycle , 4 , 1 , file ) ;
2009-02-15 05:15:39 +00:00
replay_mode = true ;
2011-06-25 23:45:58 +00:00
InitWaitSync ( ) ; // Initialize the WaitSync stuff
2009-02-15 05:15:39 +00:00
SPU2init ( ) ;
SPU2irqCallback ( dummy1 , dummy4 , dummy7 ) ;
2011-06-25 23:45:58 +00:00
SPU2setClockPtr ( & CurrentIOPCycle ) ;
SPU2open ( & hwnd ) ;
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
CurrentIOPCycle = 0 ;
2009-02-15 05:15:39 +00:00
SPU2async ( 0 ) ;
2011-06-25 23:45:58 +00:00
while ( ! feof ( file ) & & Running )
2009-02-15 05:15:39 +00:00
{
u32 ccycle = 0 ;
u32 evid = 0 ;
u32 sval = 0 ;
u32 tval = 0 ;
2011-06-25 23:45:58 +00:00
TryRead ( & ccycle , 4 , 1 , file ) ;
TryRead ( & sval , 4 , 1 , file ) ;
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
evid = sval > > 29 ;
sval & = 0x1FFFFFFF ;
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
u32 TargetCycle = ccycle * 768 ;
2009-02-15 05:15:39 +00:00
2011-06-25 23:45:58 +00:00
while ( TargetCycle > CurrentIOPCycle )
{
u32 delta = WaitSync ( TargetCycle ) ;
SPU2async ( delta ) ;
2009-02-15 05:15:39 +00:00
}
2011-06-25 23:45:58 +00:00
2009-02-15 05:15:39 +00:00
switch ( evid )
{
case 0 :
SPU2read ( sval ) ;
break ;
case 1 :
2011-06-25 23:45:58 +00:00
TryRead ( & tval , 2 , 1 , file ) ;
2009-02-15 05:15:39 +00:00
SPU2write ( sval , tval ) ;
break ;
case 2 :
2011-06-25 23:45:58 +00:00
TryRead ( dmabuffer , sval , 2 , file ) ;
2009-02-15 05:15:39 +00:00
SPU2writeDMA4Mem ( dmabuffer , sval ) ;
break ;
case 3 :
2011-06-25 23:45:58 +00:00
TryRead ( dmabuffer , sval , 2 , file ) ;
2009-02-15 05:15:39 +00:00
SPU2writeDMA7Mem ( dmabuffer , sval ) ;
break ;
default :
// not implemented
return ;
break ;
}
2011-06-25 23:45:58 +00:00
events + + ;
2009-02-15 05:15:39 +00:00
}
2010-04-25 00:31:27 +00:00
2011-06-25 23:45:58 +00:00
Finish :
2009-02-15 05:15:39 +00:00
//shutdown
SPU2close ( ) ;
SPU2shutdown ( ) ;
fclose ( file ) ;
2011-06-25 23:45:58 +00:00
conprintf ( " Finished playing %s file (%d cycles, %d events). " , filename , CurrentIOPCycle , events ) ;
# ifdef WIN32
FreeConsole ( ) ;
# endif
2009-02-15 05:15:39 +00:00
replay_mode = false ;
2010-02-03 03:37:55 +00:00
# endif
2009-02-15 05:15:39 +00:00
}
2009-02-20 21:48:59 +00:00
# endif