2012-08-26 14:39:06 +00:00
#define MUSASHI
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 ;
2013-10-27 22:07:40 +00:00
using System.Runtime.InteropServices ;
using BizHawk.Common ;
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 ;
2013-11-14 15:01:32 +00:00
using BizHawk.Emulation.Common.Components.M68000 ;
using BizHawk.Emulation.Common.Components.Z80 ;
2012-08-26 14:39:06 +00:00
using Native68000 ;
2013-10-27 22:07:40 +00:00
2013-11-13 23:36:21 +00:00
namespace BizHawk.Emulation.Cores.Sega.Genesis
2011-01-11 02:55:51 +00:00
{
2011-12-24 01:59:51 +00:00
public sealed partial class Genesis : IEmulator
2011-07-30 20:49:36 +00:00
{
2011-12-24 01:59:51 +00:00
private int _lagcount = 0 ;
private bool lagged = true ;
private bool islag = false ;
2011-07-30 20:49:36 +00:00
// ROM
public byte [ ] RomData ;
// Machine stuff
2011-10-07 03:04:48 +00:00
public MC68000 MainCPU ;
2011-07-30 20:49:36 +00:00
public Z80A SoundCPU ;
public GenVDP VDP ;
public SN76489 PSG ;
public YM2612 YM2612 ;
public byte [ ] Ram = new byte [ 0x10000 ] ;
public byte [ ] Z80Ram = new byte [ 0x2000 ] ;
private bool M68000HasZ80Bus = false ;
private bool Z80Reset = false ;
private bool Z80Runnable { get { return ( Z80Reset = = false & & M68000HasZ80Bus = = false ) ; } }
private SoundMixer SoundMixer ;
2013-11-03 16:29:51 +00:00
public void ResetCounters ( )
2011-07-30 20:49:36 +00:00
{
Frame = 0 ;
2012-11-25 15:41:40 +00:00
_lagcount = 0 ;
islag = false ;
2011-07-30 20:49:36 +00:00
}
// Genesis timings:
// 53,693,175 Machine clocks / sec
// 7,670,454 Main 68000 cycles / sec (7 mclk divisor)
// 3,579,545 Z80 cycles / sec (15 mclk divisor)
// At 59.92 FPS:
// 896,081 mclks / frame
// 128,011 Main 68000 cycles / frame
// 59,738 Z80 cycles / frame
// At 262 lines/frame:
// 3420 mclks / line
// ~ 488.5 Main 68000 cycles / line
// 228 Z80 cycles / line
// Video characteristics:
// 224 lines are active display. The remaining 38 lines are vertical blanking.
// In H40 mode, the dot clock is 480 pixels per line.
// 320 are active display, the remaining 160 are horizontal blanking.
// A total of 3420 mclks per line, but 2560 mclks are active display and 860 mclks are blanking.
2012-08-26 14:39:06 +00:00
#if MUSASHI
2013-11-04 01:06:36 +00:00
VdpCallback _vdp ;
ReadCallback read8 ;
ReadCallback read16 ;
ReadCallback read32 ;
WriteCallback write8 ;
WriteCallback write16 ;
WriteCallback write32 ;
2012-08-26 14:39:06 +00:00
#endif
2012-12-10 00:43:43 +00:00
public Genesis ( CoreComm comm , GameInfo game , byte [ ] rom )
2011-07-30 20:49:36 +00:00
{
2012-12-10 00:43:43 +00:00
CoreComm = comm ;
2011-10-07 03:04:48 +00:00
MainCPU = new MC68000 ( ) ;
2011-07-30 20:49:36 +00:00
SoundCPU = new Z80A ( ) ;
2013-11-04 01:06:36 +00:00
YM2612 = new YM2612 ( ) { MaxVolume = 23405 } ;
PSG = new SN76489 ( ) { MaxVolume = 4681 } ;
2011-07-30 20:49:36 +00:00
VDP = new GenVDP ( ) ;
2011-10-11 03:52:44 +00:00
VDP . DmaReadFrom68000 = ReadWord ;
2011-07-30 20:49:36 +00:00
SoundMixer = new SoundMixer ( YM2612 , PSG ) ;
2011-10-11 03:52:44 +00:00
MainCPU . ReadByte = ReadByte ;
MainCPU . ReadWord = ReadWord ;
MainCPU . ReadLong = ReadLong ;
MainCPU . WriteByte = WriteByte ;
MainCPU . WriteWord = WriteWord ;
MainCPU . WriteLong = WriteLong ;
2013-11-04 01:06:36 +00:00
MainCPU . IrqCallback = InterruptCallback ;
2012-08-26 14:39:06 +00:00
2013-11-04 01:06:36 +00:00
// ---------------------- musashi -----------------------
2012-08-26 14:39:06 +00:00
#if MUSASHI
2013-11-04 01:06:36 +00:00
_vdp = vdpcallback ;
read8 = Read8 ;
read16 = Read16 ;
read32 = Read32 ;
write8 = Write8 ;
write16 = Write16 ;
write32 = Write32 ;
Musashi . RegisterVdpCallback ( Marshal . GetFunctionPointerForDelegate ( _vdp ) ) ;
Musashi . RegisterRead8 ( Marshal . GetFunctionPointerForDelegate ( read8 ) ) ;
Musashi . RegisterRead16 ( Marshal . GetFunctionPointerForDelegate ( read16 ) ) ;
Musashi . RegisterRead32 ( Marshal . GetFunctionPointerForDelegate ( read32 ) ) ;
Musashi . RegisterWrite8 ( Marshal . GetFunctionPointerForDelegate ( write8 ) ) ;
Musashi . RegisterWrite16 ( Marshal . GetFunctionPointerForDelegate ( write16 ) ) ;
Musashi . RegisterWrite32 ( Marshal . GetFunctionPointerForDelegate ( write32 ) ) ;
2012-08-26 14:39:06 +00:00
#endif
2013-11-04 01:06:36 +00:00
// ---------------------- musashi -----------------------
2011-07-30 20:49:36 +00:00
SoundCPU . ReadMemory = ReadMemoryZ80 ;
SoundCPU . WriteMemory = WriteMemoryZ80 ;
SoundCPU . WriteHardware = ( a , v ) = > { Console . WriteLine ( "Z80: Attempt I/O Write {0:X2}:{1:X2}" , a , v ) ; } ;
SoundCPU . ReadHardware = x = > 0xFF ;
SoundCPU . IRQCallback = ( ) = > SoundCPU . Interrupt = false ;
Z80Reset = true ;
2011-12-24 01:59:51 +00:00
RomData = new byte [ 0x400000 ] ;
for ( int i = 0 ; i < rom . Length ; i + + )
RomData [ i ] = rom [ i ] ;
2011-07-30 20:49:36 +00:00
2011-12-24 01:59:51 +00:00
SetupMemoryDomains ( ) ;
2012-08-26 14:39:06 +00:00
#if MUSASHI
2013-11-04 01:06:36 +00:00
Musashi . Init ( ) ;
Musashi . Reset ( ) ;
VDP . GetPC = ( ) = > Musashi . PC ;
2012-08-26 14:39:06 +00:00
#else
MainCPU . Reset ( ) ;
2012-09-09 21:15:20 +00:00
VDP . GetPC = ( ) = > MainCPU . PC ;
2012-08-26 14:39:06 +00:00
#endif
2013-11-04 01:06:36 +00:00
InitializeCartHardware ( game ) ;
}
2012-09-13 04:13:49 +00:00
2013-11-04 01:06:36 +00:00
void InitializeCartHardware ( GameInfo game )
{
LogCartInfo ( ) ;
InitializeEeprom ( game ) ;
InitializeSaveRam ( game ) ;
}
2011-07-30 20:49:36 +00:00
2012-09-20 19:52:47 +00:00
public void FrameAdvance ( bool render , bool rendersound )
2011-07-30 20:49:36 +00:00
{
2011-12-24 01:59:51 +00:00
lagged = true ;
2013-12-07 00:53:06 +00:00
Frame + + ;
2011-07-30 20:49:36 +00:00
PSG . BeginFrame ( SoundCPU . TotalExecutedCycles ) ;
2013-11-04 01:06:36 +00:00
YM2612 . BeginFrame ( SoundCPU . TotalExecutedCycles ) ;
2012-08-30 04:29:33 +00:00
2013-11-04 01:06:36 +00:00
// Do start-of-frame events
VDP . HIntLineCounter = VDP . Registers [ 10 ] ;
//VDP.VdpStatusWord &=
unchecked { VDP . VdpStatusWord & = ( ushort ) ~ GenVDP . StatusVerticalBlanking ; }
2012-08-30 04:29:33 +00:00
2011-07-30 20:49:36 +00:00
for ( VDP . ScanLine = 0 ; VDP . ScanLine < 262 ; VDP . ScanLine + + )
{
2011-10-16 06:23:15 +00:00
//Log.Error("VDP","FRAME {0}, SCANLINE {1}", Frame, VDP.ScanLine);
2011-07-30 20:49:36 +00:00
2012-09-01 18:40:52 +00:00
if ( VDP . ScanLine < VDP . FrameHeight )
2011-07-30 20:49:36 +00:00
VDP . RenderLine ( ) ;
2011-12-24 01:59:51 +00:00
2013-11-04 01:06:36 +00:00
Exec68k ( 365 ) ;
RunZ80 ( 171 ) ;
2012-09-01 18:40:52 +00:00
2013-11-04 01:06:36 +00:00
// H-Int now?
2012-09-01 18:40:52 +00:00
2013-11-04 01:06:36 +00:00
VDP . HIntLineCounter - - ;
if ( VDP . HIntLineCounter < 0 & & VDP . ScanLine < 224 ) // FIXME
{
VDP . HIntLineCounter = VDP . Registers [ 10 ] ;
VDP . VdpStatusWord | = GenVDP . StatusHorizBlanking ;
2012-09-01 18:40:52 +00:00
2013-11-04 01:06:36 +00:00
if ( VDP . HInterruptsEnabled )
{
Set68kIrq ( 4 ) ;
//Console.WriteLine("Fire hint!");
}
2012-09-01 18:40:52 +00:00
2013-11-04 01:06:36 +00:00
}
2011-07-30 20:49:36 +00:00
2013-11-04 01:06:36 +00:00
Exec68k ( 488 - 365 ) ;
RunZ80 ( 228 - 171 ) ;
2012-09-01 18:40:52 +00:00
2013-11-04 01:06:36 +00:00
if ( VDP . ScanLine = = 224 )
2011-07-30 20:49:36 +00:00
{
2013-11-04 01:06:36 +00:00
VDP . VdpStatusWord | = GenVDP . StatusVerticalInterruptPending ;
VDP . VdpStatusWord | = GenVDP . StatusVerticalBlanking ;
Exec68k ( 16 ) ; // this is stupidly wrong.
2011-07-30 20:49:36 +00:00
// End-frame stuff
2013-11-04 01:06:36 +00:00
if ( VDP . VInterruptEnabled )
Set68kIrq ( 6 ) ;
2011-07-30 20:49:36 +00:00
2012-09-01 18:40:52 +00:00
SoundCPU . Interrupt = true ;
2013-11-04 01:06:36 +00:00
//The INT output is asserted every frame for exactly one scanline, and it can't be disabled. A very short Z80 interrupt routine would be triggered multiple times if it finishes within 228 Z80 clock cycles. I think (but cannot recall the specifics) that some games have delay loops in the interrupt handler for this very reason.
2011-07-30 20:49:36 +00:00
}
}
PSG . EndFrame ( SoundCPU . TotalExecutedCycles ) ;
2013-11-04 01:06:36 +00:00
YM2612 . EndFrame ( SoundCPU . TotalExecutedCycles ) ;
2011-12-24 01:59:51 +00:00
2012-08-26 14:39:06 +00:00
2011-12-24 01:59:51 +00:00
if ( lagged )
{
_lagcount + + ;
islag = true ;
}
else
islag = false ;
2011-06-11 22:15:08 +00:00
}
2013-11-04 01:06:36 +00:00
void Exec68k ( int cycles )
{
2012-08-26 14:39:06 +00:00
#if MUSASHI
2013-11-04 01:06:36 +00:00
Musashi . Execute ( cycles ) ;
2012-08-26 14:39:06 +00:00
#else
MainCPU . ExecuteCycles ( cycles ) ;
#endif
2013-11-04 01:06:36 +00:00
}
2012-08-26 14:39:06 +00:00
2013-11-04 01:06:36 +00:00
void RunZ80 ( int cycles )
{
// I emulate the YM2612 synced to Z80 clock, for better or worse.
// So we still need to keep the Z80 cycle count accurate even if the Z80 isn't running.
2012-09-01 18:40:52 +00:00
2013-11-04 01:06:36 +00:00
if ( Z80Runnable )
SoundCPU . ExecuteCycles ( cycles ) ;
else
SoundCPU . TotalExecutedCycles + = cycles ;
}
2012-09-01 18:40:52 +00:00
2013-11-04 01:06:36 +00:00
void Set68kIrq ( int irq )
{
2012-08-26 14:39:06 +00:00
#if MUSASHI
2013-11-04 01:06:36 +00:00
Musashi . SetIRQ ( irq ) ;
2012-08-26 14:39:06 +00:00
#else
MainCPU . Interrupt = irq ;
#endif
2013-11-04 01:06:36 +00:00
}
2012-08-26 14:39:06 +00:00
2013-11-11 03:20:33 +00:00
public List < KeyValuePair < string , int > > GetCpuFlagsAndRegisters ( )
{
2013-11-11 17:21:38 +00:00
return new List < KeyValuePair < string , int > >
{
new KeyValuePair < string , int > ( "A-0" , MainCPU . A [ 0 ] . s32 ) ,
new KeyValuePair < string , int > ( "A-1" , MainCPU . A [ 1 ] . s32 ) ,
new KeyValuePair < string , int > ( "A-2" , MainCPU . A [ 2 ] . s32 ) ,
new KeyValuePair < string , int > ( "A-3" , MainCPU . A [ 3 ] . s32 ) ,
new KeyValuePair < string , int > ( "A-4" , MainCPU . A [ 4 ] . s32 ) ,
new KeyValuePair < string , int > ( "A-5" , MainCPU . A [ 5 ] . s32 ) ,
new KeyValuePair < string , int > ( "A-6" , MainCPU . A [ 6 ] . s32 ) ,
new KeyValuePair < string , int > ( "A-7" , MainCPU . A [ 7 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-0" , MainCPU . D [ 0 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-1" , MainCPU . D [ 1 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-2" , MainCPU . D [ 2 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-3" , MainCPU . D [ 3 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-4" , MainCPU . D [ 4 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-5" , MainCPU . D [ 5 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-6" , MainCPU . D [ 6 ] . s32 ) ,
new KeyValuePair < string , int > ( "D-7" , MainCPU . D [ 7 ] . s32 ) ,
new KeyValuePair < string , int > ( "SR" , MainCPU . SR ) ,
new KeyValuePair < string , int > ( "Flag X" , MainCPU . X ? 1 : 0 ) ,
new KeyValuePair < string , int > ( "Flag N" , MainCPU . N ? 1 : 0 ) ,
new KeyValuePair < string , int > ( "Flag Z" , MainCPU . Z ? 1 : 0 ) ,
new KeyValuePair < string , int > ( "Flag V" , MainCPU . V ? 1 : 0 ) ,
new KeyValuePair < string , int > ( "Flag C" , MainCPU . C ? 1 : 0 )
} ;
2013-11-11 03:20:33 +00:00
}
2013-11-04 01:06:36 +00:00
int vdpcallback ( int level ) // Musashi handler
{
InterruptCallback ( level ) ;
return - 1 ;
}
2012-08-26 14:39:06 +00:00
2013-11-04 01:06:36 +00:00
void InterruptCallback ( int level )
{
unchecked { VDP . VdpStatusWord & = ( ushort ) ~ GenVDP . StatusVerticalInterruptPending ; }
}
2012-08-26 14:39:06 +00:00
2012-12-10 00:43:43 +00:00
public CoreComm CoreComm { get ; private set ; }
2011-06-11 22:15:08 +00:00
public IVideoProvider VideoProvider
2011-07-30 20:49:36 +00:00
{
get { return VDP ; }
}
public ISoundProvider SoundProvider
{
get { return SoundMixer ; }
}
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 ( SoundMixer , 735 ) ; } }
public bool StartAsyncSound ( ) { return true ; }
public void EndAsyncSound ( ) { }
2011-07-30 20:49:36 +00:00
public int Frame { get ; set ; }
2011-12-24 01:59:51 +00:00
public int LagCount { get { return _lagcount ; } set { _lagcount = value ; } }
public bool IsLagFrame { get { return islag ; } }
2012-10-03 15:31:04 +00:00
public bool DeterministicEmulation { get { return true ; } }
2011-07-30 20:49:36 +00:00
public string SystemId { get { return "GEN" ; } }
2013-08-24 16:54:22 +00:00
public string BoardName { get { return null ; } }
2011-07-30 20:49:36 +00:00
2013-11-04 01:06:36 +00:00
public void SaveStateText ( TextWriter writer )
{
var buf = new byte [ 141501 + SaveRAM . Length ] ;
var stream = new MemoryStream ( buf ) ;
var bwriter = new BinaryWriter ( stream ) ;
SaveStateBinary ( bwriter ) ;
writer . WriteLine ( "Version 1" ) ;
writer . Write ( "BigFatBlob " ) ;
buf . SaveAsHex ( writer ) ;
/ * writer . WriteLine ( "[MegaDrive]" ) ;
MainCPU . SaveStateText ( writer , "Main68K" ) ;
SoundCPU . SaveStateText ( writer ) ;
PSG . SaveStateText ( writer ) ;
VDP . SaveStateText ( writer ) ;
2012-07-30 13:43:25 +00:00
writer . WriteLine ( "Frame {0}" , Frame ) ;
writer . WriteLine ( "Lag {0}" , _lagcount ) ;
2012-07-30 14:42:52 +00:00
writer . WriteLine ( "IsLag {0}" , islag ) ;
2013-11-04 01:06:36 +00:00
writer . Write ( "MainRAM " ) ;
Ram . SaveAsHex ( writer ) ;
writer . Write ( "Z80RAM " ) ;
Z80Ram . SaveAsHex ( writer ) ;
writer . WriteLine ( "[/MegaDrive]" ) ; * /
}
public void LoadStateText ( TextReader reader )
{
var buf = new byte [ 141501 + SaveRAM . Length ] ;
var version = reader . ReadLine ( ) ;
if ( version ! = "Version 1" )
throw new Exception ( "Not a valid state vesrion! sorry! your state is bad! Robust states will be added later!" ) ;
var omgstate = reader . ReadLine ( ) . Split ( ' ' ) [ 1 ] ;
buf . ReadFromHex ( omgstate ) ;
LoadStateBinary ( new BinaryReader ( new MemoryStream ( buf ) ) ) ;
/ * while ( true )
{
string [ ] args = reader . ReadLine ( ) . Split ( ' ' ) ;
if ( args [ 0 ] . Trim ( ) = = "" ) continue ;
if ( args [ 0 ] = = "[MegaDrive]" ) continue ;
if ( args [ 0 ] = = "[/MegaDrive]" ) break ;
if ( args [ 0 ] = = "MainRAM" )
Ram . ReadFromHex ( args [ 1 ] ) ;
else if ( args [ 0 ] = = "Z80RAM" )
Z80Ram . ReadFromHex ( args [ 1 ] ) ;
else if ( args [ 0 ] = = "[Main68K]" )
MainCPU . LoadStateText ( reader , "Main68K" ) ;
else if ( args [ 0 ] = = "[Z80]" )
SoundCPU . LoadStateText ( reader ) ;
2012-07-30 13:43:25 +00:00
else if ( args [ 0 ] = = "Frame" )
Frame = int . Parse ( args [ 1 ] ) ;
else if ( args [ 0 ] = = "Lag" )
_lagcount = int . Parse ( args [ 1 ] ) ;
2012-07-30 14:42:52 +00:00
else if ( args [ 0 ] = = "IsLag" )
islag = bool . Parse ( args [ 1 ] ) ;
2013-11-04 01:06:36 +00:00
else if ( args [ 0 ] = = "[PSG]" )
PSG . LoadStateText ( reader ) ;
else if ( args [ 0 ] = = "[VDP]" )
VDP . LoadStateText ( reader ) ;
else
Console . WriteLine ( "Skipping unrecognized identifier " + args [ 0 ] ) ;
} * /
}
2011-07-30 20:49:36 +00:00
public void SaveStateBinary ( BinaryWriter writer )
{
2013-11-04 01:06:36 +00:00
Musashi . SaveStateBinary ( writer ) ; // 124
SoundCPU . SaveStateBinary ( writer ) ; // 46
PSG . SaveStateBinary ( writer ) ; // 15
VDP . SaveStateBinary ( writer ) ; // 65781
YM2612 . SaveStateBinary ( writer ) ; // 1785
writer . Write ( Ram ) ; // 65535
writer . Write ( Z80Ram ) ; // 8192
writer . Write ( Frame ) ; // 4
writer . Write ( M68000HasZ80Bus ) ; // 1
writer . Write ( Z80Reset ) ; // 1
writer . Write ( BankRegion ) ; // 4
for ( int i = 0 ; i < 3 ; i + + )
{
writer . Write ( IOPorts [ i ] . Data ) ;
writer . Write ( IOPorts [ i ] . TxData ) ;
writer . Write ( IOPorts [ i ] . RxData ) ;
writer . Write ( IOPorts [ i ] . SCtrl ) ;
}
if ( SaveRAM . Length > 0 )
writer . Write ( SaveRAM ) ;
// TODO: EEPROM/cart HW state
// TODO: lag counter crap
2011-07-30 20:49:36 +00:00
}
public void LoadStateBinary ( BinaryReader reader )
{
2013-11-04 01:06:36 +00:00
Musashi . LoadStateBinary ( reader ) ;
SoundCPU . LoadStateBinary ( reader ) ;
PSG . LoadStateBinary ( reader ) ;
VDP . LoadStateBinary ( reader ) ;
YM2612 . LoadStateBinary ( reader ) ;
Ram = reader . ReadBytes ( Ram . Length ) ;
Z80Ram = reader . ReadBytes ( Z80Ram . Length ) ;
Frame = reader . ReadInt32 ( ) ;
M68000HasZ80Bus = reader . ReadBoolean ( ) ;
Z80Reset = reader . ReadBoolean ( ) ;
BankRegion = reader . ReadInt32 ( ) ;
for ( int i = 0 ; i < 3 ; i + + )
{
IOPorts [ i ] . Data = reader . ReadByte ( ) ;
IOPorts [ i ] . TxData = reader . ReadByte ( ) ;
IOPorts [ i ] . RxData = reader . ReadByte ( ) ;
IOPorts [ i ] . SCtrl = reader . ReadByte ( ) ;
}
if ( SaveRAM . Length > 0 )
SaveRAM = reader . ReadBytes ( SaveRAM . Length ) ;
2011-07-30 20:49:36 +00:00
}
public byte [ ] SaveStateBinary ( )
{
2013-11-04 01:06:36 +00:00
var buf = new byte [ 141501 + SaveRAM . Length ] ;
var stream = new MemoryStream ( buf ) ;
var writer = new BinaryWriter ( stream ) ;
SaveStateBinary ( writer ) ;
//Console.WriteLine("buf len = {0}", stream.Position);
writer . Close ( ) ;
return buf ;
2011-07-30 20:49:36 +00:00
}
2013-05-06 20:51:28 +00:00
public bool BinarySaveStatesPreferred { get { return false ; } }
2013-11-06 02:15:29 +00:00
MemoryDomainList memoryDomains ;
2011-12-24 01:59:51 +00:00
void SetupMemoryDomains ( )
{
var domains = new List < MemoryDomain > ( 3 ) ;
2013-11-04 02:11:40 +00:00
var MainMemoryDomain = new MemoryDomain ( "Main RAM" , Ram . Length , MemoryDomain . Endian . Big ,
2011-12-24 01:59:51 +00:00
addr = > Ram [ addr & 0xFFFF ] ,
( addr , value ) = > Ram [ addr & 0xFFFF ] = value ) ;
2013-11-04 02:11:40 +00:00
var Z80Domain = new MemoryDomain ( "Z80 RAM" , Z80Ram . Length , MemoryDomain . Endian . Little ,
2011-12-24 01:59:51 +00:00
addr = > Z80Ram [ addr & 0x1FFF ] ,
( addr , value ) = > { Z80Ram [ addr & 0x1FFF ] = value ; } ) ;
2013-11-04 02:11:40 +00:00
var VRamDomain = new MemoryDomain ( "Video RAM" , VDP . VRAM . Length , MemoryDomain . Endian . Big ,
2011-12-24 01:59:51 +00:00
addr = > VDP . VRAM [ addr & 0xFFFF ] ,
( addr , value ) = > VDP . VRAM [ addr & 0xFFFF ] = value ) ;
2013-11-04 02:11:40 +00:00
var RomDomain = new MemoryDomain ( "Rom Data" , RomData . Length , MemoryDomain . Endian . Big ,
2012-09-02 01:52:16 +00:00
addr = > RomData [ addr ] , //adelikat: For speed considerations, I didn't mask this, every tool that uses memory domains is smart enough not to overflow, if I'm wrong let me know!
2012-09-02 01:33:12 +00:00
( addr , value ) = > RomData [ addr & ( RomData . Length - 1 ) ] = value ) ;
2013-11-04 02:11:40 +00:00
var SystemBusDomain = new MemoryDomain ( "System Bus" , 0x1000000 , MemoryDomain . Endian . Big ,
2012-09-01 19:49:40 +00:00
addr = > ( byte ) ReadByte ( addr ) ,
( addr , value ) = > Write8 ( ( uint ) addr , ( uint ) value ) ) ;
2011-12-24 01:59:51 +00:00
domains . Add ( MainMemoryDomain ) ;
domains . Add ( Z80Domain ) ;
domains . Add ( VRamDomain ) ;
2012-09-02 01:33:12 +00:00
domains . Add ( RomDomain ) ;
2012-09-01 19:49:40 +00:00
domains . Add ( SystemBusDomain ) ;
2013-11-06 02:15:29 +00:00
memoryDomains = new MemoryDomainList ( domains ) ;
2011-12-24 01:59:51 +00:00
}
2013-11-06 02:15:29 +00:00
public MemoryDomainList MemoryDomains { get { return memoryDomains ; } }
2011-07-30 20:49:36 +00:00
public void Dispose ( ) { }
}
2011-01-11 02:55:51 +00:00
}