2011-01-11 02:55:51 +00:00
using System ;
2011-01-21 03:59:50 +00:00
using System.Collections.Generic ;
2011-01-11 02:55:51 +00:00
using System.IO ;
2016-07-16 17:57:24 +00:00
using System.Linq ;
2013-10-27 22:07:40 +00:00
using BizHawk.Common ;
2014-07-03 19:20:34 +00:00
using BizHawk.Common.BufferExtensions ;
2013-11-04 01:06:36 +00:00
using BizHawk.Emulation.Common ;
2013-11-14 19:33:13 +00:00
using BizHawk.Emulation.Common.Components ;
2014-07-03 19:20:34 +00:00
2016-03-04 13:37:09 +00:00
using BizHawk.Emulation.Cores.Components ;
2014-01-22 01:14:36 +00:00
using BizHawk.Emulation.Cores.Components.H6280 ;
2013-11-03 23:45:44 +00:00
using BizHawk.Emulation.DiscSystem ;
2011-01-11 02:55:51 +00:00
2013-11-13 23:36:21 +00:00
namespace BizHawk.Emulation.Cores.PCEngine
2011-01-11 02:55:51 +00:00
{
2011-09-24 17:05:34 +00:00
public enum NecSystemType { TurboGrafx , TurboCD , SuperGrafx }
2014-04-25 01:19:57 +00:00
[ CoreAttributes (
"PCEHawk" ,
"Vecna" ,
isPorted : false ,
isReleased : true
) ]
2015-01-14 21:55:48 +00:00
public sealed partial class PCEngine : IEmulator , ISaveRam , IStatable , IInputPollable ,
2015-10-28 08:51:53 +00:00
IDebuggable , ISettable < PCEngine . PCESettings , PCEngine . PCESyncSettings > , IDriveLight , ICodeDataLogger
2011-09-24 17:05:34 +00:00
{
// ROM
public byte [ ] RomData ;
public int RomLength ;
Disc disc ;
// Machine
public NecSystemType Type ;
public HuC6280 Cpu ;
public VDC VDC1 , VDC2 ;
public VCE VCE ;
public VPC VPC ;
public ScsiCDBus SCSI ;
public ADPCM ADPCM ;
public HuC6280PSG PSG ;
public CDAudio CDAudio ;
public SoundMixer SoundMixer ;
2016-12-11 17:14:42 +00:00
//public MetaspuSoundProvider SoundSynchronizer;
2011-09-24 17:05:34 +00:00
bool TurboGrafx { get { return Type = = NecSystemType . TurboGrafx ; } }
bool SuperGrafx { get { return Type = = NecSystemType . SuperGrafx ; } }
bool TurboCD { get { return Type = = NecSystemType . TurboCD ; } }
// BRAM
bool BramEnabled = false ;
bool BramLocked = true ;
byte [ ] BRAM ;
// Memory system
public byte [ ] Ram ; // PCE= 8K base ram, SGX= 64k base ram
public byte [ ] CDRam ; // TurboCD extra 64k of ram
public byte [ ] SuperRam ; // Super System Card 192K of additional RAM
public byte [ ] ArcadeRam ; // Arcade Card 2048K of additional RAM
2014-02-27 01:00:21 +00:00
string systemid = "PCE" ;
bool ForceSpriteLimit ;
2011-09-24 17:05:34 +00:00
// 21,477,270 Machine clocks / sec
// 7,159,090 Cpu cycles / sec
2014-08-23 19:06:37 +00:00
[CoreConstructor("PCE", "SGX")]
2014-06-28 22:48:07 +00:00
public PCEngine ( CoreComm comm , GameInfo game , byte [ ] rom , object Settings , object syncSettings )
2011-09-24 17:05:34 +00:00
{
2014-12-23 01:58:12 +00:00
2014-12-05 01:56:45 +00:00
MemoryCallbacks = new MemoryCallbackSystem ( ) ;
2012-12-10 00:43:43 +00:00
CoreComm = comm ;
2011-09-24 17:05:34 +00:00
switch ( game . System )
{
case "PCE" :
systemid = "PCE" ;
2012-09-14 23:18:16 +00:00
Type = NecSystemType . TurboGrafx ;
2011-09-24 17:05:34 +00:00
break ;
case "SGX" :
systemid = "SGX" ;
2012-09-14 23:18:16 +00:00
Type = NecSystemType . SuperGrafx ;
2011-09-24 17:05:34 +00:00
break ;
}
2014-08-03 22:05:32 +00:00
this . _settings = ( PCESettings ) Settings ? ? new PCESettings ( ) ;
2014-06-28 22:48:07 +00:00
_syncSettings = ( PCESyncSettings ) syncSettings ? ? new PCESyncSettings ( ) ;
2013-12-30 20:26:33 +00:00
Init ( game , rom ) ;
2014-06-28 22:48:07 +00:00
SetControllerButtons ( ) ;
2011-09-24 17:05:34 +00:00
}
2014-12-04 03:38:30 +00:00
public IEmulatorServiceProvider ServiceProvider { get ; private set ; }
2013-08-24 16:54:22 +00:00
public string BoardName { get { return null ; } }
2014-12-23 01:58:12 +00:00
private ITraceable Tracer { get ; set ; }
2014-12-05 01:56:45 +00:00
public IMemoryCallbackSystem MemoryCallbacks { get ; private set ; }
2014-12-05 00:05:40 +00:00
2014-06-28 22:48:07 +00:00
public PCEngine ( CoreComm comm , GameInfo game , Disc disc , object Settings , object syncSettings )
2011-09-24 17:05:34 +00:00
{
2012-12-10 00:43:43 +00:00
CoreComm = comm ;
2014-12-05 01:56:45 +00:00
MemoryCallbacks = new MemoryCallbackSystem ( ) ;
2014-12-12 01:49:54 +00:00
DriveLightEnabled = true ;
2011-09-24 17:05:34 +00:00
systemid = "PCECD" ;
Type = NecSystemType . TurboCD ;
this . disc = disc ;
2014-08-03 22:05:32 +00:00
this . _settings = ( PCESettings ) Settings ? ? new PCESettings ( ) ;
2014-06-28 22:48:07 +00:00
_syncSettings = ( PCESyncSettings ) syncSettings ? ? new PCESyncSettings ( ) ;
2014-02-10 15:26:18 +00:00
GameInfo biosInfo ;
byte [ ] rom = CoreComm . CoreFileProvider . GetFirmwareWithGameInfo ( "PCECD" , "Bios" , true , out biosInfo ,
"PCE-CD System Card not found. Please check the BIOS settings in Config->Firmwares." ) ;
if ( biosInfo . Status = = RomStatus . BadDump )
{
CoreComm . ShowMessage (
"The PCE-CD System Card you have selected is known to be a bad dump. This may cause problems playing PCE-CD games.\n\n"
+ "It is recommended that you find a good dump of the system card. Sorry to be the bearer of bad news!" ) ;
}
else if ( biosInfo . NotInDatabase )
{
CoreComm . ShowMessage (
"The PCE-CD System Card you have selected is not recognized in our database. That might mean it's a bad dump, or isn't the correct rom." ) ;
}
else if ( biosInfo [ "BIOS" ] = = false )
{
2014-05-08 03:18:00 +00:00
//zeromus says: someone please write a note about how this could possibly happen.
//it seems like this is a relic of using gameDB for storing whether something is a bios? firmwareDB should be handling it now.
2014-02-10 15:26:18 +00:00
CoreComm . ShowMessage (
2014-05-08 03:18:00 +00:00
"The PCE-CD System Card you have selected is not a BIOS image. You may have selected the wrong rom. FYI-Please report this to developers, I don't think this error message should happen." ) ;
2014-02-10 15:26:18 +00:00
}
if ( biosInfo [ "SuperSysCard" ] )
{
game . AddOption ( "SuperSysCard" ) ;
}
if ( game [ "NeedSuperSysCard" ] & & game [ "SuperSysCard" ] = = false )
{
CoreComm . ShowMessage (
"This game requires a version 3.0 System card and won't run with the system card you've selected. Try selecting a 3.0 System Card in the firmware configuration." ) ;
throw new Exception ( ) ;
}
2014-07-03 19:20:34 +00:00
game . FirmwareHash = rom . HashSHA1 ( ) ;
2014-02-10 15:26:18 +00:00
2013-12-30 20:26:33 +00:00
Init ( game , rom ) ;
2012-10-08 20:37:41 +00:00
// the default RomStatusDetails don't do anything with Disc
2015-07-03 09:11:07 +00:00
CoreComm . RomStatusDetails = string . Format ( "{0}\r\nDisk partial hash:{1}" , game . Name , new DiscSystem . DiscHasher ( disc ) . OldHash ( ) ) ;
2014-06-28 22:48:07 +00:00
SetControllerButtons ( ) ;
2011-09-24 17:05:34 +00:00
}
2014-12-12 01:49:54 +00:00
public bool DriveLightEnabled { get ; private set ; }
public bool DriveLightOn { get ; internal set ; }
2013-12-30 20:26:33 +00:00
void Init ( GameInfo game , byte [ ] rom )
2011-09-24 17:05:34 +00:00
{
Controller = NullController . GetNullController ( ) ;
2015-01-24 15:05:03 +00:00
Cpu = new HuC6280 ( MemoryCallbacks ) ;
2011-09-24 17:05:34 +00:00
VCE = new VCE ( ) ;
2012-03-11 06:50:46 +00:00
VDC1 = new VDC ( this , Cpu , VCE ) ;
2011-09-24 17:05:34 +00:00
PSG = new HuC6280PSG ( ) ;
SCSI = new ScsiCDBus ( this , disc ) ;
2014-12-05 00:05:40 +00:00
Cpu . Logger = ( s ) = > Tracer . Put ( s ) ;
2012-10-01 00:21:25 +00:00
2011-09-24 17:05:34 +00:00
if ( TurboGrafx )
{
Ram = new byte [ 0x2000 ] ;
Cpu . ReadMemory21 = ReadMemory ;
Cpu . WriteMemory21 = WriteMemory ;
Cpu . WriteVDC = VDC1 . WriteVDC ;
2016-12-11 17:14:42 +00:00
soundProvider = new FakeSyncSound ( PSG , 735 ) ;
2011-09-24 17:05:34 +00:00
CDAudio = new CDAudio ( null , 0 ) ;
}
else if ( SuperGrafx )
{
2012-03-11 06:50:46 +00:00
VDC2 = new VDC ( this , Cpu , VCE ) ;
2012-03-11 09:51:23 +00:00
VPC = new VPC ( this , VDC1 , VDC2 , VCE , Cpu ) ;
2011-09-24 17:05:34 +00:00
Ram = new byte [ 0x8000 ] ;
Cpu . ReadMemory21 = ReadMemorySGX ;
Cpu . WriteMemory21 = WriteMemorySGX ;
Cpu . WriteVDC = VDC1 . WriteVDC ;
2016-12-11 17:14:42 +00:00
soundProvider = new FakeSyncSound ( PSG , 735 ) ;
2011-09-24 17:05:34 +00:00
CDAudio = new CDAudio ( null , 0 ) ;
}
else if ( TurboCD )
{
Ram = new byte [ 0x2000 ] ;
CDRam = new byte [ 0x10000 ] ;
ADPCM = new ADPCM ( this , SCSI ) ;
Cpu . ReadMemory21 = ReadMemoryCD ;
Cpu . WriteMemory21 = WriteMemoryCD ;
Cpu . WriteVDC = VDC1 . WriteVDC ;
CDAudio = new CDAudio ( disc ) ;
SetCDAudioCallback ( ) ;
PSG . MaxVolume = short . MaxValue * 3 / 4 ;
SoundMixer = new SoundMixer ( PSG , CDAudio , ADPCM ) ;
2016-12-11 17:14:42 +00:00
soundProvider = new FakeSyncSound ( SoundMixer , 735 ) ;
2011-09-24 17:05:34 +00:00
Cpu . ThinkAction = ( cycles ) = > { SCSI . Think ( ) ; ADPCM . Think ( cycles ) ; } ;
}
if ( rom . Length = = 0x60000 )
{
// 384k roms require special loading code. Why ;_;
// In memory, 384k roms look like [1st 256k][Then full 384k]
RomData = new byte [ 0xA0000 ] ;
var origRom = rom ;
for ( int i = 0 ; i < 0x40000 ; i + + )
RomData [ i ] = origRom [ i ] ;
for ( int i = 0 ; i < 0x60000 ; i + + )
RomData [ i + 0x40000 ] = origRom [ i ] ;
RomLength = RomData . Length ;
}
else if ( rom . Length > 1024 * 1024 )
{
// If the rom is bigger than 1 megabyte, switch to Street Fighter 2 mapper
Cpu . ReadMemory21 = ReadMemorySF2 ;
Cpu . WriteMemory21 = WriteMemorySF2 ;
RomData = rom ;
RomLength = RomData . Length ;
2014-02-09 05:49:05 +00:00
// user request: current value of the SF2MapperLatch on the tracelogger
2016-02-21 22:34:14 +00:00
Cpu . Logger = ( s ) = > Tracer . Put ( new TraceInfo
{
Disassembly = string . Format ( "{0:X1}:{1}" , SF2MapperLatch , s ) ,
RegisterInfo = ""
} ) ;
2011-09-24 17:05:34 +00:00
}
else
{
// normal rom.
RomData = rom ;
RomLength = RomData . Length ;
}
if ( game [ "BRAM" ] | | Type = = NecSystemType . TurboCD )
{
BramEnabled = true ;
BRAM = new byte [ 2048 ] ;
// pre-format BRAM. damn are we helpful.
BRAM [ 0 ] = 0x48 ; BRAM [ 1 ] = 0x55 ; BRAM [ 2 ] = 0x42 ; BRAM [ 3 ] = 0x4D ;
BRAM [ 4 ] = 0x00 ; BRAM [ 5 ] = 0x88 ; BRAM [ 6 ] = 0x10 ; BRAM [ 7 ] = 0x80 ;
}
if ( game [ "SuperSysCard" ] )
SuperRam = new byte [ 0x30000 ] ;
if ( game [ "ArcadeCard" ] )
{
ArcadeRam = new byte [ 0x200000 ] ;
ArcadeCard = true ;
2014-08-03 22:05:32 +00:00
ArcadeCardRewindHack = _settings . ArcadeCardRewindHack ;
2011-09-24 17:05:34 +00:00
for ( int i = 0 ; i < 4 ; i + + )
ArcadePage [ i ] = new ArcadeCardPage ( ) ;
}
if ( game [ "PopulousSRAM" ] )
{
PopulousRAM = new byte [ 0x8000 ] ;
Cpu . ReadMemory21 = ReadMemoryPopulous ;
Cpu . WriteMemory21 = WriteMemoryPopulous ;
}
2013-12-23 21:54:10 +00:00
// the gamedb can force sprite limit on, ignoring settings
2014-02-27 01:00:21 +00:00
if ( game [ "ForceSpriteLimit" ] | | game . NotInDatabase )
ForceSpriteLimit = true ;
2011-09-24 17:05:34 +00:00
if ( game [ "CdVol" ] )
CDAudio . MaxVolume = int . Parse ( game . OptionValue ( "CdVol" ) ) ;
if ( game [ "PsgVol" ] )
PSG . MaxVolume = int . Parse ( game . OptionValue ( "PsgVol" ) ) ;
if ( game [ "AdpcmVol" ] )
ADPCM . MaxVolume = int . Parse ( game . OptionValue ( "AdpcmVol" ) ) ;
2013-12-23 21:54:10 +00:00
// the gamedb can also force equalizevolumes on
2014-08-03 22:05:32 +00:00
if ( TurboCD & & ( _settings . EqualizeVolume | | game [ "EqualizeVolumes" ] | | game . NotInDatabase ) )
2011-09-24 17:05:34 +00:00
SoundMixer . EqualizeVolumes ( ) ;
// Ok, yes, HBlankPeriod's only purpose is game-specific hax.
// 1) At least they're not coded directly into the emulator, but instead data-driven.
// 2) The games which have custom HBlankPeriods work without it, the override only
// serves to clean up minor gfx anomalies.
// 3) There's no point in haxing the timing with incorrect values in an attempt to avoid this.
// The proper fix is cycle-accurate/bus-accurate timing. That isn't coming to the C#
// version of this core. Let's just acknolwedge that the timing is imperfect and fix
// it in the least intrusive and most honest way we can.
if ( game [ "HBlankPeriod" ] )
2012-09-13 04:13:49 +00:00
VDC1 . HBlankCycles = game . GetIntValue ( "HBlankPeriod" ) ;
2011-09-24 17:05:34 +00:00
// This is also a hack. Proper multi-res/TV emulation will be a native-code core feature.
if ( game [ "MultiResHack" ] )
2012-09-13 04:13:49 +00:00
VDC1 . MultiResHack = game . GetIntValue ( "MultiResHack" ) ;
2011-09-24 17:05:34 +00:00
Cpu . ResetPC ( ) ;
2015-01-14 22:37:37 +00:00
2016-02-28 13:28:00 +00:00
Tracer = new TraceBuffer { Header = Cpu . TraceHeader } ;
2015-01-15 22:39:43 +00:00
var ser = new BasicServiceProvider ( this ) ;
ServiceProvider = ser ;
2015-01-15 15:56:41 +00:00
ser . Register < ITraceable > ( Tracer ) ;
ser . Register < IDisassemblable > ( Cpu ) ;
ser . Register < IVideoProvider > ( ( IVideoProvider ) VPC ? ? VDC1 ) ;
2016-12-11 17:14:42 +00:00
ser . Register < ISoundProvider > ( soundProvider ) ;
2015-01-15 22:39:43 +00:00
SetupMemoryDomains ( ) ;
2011-09-24 17:05:34 +00:00
}
2014-04-07 04:53:18 +00:00
int lagCount ;
int frame ;
2011-09-24 17:05:34 +00:00
bool lagged = true ;
2014-04-07 04:53:18 +00:00
bool isLag = false ;
public int Frame { get { return frame ; } set { frame = value ; } }
2015-07-09 17:05:30 +00:00
public int LagCount { get { return lagCount ; } set { lagCount = value ; } }
2016-01-26 10:34:42 +00:00
public bool IsLagFrame { get { return isLag ; } set { isLag = value ; } }
2011-09-24 17:05:34 +00:00
2014-12-04 00:43:12 +00:00
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem ( ) ;
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks ; } }
2015-10-28 08:51:53 +00:00
void ICodeDataLogger . SetCDL ( CodeDataLog cdl )
{
Cpu . CDL = cdl ;
}
void ICodeDataLogger . NewCDL ( CodeDataLog cdl )
{
InitCDLMappings ( ) ;
var mm = this . Cpu . Mappings ;
foreach ( var kvp in SizesFromHuMap ( mm ) )
{
cdl [ kvp . Key ] = new byte [ kvp . Value ] ;
}
cdl . SubType = "PCE" ;
cdl . SubVer = 0 ;
}
void ICodeDataLogger . DisassembleCDL ( Stream s , CodeDataLog cdl )
{
2016-07-16 17:57:24 +00:00
Cpu . DisassembleCDL ( s , cdl , _memoryDomains ) ;
2015-10-28 08:51:53 +00:00
}
private static Dictionary < string , int > SizesFromHuMap ( IEnumerable < HuC6280 . MemMapping > mm )
{
Dictionary < string , int > sizes = new Dictionary < string , int > ( ) ;
foreach ( var m in mm )
{
if ( ! sizes . ContainsKey ( m . Name ) | | m . MaxOffs > = sizes [ m . Name ] )
sizes [ m . Name ] = m . MaxOffs ;
}
List < string > keys = new List < string > ( sizes . Keys ) ;
foreach ( var key in keys )
{
// becase we were looking at offsets, and each bank is 8192 big, we need to add that size
sizes [ key ] + = 8192 ;
}
return sizes ;
}
2013-11-03 16:29:51 +00:00
public void ResetCounters ( )
2011-09-24 17:05:34 +00:00
{
// this should just be a public setter instead of a new method.
Frame = 0 ;
2014-04-07 04:53:18 +00:00
lagCount = 0 ;
isLag = false ;
2011-09-24 17:05:34 +00:00
}
2012-09-20 19:52:47 +00:00
public void FrameAdvance ( bool render , bool rendersound )
2011-09-24 17:05:34 +00:00
{
2012-09-14 23:18:16 +00:00
lagged = true ;
2014-12-12 01:49:54 +00:00
DriveLightOn = false ;
2013-12-07 00:53:06 +00:00
Frame + + ;
2014-02-27 01:00:21 +00:00
CheckSpriteLimit ( ) ;
2011-09-24 17:05:34 +00:00
PSG . BeginFrame ( Cpu . TotalExecutedCycles ) ;
2014-12-05 00:05:40 +00:00
Cpu . Debug = Tracer . Enabled ;
2012-12-10 00:43:43 +00:00
2011-09-24 17:05:34 +00:00
if ( SuperGrafx )
VPC . ExecFrame ( render ) ;
else
VDC1 . ExecFrame ( render ) ;
PSG . EndFrame ( Cpu . TotalExecutedCycles ) ;
if ( lagged )
{
2014-04-07 04:53:18 +00:00
lagCount + + ;
isLag = true ;
2011-09-24 17:05:34 +00:00
}
else
2014-04-07 04:53:18 +00:00
isLag = false ;
2011-09-24 17:05:34 +00:00
}
2011-01-11 02:55:51 +00:00
2014-02-27 01:00:21 +00:00
void CheckSpriteLimit ( )
{
2014-08-03 22:05:32 +00:00
bool spriteLimit = ForceSpriteLimit | _settings . SpriteLimit ;
2014-02-27 01:00:21 +00:00
VDC1 . PerformSpriteLimit = spriteLimit ;
if ( VDC2 ! = null )
VDC2 . PerformSpriteLimit = spriteLimit ;
}
2012-12-10 00:43:43 +00:00
public CoreComm CoreComm { get ; private set ; }
2011-06-11 22:15:08 +00:00
2016-12-11 17:14:42 +00:00
private ISoundProvider soundProvider ;
2011-09-24 17:05:34 +00:00
public string SystemId { get { return systemid ; } }
public string Region { get ; set ; }
2012-10-03 15:31:04 +00:00
public bool DeterministicEmulation { get { return true ; } }
2011-09-24 17:05:34 +00:00
2014-08-13 17:52:13 +00:00
public byte [ ] CloneSaveRam ( )
2012-09-14 23:18:16 +00:00
{
if ( BRAM ! = null )
return ( byte [ ] ) BRAM . Clone ( ) ;
else
return null ;
}
2014-11-24 15:00:54 +00:00
2012-09-14 23:18:16 +00:00
public void StoreSaveRam ( byte [ ] data )
{
if ( BRAM ! = null )
Array . Copy ( data , BRAM , data . Length ) ;
}
2014-11-24 15:00:54 +00:00
2014-11-30 15:22:08 +00:00
public bool SaveRamModified { get ; private set ; }
2011-09-24 17:05:34 +00:00
2014-04-07 04:53:18 +00:00
public bool BinarySaveStatesPreferred { get { return false ; } }
public void SaveStateBinary ( BinaryWriter bw ) { SyncState ( Serializer . CreateBinaryWriter ( bw ) ) ; }
public void LoadStateBinary ( BinaryReader br ) { SyncState ( Serializer . CreateBinaryReader ( br ) ) ; }
public void SaveStateText ( TextWriter tw ) { SyncState ( Serializer . CreateTextWriter ( tw ) ) ; }
public void LoadStateText ( TextReader tr ) { SyncState ( Serializer . CreateTextReader ( tr ) ) ; }
void SyncState ( Serializer ser )
2011-09-24 17:05:34 +00:00
{
2014-04-07 04:53:18 +00:00
ser . BeginSection ( "PCEngine" ) ;
Cpu . SyncState ( ser ) ;
VCE . SyncState ( ser ) ;
VDC1 . SyncState ( ser , 1 ) ;
PSG . SyncState ( ser ) ;
2011-09-24 17:05:34 +00:00
if ( SuperGrafx )
{
2014-04-07 04:53:18 +00:00
VPC . SyncState ( ser ) ;
VDC2 . SyncState ( ser , 2 ) ;
2011-09-24 17:05:34 +00:00
}
2014-04-07 04:53:18 +00:00
2011-09-24 17:05:34 +00:00
if ( TurboCD )
{
2014-04-07 04:53:18 +00:00
ADPCM . SyncState ( ser ) ;
CDAudio . SyncState ( ser ) ;
SCSI . SyncState ( ser ) ;
2011-09-24 17:05:34 +00:00
2014-04-07 04:53:18 +00:00
ser . Sync ( "CDRAM" , ref CDRam , false ) ;
if ( SuperRam ! = null )
ser . Sync ( "SuperRAM" , ref SuperRam , false ) ;
if ( ArcadeCard )
ArcadeCardSyncState ( ser ) ;
2011-09-24 17:05:34 +00:00
}
2014-04-07 04:53:18 +00:00
ser . Sync ( "RAM" , ref Ram , false ) ;
ser . Sync ( "IOBuffer" , ref IOBuffer ) ;
ser . Sync ( "CdIoPorts" , ref CdIoPorts , false ) ;
ser . Sync ( "BramLocked" , ref BramLocked ) ;
2011-09-24 17:05:34 +00:00
2014-04-07 04:53:18 +00:00
ser . Sync ( "Frame" , ref frame ) ;
ser . Sync ( "Lag" , ref lagCount ) ;
ser . Sync ( "IsLag" , ref isLag ) ;
if ( Cpu . ReadMemory21 = = ReadMemorySF2 )
ser . Sync ( "SF2MapperLatch" , ref SF2MapperLatch ) ;
if ( PopulousRAM ! = null )
ser . Sync ( "PopulousRAM" , ref PopulousRAM , false ) ;
if ( BRAM ! = null )
ser . Sync ( "BRAM" , ref BRAM , false ) ;
2011-09-24 17:05:34 +00:00
2014-04-07 04:53:18 +00:00
ser . EndSection ( ) ;
2016-07-16 17:57:24 +00:00
if ( ser . IsReader )
SyncAllByteArrayDomains ( ) ;
2011-09-24 17:05:34 +00:00
}
2014-04-07 04:53:18 +00:00
byte [ ] stateBuffer ;
public byte [ ] SaveStateBinary ( )
2011-09-24 17:05:34 +00:00
{
2014-04-07 04:53:18 +00:00
if ( stateBuffer = = null )
2011-09-24 17:05:34 +00:00
{
2014-04-07 04:53:18 +00:00
var stream = new MemoryStream ( ) ;
var writer = new BinaryWriter ( stream ) ;
SaveStateBinary ( writer ) ;
2014-04-08 00:22:42 +00:00
writer . Flush ( ) ;
2014-04-07 04:53:18 +00:00
stateBuffer = stream . ToArray ( ) ;
writer . Close ( ) ;
return stateBuffer ;
2011-09-24 17:05:34 +00:00
}
else
{
2014-04-07 04:53:18 +00:00
var stream = new MemoryStream ( stateBuffer ) ;
var writer = new BinaryWriter ( stream ) ;
SaveStateBinary ( writer ) ;
2014-04-08 00:22:42 +00:00
writer . Flush ( ) ;
2014-04-07 04:53:18 +00:00
writer . Close ( ) ;
return stateBuffer ;
2011-09-24 17:05:34 +00:00
}
}
void SetupMemoryDomains ( )
{
2016-07-16 17:57:24 +00:00
var domains = new List < MemoryDomain > ( 2 ) ;
2011-09-24 17:05:34 +00:00
2016-04-13 23:50:06 +00:00
var SystemBusDomain = new MemoryDomainDelegate ( "System Bus (21 bit)" , 0x200000 , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
( addr ) = >
{
if ( addr < 0 | | addr > = 0x200000 )
throw new ArgumentOutOfRangeException ( ) ;
2015-01-18 15:25:47 +00:00
return Cpu . ReadMemory21 ( ( int ) addr ) ;
2014-02-26 20:18:48 +00:00
} ,
( addr , value ) = >
{
if ( addr < 0 | | addr > = 0x200000 )
throw new ArgumentOutOfRangeException ( ) ;
2015-01-18 15:25:47 +00:00
Cpu . WriteMemory21 ( ( int ) addr , value ) ;
2015-02-22 15:19:38 +00:00
} ,
2016-04-13 23:50:06 +00:00
wordSize : 2 ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( SystemBusDomain ) ;
2016-04-13 23:50:06 +00:00
var CpuBusDomain = new MemoryDomainDelegate ( "System Bus" , 0x10000 , MemoryDomain . Endian . Little ,
2015-01-05 21:03:54 +00:00
( addr ) = >
{
if ( addr < 0 | | addr > = 0x10000 )
throw new ArgumentOutOfRangeException ( ) ;
return Cpu . ReadMemory ( ( ushort ) addr ) ;
} ,
( addr , value ) = >
{
if ( addr < 0 | | addr > = 0x10000 )
throw new ArgumentOutOfRangeException ( ) ;
Cpu . WriteMemory ( ( ushort ) addr , value ) ;
2015-02-22 15:19:38 +00:00
} ,
2016-04-13 23:50:06 +00:00
wordSize : 2 ) ;
2015-01-05 21:03:54 +00:00
domains . Add ( CpuBusDomain ) ;
2016-07-16 17:57:24 +00:00
SyncAllByteArrayDomains ( ) ;
_memoryDomains = new MemoryDomainList ( domains . Concat ( _byteArrayDomains . Values ) . ToList ( ) ) ;
_memoryDomains . SystemBus = CpuBusDomain ;
_memoryDomains . MainMemory = _byteArrayDomains [ "Main Memory" ] ;
( ServiceProvider as BasicServiceProvider ) . Register < IMemoryDomains > ( _memoryDomains ) ;
_memoryDomainsInit = true ;
}
private void SyncAllByteArrayDomains ( )
{
SyncByteArrayDomain ( "Main Memory" , Ram ) ;
SyncByteArrayDomain ( "ROM" , RomData ) ;
2014-02-09 06:57:54 +00:00
2011-09-24 17:05:34 +00:00
if ( BRAM ! = null )
2016-07-16 17:57:24 +00:00
SyncByteArrayDomain ( "Battery RAM" , BRAM ) ;
2011-09-24 17:05:34 +00:00
if ( TurboCD )
{
2016-07-16 17:57:24 +00:00
SyncByteArrayDomain ( "TurboCD RAM" , CDRam ) ;
SyncByteArrayDomain ( "ADPCM RAM" , ADPCM . RAM ) ;
2011-09-24 17:05:34 +00:00
if ( SuperRam ! = null )
2016-07-16 17:57:24 +00:00
SyncByteArrayDomain ( "Super System Card RAM" , SuperRam ) ;
2011-09-24 17:05:34 +00:00
}
if ( ArcadeCard )
2016-07-16 17:57:24 +00:00
SyncByteArrayDomain ( "Arcade Card RAM" , ArcadeRam ) ;
2011-09-24 17:05:34 +00:00
2014-02-10 01:21:13 +00:00
if ( PopulousRAM ! = null )
2016-07-16 17:57:24 +00:00
SyncByteArrayDomain ( "Cart Battery RAM" , PopulousRAM ) ;
}
private void SyncByteArrayDomain ( string name , byte [ ] data )
{
if ( _memoryDomainsInit )
2014-02-10 01:21:13 +00:00
{
2016-07-16 17:57:24 +00:00
var m = _byteArrayDomains [ name ] ;
m . Data = data ;
}
else
{
var m = new MemoryDomainByteArray ( name , MemoryDomain . Endian . Little , data , true , 1 ) ;
_byteArrayDomains . Add ( name , m ) ;
2014-02-10 01:21:13 +00:00
}
2011-09-24 17:05:34 +00:00
}
2016-07-16 17:57:24 +00:00
private Dictionary < string , MemoryDomainByteArray > _byteArrayDomains = new Dictionary < string , MemoryDomainByteArray > ( ) ;
private bool _memoryDomainsInit = false ;
private MemoryDomainList _memoryDomains ;
2011-09-24 17:05:34 +00:00
2014-12-20 13:16:15 +00:00
public IDictionary < string , RegisterValue > GetCpuFlagsAndRegisters ( )
2013-11-11 03:20:33 +00:00
{
2014-12-20 13:16:15 +00:00
return new Dictionary < string , RegisterValue >
2013-11-11 17:03:55 +00:00
{
2014-04-19 22:23:13 +00:00
{ "A" , Cpu . A } ,
{ "X" , Cpu . X } ,
{ "Y" , Cpu . Y } ,
{ "PC" , Cpu . PC } ,
{ "S" , Cpu . S } ,
{ "MPR-0" , Cpu . MPR [ 0 ] } ,
{ "MPR-1" , Cpu . MPR [ 1 ] } ,
{ "MPR-2" , Cpu . MPR [ 2 ] } ,
{ "MPR-3" , Cpu . MPR [ 3 ] } ,
{ "MPR-4" , Cpu . MPR [ 4 ] } ,
{ "MPR-5" , Cpu . MPR [ 5 ] } ,
{ "MPR-6" , Cpu . MPR [ 6 ] } ,
{ "MPR-7" , Cpu . MPR [ 7 ] }
2013-11-11 17:03:55 +00:00
} ;
2014-05-31 17:03:21 +00:00
}
2014-12-20 13:29:57 +00:00
public bool CanStep ( StepType type ) { return false ; }
2014-12-14 18:58:16 +00:00
[FeatureNotImplemented]
2014-12-15 22:19:10 +00:00
public void Step ( StepType type ) { throw new NotImplementedException ( ) ; }
2014-12-14 18:58:16 +00:00
2014-11-24 01:17:05 +00:00
[FeatureNotImplemented]
2014-05-31 17:03:21 +00:00
public void SetCpuRegister ( string register , int value )
{
throw new NotImplementedException ( ) ;
2013-11-11 03:20:33 +00:00
}
2011-09-24 17:05:34 +00:00
public void Dispose ( )
{
if ( disc ! = null )
disc . Dispose ( ) ;
}
2013-12-22 00:44:39 +00:00
2014-08-03 22:05:32 +00:00
public PCESettings _settings ;
2014-06-28 22:48:07 +00:00
private PCESyncSettings _syncSettings ;
2013-12-22 05:58:24 +00:00
2014-10-19 01:22:47 +00:00
public PCESettings GetSettings ( ) { return _settings . Clone ( ) ; }
public PCESyncSettings GetSyncSettings ( ) { return _syncSettings . Clone ( ) ; }
public bool PutSettings ( PCESettings o )
2013-12-22 05:58:24 +00:00
{
2013-12-22 20:41:21 +00:00
bool ret ;
2014-10-19 01:22:47 +00:00
if ( o . ArcadeCardRewindHack ! = _settings . ArcadeCardRewindHack | |
o . EqualizeVolume ! = _settings . EqualizeVolume )
2013-12-22 20:41:21 +00:00
ret = true ;
else
ret = false ;
2014-10-19 01:22:47 +00:00
_settings = o ;
2013-12-22 20:41:21 +00:00
return ret ;
2013-12-22 05:58:24 +00:00
}
2014-06-28 22:48:07 +00:00
2014-10-19 01:22:47 +00:00
public bool PutSyncSettings ( PCESyncSettings o )
2014-08-20 18:03:04 +00:00
{
2014-10-19 01:22:47 +00:00
bool ret = PCESyncSettings . NeedsReboot ( o , _syncSettings ) ;
_syncSettings = o ;
2014-08-20 18:03:04 +00:00
// SetControllerButtons(); // not safe to change the controller during emulation, so instead make it a reboot event
return ret ;
}
2013-12-22 05:58:24 +00:00
public class PCESettings
{
public bool ShowBG1 = true ;
public bool ShowOBJ1 = true ;
public bool ShowBG2 = true ;
public bool ShowOBJ2 = true ;
2013-12-22 20:41:21 +00:00
// these three require core reboot to use
public bool SpriteLimit = false ;
public bool EqualizeVolume = false ;
public bool ArcadeCardRewindHack = true ;
2013-12-22 05:58:24 +00:00
public PCESettings Clone ( )
{
return ( PCESettings ) MemberwiseClone ( ) ;
}
}
2014-06-28 22:48:07 +00:00
public class PCESyncSettings
{
public ControllerSetting [ ] Controllers =
{
new ControllerSetting { IsConnected = true } ,
new ControllerSetting { IsConnected = false } ,
new ControllerSetting { IsConnected = false } ,
new ControllerSetting { IsConnected = false } ,
new ControllerSetting { IsConnected = false }
} ;
public PCESyncSettings Clone ( )
{
2014-08-03 22:05:32 +00:00
var ret = new PCESyncSettings ( ) ;
for ( int i = 0 ; i < Controllers . Length ; i + + )
{
ret . Controllers [ i ] . IsConnected = Controllers [ i ] . IsConnected ;
}
return ret ;
2014-06-28 22:48:07 +00:00
}
public class ControllerSetting
{
public bool IsConnected { get ; set ; }
}
2014-08-20 18:03:04 +00:00
public static bool NeedsReboot ( PCESyncSettings x , PCESyncSettings y )
{
for ( int i = 0 ; i < x . Controllers . Length ; i + + )
{
if ( x . Controllers [ i ] . IsConnected ! = y . Controllers [ i ] . IsConnected )
return true ;
}
return false ;
}
2014-06-28 22:48:07 +00:00
}
2011-09-24 17:05:34 +00:00
}
2011-01-11 02:55:51 +00:00
}