2012-10-23 03:33:57 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using EMU7800.Core ;
namespace BizHawk
{
public partial class Atari7800 : IEmulator
{
2012-12-12 01:32:58 +00:00
static Atari7800 ( )
{
// add alpha bits to palette tables
for ( int i = 0 ; i < TIATables . NTSCPalette . Length ; i + + )
TIATables . NTSCPalette [ i ] | = unchecked ( ( int ) 0xff000000 ) ;
for ( int i = 0 ; i < TIATables . PALPalette . Length ; i + + )
TIATables . PALPalette [ i ] | = unchecked ( ( int ) 0xff000000 ) ;
}
2012-10-23 03:33:57 +00:00
public string SystemId { get { return "A78" ; } } //TODO: are we going to allow this core to do 2600 games?
public GameInfo game ;
public void FrameAdvance ( bool render , bool rendersound )
{
_frame + + ;
_islag = true ;
2012-12-12 01:32:58 +00:00
theMachine . ComputeNextFrame ( avProvider . framebuffer ) ;
2012-10-24 01:47:04 +00:00
2012-10-23 03:33:57 +00:00
if ( _islag )
{
LagCount + + ;
}
2012-12-12 01:32:58 +00:00
avProvider . FillFrameBuffer ( ) ;
2012-10-23 03:33:57 +00:00
}
/* TODO */
2012-12-10 00:43:43 +00:00
public CoreComm CoreComm { get ; private set ; }
2012-12-12 01:32:58 +00:00
public ISyncSoundProvider SyncSoundProvider { get { return avProvider ; } }
public bool StartAsyncSound ( ) { return false ; }
2012-10-23 03:33:57 +00:00
public void EndAsyncSound ( ) { }
public bool DeterministicEmulation { get ; set ; }
public void SaveStateText ( TextWriter writer ) { }
public void LoadStateText ( TextReader reader ) { }
public void SaveStateBinary ( BinaryWriter bw ) { }
public void LoadStateBinary ( BinaryReader br ) { }
private IList < MemoryDomain > memoryDomains ;
public IList < MemoryDomain > MemoryDomains { get { return null ; } }
public MemoryDomain MainMemory { get { return null ; } }
/********************/
public int Frame { get { return _frame ; } set { _frame = value ; } }
public int LagCount { get { return _lagcount ; } set { _lagcount = value ; } }
public bool IsLagFrame { get { return _islag ; } }
private bool _islag = true ;
private int _lagcount = 0 ;
private int _frame = 0 ;
public byte [ ] ReadSaveRam ( ) { return null ; }
public void StoreSaveRam ( byte [ ] data ) { }
public void ClearSaveRam ( ) { }
public bool SaveRamModified { get ; set ; }
2012-12-12 01:32:58 +00:00
public void Dispose ( )
{
if ( avProvider ! = null )
{
avProvider . Dispose ( ) ;
avProvider = null ;
}
}
public IVideoProvider VideoProvider { get { return avProvider ; } }
public ISoundProvider SoundProvider { get { return null ; } }
2012-10-23 03:33:57 +00:00
public void ResetFrameCounter ( )
{
_frame = 0 ;
2012-11-25 15:41:40 +00:00
_lagcount = 0 ;
_islag = false ;
2012-10-23 03:33:57 +00:00
}
public byte [ ] SaveStateBinary ( )
{
MemoryStream ms = new MemoryStream ( ) ;
BinaryWriter bw = new BinaryWriter ( ms ) ;
SaveStateBinary ( bw ) ;
bw . Flush ( ) ;
return ms . ToArray ( ) ;
}
public ControllerDefinition ControllerDefinition { get { return Atari7800ControllerDefinition ; } }
public IController Controller { get ; set ; }
public static readonly ControllerDefinition Atari7800ControllerDefinition = new ControllerDefinition
{
Name = "Atari 7800 Basic Controller" , //TODO
BoolButtons =
{
"P1 Up" , "P1 Down" , "P1 Left" , "P1 Right" , "P1 Button" ,
"P2 Up" , "P2 Down" , "P2 Left" , "P2 Right" , "P2 Button" ,
"Reset" , "Select"
}
} ;
2012-12-10 21:29:50 +00:00
class ConsoleLogger : ILogger
{
public void WriteLine ( string format , params object [ ] args )
{
Console . WriteLine ( format , args ) ;
}
public void WriteLine ( object value )
{
Console . WriteLine ( value ) ;
}
public void Write ( string format , params object [ ] args )
{
Console . Write ( format , args ) ;
}
public void Write ( object value )
{
Console . Write ( value ) ;
}
}
2012-12-10 00:43:43 +00:00
public Atari7800 ( CoreComm comm , GameInfo game , byte [ ] rom , byte [ ] ntsc_bios , byte [ ] pal_bios , byte [ ] highscoreBIOS )
2012-10-23 03:33:57 +00:00
{
2012-12-10 00:43:43 +00:00
CoreComm = comm ;
2012-10-23 20:21:55 +00:00
//TODO: store both the ntsc bios and the pal bios
2012-10-23 03:33:57 +00:00
var domains = new List < MemoryDomain > ( 1 ) ;
domains . Add ( new MemoryDomain ( "Main RAM" , 1 , Endian . Little , addr = > 0xFF , null ) ) ; //TODO
memoryDomains = domains . AsReadOnly ( ) ;
this . rom = rom ;
this . game = game ;
this . hsbios = highscoreBIOS ;
2012-10-23 20:21:55 +00:00
NTSC_BIOS = new Bios7800 ( ntsc_bios ) ;
PAL_BIOS = new Bios7800 ( pal_bios ) ;
2012-10-23 03:33:57 +00:00
HardReset ( ) ;
}
public void HardReset ( )
{
_lagcount = 0 ;
// show mapper class on romstatusdetails
2012-12-10 00:43:43 +00:00
CoreComm . RomStatusDetails =
2012-10-23 03:33:57 +00:00
string . Format ( "{0}\r\nSHA1:{1}\r\nMD5:{2}\r\nMapper Impl \"{3}\"" ,
game . Name ,
Util . BytesToHexString ( System . Security . Cryptography . SHA1 . Create ( ) . ComputeHash ( rom ) ) ,
Util . BytesToHexString ( System . Security . Cryptography . MD5 . Create ( ) . ComputeHash ( rom ) ) ,
"TODO" ) ;
2012-12-12 01:59:10 +00:00
cart = Cart . Create ( rom , CartType . A7848 ) ; //TODO: mapper selection system
2012-10-23 03:33:57 +00:00
int [ ] bob = new int [ ] { 0 , 0 , 0 } ;
2012-12-10 21:29:50 +00:00
//FileStream fs = new FileStream("C:\\dummy", FileMode.Create, FileAccess.ReadWrite); //TODO: I don't see what this context is used for, see if it can be whacked or pass in a null
//BinaryReader blah = new BinaryReader(fs);
//DeserializationContext george = new DeserializationContext(blah);
ILogger logger = new ConsoleLogger ( ) ;
HSC7800 hsc7800 = new HSC7800 ( hsbios , new byte [ 2048 ] ) ; //TODO: why should I have to feed it ram? how much?
2012-10-23 20:21:55 +00:00
theMachine = new Machine7800NTSC ( cart , NTSC_BIOS , hsc7800 , logger ) ;
2012-12-10 21:29:50 +00:00
//theMachine = new Machine7800NTSC(cart, null, null, logger);
2012-10-23 03:33:57 +00:00
//TODO: clean up, the hs and bios are passed in, the bios has an object AND byte array in the core, and naming is inconsistent
2012-12-11 23:01:01 +00:00
theMachine . Reset ( ) ;
2012-12-12 01:32:58 +00:00
avProvider = new MyAVProvider ( theMachine ) ;
2012-10-23 03:33:57 +00:00
}
void SyncState ( Serializer ser ) //TODO
{
ser . Sync ( "Lag" , ref _lagcount ) ;
ser . Sync ( "Frame" , ref _frame ) ;
ser . Sync ( "IsLag" , ref _islag ) ;
}
private void SoftReset ( ) //TOOD: hook this up
{
theMachine . Reset ( ) ;
}
2012-12-12 01:32:58 +00:00
MyAVProvider avProvider ;
2012-10-23 03:33:57 +00:00
2012-12-12 01:32:58 +00:00
class MyAVProvider : IVideoProvider , ISyncSoundProvider , IDisposable
2012-10-23 03:33:57 +00:00
{
2012-12-12 01:32:58 +00:00
public FrameBuffer framebuffer { get ; private set ; }
public MyAVProvider ( MachineBase m )
2012-10-23 03:33:57 +00:00
{
2012-12-12 01:32:58 +00:00
framebuffer = m . CreateFrameBuffer ( ) ;
BufferWidth = framebuffer . VisiblePitch ;
BufferHeight = framebuffer . Scanlines ;
vidbuffer = new int [ BufferWidth * BufferHeight ] ;
uint samplerate = ( uint ) m . SoundSampleFrequency ;
resampler = new Emulation . Sound . Utilities . SpeexResampler ( 3 , samplerate , 44100 , samplerate , 44100 , null , null ) ;
dcfilter = Emulation . Sound . Utilities . DCFilter . DetatchedMode ( 256 ) ;
2012-10-23 03:33:57 +00:00
}
2012-12-12 01:32:58 +00:00
int [ ] vidbuffer ;
Emulation . Sound . Utilities . SpeexResampler resampler ;
Emulation . Sound . Utilities . DCFilter dcfilter ;
2012-10-23 03:33:57 +00:00
2012-12-12 00:30:36 +00:00
public void FillFrameBuffer ( )
2012-10-23 03:33:57 +00:00
{
2012-12-12 01:32:58 +00:00
unsafe
2012-10-23 03:33:57 +00:00
{
2012-12-12 01:32:58 +00:00
fixed ( BufferElement * src_ = framebuffer . VideoBuffer )
2012-10-23 03:33:57 +00:00
{
2012-12-12 01:32:58 +00:00
fixed ( int * dst_ = vidbuffer )
2012-12-12 00:23:01 +00:00
{
2012-12-12 01:32:58 +00:00
fixed ( int * pal = TIATables . NTSCPalette )
{
byte * src = ( byte * ) src_ ;
int * dst = dst_ ;
for ( int i = 0 ; i < vidbuffer . Length ; i + + )
{
* dst + + = pal [ * src + + ] ;
}
}
2012-12-12 00:23:01 +00:00
}
2012-10-23 03:33:57 +00:00
}
}
}
public int [ ] GetVideoBuffer ( )
{
2012-12-12 01:32:58 +00:00
return vidbuffer ;
2012-10-23 03:33:57 +00:00
}
public int VirtualWidth { get { return BufferWidth ; } }
2012-12-12 00:30:36 +00:00
public int BufferWidth { get ; private set ; }
public int BufferHeight { get ; private set ; }
public int BackgroundColor { get { return unchecked ( ( int ) 0xff000000 ) ; } }
2012-10-23 03:33:57 +00:00
2012-12-12 01:32:58 +00:00
public void GetSamples ( out short [ ] samples , out int nsamp )
2012-10-23 20:21:55 +00:00
{
2012-12-12 01:32:58 +00:00
int nsampin = framebuffer . SoundBufferByteLength ;
unsafe
{
fixed ( BufferElement * src_ = framebuffer . SoundBuffer )
{
byte * src = ( byte * ) src_ ;
for ( int i = 0 ; i < nsampin ; i + + )
{
short s = ( short ) ( src [ i ] * 200 - 25500 ) ;
resampler . EnqueueSample ( s , s ) ;
}
}
}
resampler . GetSamples ( out samples , out nsamp ) ;
dcfilter . PushThroughSamples ( samples , nsamp * 2 ) ;
2012-10-23 20:21:55 +00:00
}
2012-12-12 01:32:58 +00:00
2012-10-23 03:33:57 +00:00
public void DiscardSamples ( )
{
2012-12-12 01:32:58 +00:00
resampler . DiscardSamples ( ) ;
2012-10-23 03:33:57 +00:00
}
2012-12-12 01:32:58 +00:00
public void Dispose ( )
2012-10-23 03:33:57 +00:00
{
2012-12-12 01:32:58 +00:00
if ( resampler ! = null )
{
resampler . Dispose ( ) ;
resampler = null ;
}
2012-10-23 03:33:57 +00:00
}
}
}
}