BizHawk/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs

171 lines
4.0 KiB
C#
Raw Normal View History

2012-03-25 01:33:05 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using BizHawk.Common;
2014-07-03 17:23:03 +00:00
using BizHawk.Common.NumberExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components;
using BizHawk.Emulation.Cores.Components.Z80;
2012-03-25 01:33:05 +00:00
namespace BizHawk.Emulation.Cores.ColecoVision
2012-03-25 01:33:05 +00:00
{
[CoreAttributes(
"ColecoHawk",
"Vecna",
isPorted: false,
isReleased: true
)]
[ServiceNotApplicable(typeof(ISaveRam), typeof(IDriveLight))]
2014-11-30 20:34:51 +00:00
public sealed partial class ColecoVision : IEmulator, IMemoryDomains, IDebuggable, IInputPollable, IStatable, ISettable<object, ColecoVision.ColecoSyncSettings>
2012-03-25 01:33:05 +00:00
{
// ROM
public byte[] RomData;
public int RomLength;
public byte[] BiosRom;
// Machine
public Z80A Cpu;
public TMS9918A VDP;
public SN76489 PSG;
public byte[] Ram = new byte[1024];
[CoreConstructor("Coleco")]
2013-12-24 23:32:43 +00:00
public ColecoVision(CoreComm comm, GameInfo game, byte[] rom, object SyncSettings)
2012-03-25 01:33:05 +00:00
{
ServiceProvider = new BasicServiceProvider(this);
CoreComm = comm;
_syncSettings = (ColecoSyncSettings)SyncSettings ?? new ColecoSyncSettings();
bool skipbios = this._syncSettings.SkipBiosIntro;
Cpu = new Z80A();
Cpu.ReadMemory = ReadMemory;
Cpu.WriteMemory = WriteMemory;
Cpu.ReadHardware = ReadPort;
Cpu.WriteHardware = WritePort;
VDP = new TMS9918A(Cpu);
PSG = new SN76489();
// TODO: hack to allow bios-less operation would be nice, no idea if its feasible
string biosPath = CoreComm.CoreFileProvider.GetFirmwarePath("Coleco", "Bios", true, "Coleco BIOS file is required.");
BiosRom = File.ReadAllBytes(biosPath);
2013-12-24 23:32:43 +00:00
// gamedb can overwrite the syncsettings; this is ok
if (game["NoSkip"])
skipbios = false;
LoadRom(rom, skipbios);
this.game = game;
2012-11-20 00:35:22 +00:00
SetupMemoryDomains();
2012-03-25 01:33:05 +00:00
}
public IEmulatorServiceProvider ServiceProvider { get; private set; }
2012-11-20 00:35:22 +00:00
const ushort RamSizeMask = 0x03FF;
public void FrameAdvance(bool render, bool renderSound)
{
Frame++;
_isLag = true;
PSG.BeginFrame(Cpu.TotalExecutedCycles);
VDP.ExecuteFrame();
PSG.EndFrame(Cpu.TotalExecutedCycles);
if (_isLag)
{
LagCount++;
}
}
void LoadRom(byte[] rom, bool skipbios)
{
RomData = new byte[0x8000];
for (int i = 0; i < 0x8000; i++)
RomData[i] = rom[i % rom.Length];
2012-11-18 00:40:22 +00:00
// hack to skip colecovision title screen
if (skipbios)
{
RomData[0] = 0x55;
RomData[1] = 0xAA;
}
}
byte ReadPort(ushort port)
{
port &= 0xFF;
if (port >= 0xA0 && port < 0xC0)
{
if ((port & 1) == 0)
return VDP.ReadData();
return VDP.ReadVdpStatus();
}
if (port >= 0xE0)
{
if ((port & 1) == 0)
return ReadController1();
return ReadController2();
}
2012-11-18 00:40:22 +00:00
return 0xFF;
}
void WritePort(ushort port, byte value)
{
port &= 0xFF;
if (port >= 0xA0 && port <= 0xBF)
{
if ((port & 1) == 0)
VDP.WriteVdpData(value);
else
VDP.WriteVdpControl(value);
return;
}
if (port >= 0x80 && port <= 0x9F)
{
InputPortSelection = InputPortMode.Right;
return;
}
if (port >= 0xC0 && port <= 0xDF)
{
InputPortSelection = InputPortMode.Left;
return;
}
if (port >= 0xE0)
{
PSG.WritePsgData(value, Cpu.TotalExecutedCycles);
return;
}
}
2012-03-25 01:33:05 +00:00
public bool DeterministicEmulation { get { return true; } }
public void Dispose() { }
public void ResetCounters()
{
Frame = 0;
_lagCount = 0;
_isLag = false;
}
public string SystemId { get { return "Coleco"; } }
public GameInfo game;
public CoreComm CoreComm { get; private set; }
public IVideoProvider VideoProvider { get { return VDP; } }
public ISoundProvider SoundProvider { get { return PSG; } }
public string BoardName { get { return null; } }
public ISyncSoundProvider SyncSoundProvider { get { return null; } }
public bool StartAsyncSound() { return true; }
public void EndAsyncSound() { }
2012-03-25 01:33:05 +00:00
}
}