2012-03-07 00:40:20 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
2014-04-15 22:10:39 +00:00
|
|
|
|
using System.Linq;
|
2012-03-07 00:40:20 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
using BizHawk.Common;
|
2013-11-04 01:06:36 +00:00
|
|
|
|
using BizHawk.Emulation.Common;
|
2013-11-04 00:36:15 +00:00
|
|
|
|
|
2013-11-13 03:32:25 +00:00
|
|
|
|
namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
2012-03-07 00:40:20 +00:00
|
|
|
|
{
|
2014-04-25 01:19:57 +00:00
|
|
|
|
[CoreAttributes(
|
|
|
|
|
"Atari2600Hawk",
|
|
|
|
|
"Micro500, adelikat",
|
|
|
|
|
isPorted: false,
|
|
|
|
|
isReleased: true
|
|
|
|
|
)]
|
2012-04-02 20:55:29 +00:00
|
|
|
|
public partial class Atari2600 : IEmulator
|
2012-03-07 00:40:20 +00:00
|
|
|
|
{
|
2014-04-05 14:13:05 +00:00
|
|
|
|
private readonly GameInfo _game;
|
|
|
|
|
private bool _islag = true;
|
|
|
|
|
private int _lagcount;
|
|
|
|
|
private int _frame;
|
2012-03-30 00:35:15 +00:00
|
|
|
|
|
2014-04-05 14:13:05 +00:00
|
|
|
|
public Atari2600(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
|
2012-03-07 00:40:20 +00:00
|
|
|
|
{
|
2014-04-05 14:13:05 +00:00
|
|
|
|
Ram = new byte[128];
|
2012-12-10 00:43:43 +00:00
|
|
|
|
CoreComm = comm;
|
2014-04-05 14:13:05 +00:00
|
|
|
|
Settings = (A2600Settings)settings ?? A2600Settings.GetDefaults();
|
|
|
|
|
SyncSettings = (A2600SyncSettings)syncSettings ?? A2600SyncSettings.GetDefaults();
|
2013-12-24 20:50:53 +00:00
|
|
|
|
|
2014-04-05 14:13:05 +00:00
|
|
|
|
var domains = new List<MemoryDomain>
|
|
|
|
|
{
|
|
|
|
|
new MemoryDomain(
|
|
|
|
|
"Main RAM",
|
|
|
|
|
128,
|
|
|
|
|
MemoryDomain.Endian.Little,
|
|
|
|
|
addr => Ram[addr],
|
|
|
|
|
(addr, value) => Ram[addr] = value),
|
|
|
|
|
new MemoryDomain(
|
|
|
|
|
"TIA",
|
|
|
|
|
16,
|
|
|
|
|
MemoryDomain.Endian.Little,
|
|
|
|
|
addr => _tia.ReadMemory((ushort)addr, true),
|
|
|
|
|
(addr, value) => this._tia.WriteMemory((ushort)addr, value)),
|
|
|
|
|
new MemoryDomain(
|
|
|
|
|
"PIA",
|
|
|
|
|
1024,
|
|
|
|
|
MemoryDomain.Endian.Little,
|
|
|
|
|
addr => M6532.ReadMemory((ushort)addr, true),
|
|
|
|
|
(addr, value) => M6532.WriteMemory((ushort)addr, value)),
|
|
|
|
|
new MemoryDomain(
|
|
|
|
|
"System Bus",
|
|
|
|
|
8192,
|
|
|
|
|
MemoryDomain.Endian.Little,
|
|
|
|
|
addr => _mapper.PeekMemory((ushort) addr),
|
|
|
|
|
(addr, value) => { })
|
|
|
|
|
};
|
2014-04-11 01:05:50 +00:00
|
|
|
|
|
2012-12-10 00:43:43 +00:00
|
|
|
|
CoreComm.CpuTraceAvailable = true;
|
2014-04-05 14:13:05 +00:00
|
|
|
|
Rom = rom;
|
|
|
|
|
_game = game;
|
2014-02-08 04:59:45 +00:00
|
|
|
|
|
|
|
|
|
if (!game.GetOptionsDict().ContainsKey("m"))
|
2014-04-02 21:07:55 +00:00
|
|
|
|
{
|
2014-04-04 19:46:41 +00:00
|
|
|
|
game.AddOption("m", DetectMapper(rom));
|
2014-04-02 21:07:55 +00:00
|
|
|
|
}
|
2014-02-08 04:59:45 +00:00
|
|
|
|
|
2012-03-30 00:35:15 +00:00
|
|
|
|
Console.WriteLine("Game uses mapper " + game.GetOptionsDict()["m"]);
|
2014-04-06 22:40:10 +00:00
|
|
|
|
RebootCore();
|
2014-04-11 01:05:50 +00:00
|
|
|
|
|
|
|
|
|
if (_mapper is mDPC) // TODO: also mDPCPlus
|
|
|
|
|
{
|
|
|
|
|
domains.Add(new MemoryDomain(
|
|
|
|
|
"DPC",
|
|
|
|
|
2048,
|
|
|
|
|
MemoryDomain.Endian.Little,
|
|
|
|
|
addr => (_mapper as mDPC).DspData[addr],
|
|
|
|
|
(addr, value) => (_mapper as mDPC).DspData[addr] = value));
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-11 01:31:10 +00:00
|
|
|
|
if (_mapper.HasCartRam)
|
|
|
|
|
{
|
|
|
|
|
domains.Add(new MemoryDomain(
|
|
|
|
|
"Cart Ram",
|
|
|
|
|
_mapper.CartRam.Len,
|
|
|
|
|
MemoryDomain.Endian.Little,
|
|
|
|
|
addr => _mapper.CartRam[addr],
|
|
|
|
|
(addr, value) => _mapper.CartRam[addr] = value));
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-11 01:05:50 +00:00
|
|
|
|
MemoryDomains = new MemoryDomainList(domains);
|
2012-03-07 00:40:20 +00:00
|
|
|
|
}
|
2013-11-11 03:20:33 +00:00
|
|
|
|
|
2014-04-05 14:13:05 +00:00
|
|
|
|
public string SystemId { get { return "A26"; } }
|
|
|
|
|
|
|
|
|
|
public string BoardName { get { return _mapper.GetType().Name; } }
|
|
|
|
|
|
|
|
|
|
public CoreComm CoreComm { get; private set; }
|
|
|
|
|
|
|
|
|
|
public IVideoProvider VideoProvider { get { return _tia; } }
|
|
|
|
|
|
|
|
|
|
public ISoundProvider SoundProvider { get { return _dcfilter; } }
|
|
|
|
|
|
|
|
|
|
public ISyncSoundProvider SyncSoundProvider { get { return new FakeSyncSound(_dcfilter, 735); } }
|
|
|
|
|
|
|
|
|
|
public ControllerDefinition ControllerDefinition { get { return Atari2600ControllerDefinition; } }
|
|
|
|
|
|
|
|
|
|
public IController Controller { get; set; }
|
|
|
|
|
|
|
|
|
|
public int Frame { get { return _frame; } set { _frame = value; } }
|
|
|
|
|
|
|
|
|
|
public int LagCount { get { return _lagcount; } set { _lagcount = value; } }
|
|
|
|
|
|
|
|
|
|
public bool IsLagFrame { get { return _islag; } }
|
|
|
|
|
|
|
|
|
|
public bool SaveRamModified { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool DeterministicEmulation { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool BinarySaveStatesPreferred { get { return false; } }
|
|
|
|
|
|
|
|
|
|
public A2600Settings Settings { get; private set; }
|
|
|
|
|
|
|
|
|
|
public A2600SyncSettings SyncSettings { get; private set; }
|
|
|
|
|
|
|
|
|
|
public MemoryDomainList MemoryDomains { get; private set; }
|
|
|
|
|
|
|
|
|
|
public static readonly ControllerDefinition Atari2600ControllerDefinition = new ControllerDefinition
|
|
|
|
|
{
|
|
|
|
|
Name = "Atari 2600 Basic Controller",
|
|
|
|
|
BoolButtons =
|
|
|
|
|
{
|
|
|
|
|
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button",
|
|
|
|
|
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button",
|
2014-04-06 22:40:10 +00:00
|
|
|
|
"Reset", "Select", "Power"
|
2014-04-05 14:13:05 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-04-20 01:19:33 +00:00
|
|
|
|
public int CurrentScanLine
|
|
|
|
|
{
|
|
|
|
|
get { return _tia.CurrentScanLine; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsVsync
|
|
|
|
|
{
|
|
|
|
|
get { return _tia.IsVSync; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsVBlank
|
|
|
|
|
{
|
|
|
|
|
get { return _tia.IsVBlank; }
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-15 22:10:39 +00:00
|
|
|
|
public CompactGameInfo GenerateGameDbEntry()
|
|
|
|
|
{
|
|
|
|
|
return new CompactGameInfo
|
|
|
|
|
{
|
|
|
|
|
Name = _game.Name,
|
|
|
|
|
System = "A26",
|
|
|
|
|
MetaData = "m=" + _mapper.GetType().ToString().Split('.').ToList().Last(),
|
|
|
|
|
Hash = Util.Hash_SHA1(Rom),
|
|
|
|
|
Region = _game.Region,
|
|
|
|
|
Status = RomStatus.Unknown
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-19 22:23:13 +00:00
|
|
|
|
public Dictionary<string, int> GetCpuFlagsAndRegisters()
|
2014-04-19 19:01:13 +00:00
|
|
|
|
{
|
|
|
|
|
return new Dictionary<string, int>
|
|
|
|
|
{
|
|
|
|
|
{ "A", Cpu.A },
|
|
|
|
|
{ "X", Cpu.X },
|
|
|
|
|
{ "Y", Cpu.Y },
|
|
|
|
|
{ "S", Cpu.S },
|
|
|
|
|
{ "PC", Cpu.PC },
|
|
|
|
|
|
|
|
|
|
{ "Flag C", Cpu.FlagC ? 1 : 0 },
|
|
|
|
|
{ "Flag Z", Cpu.FlagZ ? 1 : 0 },
|
|
|
|
|
{ "Flag I", Cpu.FlagI ? 1 : 0 },
|
|
|
|
|
{ "Flag D", Cpu.FlagD ? 1 : 0 },
|
|
|
|
|
|
|
|
|
|
{ "Flag B", Cpu.FlagB ? 1 : 0 },
|
|
|
|
|
{ "Flag V", Cpu.FlagV ? 1 : 0 },
|
|
|
|
|
{ "Flag N", Cpu.FlagN ? 1 : 0 },
|
|
|
|
|
{ "Flag T", Cpu.FlagT ? 1 : 0 }
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-05 14:13:05 +00:00
|
|
|
|
public bool StartAsyncSound() { return true; }
|
|
|
|
|
|
|
|
|
|
public void EndAsyncSound() { }
|
|
|
|
|
|
2013-11-03 16:29:51 +00:00
|
|
|
|
public void ResetCounters()
|
2012-03-07 00:40:20 +00:00
|
|
|
|
{
|
2012-03-23 02:55:46 +00:00
|
|
|
|
_frame = 0;
|
2012-11-25 15:41:40 +00:00
|
|
|
|
_lagcount = 0;
|
|
|
|
|
_islag = false;
|
2012-03-07 00:40:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-05 14:13:05 +00:00
|
|
|
|
private void SyncState(Serializer ser)
|
2012-03-07 00:40:20 +00:00
|
|
|
|
{
|
2012-11-28 18:27:14 +00:00
|
|
|
|
ser.BeginSection("A2600");
|
2014-04-05 14:13:05 +00:00
|
|
|
|
Cpu.SyncState(ser);
|
|
|
|
|
ser.Sync("ram", ref this.Ram, false);
|
2012-03-23 02:55:46 +00:00
|
|
|
|
ser.Sync("Lag", ref _lagcount);
|
|
|
|
|
ser.Sync("Frame", ref _frame);
|
2012-07-30 14:42:52 +00:00
|
|
|
|
ser.Sync("IsLag", ref _islag);
|
2014-04-05 14:13:05 +00:00
|
|
|
|
_tia.SyncState(ser);
|
|
|
|
|
M6532.SyncState(ser);
|
2012-12-18 20:37:31 +00:00
|
|
|
|
ser.BeginSection("Mapper");
|
2014-04-05 14:13:05 +00:00
|
|
|
|
_mapper.SyncState(ser);
|
2012-11-28 18:27:14 +00:00
|
|
|
|
ser.EndSection();
|
2012-12-18 20:37:31 +00:00
|
|
|
|
ser.EndSection();
|
2012-03-07 00:40:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-05 14:13:05 +00:00
|
|
|
|
public byte[] ReadSaveRam()
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2012-03-07 00:40:20 +00:00
|
|
|
|
|
2012-09-14 22:28:38 +00:00
|
|
|
|
public void StoreSaveRam(byte[] data) { }
|
2014-05-21 14:32:41 +00:00
|
|
|
|
|
2012-09-14 22:28:38 +00:00
|
|
|
|
public void ClearSaveRam() { }
|
|
|
|
|
|
2014-04-05 14:13:05 +00:00
|
|
|
|
public void SaveStateText(TextWriter writer)
|
|
|
|
|
{
|
|
|
|
|
SyncState(Serializer.CreateTextWriter(writer));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadStateText(TextReader reader)
|
|
|
|
|
{
|
|
|
|
|
SyncState(Serializer.CreateTextReader(reader));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SaveStateBinary(BinaryWriter bw)
|
|
|
|
|
{
|
|
|
|
|
SyncState(Serializer.CreateBinaryWriter(bw));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadStateBinary(BinaryReader br)
|
|
|
|
|
{
|
|
|
|
|
SyncState(Serializer.CreateBinaryReader(br));
|
|
|
|
|
}
|
2012-03-07 00:40:20 +00:00
|
|
|
|
|
|
|
|
|
public byte[] SaveStateBinary()
|
|
|
|
|
{
|
2014-04-05 14:13:05 +00:00
|
|
|
|
var ms = new MemoryStream();
|
|
|
|
|
var bw = new BinaryWriter(ms);
|
2012-03-07 00:40:20 +00:00
|
|
|
|
SaveStateBinary(bw);
|
|
|
|
|
bw.Flush();
|
|
|
|
|
return ms.ToArray();
|
|
|
|
|
}
|
2012-09-14 22:28:38 +00:00
|
|
|
|
|
2012-03-07 00:40:20 +00:00
|
|
|
|
public void Dispose() { }
|
2014-05-21 14:32:41 +00:00
|
|
|
|
|
|
|
|
|
private static bool DetectPal(GameInfo game, byte[] rom)
|
|
|
|
|
{
|
|
|
|
|
var comm = new CoreComm(null, null);
|
|
|
|
|
comm.InputCallback = new InputCallbackSystem();
|
|
|
|
|
|
|
|
|
|
Atari2600 emu = new Atari2600(new CoreComm(null, null), game, rom, null, null);
|
|
|
|
|
emu.Controller = new NullController();
|
|
|
|
|
|
|
|
|
|
List<int> framecounts = new List<int>();
|
|
|
|
|
emu._tia.FrameEndCallBack = (i) => framecounts.Add(i);
|
|
|
|
|
for (int i = 0; i < 71; i++) // run for 71 * 262 lines, since we're in NTSC mode
|
|
|
|
|
emu.FrameAdvance(false, false);
|
|
|
|
|
int numpal = framecounts.Where((i) => i > 287).Count();
|
|
|
|
|
Console.WriteLine("{0} PAL", numpal);
|
|
|
|
|
return numpal >= 25;
|
|
|
|
|
}
|
2012-03-07 00:40:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|