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.Globalization ;
using System.IO ;
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
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
) ]
2014-09-01 18:43:41 +00:00
public sealed partial class PCEngine : IEmulator , IMemoryDomains
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 ;
public MetaspuSoundProvider SoundSynchronizer ;
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
{
2012-12-10 00:43:43 +00:00
CoreComm = comm ;
CoreComm . CpuTraceAvailable = true ;
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
}
2013-08-24 16:54:22 +00:00
public string BoardName { get { return null ; } }
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 ;
CoreComm . CpuTraceAvailable = true ;
CoreComm . UsesDriveLed = 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
2012-12-10 00:43:43 +00:00
CoreComm . RomStatusDetails = string . Format ( "{0}\r\nDisk partial hash:{1}" , game . Name , disc . GetHash ( ) ) ;
2014-06-28 22:48:07 +00:00
SetControllerButtons ( ) ;
2011-09-24 17:05:34 +00:00
}
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 ( ) ;
2014-02-09 20:17:59 +00:00
Cpu = new HuC6280 ( CoreComm ) ;
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-02-09 20:17:59 +00:00
Cpu . Logger = ( s ) = > CoreComm . 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 ;
soundProvider = PSG ;
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 ;
soundProvider = PSG ;
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 ) ;
SoundSynchronizer = new MetaspuSoundProvider ( ESynchMethod . ESynchMethod_V ) ;
soundProvider = SoundSynchronizer ;
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
2014-02-09 20:17:59 +00:00
Cpu . Logger = ( s ) = > CoreComm . Tracer . Put ( string . Format ( "{0:X1}:{1}" , SF2MapperLatch , s ) ) ;
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 ( ) ;
SetupMemoryDomains ( ) ;
}
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 ; } }
public int LagCount { get { return lagCount ; } set { lagCount = value ; } }
public bool IsLagFrame { get { return isLag ; } }
2011-09-24 17:05:34 +00:00
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 ;
2012-12-10 00:43:43 +00:00
CoreComm . DriveLED = 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-02-09 20:17:59 +00:00
Cpu . Debug = CoreComm . 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 ( TurboCD )
SoundSynchronizer . PullSamples ( SoundMixer ) ;
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
2011-09-24 17:05:34 +00:00
public IVideoProvider VideoProvider
{
get { return ( IVideoProvider ) VPC ? ? VDC1 ; }
}
ISoundProvider soundProvider ;
public ISoundProvider SoundProvider
{
get { return soundProvider ; }
}
sound api changes. added a new ISyncSoundProvider, which works similarly to ISoundProvider except the source (not the sink) determines the number of samples to process. Added facilities to metaspu, dcfilter, speexresampler to work with ISyncSoundProvider. Add ISyncSoundProvider to IEmulator. All IEmulators must provide sync sound, but they need not provide async sound. When async is needed and an IEmulator doesn't provide it, the frontend will wrap it in a vecna metaspu. SNES, GB changed to provide sync sound only. All other emulator cores mostly unchanged; they just provide stub fakesync alongside async, for now. For the moment, the only use of the sync sound is for realtime audio throttling, where it works and sounds quite nice. In the future, sync sound will be supported for AV dumping as well.
2012-10-11 00:44:59 +00:00
public ISyncSoundProvider SyncSoundProvider { get { return new FakeSyncSound ( soundProvider , 735 ) ; } }
public bool StartAsyncSound ( ) { return true ; }
public void EndAsyncSound ( ) { }
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 ;
}
public void StoreSaveRam ( byte [ ] data )
{
if ( BRAM ! = null )
Array . Copy ( data , BRAM , data . Length ) ;
}
public void ClearSaveRam ( )
{
if ( BRAM ! = null )
BRAM = new byte [ BRAM . Length ] ;
}
2011-09-24 17:05:34 +00:00
public bool SaveRamModified { get ; set ; }
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 ( ) ;
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 ( )
{
var domains = new List < MemoryDomain > ( 10 ) ;
2014-02-10 01:21:13 +00:00
int mainmemorymask = Ram . Length - 1 ;
2013-11-04 02:11:40 +00:00
var MainMemoryDomain = new MemoryDomain ( "Main Memory" , Ram . Length , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
addr = > Ram [ addr ] ,
( addr , value ) = > Ram [ addr ] = value ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( MainMemoryDomain ) ;
2013-11-04 02:11:40 +00:00
var SystemBusDomain = new MemoryDomain ( "System Bus" , 0x200000 , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
( addr ) = >
{
if ( addr < 0 | | addr > = 0x200000 )
throw new ArgumentOutOfRangeException ( ) ;
return Cpu . ReadMemory21 ( addr ) ;
} ,
( addr , value ) = >
{
if ( addr < 0 | | addr > = 0x200000 )
throw new ArgumentOutOfRangeException ( ) ;
Cpu . WriteMemory21 ( addr , value ) ;
} ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( SystemBusDomain ) ;
2014-02-09 06:57:54 +00:00
var RomDomain = new MemoryDomain ( "ROM" , RomLength , MemoryDomain . Endian . Little ,
addr = > RomData [ addr ] ,
( addr , value ) = > RomData [ addr ] = value ) ;
domains . Add ( RomDomain ) ;
2011-09-24 17:05:34 +00:00
if ( BRAM ! = null )
{
2013-11-04 02:11:40 +00:00
var BRAMMemoryDomain = new MemoryDomain ( "Battery RAM" , Ram . Length , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
addr = > BRAM [ addr ] ,
( addr , value ) = > BRAM [ addr ] = value ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( BRAMMemoryDomain ) ;
}
if ( TurboCD )
{
2013-11-04 02:11:40 +00:00
var CDRamMemoryDomain = new MemoryDomain ( "TurboCD RAM" , CDRam . Length , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
addr = > CDRam [ addr ] ,
( addr , value ) = > CDRam [ addr ] = value ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( CDRamMemoryDomain ) ;
2013-11-04 02:11:40 +00:00
var AdpcmMemoryDomain = new MemoryDomain ( "ADPCM RAM" , ADPCM . RAM . Length , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
addr = > ADPCM . RAM [ addr ] ,
( addr , value ) = > ADPCM . RAM [ addr ] = value ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( AdpcmMemoryDomain ) ;
if ( SuperRam ! = null )
{
2013-11-04 02:11:40 +00:00
var SuperRamMemoryDomain = new MemoryDomain ( "Super System Card RAM" , SuperRam . Length , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
addr = > SuperRam [ addr ] ,
( addr , value ) = > SuperRam [ addr ] = value ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( SuperRamMemoryDomain ) ;
}
}
if ( ArcadeCard )
{
2013-11-04 02:11:40 +00:00
var ArcadeRamMemoryDomain = new MemoryDomain ( "Arcade Card RAM" , ArcadeRam . Length , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
addr = > ArcadeRam [ addr ] ,
( addr , value ) = > ArcadeRam [ addr ] = value ) ;
2011-09-24 17:05:34 +00:00
domains . Add ( ArcadeRamMemoryDomain ) ;
}
2014-02-10 01:21:13 +00:00
if ( PopulousRAM ! = null )
{
var PopulusRAMDomain = new MemoryDomain ( "Cart Battery RAM" , PopulousRAM . Length , MemoryDomain . Endian . Little ,
2014-02-26 20:18:48 +00:00
addr = > PopulousRAM [ addr ] ,
( addr , value ) = > PopulousRAM [ addr ] = value ) ;
2014-02-10 01:21:13 +00:00
domains . Add ( PopulusRAMDomain ) ;
}
2013-11-06 02:15:29 +00:00
memoryDomains = new MemoryDomainList ( domains ) ;
2011-09-24 17:05:34 +00:00
}
2013-11-06 02:15:29 +00:00
MemoryDomainList memoryDomains ;
public MemoryDomainList MemoryDomains { get { return memoryDomains ; } }
2011-09-24 17:05:34 +00:00
2014-04-19 22:23:13 +00:00
public Dictionary < string , int > GetCpuFlagsAndRegisters ( )
2013-11-11 03:20:33 +00:00
{
2014-04-19 22:23:13 +00:00
return new Dictionary < string , int >
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
}
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-08-03 22:05:32 +00:00
public object GetSettings ( ) { return _settings . Clone ( ) ; }
public object GetSyncSettings ( ) { return _syncSettings . Clone ( ) ; }
2013-12-22 05:58:24 +00:00
public bool PutSettings ( object o )
{
2013-12-22 20:41:21 +00:00
PCESettings n = ( PCESettings ) o ;
bool ret ;
2014-08-03 22:05:32 +00:00
if ( n . ArcadeCardRewindHack ! = _settings . ArcadeCardRewindHack | |
n . EqualizeVolume ! = _settings . EqualizeVolume )
2013-12-22 20:41:21 +00:00
ret = true ;
else
ret = false ;
2014-08-03 22:05:32 +00:00
_settings = n ;
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-08-20 18:03:04 +00:00
public bool PutSyncSettings ( object o )
{
var newsyncsettings = ( PCESyncSettings ) o ;
bool ret = PCESyncSettings . NeedsReboot ( newsyncsettings , _syncSettings ) ;
_syncSettings = newsyncsettings ;
// 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
}