2012-11-01 16:48:32 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2013-11-04 01:06:36 +00:00
using BizHawk.Emulation.Common ;
2012-11-01 16:48:32 +00:00
namespace BizHawk.Emulation.Computers.Commodore64
{
2013-08-24 20:13:16 +00:00
sealed public partial class C64 : IEmulator
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 ;
2013-11-04 01:06:36 +00:00
private int cyclesPerFrame ;
private InputFileInfo inputFileInfo ;
2012-11-17 03:58:06 +00:00
// bizhawk I/O
2012-12-10 00:43:43 +00:00
public CoreComm CoreComm { get ; private set ; }
2012-11-17 03:58:06 +00:00
// game/rom specific
public GameInfo game ;
public string SystemId { get { return "C64" ; } }
2013-08-24 16:54:22 +00:00
public string BoardName { get { return null ; } }
2012-11-17 03:58:06 +00:00
// 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 ; } }
2013-11-03 16:29:51 +00:00
public void ResetCounters ( )
2012-11-01 16:48:32 +00:00
{
_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-12-08 16:05:00 +00:00
public ISoundProvider SoundProvider { get { return null ; } }
public bool StartAsyncSound ( ) { return false ; } //TODO
public ISyncSoundProvider SyncSoundProvider { get { return board . sid . resampler ; } }
2012-12-05 21:07:51 +00:00
public IVideoProvider VideoProvider { get { return board . 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-12-05 21:07:51 +00:00
public IController Controller { get { return board . controller ; } set { board . 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
{
2013-08-19 03:42:40 +00:00
Name = "Commodore 64 Controller" ,
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-12-06 00:41:31 +00:00
"P2 Up" , "P2 Down" , "P2 Left" , "P2 Right" , "P2 Button" ,
2012-12-06 01:19:32 +00:00
"Key Restore" , "Key Lck"
2012-11-01 16:48:32 +00:00
}
} ;
2012-11-17 03:58:06 +00:00
// framework
2013-08-19 03:42:40 +00:00
public C64 ( CoreComm comm , GameInfo game , byte [ ] rom , string romextension )
{
inputFileInfo = new InputFileInfo ( ) ;
inputFileInfo . Data = rom ;
inputFileInfo . Extension = romextension ;
CoreComm = comm ;
Init ( Region . PAL ) ;
cyclesPerFrame = board . vic . CyclesPerFrame ;
CoreComm . UsesDriveLed = true ;
SetupMemoryDomains ( ) ;
}
public void Dispose ( )
2012-12-08 16:07:06 +00:00
{
if ( board . sid ! = null )
{
board . sid . Dispose ( ) ;
board . sid = null ;
}
}
2012-11-17 03:58:06 +00:00
// process frame
2012-11-01 16:48:32 +00:00
public void FrameAdvance ( bool render , bool rendersound )
{
2013-08-14 13:53:48 +00:00
board . inputRead = false ;
2012-12-05 21:07:51 +00:00
board . PollInput ( ) ;
2013-08-19 03:42:40 +00:00
2013-08-17 10:46:27 +00:00
for ( int count = 0 ; count < cyclesPerFrame ; count + + )
2012-12-07 05:24:00 +00:00
{
2013-08-09 04:15:33 +00:00
//disk.Execute();
2012-12-07 05:24:00 +00:00
board . Execute ( ) ;
2013-08-19 03:42:40 +00:00
// load PRG file if needed
if ( loadPrg )
{
// check to see if cpu PC is at the BASIC warm start vector
if ( board . cpu . PC = = ( ( board . ram . Peek ( 0x0303 ) < < 8 ) | board . ram . Peek ( 0x0302 ) ) )
{
//board.ram.Poke(0x0302, 0xAE);
//board.ram.Poke(0x0303, 0xA7);
////board.ram.Poke(0x0302, board.ram.Peek(0x0308));
////board.ram.Poke(0x0303, board.ram.Peek(0x0309));
//if (inputFileInfo.Data.Length >= 6)
//{
// board.ram.Poke(0x0039, inputFileInfo.Data[4]);
// board.ram.Poke(0x003A, inputFileInfo.Data[5]);
//}
Media . PRG . Load ( board . pla , inputFileInfo . Data ) ;
loadPrg = false ;
}
}
}
2013-08-17 23:15:31 +00:00
board . Flush ( ) ;
2012-12-05 21:07:51 +00:00
_islag = ! board . inputRead ;
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
2013-08-13 12:23:32 +00:00
//Console.WriteLine("CPUPC: " + C64Util.ToHex(board.cpu.PC, 4) + " 1541PC: " + C64Util.ToHex(disk.PC, 4));
2012-12-07 21:01:22 +00:00
2012-12-10 00:43:43 +00:00
CoreComm . 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 ( ) ;
}
2013-05-06 20:51:28 +00:00
public bool BinarySaveStatesPreferred { get { return false ; } }
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 ) ;
2013-08-14 05:05:17 +00:00
domains . Add ( new MemoryDomain ( "System Bus" , 0x10000 , Endian . Little , board . cpu . Peek , board . cpu . Poke ) ) ;
domains . Add ( new MemoryDomain ( "RAM" , 0x10000 , Endian . Little , board . ram . Peek , board . ram . Poke ) ) ;
domains . Add ( new MemoryDomain ( "CIA0" , 0x10 , Endian . Little , board . cia0 . Peek , board . cia0 . Poke ) ) ;
domains . Add ( new MemoryDomain ( "CIA1" , 0x10 , Endian . Little , board . cia1 . Peek , board . cia1 . Poke ) ) ;
domains . Add ( new MemoryDomain ( "VIC" , 0x40 , Endian . Little , board . vic . Peek , board . vic . Poke ) ) ;
domains . Add ( new MemoryDomain ( "SID" , 0x20 , Endian . Little , board . sid . Peek , board . sid . Poke ) ) ;
2013-08-13 12:23:32 +00:00
//domains.Add(new MemoryDomain("1541 Bus", 0x10000, Endian.Little, new Func<int, byte>(disk.Peek), new Action<int, byte>(disk.Poke)));
//domains.Add(new MemoryDomain("1541 VIA0", 0x10, Endian.Little, new Func<int, byte>(disk.PeekVia0), new Action<int, byte>(disk.PokeVia0)));
//domains.Add(new MemoryDomain("1541 VIA1", 0x10, Endian.Little, new Func<int, byte>(disk.PeekVia1), new Action<int, byte>(disk.PokeVia1)));
//domains.Add(new MemoryDomain("1541 RAM", 0x1000, Endian.Little, new Func<int, byte>(disk.PeekRam), new Action<int, byte>(disk.PokeRam)));
2012-11-01 16:48:32 +00:00
memoryDomains = domains . AsReadOnly ( ) ;
}
}
}