2013-04-30 21:28:35 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using System.Runtime.InteropServices ;
2013-05-02 23:35:12 +00:00
using System.IO ;
2014-05-28 17:31:22 +00:00
using System.ComponentModel ;
2013-04-30 21:28:35 +00:00
2013-10-27 22:07:40 +00:00
using BizHawk.Common ;
2014-07-03 18:54:53 +00:00
using BizHawk.Common.BufferExtensions ;
2013-11-04 01:39:19 +00:00
using BizHawk.Emulation.Common ;
2013-11-03 23:45:44 +00:00
using BizHawk.Emulation.DiscSystem ;
2013-10-27 22:07:40 +00:00
2014-05-28 17:31:22 +00:00
using Newtonsoft.Json ;
2013-11-13 23:36:21 +00:00
namespace BizHawk.Emulation.Cores.Sega.Saturn
2013-04-30 21:28:35 +00:00
{
2014-04-25 01:19:57 +00:00
[ CoreAttributes (
"Yabause" ,
2014-06-01 01:57:22 +00:00
"" ,
2014-04-25 01:19:57 +00:00
isPorted : true ,
2014-06-01 01:57:22 +00:00
isReleased : true ,
portedVersion : "9.12" ,
portedUrl : "http://yabause.org"
2014-04-25 01:19:57 +00:00
) ]
2014-11-30 20:38:15 +00:00
public class Yabause : IEmulator , IVideoProvider , ISyncSoundProvider , IMemoryDomains , ISaveRam , IStatable , IInputPollable ,
2014-12-12 01:49:54 +00:00
ISettable < object , Yabause . SaturnSyncSettings > , IDriveLight
2013-04-30 21:28:35 +00:00
{
public static ControllerDefinition SaturnController = new ControllerDefinition
{
Name = "Saturn Controller" ,
BoolButtons =
2013-05-01 02:53:53 +00:00
{
"Power" , "Reset" ,
2014-06-29 13:20:30 +00:00
"P1 Up" , "P1 Down" , "P1 Left" , "P1 Right" , "P1 Start" , "P1 A" , "P1 B" , "P1 C" , "P1 X" , "P1 Y" , "P1 Z" , "P1 L" , "P1 R" ,
"P2 Up" , "P2 Down" , "P2 Left" , "P2 Right" , "P2 Start" , "P2 A" , "P2 B" , "P2 C" , "P2 X" , "P2 Y" , "P2 Z" , "P2 L" , "P2 R" ,
2013-04-30 21:28:35 +00:00
}
} ;
static Yabause AttachedCore = null ;
GCHandle VideoHandle ;
2013-11-03 23:45:44 +00:00
Disc CD ;
2013-05-01 01:46:20 +00:00
GCHandle SoundHandle ;
bool Disposed = false ;
2013-05-09 00:47:16 +00:00
byte [ ] DisposedSaveRam ;
2013-04-30 21:28:35 +00:00
2013-05-01 00:27:36 +00:00
LibYabause . CDInterface . Init InitH ;
LibYabause . CDInterface . DeInit DeInitH ;
LibYabause . CDInterface . GetStatus GetStatusH ;
LibYabause . CDInterface . ReadTOC ReadTOCH ;
LibYabause . CDInterface . ReadSectorFAD ReadSectorFADH ;
LibYabause . CDInterface . ReadAheadFAD ReadAheadFADH ;
2013-11-17 02:10:38 +00:00
LibYabause . InputCallback InputCallbackH ;
2013-12-27 03:02:28 +00:00
public Yabause ( CoreComm CoreComm , DiscSystem . Disc CD , object SyncSettings )
2013-04-30 21:28:35 +00:00
{
2014-12-04 03:38:30 +00:00
ServiceProvider = new BasicServiceProvider ( this ) ;
2013-12-10 17:58:12 +00:00
byte [ ] bios = CoreComm . CoreFileProvider . GetFirmware ( "SAT" , "J" , true , "Saturn BIOS is required." ) ;
2013-12-08 17:48:30 +00:00
CoreComm . RomStatusDetails = string . Format ( "Disk partial hash:{0}" , CD . GetHash ( ) ) ;
2013-04-30 21:28:35 +00:00
this . CoreComm = CoreComm ;
2013-05-01 00:27:36 +00:00
this . CD = CD ;
2013-12-27 03:02:28 +00:00
this . SyncSettings = ( SaturnSyncSettings ) SyncSettings ? ? new SaturnSyncSettings ( ) ;
2014-06-08 23:30:34 +00:00
if ( this . SyncSettings . UseGL & & glContext = = null )
{
glContext = CoreComm . RequestGLContext ( ) ;
}
2013-11-03 16:29:51 +00:00
ResetCounters ( ) ;
2014-06-08 23:30:34 +00:00
2014-06-09 19:19:12 +00:00
ActivateGL ( ) ;
2013-12-27 03:02:28 +00:00
Init ( bios ) ;
2013-11-17 02:10:38 +00:00
2014-12-04 00:43:12 +00:00
InputCallbackH = new LibYabause . InputCallback ( ( ) = > InputCallbacks . Call ( ) ) ;
2013-11-17 02:10:38 +00:00
LibYabause . libyabause_setinputcallback ( InputCallbackH ) ;
2014-12-12 01:49:54 +00:00
DriveLightEnabled = true ;
2014-06-08 23:30:34 +00:00
2014-06-09 19:19:12 +00:00
DeactivateGL ( ) ;
2013-04-30 21:28:35 +00:00
}
2014-12-04 03:38:30 +00:00
public IEmulatorServiceProvider ServiceProvider { get ; private set ; }
2014-12-12 01:49:54 +00:00
public bool DriveLightEnabled { get ; private set ; }
public bool DriveLightOn { get ; private set ; }
2014-06-08 23:30:34 +00:00
static object glContext ;
2014-06-09 19:19:12 +00:00
void ActivateGL ( )
{
//if (!SyncSettings.UseGL) return; //not safe
if ( glContext = = null ) return ;
CoreComm . ActivateGLContext ( glContext ) ;
}
void DeactivateGL ( )
{
//if (!SyncSettings.UseGL) return; //not safe
if ( glContext = = null ) return ;
CoreComm . DeactivateGLContext ( ) ;
}
2013-12-27 03:02:28 +00:00
void Init ( byte [ ] bios )
2013-04-30 21:28:35 +00:00
{
2013-12-27 03:02:28 +00:00
bool GL = SyncSettings . UseGL ;
2013-04-30 21:28:35 +00:00
if ( AttachedCore ! = null )
{
AttachedCore . Dispose ( ) ;
AttachedCore = null ;
}
VideoHandle = GCHandle . Alloc ( VideoBuffer , GCHandleType . Pinned ) ;
2013-05-01 01:46:20 +00:00
SoundHandle = GCHandle . Alloc ( SoundBuffer , GCHandleType . Pinned ) ;
2013-04-30 21:28:35 +00:00
2013-05-01 00:27:36 +00:00
LibYabause . CDInterface CDInt = new LibYabause . CDInterface ( ) ;
CDInt . InitFunc = InitH = new LibYabause . CDInterface . Init ( CD_Init ) ;
CDInt . DeInitFunc = DeInitH = new LibYabause . CDInterface . DeInit ( CD_DeInit ) ;
CDInt . GetStatusFunc = GetStatusH = new LibYabause . CDInterface . GetStatus ( CD_GetStatus ) ;
CDInt . ReadTOCFunc = ReadTOCH = new LibYabause . CDInterface . ReadTOC ( CD_ReadTOC ) ;
CDInt . ReadSectorFADFunc = ReadSectorFADH = new LibYabause . CDInterface . ReadSectorFAD ( CD_ReadSectorFAD ) ;
CDInt . ReadAheadFADFunc = ReadAheadFADH = new LibYabause . CDInterface . ReadAheadFAD ( CD_ReadAheadFAD ) ;
2013-05-02 20:47:56 +00:00
var fp = new FilePiping ( ) ;
string BiosPipe = fp . GetPipeNameNative ( ) ;
fp . Offer ( bios ) ;
2014-05-28 17:31:22 +00:00
int basetime ;
if ( SyncSettings . RealTimeRTC )
basetime = 0 ;
else
basetime = ( int ) ( ( SyncSettings . RTCInitialTime - new DateTime ( 1970 , 1 , 1 ) . ToLocalTime ( ) ) . TotalSeconds ) ;
if ( ! LibYabause . libyabause_init
(
ref CDInt ,
BiosPipe ,
GL ,
SyncSettings . CartType ,
SyncSettings . SkipBios ,
! SyncSettings . RealTimeRTC ,
basetime
) )
2013-04-30 21:28:35 +00:00
throw new Exception ( "libyabause_init() failed!" ) ;
2013-12-11 04:01:33 +00:00
fp . Finish ( ) ;
2013-05-02 20:47:56 +00:00
2013-04-30 21:28:35 +00:00
LibYabause . libyabause_setvidbuff ( VideoHandle . AddrOfPinnedObject ( ) ) ;
2013-05-01 01:46:20 +00:00
LibYabause . libyabause_setsndbuff ( SoundHandle . AddrOfPinnedObject ( ) ) ;
2013-04-30 21:28:35 +00:00
AttachedCore = this ;
2013-05-01 01:46:20 +00:00
2013-05-14 03:06:37 +00:00
// with or without GL, this is the guaranteed frame -1 size; (unless you do a gl resize)
2013-05-01 01:46:20 +00:00
BufferWidth = 320 ;
BufferHeight = 224 ;
2013-05-07 21:35:55 +00:00
InitMemoryDomains ( ) ;
2013-05-14 03:06:37 +00:00
GLMode = GL ;
2013-12-27 03:02:28 +00:00
// if in GL mode, this will trigger the initial GL resize
PutSyncSettings ( this . SyncSettings ) ;
2013-04-30 21:28:35 +00:00
}
public ControllerDefinition ControllerDefinition
{
get { return SaturnController ; }
}
public IController Controller { get ; set ; }
2013-05-14 03:06:37 +00:00
public bool GLMode { get ; private set ; }
public void SetGLRes ( int factor , int width , int height )
{
if ( ! GLMode )
return ;
if ( factor < 0 ) factor = 0 ;
if ( factor > 4 ) factor = 4 ;
int maxwidth , maxheight ;
if ( factor = = 0 )
{
maxwidth = width ;
maxheight = height ;
}
else
{
maxwidth = 704 * factor ;
maxheight = 512 * factor ;
}
if ( maxwidth * maxheight > VideoBuffer . Length )
{
VideoHandle . Free ( ) ;
VideoBuffer = new int [ maxwidth * maxheight ] ;
VideoHandle = GCHandle . Alloc ( VideoBuffer , GCHandleType . Pinned ) ;
LibYabause . libyabause_setvidbuff ( VideoHandle . AddrOfPinnedObject ( ) ) ;
}
LibYabause . libyabause_glsetnativefactor ( factor ) ;
if ( factor = = 0 )
LibYabause . libyabause_glresize ( width , height ) ;
}
2013-12-22 00:44:39 +00:00
2013-05-14 03:06:37 +00:00
2013-04-30 21:28:35 +00:00
public void FrameAdvance ( bool render , bool rendersound = true )
{
2013-05-01 01:46:20 +00:00
int w , h , nsamp ;
2013-05-01 02:53:53 +00:00
2014-06-09 19:19:12 +00:00
ActivateGL ( ) ;
2014-06-08 23:30:34 +00:00
2013-05-01 02:53:53 +00:00
LibYabause . Buttons1 p11 = ( LibYabause . Buttons1 ) 0xff ;
LibYabause . Buttons2 p12 = ( LibYabause . Buttons2 ) 0xff ;
LibYabause . Buttons1 p21 = ( LibYabause . Buttons1 ) 0xff ;
LibYabause . Buttons2 p22 = ( LibYabause . Buttons2 ) 0xff ;
if ( Controller [ "P1 A" ] )
p11 & = ~ LibYabause . Buttons1 . A ;
if ( Controller [ "P1 B" ] )
p11 & = ~ LibYabause . Buttons1 . B ;
if ( Controller [ "P1 C" ] )
p11 & = ~ LibYabause . Buttons1 . C ;
if ( Controller [ "P1 Start" ] )
p11 & = ~ LibYabause . Buttons1 . S ;
if ( Controller [ "P1 Left" ] )
p11 & = ~ LibYabause . Buttons1 . L ;
if ( Controller [ "P1 Right" ] )
p11 & = ~ LibYabause . Buttons1 . R ;
if ( Controller [ "P1 Up" ] )
p11 & = ~ LibYabause . Buttons1 . U ;
if ( Controller [ "P1 Down" ] )
p11 & = ~ LibYabause . Buttons1 . D ;
if ( Controller [ "P1 L" ] )
p12 & = ~ LibYabause . Buttons2 . L ;
if ( Controller [ "P1 R" ] )
p12 & = ~ LibYabause . Buttons2 . R ;
if ( Controller [ "P1 X" ] )
p12 & = ~ LibYabause . Buttons2 . X ;
if ( Controller [ "P1 Y" ] )
p12 & = ~ LibYabause . Buttons2 . Y ;
if ( Controller [ "P1 Z" ] )
p12 & = ~ LibYabause . Buttons2 . Z ;
if ( Controller [ "P2 A" ] )
p21 & = ~ LibYabause . Buttons1 . A ;
if ( Controller [ "P2 B" ] )
p21 & = ~ LibYabause . Buttons1 . B ;
if ( Controller [ "P2 C" ] )
p21 & = ~ LibYabause . Buttons1 . C ;
if ( Controller [ "P2 Start" ] )
p21 & = ~ LibYabause . Buttons1 . S ;
if ( Controller [ "P2 Left" ] )
p21 & = ~ LibYabause . Buttons1 . L ;
if ( Controller [ "P2 Right" ] )
p21 & = ~ LibYabause . Buttons1 . R ;
if ( Controller [ "P2 Up" ] )
p21 & = ~ LibYabause . Buttons1 . U ;
if ( Controller [ "P2 Down" ] )
p21 & = ~ LibYabause . Buttons1 . D ;
if ( Controller [ "P2 L" ] )
p22 & = ~ LibYabause . Buttons2 . L ;
if ( Controller [ "P2 R" ] )
p22 & = ~ LibYabause . Buttons2 . R ;
if ( Controller [ "P2 X" ] )
p22 & = ~ LibYabause . Buttons2 . X ;
if ( Controller [ "P2 Y" ] )
p22 & = ~ LibYabause . Buttons2 . Y ;
if ( Controller [ "P2 Z" ] )
p22 & = ~ LibYabause . Buttons2 . Z ;
if ( Controller [ "Reset" ] )
LibYabause . libyabause_softreset ( ) ;
if ( Controller [ "Power" ] )
2013-05-03 01:32:16 +00:00
LibYabause . libyabause_hardreset ( ) ;
2013-05-01 02:53:53 +00:00
LibYabause . libyabause_setpads ( p11 , p12 , p21 , p22 ) ;
2014-12-12 01:49:54 +00:00
DriveLightOn = false ;
2013-12-30 20:44:38 +00:00
2013-05-01 17:22:12 +00:00
IsLagFrame = LibYabause . libyabause_frameadvance ( out w , out h , out nsamp ) ;
2013-04-30 21:28:35 +00:00
BufferWidth = w ;
BufferHeight = h ;
2013-05-01 01:46:20 +00:00
SoundNSamp = nsamp ;
2013-04-30 21:28:35 +00:00
Frame + + ;
2013-05-01 17:22:12 +00:00
if ( IsLagFrame )
LagCount + + ;
2013-05-01 01:46:20 +00:00
//Console.WriteLine(nsamp);
2013-05-03 22:12:35 +00:00
//CheckStates();
2014-06-08 23:30:34 +00:00
2014-06-09 19:19:12 +00:00
DeactivateGL ( ) ;
2013-04-30 21:28:35 +00:00
}
2013-05-01 17:22:12 +00:00
public int Frame { get ; private set ; }
public int LagCount { get ; set ; }
public bool IsLagFrame { get ; private set ; }
2013-04-30 21:28:35 +00:00
2014-12-04 00:43:12 +00:00
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem ( ) ;
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [ FeatureNotImplemented ] get { return _inputCallbacks ; } }
2013-05-01 17:22:12 +00:00
public string SystemId { get { return "SAT" ; } }
public bool DeterministicEmulation { get { return true ; } }
2013-04-30 21:28:35 +00:00
2013-08-24 16:54:22 +00:00
public string BoardName { get { return null ; } }
2013-05-03 01:32:16 +00:00
#region saveram
2014-08-13 17:52:13 +00:00
public byte [ ] CloneSaveRam ( )
2013-04-30 21:28:35 +00:00
{
2013-05-09 00:47:16 +00:00
if ( Disposed )
{
2014-08-13 17:52:13 +00:00
if ( DisposedSaveRam ! = null )
{
return ( byte [ ] ) DisposedSaveRam . Clone ( ) ;
}
else
{
return new byte [ 0 ] ;
}
2013-05-09 00:47:16 +00:00
}
else
{
var ms = new MemoryStream ( ) ;
var fp = new FilePiping ( ) ;
fp . Get ( ms ) ;
bool success = LibYabause . libyabause_savesaveram ( fp . GetPipeNameNative ( ) ) ;
2013-12-11 04:01:33 +00:00
fp . Finish ( ) ;
2013-05-09 00:47:16 +00:00
if ( ! success )
throw new Exception ( "libyabause_savesaveram() failed!" ) ;
var ret = ms . ToArray ( ) ;
ms . Dispose ( ) ;
return ret ;
}
2013-04-30 21:28:35 +00:00
}
public void StoreSaveRam ( byte [ ] data )
{
2013-05-09 00:47:16 +00:00
if ( Disposed )
{
throw new Exception ( "It's a bit late for that" ) ;
}
else
{
var fp = new FilePiping ( ) ;
fp . Offer ( data ) ;
bool success = LibYabause . libyabause_loadsaveram ( fp . GetPipeNameNative ( ) ) ;
2013-12-11 04:01:33 +00:00
fp . Finish ( ) ;
2013-05-09 00:47:16 +00:00
if ( ! success )
throw new Exception ( "libyabause_loadsaveram() failed!" ) ;
}
2013-04-30 21:28:35 +00:00
}
public bool SaveRamModified
{
2013-05-09 00:47:16 +00:00
get
{
if ( Disposed )
return DisposedSaveRam ! = null ;
else
return LibYabause . libyabause_saveramodified ( ) ;
}
2013-04-30 21:28:35 +00:00
}
2013-05-03 01:32:16 +00:00
#endregion
2013-11-03 16:29:51 +00:00
public void ResetCounters ( )
2013-04-30 21:28:35 +00:00
{
Frame = 0 ;
LagCount = 0 ;
2013-05-01 17:22:12 +00:00
IsLagFrame = false ;
2013-04-30 21:28:35 +00:00
}
2013-05-02 23:35:12 +00:00
#region savestates
void LoadCoreBinary ( byte [ ] data )
{
var fp = new FilePiping ( ) ;
fp . Offer ( data ) ;
2014-06-09 03:13:59 +00:00
//loadstate can trigger GL work
2014-06-09 19:19:12 +00:00
ActivateGL ( ) ;
2014-06-09 03:13:59 +00:00
2013-05-02 23:35:12 +00:00
bool succeed = LibYabause . libyabause_loadstate ( fp . GetPipeNameNative ( ) ) ;
2014-06-09 03:13:59 +00:00
2014-06-09 19:19:12 +00:00
DeactivateGL ( ) ;
2014-06-09 03:13:59 +00:00
2013-12-11 04:01:33 +00:00
fp . Finish ( ) ;
2013-05-02 23:35:12 +00:00
if ( ! succeed )
throw new Exception ( "libyabause_loadstate() failed" ) ;
}
byte [ ] SaveCoreBinary ( )
{
var ms = new MemoryStream ( ) ;
var fp = new FilePiping ( ) ;
fp . Get ( ms ) ;
bool succeed = LibYabause . libyabause_savestate ( fp . GetPipeNameNative ( ) ) ;
2013-12-11 04:01:33 +00:00
fp . Finish ( ) ;
2013-05-02 23:35:12 +00:00
var ret = ms . ToArray ( ) ;
ms . Close ( ) ;
if ( ! succeed )
throw new Exception ( "libyabause_savestate() failed" ) ;
return ret ;
}
// these next 5 functions are all exact copy paste from gambatte.
// if something's wrong here, it's probably wrong there too
public void SaveStateText ( TextWriter writer )
2013-04-30 21:28:35 +00:00
{
2013-05-02 23:35:12 +00:00
var temp = SaveStateBinary ( ) ;
2013-06-05 18:42:54 +00:00
temp . SaveAsHexFast ( writer ) ;
2013-05-02 23:35:12 +00:00
// write extra copy of stuff we don't use
writer . WriteLine ( "Frame {0}" , Frame ) ;
2013-04-30 21:28:35 +00:00
}
2013-05-02 23:35:12 +00:00
public void LoadStateText ( TextReader reader )
2013-04-30 21:28:35 +00:00
{
2013-05-02 23:35:12 +00:00
string hex = reader . ReadLine ( ) ;
byte [ ] state = new byte [ hex . Length / 2 ] ;
2013-06-05 17:42:53 +00:00
state . ReadFromHexFast ( hex ) ;
2013-05-02 23:35:12 +00:00
LoadStateBinary ( new BinaryReader ( new MemoryStream ( state ) ) ) ;
2013-04-30 21:28:35 +00:00
}
2013-05-02 23:35:12 +00:00
public void SaveStateBinary ( BinaryWriter writer )
2013-04-30 21:28:35 +00:00
{
2013-05-02 23:35:12 +00:00
byte [ ] data = SaveCoreBinary ( ) ;
writer . Write ( data . Length ) ;
writer . Write ( data ) ;
// other variables
writer . Write ( IsLagFrame ) ;
writer . Write ( LagCount ) ;
writer . Write ( Frame ) ;
2013-04-30 21:28:35 +00:00
}
2013-05-02 23:35:12 +00:00
public void LoadStateBinary ( BinaryReader reader )
2013-04-30 21:28:35 +00:00
{
2013-05-02 23:35:12 +00:00
int length = reader . ReadInt32 ( ) ;
byte [ ] data = reader . ReadBytes ( length ) ;
LoadCoreBinary ( data ) ;
// other variables
IsLagFrame = reader . ReadBoolean ( ) ;
LagCount = reader . ReadInt32 ( ) ;
Frame = reader . ReadInt32 ( ) ;
2013-04-30 21:28:35 +00:00
}
2013-05-06 20:51:28 +00:00
public bool BinarySaveStatesPreferred { get { return true ; } }
2013-04-30 21:28:35 +00:00
public byte [ ] SaveStateBinary ( )
{
2013-05-02 23:35:12 +00:00
MemoryStream ms = new MemoryStream ( ) ;
BinaryWriter bw = new BinaryWriter ( ms ) ;
SaveStateBinary ( bw ) ;
bw . Flush ( ) ;
return ms . ToArray ( ) ;
2013-04-30 21:28:35 +00:00
}
2013-05-03 22:12:35 +00:00
/// <summary>
/// does a save, load, save combo, and checks the two saves for identicalness.
/// </summary>
void CheckStates ( )
{
byte [ ] s1 = SaveStateBinary ( ) ;
LoadStateBinary ( new BinaryReader ( new MemoryStream ( s1 , false ) ) ) ;
byte [ ] s2 = SaveStateBinary ( ) ;
if ( s1 . Length ! = s2 . Length )
throw new Exception ( string . Format ( "CheckStates: Length {0} != {1}" , s1 . Length , s2 . Length ) ) ;
unsafe
{
fixed ( byte * b1 = & s1 [ 0 ] , b2 = & s2 [ 0 ] )
{
for ( int i = 0 ; i < s1 . Length ; i + + )
{
if ( b1 [ i ] ! = b2 [ i ] )
{
File . WriteAllBytes ( "save1.raw" , s1 ) ;
File . WriteAllBytes ( "save2.raw" , s2 ) ;
throw new Exception ( string . Format ( "CheckStates s1[{0}] = {1}, s2[{0}] = {2}" , i , b1 [ i ] , b2 [ i ] ) ) ;
}
}
}
}
}
2013-12-22 00:44:39 +00:00
2013-05-03 22:12:35 +00:00
2013-05-03 01:32:16 +00:00
#endregion
2013-05-02 23:35:12 +00:00
2013-04-30 21:28:35 +00:00
public CoreComm CoreComm { get ; private set ; }
2013-05-07 21:35:55 +00:00
#region memorydomains
2013-04-30 21:28:35 +00:00
2013-05-07 21:35:55 +00:00
void InitMemoryDomains ( )
2013-04-30 21:28:35 +00:00
{
2013-05-07 21:35:55 +00:00
var ret = new List < MemoryDomain > ( ) ;
var nmds = LibYabause . libyabause_getmemoryareas_ex ( ) ;
foreach ( var nmd in nmds )
{
int l = nmd . length ;
IntPtr d = nmd . data ;
ret . Add ( new MemoryDomain (
nmd . name ,
nmd . length ,
2013-11-04 02:11:40 +00:00
MemoryDomain . Endian . Little ,
2013-05-07 21:35:55 +00:00
delegate ( int addr )
{
if ( addr < 0 | | addr > = l )
throw new ArgumentOutOfRangeException ( ) ;
unsafe
{
byte * p = ( byte * ) d ;
return p [ addr ] ;
}
} ,
delegate ( int addr , byte val )
{
if ( addr < 0 | | addr > = l )
throw new ArgumentOutOfRangeException ( ) ;
unsafe
{
byte * p = ( byte * ) d ;
2013-05-11 14:24:01 +00:00
p [ addr ] = val ;
2013-05-07 21:35:55 +00:00
}
}
) ) ;
}
// fulfill the prophecy of MainMemory always being MemoryDomains[0]
var tmp = ret [ 2 ] ;
ret [ 2 ] = ret [ 0 ] ;
ret [ 0 ] = tmp ;
2013-11-06 02:15:29 +00:00
MemoryDomains = new MemoryDomainList ( ret ) ;
2013-04-30 21:28:35 +00:00
}
2013-11-06 02:15:29 +00:00
public MemoryDomainList MemoryDomains { get ; private set ; }
2013-05-07 21:35:55 +00:00
#endregion
2013-04-30 21:28:35 +00:00
public void Dispose ( )
{
2013-05-01 01:46:20 +00:00
if ( ! Disposed )
{
2014-06-09 19:19:12 +00:00
ActivateGL ( ) ;
2013-05-09 00:47:16 +00:00
if ( SaveRamModified )
2014-08-13 17:52:13 +00:00
DisposedSaveRam = CloneSaveRam ( ) ;
2013-05-01 01:46:20 +00:00
LibYabause . libyabause_setvidbuff ( IntPtr . Zero ) ;
LibYabause . libyabause_setsndbuff ( IntPtr . Zero ) ;
LibYabause . libyabause_deinit ( ) ;
VideoHandle . Free ( ) ;
SoundHandle . Free ( ) ;
2014-12-19 21:53:43 +00:00
CD . Dispose ( ) ;
2013-05-01 01:46:20 +00:00
Disposed = true ;
2014-06-09 19:19:12 +00:00
DeactivateGL ( ) ;
2013-05-01 01:46:20 +00:00
}
2013-04-30 21:28:35 +00:00
}
#region IVideoProvider
public IVideoProvider VideoProvider { get { return this ; } }
int [ ] VideoBuffer = new int [ 704 * 512 ] ;
public int [ ] GetVideoBuffer ( ) { return VideoBuffer ; }
2014-04-30 23:48:37 +00:00
public int VirtualWidth { get { return BufferWidth ; } }
public int VirtualHeight { get { return BufferHeight ; } }
2013-04-30 21:28:35 +00:00
public int BufferWidth { get ; private set ; }
public int BufferHeight { get ; private set ; }
public int BackgroundColor { get { return unchecked ( ( int ) 0xff000000 ) ; } }
#endregion
#region ISyncSoundProvider
2013-05-01 01:46:20 +00:00
short [ ] SoundBuffer = new short [ 44100 * 2 ] ;
int SoundNSamp = 0 ;
2013-04-30 21:28:35 +00:00
public void GetSamples ( out short [ ] samples , out int nsamp )
{
2013-05-01 01:46:20 +00:00
nsamp = SoundNSamp ;
2013-04-30 21:28:35 +00:00
samples = SoundBuffer ;
}
2013-05-03 01:32:16 +00:00
public void DiscardSamples ( ) { }
public ISoundProvider SoundProvider { get { return null ; } }
public ISyncSoundProvider SyncSoundProvider { get { return this ; } }
public bool StartAsyncSound ( ) { return false ; }
public void EndAsyncSound ( ) { }
2013-04-30 21:28:35 +00:00
2013-05-01 00:27:36 +00:00
#endregion
#region CD
/// <summary>
/// init cd functions
/// </summary>
/// <param name="unused"></param>
/// <returns>0 on success, -1 on failure</returns>
int CD_Init ( string unused )
{
return 0 ;
}
/// <summary>
/// deinit cd functions
/// </summary>
void CD_DeInit ( )
{
}
/// <summary>
/// 0 = cd present, spinning
/// 1 = cd present, not spinning
/// 2 = no cd
/// 3 = tray open
/// </summary>
/// <returns></returns>
int CD_GetStatus ( )
{
return 0 ;
}
/// <summary>
/// read all TOC entries
/// </summary>
/// <param name="dest">place to copy to</param>
/// <returns>number of bytes written. should be 408 (99 tracks, 3 specials)</returns>
int CD_ReadTOC ( IntPtr dest )
{
// this stuff from yabause's cdbase.c. don't ask me to explain it
2014-12-04 05:40:10 +00:00
var TOC = CD . ReadStructure ( ) ;
2013-05-01 00:27:36 +00:00
int [ ] rTOC = new int [ 102 ] ;
var ses = TOC . Sessions [ 0 ] ;
int ntrk = ses . Tracks . Count ;
for ( int i = 0 ; i < 99 ; i + + )
{
if ( i < ntrk )
{
var trk = ses . Tracks [ i ] ;
uint t = ( uint ) trk . Indexes [ 1 ] . aba ;
switch ( trk . TrackType )
{
case DiscSystem . ETrackType . Audio :
t | = 0x01000000 ;
break ;
case DiscSystem . ETrackType . Mode1_2048 :
case DiscSystem . ETrackType . Mode1_2352 :
case DiscSystem . ETrackType . Mode2_2352 :
t | = 0x41000000 ;
break ;
}
rTOC [ i ] = ( int ) t ;
}
else
{
rTOC [ i ] = unchecked ( ( int ) 0xffffffff ) ;
}
}
rTOC [ 99 ] = ( int ) ( rTOC [ 0 ] & 0xff000000 | 0x010000 ) ;
rTOC [ 100 ] = ( int ) ( rTOC [ ntrk - 1 ] & 0xff000000 | ( uint ) ( ntrk < < 16 ) ) ;
rTOC [ 101 ] = ( int ) ( rTOC [ ntrk - 1 ] & 0xff000000 | ( uint ) ( ses . length_aba ) ) ;
Marshal . Copy ( rTOC , 0 , dest , 102 ) ;
return 408 ;
}
/// <summary>
/// read a sector, should be 2352 bytes
/// </summary>
/// <param name="FAD"></param>
/// <param name="dest"></param>
/// <returns></returns>
int CD_ReadSectorFAD ( int FAD , IntPtr dest )
{
byte [ ] data = new byte [ 2352 ] ;
try
{
CD . ReadABA_2352 ( FAD , data , 0 ) ;
}
catch ( Exception e )
{
Console . WriteLine ( "CD_ReadSectorFAD: Managed Exception:\n" + e . ToString ( ) ) ;
return 0 ; // failure
}
Marshal . Copy ( data , 0 , dest , 2352 ) ;
2014-12-12 01:49:54 +00:00
DriveLightOn = true ;
2013-05-01 00:27:36 +00:00
return 1 ; // success
}
/// <summary>
/// hint the next sector, for async loading
/// </summary>
/// <param name="FAD"></param>
void CD_ReadAheadFAD ( int FAD )
{
// ignored for now
}
2013-04-30 21:28:35 +00:00
#endregion
2013-12-22 00:44:39 +00:00
2014-07-14 16:10:45 +00:00
SaturnSyncSettings SyncSettings ;
2013-12-27 03:02:28 +00:00
2013-12-22 00:44:39 +00:00
public object GetSettings ( ) { return null ; }
2014-10-19 01:22:47 +00:00
public SaturnSyncSettings GetSyncSettings ( ) { return SyncSettings . Clone ( ) ; }
2013-12-22 00:44:39 +00:00
public bool PutSettings ( object o ) { return false ; }
2014-10-19 01:22:47 +00:00
public bool PutSyncSettings ( SaturnSyncSettings o )
2013-12-27 03:02:28 +00:00
{
2014-10-19 01:22:47 +00:00
bool ret = SaturnSyncSettings . NeedsReboot ( SyncSettings , o ) ;
2013-12-27 03:02:28 +00:00
2014-10-19 01:22:47 +00:00
SyncSettings = o ;
2013-12-27 03:02:28 +00:00
if ( GLMode & & SyncSettings . UseGL )
if ( SyncSettings . DispFree )
SetGLRes ( 0 , SyncSettings . GLW , SyncSettings . GLH ) ;
else
SetGLRes ( SyncSettings . DispFactor , 0 , 0 ) ;
return ret ;
}
public class SaturnSyncSettings
{
2014-07-20 00:31:01 +00:00
[DisplayName("Open GL Mode")]
2014-05-28 17:31:22 +00:00
[Description("Use OpenGL mode for rendering instead of software.")]
[DefaultValue(false)]
public bool UseGL { get ; set ; }
2014-07-20 00:31:01 +00:00
[DisplayName("Display Factor")]
2014-05-28 17:31:22 +00:00
[Description("In OpenGL mode, the internal resolution as a multiple of the normal internal resolution (1x, 2x, 3x, 4x). Ignored in software mode or when a custom resolution is used.")]
[DefaultValue(1)]
public int DispFactor { get { return _DispFactor ; } set { _DispFactor = Math . Max ( 1 , Math . Min ( value , 4 ) ) ; } }
[JsonIgnore]
2014-08-03 22:19:55 +00:00
[DeepEqualsIgnore]
2014-05-28 17:31:22 +00:00
private int _DispFactor ;
2014-07-20 00:31:01 +00:00
[DisplayName("Display Free")]
2014-05-28 17:31:22 +00:00
[Description("In OpenGL mode, set to true to use a custom resolution and ignore DispFactor.")]
[DefaultValue(false)]
2014-08-03 22:19:55 +00:00
public bool DispFree { get { return _DispFree ; } set { _DispFree = value ; } }
[JsonIgnore]
[DeepEqualsIgnore]
private bool _DispFree ;
2014-05-28 17:31:22 +00:00
2014-07-20 00:31:01 +00:00
[DisplayName("DispFree Final Width")]
2014-05-28 17:31:22 +00:00
[Description("In OpenGL mode and when DispFree is true, the width of the final resolution.")]
[DefaultValue(640)]
public int GLW { get { return _GLW ; } set { _GLW = Math . Max ( 320 , Math . Min ( value , 2048 ) ) ; } }
[JsonIgnore]
2014-08-03 22:19:55 +00:00
[DeepEqualsIgnore]
2014-05-28 17:31:22 +00:00
private int _GLW ;
2014-07-20 00:31:01 +00:00
[DisplayName("DispFree Final Height")]
2014-05-28 17:31:22 +00:00
[Description("In OpenGL mode and when DispFree is true, the height of the final resolution.")]
[DefaultValue(480)]
public int GLH { get { return _GLH ; } set { _GLH = Math . Max ( 224 , Math . Min ( value , 1024 ) ) ; } }
[JsonIgnore]
2014-08-03 22:19:55 +00:00
[DeepEqualsIgnore]
2014-05-28 17:31:22 +00:00
private int _GLH ;
2014-07-20 00:31:01 +00:00
[DisplayName("Ram Cart Type")]
2014-05-28 17:31:22 +00:00
[Description("The type of the attached RAM cart. Most games will not use this.")]
[DefaultValue(LibYabause.CartType.NONE)]
public LibYabause . CartType CartType { get ; set ; }
2014-07-20 00:31:01 +00:00
[DisplayName("Skip BIOS")]
2014-05-28 17:31:22 +00:00
[Description("Skip the Bios Intro screen.")]
[DefaultValue(false)]
public bool SkipBios { get ; set ; }
2014-07-20 00:31:01 +00:00
[DisplayName("Use RealTime RTC")]
2014-05-28 17:31:22 +00:00
[Description("If true, the real time clock will reflect real time, instead of emulated time. Ignored (forced to false) when a movie is recording.")]
[DefaultValue(false)]
public bool RealTimeRTC { get ; set ; }
2014-07-20 00:31:01 +00:00
[DisplayName("RTC intiial time")]
2014-05-28 17:31:22 +00:00
[Description("Set the initial RTC time. Only used when RealTimeRTC is false.")]
[DefaultValue(typeof(DateTime), "2010-01-01")]
public DateTime RTCInitialTime { get ; set ; }
2013-12-27 03:02:28 +00:00
public static bool NeedsReboot ( SaturnSyncSettings x , SaturnSyncSettings y )
{
2014-08-03 22:19:55 +00:00
return ! DeepEquality . DeepEquals ( x , y ) ;
2013-12-27 03:02:28 +00:00
}
public SaturnSyncSettings Clone ( )
{
return ( SaturnSyncSettings ) MemberwiseClone ( ) ;
}
2014-05-28 17:31:22 +00:00
public SaturnSyncSettings ( )
{
2014-07-14 16:10:45 +00:00
SettingsUtil . SetDefaultValues ( this ) ;
2014-05-28 17:31:22 +00:00
}
2013-12-27 03:02:28 +00:00
}
2013-04-30 21:28:35 +00:00
}
}