2012-11-01 16:48:32 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using System.IO ;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class C64 : IEmulator
{
2012-11-28 17:26:40 +00:00
private IController controller ;
2012-11-27 05:11:40 +00:00
private uint cyclesPerFrame ;
private string extension ;
private byte [ ] inputFile ;
2012-11-01 17:56:48 +00:00
public C64 ( GameInfo game , byte [ ] rom , string romextension )
2012-11-01 16:48:32 +00:00
{
2012-11-03 17:57:14 +00:00
inputFile = rom ;
2012-11-06 05:49:42 +00:00
extension = romextension ;
2012-11-03 17:57:14 +00:00
CoreOutputComm = new CoreOutputComm ( ) ;
CoreInputComm = new CoreInputComm ( ) ;
2012-11-18 10:25:57 +00:00
Init ( Region . PAL ) ;
2012-11-27 05:11:40 +00:00
cyclesPerFrame = ( uint ) chips . vic . CyclesPerFrame ;
2012-11-26 01:43:34 +00:00
CoreOutputComm . UsesDriveLed = true ;
2012-11-27 20:23:27 +00:00
SetupMemoryDomains ( ) ;
2012-11-01 16:48:32 +00:00
}
2012-11-17 03:58:06 +00:00
// internal variables
private bool _islag = true ;
private int _lagcount = 0 ;
private int _frame = 0 ;
// bizhawk I/O
2012-11-01 16:48:32 +00:00
public CoreInputComm CoreInputComm { get ; set ; }
public CoreOutputComm CoreOutputComm { get ; private set ; }
2012-11-17 03:58:06 +00:00
// game/rom specific
public GameInfo game ;
public string SystemId { get { return "C64" ; } }
// memory domains
public MemoryDomain MainMemory { get { return memoryDomains [ 0 ] ; } }
2012-11-01 16:48:32 +00:00
private IList < MemoryDomain > memoryDomains ;
public IList < MemoryDomain > MemoryDomains { get { return memoryDomains ; } }
2012-11-17 03:58:06 +00:00
// running state
public bool DeterministicEmulation { get { return true ; } set { ; } }
public int Frame { get { return _frame ; } set { _frame = value ; } }
public bool IsLagFrame { get { return _islag ; } }
public int LagCount { get { return _lagcount ; } set { _lagcount = value ; } }
2012-11-01 16:48:32 +00:00
public void ResetFrameCounter ( )
{
_frame = 0 ;
2012-11-25 15:41:40 +00:00
_lagcount = 0 ;
_islag = false ;
2012-11-01 16:48:32 +00:00
}
2012-11-17 03:58:06 +00:00
// audio/video
2012-11-01 16:48:32 +00:00
public void EndAsyncSound ( ) { } //TODO
2012-11-27 05:11:40 +00:00
public ISoundProvider SoundProvider { get { return chips . sid ; } }
2012-11-17 03:58:06 +00:00
public bool StartAsyncSound ( ) { return true ; } //TODO
2012-11-27 05:11:40 +00:00
public ISyncSoundProvider SyncSoundProvider { get { return chips . sid ; } }
public IVideoProvider VideoProvider { get { return chips . vic ; } }
2012-11-17 03:58:06 +00:00
// controller
2012-11-03 13:55:22 +00:00
public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition ; } }
2012-11-28 17:26:40 +00:00
public IController Controller { get { return controller ; } set { controller = value ; } }
2012-11-03 13:55:22 +00:00
public static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition
2012-11-01 16:48:32 +00:00
{
2012-11-03 06:03:58 +00:00
Name = "Commodore 64 Controller" , //TODO
2012-11-01 16:48:32 +00:00
BoolButtons =
{
2012-11-09 23:37:32 +00:00
"Key Insert/Delete" , "Key Return" , "Key Cursor Left/Right" , "Key F7" , "Key F1" , "Key F3" , "Key F5" , "Key Cursor Up/Down" ,
"Key 3" , "Key W" , "Key A" , "Key 4" , "Key Z" , "Key S" , "Key E" , "Key Left Shift" ,
"Key 5" , "Key R" , "Key D" , "Key 6" , "Key C" , "Key F" , "Key T" , "Key X" ,
"Key 7" , "Key Y" , "Key G" , "Key 8" , "Key B" , "Key H" , "Key U" , "Key V" ,
"Key 9" , "Key I" , "Key J" , "Key 0" , "Key M" , "Key K" , "Key O" , "Key N" ,
"Key Plus" , "Key P" , "Key L" , "Key Minus" , "Key Period" , "Key Colon" , "Key At" , "Key Comma" ,
"Key Pound" , "Key Asterisk" , "Key Semicolon" , "Key Clear/Home" , "Key Right Shift" , "Key Equal" , "Key Up Arrow" , "Key Slash" ,
"Key 1" , "Key Left Arrow" , "Key Control" , "Key 2" , "Key Space" , "Key Commodore" , "Key Q" , "Key Run/Stop" ,
2012-11-03 06:03:58 +00:00
"P1 Up" , "P1 Down" , "P1 Left" , "P1 Right" , "P1 Button" ,
2012-11-09 23:37:32 +00:00
"P2 Up" , "P2 Down" , "P2 Left" , "P2 Right" , "P2 Button"
2012-11-01 16:48:32 +00:00
}
} ;
2012-11-17 03:58:06 +00:00
// framework
public void Dispose ( ) { }
// process frame
2012-11-01 16:48:32 +00:00
public void FrameAdvance ( bool render , bool rendersound )
{
2012-11-28 17:49:42 +00:00
// load PRG file if needed
if ( loadPrg )
{
if ( chips . pla . Peek ( 0x04C8 ) = = 0x12 & &
chips . pla . Peek ( 0x04C9 ) = = 0x05 & &
chips . pla . Peek ( 0x04CA ) = = 0x01 & &
chips . pla . Peek ( 0x04CB ) = = 0x04 & &
chips . pla . Peek ( 0x04CC ) = = 0x19 & &
chips . pla . Peek ( 0x04CD ) = = 0x2E )
{
Media . PRG . Load ( chips . pla , inputFile ) ;
loadPrg = false ;
}
}
2012-11-28 17:26:40 +00:00
PollInput ( ) ;
2012-11-27 05:11:40 +00:00
chips . pla . InputWasRead = false ;
Execute ( cyclesPerFrame ) ;
_islag = ! chips . pla . InputWasRead ;
2012-11-19 16:38:39 +00:00
2012-11-01 16:48:32 +00:00
if ( _islag )
LagCount + + ;
2012-11-27 05:11:40 +00:00
_frame + + ;
2012-11-26 01:43:34 +00:00
CoreOutputComm . DriveLED = DriveLED ;
2012-11-01 16:48:32 +00:00
}
2012-11-27 05:11:40 +00:00
private void HandleFirmwareError ( string file )
{
System . Windows . Forms . MessageBox . Show ( "the C64 core is referencing a firmware file which could not be found. Please make sure it's in your configured C64 firmwares folder. The referenced filename is: " + file ) ;
throw new FileNotFoundException ( ) ;
}
2012-11-17 03:58:06 +00:00
public byte [ ] SaveStateBinary ( )
{
MemoryStream ms = new MemoryStream ( ) ;
BinaryWriter bw = new BinaryWriter ( ms ) ;
SaveStateBinary ( bw ) ;
bw . Flush ( ) ;
return ms . ToArray ( ) ;
}
2012-11-01 16:48:32 +00:00
private void SetupMemoryDomains ( )
{
2012-11-27 20:23:27 +00:00
// chips must be initialized before this code runs!
2012-11-01 16:48:32 +00:00
var domains = new List < MemoryDomain > ( 1 ) ;
2012-11-27 20:23:27 +00:00
domains . Add ( new MemoryDomain ( "System Bus" , 0x10000 , Endian . Little , new Func < int , byte > ( chips . cpu . Peek ) , new Action < int , byte > ( chips . cpu . Poke ) ) ) ;
domains . Add ( new MemoryDomain ( "RAM" , 0x10000 , Endian . Little , new Func < int , byte > ( chips . ram . Peek ) , new Action < int , byte > ( chips . ram . Poke ) ) ) ;
domains . Add ( new MemoryDomain ( "CIA0" , 0x10 , Endian . Little , new Func < int , byte > ( chips . cia0 . Peek ) , new Action < int , byte > ( chips . cia0 . Poke ) ) ) ;
domains . Add ( new MemoryDomain ( "CIA1" , 0x10 , Endian . Little , new Func < int , byte > ( chips . cia1 . Peek ) , new Action < int , byte > ( chips . cia1 . Poke ) ) ) ;
domains . Add ( new MemoryDomain ( "VIC" , 0x40 , Endian . Little , new Func < int , byte > ( chips . vic . Peek ) , new Action < int , byte > ( chips . vic . Poke ) ) ) ;
domains . Add ( new MemoryDomain ( "SID" , 0x20 , Endian . Little , new Func < int , byte > ( chips . sid . Peek ) , new Action < int , byte > ( chips . sid . Poke ) ) ) ;
2012-11-01 16:48:32 +00:00
memoryDomains = domains . AsReadOnly ( ) ;
}
}
}