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-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
|
|
|
|
SetupMemoryDomains();
|
|
|
|
|
CoreOutputComm = new CoreOutputComm();
|
|
|
|
|
CoreInputComm = new CoreInputComm();
|
2012-11-18 10:25:57 +00:00
|
|
|
|
Init(Region.PAL);
|
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
|
|
|
|
|
|
|
|
|
// save state/ram
|
2012-11-01 16:48:32 +00:00
|
|
|
|
public void ClearSaveRam() { }
|
2012-11-17 03:58:06 +00:00
|
|
|
|
public void LoadStateBinary(BinaryReader br) { }
|
|
|
|
|
public void LoadStateText(TextReader reader) { }
|
|
|
|
|
public byte[] ReadSaveRam() { return null; }
|
2012-11-01 16:48:32 +00:00
|
|
|
|
public bool SaveRamModified { get; set; }
|
2012-11-17 03:58:06 +00:00
|
|
|
|
public void SaveStateBinary(BinaryWriter bw) { }
|
|
|
|
|
public void SaveStateText(TextWriter writer) { }
|
|
|
|
|
public void StoreSaveRam(byte[] data) { }
|
|
|
|
|
|
|
|
|
|
// 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-17 03:58:06 +00:00
|
|
|
|
// audio/video
|
2012-11-01 16:48:32 +00:00
|
|
|
|
public void EndAsyncSound() { } //TODO
|
2012-11-17 03:58:06 +00:00
|
|
|
|
public ISoundProvider SoundProvider { get { return sid; } }
|
|
|
|
|
public bool StartAsyncSound() { return true; } //TODO
|
2012-11-18 12:10:58 +00:00
|
|
|
|
public ISyncSoundProvider SyncSoundProvider { get { return new SidSyncSoundProvider(sid); } }
|
2012-11-17 03:58:06 +00:00
|
|
|
|
public IVideoProvider VideoProvider { get { return vic; } }
|
|
|
|
|
|
|
|
|
|
// controller
|
2012-11-03 13:55:22 +00:00
|
|
|
|
public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } }
|
2012-11-09 23:37:32 +00:00
|
|
|
|
public IController Controller { get { return input.controller; } set { input.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)
|
|
|
|
|
{
|
|
|
|
|
_frame++;
|
|
|
|
|
_islag = true;
|
|
|
|
|
|
2012-11-18 10:25:57 +00:00
|
|
|
|
int cyclesPerFrame = vic.CyclesPerFrame;
|
2012-11-03 17:57:14 +00:00
|
|
|
|
|
2012-11-07 17:52:16 +00:00
|
|
|
|
foreach (IMedia media in mediaAttached)
|
|
|
|
|
{
|
|
|
|
|
if (!media.Loaded() && media.Ready())
|
|
|
|
|
{
|
2012-11-08 19:57:22 +00:00
|
|
|
|
media.Apply();
|
2012-11-07 17:52:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-08 21:12:33 +00:00
|
|
|
|
PollInput();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < cyclesPerFrame; i++)
|
2012-11-03 17:57:14 +00:00
|
|
|
|
{
|
2012-11-10 08:48:36 +00:00
|
|
|
|
vic.PerformCycle();
|
2012-11-06 15:15:37 +00:00
|
|
|
|
cpu.IRQ = signal.CpuIRQ;
|
|
|
|
|
cpu.NMI = signal.CpuNMI;
|
2012-11-05 16:56:58 +00:00
|
|
|
|
cia0.PerformCycle();
|
2012-11-15 07:41:59 +00:00
|
|
|
|
signal.CiaIRQ0 = cia0.IRQ;
|
2012-11-03 17:57:14 +00:00
|
|
|
|
cia1.PerformCycle();
|
2012-11-15 07:41:59 +00:00
|
|
|
|
signal.CiaIRQ1 = cia1.IRQ;
|
2012-11-18 10:25:57 +00:00
|
|
|
|
sid.PerformCycle();
|
|
|
|
|
if (diskDriveAttached)
|
|
|
|
|
diskDrive.PerformCycle();
|
|
|
|
|
if (signal.CpuAEC)
|
|
|
|
|
{
|
|
|
|
|
cpu.ExecuteOne();
|
|
|
|
|
}
|
2012-11-03 17:57:14 +00:00
|
|
|
|
}
|
2012-11-01 16:48:32 +00:00
|
|
|
|
|
|
|
|
|
if (_islag)
|
|
|
|
|
{
|
|
|
|
|
LagCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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()
|
|
|
|
|
{
|
|
|
|
|
var domains = new List<MemoryDomain>(1);
|
2012-11-12 16:37:11 +00:00
|
|
|
|
domains.Add(new MemoryDomain("System Bus", 0x10000, Endian.Little, new Func<int, byte>(PeekMemoryInt), new Action<int, byte>(PokeMemoryInt)));
|
2012-11-12 15:52:31 +00:00
|
|
|
|
domains.Add(new MemoryDomain("RAM", 0x10000, Endian.Little, new Func<int, byte>(PeekRAM), new Action<int, byte>(PokeRAM)));
|
|
|
|
|
domains.Add(new MemoryDomain("CIA0", 0x10, Endian.Little, new Func<int, byte>(PeekCia0), new Action<int, byte>(PokeCia0)));
|
|
|
|
|
domains.Add(new MemoryDomain("CIA1", 0x10, Endian.Little, new Func<int, byte>(PeekCia1), new Action<int, byte>(PokeCia1)));
|
|
|
|
|
domains.Add(new MemoryDomain("SID", 0x20, Endian.Little, new Func<int, byte>(PeekSid), new Action<int, byte>(PokeSid)));
|
|
|
|
|
domains.Add(new MemoryDomain("VIC", 0x40, Endian.Little, new Func<int, byte>(PeekVic), new Action<int, byte>(PokeVic)));
|
|
|
|
|
domains.Add(new MemoryDomain("CRAM", 0x400, Endian.Little, new Func<int, byte>(PeekColorRAM), new Action<int, byte>(PokeColorRAM)));
|
2012-11-15 15:58:26 +00:00
|
|
|
|
domains.Add(new MemoryDomain("DISKRAM", 0x10000, Endian.Little, new Func<int, byte>(PeekDiskDrive), new Action<int, byte>(PokeDiskDrive)));
|
2012-11-16 09:23:34 +00:00
|
|
|
|
domains.Add(new MemoryDomain("DISKVIA0", 0x10, Endian.Little, new Func<int, byte>(PeekVia0), new Action<int, byte>(PokeVia0)));
|
|
|
|
|
domains.Add(new MemoryDomain("DISKVIA1", 0x10, Endian.Little, new Func<int, byte>(PeekVia1), new Action<int, byte>(PokeVia1)));
|
2012-11-01 16:48:32 +00:00
|
|
|
|
memoryDomains = domains.AsReadOnly();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SyncState(Serializer ser) //TODO
|
|
|
|
|
{
|
|
|
|
|
ser.Sync("Lag", ref _lagcount);
|
|
|
|
|
ser.Sync("Frame", ref _frame);
|
|
|
|
|
ser.Sync("IsLag", ref _islag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|