Add files via upload
This commit is contained in:
parent
3a020a1c40
commit
b2eecd7bec
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
["A"] = cpu.A,
|
||||
["X"] = cpu.X,
|
||||
["Y"] = cpu.Y,
|
||||
["S"] = cpu.S,
|
||||
["PC"] = cpu.PC,
|
||||
["Flag C"] = cpu.FlagC,
|
||||
["Flag Z"] = cpu.FlagZ,
|
||||
["Flag I"] = cpu.FlagI,
|
||||
["Flag D"] = cpu.FlagD,
|
||||
["Flag B"] = cpu.FlagB,
|
||||
["Flag V"] = cpu.FlagV,
|
||||
["Flag N"] = cpu.FlagN,
|
||||
["Flag T"] = cpu.FlagT
|
||||
};
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
cpu.PC = (ushort)value;
|
||||
break;
|
||||
case "Flag I":
|
||||
cpu.FlagI = value > 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks
|
||||
{
|
||||
[FeatureNotImplemented]
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles
|
||||
{
|
||||
get { return cpu.TotalExecutedCycles; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IEmulator
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition { get; private set; }
|
||||
|
||||
public void FrameAdvance(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
_frame++;
|
||||
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
// it seems that theMachine.Reset() doesn't clear ram, etc
|
||||
// this should leave hsram intact but clear most other things
|
||||
HardReset();
|
||||
}
|
||||
|
||||
if (_islag)
|
||||
{
|
||||
_lagcount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "A7800";
|
||||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
_frame = 0;
|
||||
_lagcount = 0;
|
||||
_islag = false;
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
maria = null;
|
||||
tia = null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IInputPollable
|
||||
{
|
||||
public int LagCount
|
||||
{
|
||||
get { return _lagcount; }
|
||||
set { _lagcount = value; }
|
||||
}
|
||||
|
||||
public bool IsLagFrame
|
||||
{
|
||||
get { return _islag; }
|
||||
set { _islag = value; }
|
||||
}
|
||||
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
private bool _islag = true;
|
||||
private int _lagcount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk
|
||||
{
|
||||
private IMemoryDomains MemoryDomains;
|
||||
|
||||
public void SetupMemoryDomains()
|
||||
{
|
||||
var domains = new List<MemoryDomain>
|
||||
{
|
||||
new MemoryDomainDelegate(
|
||||
"Main RAM",
|
||||
RAM.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr],
|
||||
(addr, value) => RAM[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"TIA Registers",
|
||||
TIA_regs.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => TIA_regs[addr],
|
||||
(addr, value) => TIA_regs[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"Maria Registers",
|
||||
Maria_regs.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => Maria_regs[addr],
|
||||
(addr, value) => Maria_regs[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"6532 Registers",
|
||||
regs_6532.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => regs_6532[addr],
|
||||
(addr, value) => regs_6532[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"Ram Block 0",
|
||||
0xB,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr-0x840],
|
||||
(addr, value) => RAM[addr-0x840] = value,
|
||||
1
|
||||
),
|
||||
new MemoryDomainDelegate(
|
||||
"Ram Block 1",
|
||||
0xB,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr-0x940],
|
||||
(addr, value) => RAM[addr-0x940] = value,
|
||||
1
|
||||
),
|
||||
new MemoryDomainDelegate(
|
||||
"System Bus",
|
||||
0X10000,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => PeekSystemBus(addr),
|
||||
(addr, value) => PokeSystemBus(addr, value),
|
||||
1
|
||||
)
|
||||
};
|
||||
|
||||
MemoryDomains = new MemoryDomainList(domains);
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
|
||||
}
|
||||
|
||||
private byte PeekSystemBus(long addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void PokeSystemBus(long addr, byte value)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : ISaveRam
|
||||
{
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
return (byte[])_hsram.Clone();
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
Buffer.BlockCopy(data, 0, _hsram, 0, data.Length);
|
||||
}
|
||||
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred => true;
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
SyncState(new Serializer(writer));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
SyncState(new Serializer(reader));
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
SyncState(new Serializer(bw));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
SyncState(new Serializer(br));
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SyncState(Serializer ser)
|
||||
{
|
||||
byte[] core = null;
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
|
||||
ser.BeginSection("Atari7800");
|
||||
ser.Sync("core", ref core, false);
|
||||
ser.Sync("Lag", ref _lagcount);
|
||||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("IsLag", ref _islag);
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.M6502;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
[CoreAttributes(
|
||||
"A7800Hawk",
|
||||
"",
|
||||
isPorted: false,
|
||||
isReleased: true)]
|
||||
[ServiceNotApplicable(typeof(ISettable<,>), typeof(IDriveLight))]
|
||||
public partial class A7800Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable
|
||||
{
|
||||
// memory domains
|
||||
public byte[] TIA_regs = new byte[0x20];
|
||||
public byte[] Maria_regs = new byte[0x20];
|
||||
public byte[] RAM = new byte[0x1000];
|
||||
public byte[] regs_6532 = new byte[0x80];
|
||||
|
||||
private readonly byte[] _rom;
|
||||
private readonly byte[] _hsbios;
|
||||
private readonly byte[] _bios;
|
||||
private readonly byte[] _hsram = new byte[2048];
|
||||
|
||||
private int _frame = 0;
|
||||
|
||||
public MOS6502X cpu;
|
||||
public Maria maria;
|
||||
private bool _isPAL;
|
||||
public M6532 m6532;
|
||||
public TIA tia;
|
||||
|
||||
public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
ser.Register<IVideoProvider>(maria);
|
||||
ser.Register<ISoundProvider>(tia);
|
||||
ServiceProvider = ser;
|
||||
|
||||
CoreComm = comm;
|
||||
byte[] highscoreBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS.");
|
||||
byte[] palBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available.");
|
||||
byte[] ntscBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_NTSC", false, "The game will not run if the correct region BIOS is not available.");
|
||||
|
||||
if (rom.Length % 1024 == 128)
|
||||
{
|
||||
Console.WriteLine("Trimming 128 byte .a78 header...");
|
||||
byte[] newrom = new byte[rom.Length - 128];
|
||||
Buffer.BlockCopy(rom, 128, newrom, 0, newrom.Length);
|
||||
rom = newrom;
|
||||
}
|
||||
|
||||
_isPAL = false;
|
||||
|
||||
// look up hash in gamedb to see what mapper to use
|
||||
// if none found default is zero
|
||||
// also check for PAL region
|
||||
string hash_md5 = null;
|
||||
string s_mapper = null;
|
||||
hash_md5 = "md5:" + rom.HashMD5(0, rom.Length);
|
||||
|
||||
var gi = Database.CheckDatabase(hash_md5);
|
||||
|
||||
if (gi != null)
|
||||
{
|
||||
var dict = gi.GetOptionsDict();
|
||||
if (!dict.ContainsKey("PAL"))
|
||||
{
|
||||
_isPAL = true;
|
||||
}
|
||||
if (!dict.ContainsKey("board"))
|
||||
{
|
||||
s_mapper = dict["board"];
|
||||
}
|
||||
else
|
||||
throw new Exception("No Board selected for this mapper");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("ROM not in gamedb");
|
||||
}
|
||||
|
||||
_rom = rom;
|
||||
_hsbios = highscoreBios;
|
||||
_bios = _isPAL ? palBios : ntscBios;
|
||||
|
||||
if (_bios == null)
|
||||
{
|
||||
throw new MissingFirmwareException("The BIOS corresponding to the region of the game you loaded is required to run Atari 7800 games.");
|
||||
}
|
||||
|
||||
// set up palette and frame rate
|
||||
if (_isPAL)
|
||||
{
|
||||
maria._frameHz = 50;
|
||||
maria._palette = PALPalette;
|
||||
}
|
||||
else
|
||||
{
|
||||
maria._frameHz = 60;
|
||||
maria._palette = NTSCPalette;
|
||||
}
|
||||
|
||||
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public DisplayType Region => _isPAL ? DisplayType.PAL : DisplayType.NTSC;
|
||||
|
||||
public A7800HawkControl ControlAdapter { get; private set; }
|
||||
|
||||
private void HardReset()
|
||||
{
|
||||
|
||||
|
||||
cpu.Reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* MariaTables.cs
|
||||
*
|
||||
* Palette tables for the Maria class.
|
||||
* All derived from Dan Boris' 7800/MAME code.
|
||||
*
|
||||
* Copyright © 2004 Mike Murphy
|
||||
*
|
||||
*/
|
||||
|
||||
public static readonly int[] NTSCPalette =
|
||||
{
|
||||
0x000000, 0x1c1c1c, 0x393939, 0x595959, // Grey
|
||||
0x797979, 0x929292, 0xababab, 0xbcbcbc,
|
||||
0xcdcdcd, 0xd9d9d9, 0xe6e6e6, 0xececec,
|
||||
0xf2f2f2, 0xf8f8f8, 0xffffff, 0xffffff,
|
||||
|
||||
0x391701, 0x5e2304, 0x833008, 0xa54716, // Gold
|
||||
0xc85f24, 0xe37820, 0xff911d, 0xffab1d,
|
||||
0xffc51d, 0xffce34, 0xffd84c, 0xffe651,
|
||||
0xfff456, 0xfff977, 0xffff98, 0xffff98,
|
||||
|
||||
0x451904, 0x721e11, 0x9f241e, 0xb33a20, // Orange
|
||||
0xc85122, 0xe36920, 0xff811e, 0xff8c25,
|
||||
0xff982c, 0xffae38, 0xffc545, 0xffc559,
|
||||
0xffc66d, 0xffd587, 0xffe4a1, 0xffe4a1,
|
||||
|
||||
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119, // Red Orange
|
||||
0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161,
|
||||
0xff706e, 0xff7f7e, 0xff8f8f, 0xff9d9e,
|
||||
0xffabad, 0xffb9bd, 0xffc7ce, 0xffc7ce,
|
||||
|
||||
0x050568, 0x3b136d, 0x712272, 0x8b2a8c, // Pink
|
||||
0xa532a6, 0xb938ba, 0xcd3ecf, 0xdb47dd,
|
||||
0xea51eb, 0xf45ff5, 0xfe6dff, 0xfe7afd,
|
||||
0xff87fb, 0xff95fd, 0xffa4ff, 0xffa4ff,
|
||||
|
||||
0x280479, 0x400984, 0x590f90, 0x70249d, // Purple
|
||||
0x8839aa, 0xa441c3, 0xc04adc, 0xd054ed,
|
||||
0xe05eff, 0xe96dff, 0xf27cff, 0xf88aff,
|
||||
0xff98ff, 0xfea1ff, 0xfeabff, 0xfeabff,
|
||||
|
||||
0x35088a, 0x420aad, 0x500cd0, 0x6428d0, // Purple Blue
|
||||
0x7945d0, 0x8d4bd4, 0xa251d9, 0xb058ec,
|
||||
0xbe60ff, 0xc56bff, 0xcc77ff, 0xd183ff,
|
||||
0xd790ff, 0xdb9dff, 0xdfaaff, 0xdfaaff,
|
||||
|
||||
0x051e81, 0x0626a5, 0x082fca, 0x263dd4, // Blue1
|
||||
0x444cde, 0x4f5aee, 0x5a68ff, 0x6575ff,
|
||||
0x7183ff, 0x8091ff, 0x90a0ff, 0x97a9ff,
|
||||
0x9fb2ff, 0xafbeff, 0xc0cbff, 0xc0cbff,
|
||||
|
||||
0x0c048b, 0x2218a0, 0x382db5, 0x483ec7, // Blue2
|
||||
0x584fda, 0x6159ec, 0x6b64ff, 0x7a74ff,
|
||||
0x8a84ff, 0x918eff, 0x9998ff, 0xa5a3ff,
|
||||
0xb1aeff, 0xb8b8ff, 0xc0c2ff, 0xc0c2ff,
|
||||
|
||||
0x1d295a, 0x1d3876, 0x1d4892, 0x1c5cac, // Light Blue
|
||||
0x1c71c6, 0x3286cf, 0x489bd9, 0x4ea8ec,
|
||||
0x55b6ff, 0x70c7ff, 0x8cd8ff, 0x93dbff,
|
||||
0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xc3e9ff,
|
||||
|
||||
0x2f4302, 0x395202, 0x446103, 0x417a12, // Turquoise
|
||||
0x3e9421, 0x4a9f2e, 0x57ab3b, 0x5cbd55,
|
||||
0x61d070, 0x69e27a, 0x72f584, 0x7cfa8d,
|
||||
0x87ff97, 0x9affa6, 0xadffb6, 0xadffb6,
|
||||
|
||||
0x0a4108, 0x0d540a, 0x10680d, 0x137d0f, // Green Blue
|
||||
0x169212, 0x19a514, 0x1cb917, 0x1ec919,
|
||||
0x21d91b, 0x47e42d, 0x6ef040, 0x78f74d,
|
||||
0x83ff5b, 0x9aff7a, 0xb2ff9a, 0xb2ff9a,
|
||||
|
||||
0x04410b, 0x05530e, 0x066611, 0x077714, // Green
|
||||
0x088817, 0x099b1a, 0x0baf1d, 0x48c41f,
|
||||
0x86d922, 0x8fe924, 0x99f927, 0xa8fc41,
|
||||
0xb7ff5b, 0xc9ff6e, 0xdcff81, 0xdcff81,
|
||||
|
||||
0x02350f, 0x073f15, 0x0c4a1c, 0x2d5f1e, // Yellow Green
|
||||
0x4f7420, 0x598324, 0x649228, 0x82a12e,
|
||||
0xa1b034, 0xa9c13a, 0xb2d241, 0xc4d945,
|
||||
0xd6e149, 0xe4f04e, 0xf2ff53, 0xf2ff53,
|
||||
|
||||
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green
|
||||
0x806931, 0x978135, 0xaf993a, 0xc2a73e,
|
||||
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836,
|
||||
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d,
|
||||
|
||||
0x401a02, 0x581f05, 0x702408, 0x8d3a13, // Light Orange
|
||||
0xab511f, 0xb56427, 0xbf7730, 0xd0853a,
|
||||
0xe19344, 0xeda04e, 0xf9ad58, 0xfcb75c,
|
||||
0xffc160, 0xffc671, 0xffcb83, 0xffcb83
|
||||
};
|
||||
|
||||
public static readonly int[] PALPalette =
|
||||
{
|
||||
0x000000, 0x1c1c1c, 0x393939, 0x595959, // Grey
|
||||
0x797979, 0x929292, 0xababab, 0xbcbcbc,
|
||||
0xcdcdcd, 0xd9d9d9, 0xe6e6e6, 0xececec,
|
||||
0xf2f2f2, 0xf8f8f8, 0xffffff, 0xffffff,
|
||||
|
||||
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green
|
||||
0x806931, 0x978135, 0xaf993a, 0xc2a73e,
|
||||
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836,
|
||||
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d,
|
||||
|
||||
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green
|
||||
0x806931, 0x978135, 0xaf993a, 0xc2a73e,
|
||||
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836,
|
||||
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d,
|
||||
|
||||
0x401a02, 0x581f05, 0x702408, 0x8d3a13, // Light Orange
|
||||
0xab511f, 0xb56427, 0xbf7730, 0xd0853a,
|
||||
0xe19344, 0xeda04e, 0xf9ad58, 0xfcb75c,
|
||||
0xffc160, 0xffc671, 0xffcb83, 0xffcb83,
|
||||
|
||||
0x391701, 0x5e2304, 0x833008, 0xa54716, // Gold
|
||||
0xc85f24, 0xe37820, 0xff911d, 0xffab1d,
|
||||
0xffc51d, 0xffce34, 0xffd84c, 0xffe651,
|
||||
0xfff456, 0xfff977, 0xffff98, 0xffff98,
|
||||
|
||||
0x451904, 0x721e11, 0x9f241e, 0xb33a20, // Orange
|
||||
0xc85122, 0xe36920, 0xff811e, 0xff8c25,
|
||||
0xff982c, 0xffae38, 0xffc545, 0xffc559,
|
||||
0xffc66d, 0xffd587, 0xffe4a1, 0xffe4a1,
|
||||
|
||||
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119, // Red Orange
|
||||
0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161,
|
||||
0xff706e, 0xff7f7e, 0xff8f8f, 0xff9d9e,
|
||||
0xffabad, 0xffb9bd, 0xffc7ce, 0xffc7ce,
|
||||
|
||||
0x050568, 0x3b136d, 0x712272, 0x8b2a8c, // Pink
|
||||
0xa532a6, 0xb938ba, 0xcd3ecf, 0xdb47dd,
|
||||
0xea51eb, 0xf45ff5, 0xfe6dff, 0xfe7afd,
|
||||
0xff87fb, 0xff95fd, 0xffa4ff, 0xffa4ff,
|
||||
|
||||
0x280479, 0x400984, 0x590f90, 0x70249d, // Purple
|
||||
0x8839aa, 0xa441c3, 0xc04adc, 0xd054ed,
|
||||
0xe05eff, 0xe96dff, 0xf27cff, 0xf88aff,
|
||||
0xff98ff, 0xfea1ff, 0xfeabff, 0xfeabff,
|
||||
|
||||
0x051e81, 0x0626a5, 0x082fca, 0x263dd4, // Blue1
|
||||
0x444cde, 0x4f5aee, 0x5a68ff, 0x6575ff,
|
||||
0x7183ff, 0x8091ff, 0x90a0ff, 0x97a9ff,
|
||||
0x9fb2ff, 0xafbeff, 0xc0cbff, 0xc0cbff,
|
||||
|
||||
0x0c048b, 0x2218a0, 0x382db5, 0x483ec7, // Blue2
|
||||
0x584fda, 0x6159ec, 0x6b64ff, 0x7a74ff,
|
||||
0x8a84ff, 0x918eff, 0x9998ff, 0xa5a3ff,
|
||||
0xb1aeff, 0xb8b8ff, 0xc0c2ff, 0xc0c2ff,
|
||||
|
||||
0x1d295a, 0x1d3876, 0x1d4892, 0x1c5cac, // Light Blue
|
||||
0x1c71c6, 0x3286cf, 0x489bd9, 0x4ea8ec,
|
||||
0x55b6ff, 0x70c7ff, 0x8cd8ff, 0x93dbff,
|
||||
0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xc3e9ff,
|
||||
|
||||
0x2f4302, 0x395202, 0x446103, 0x417a12, // Turquoise
|
||||
0x3e9421, 0x4a9f2e, 0x57ab3b, 0x5cbd55,
|
||||
0x61d070, 0x69e27a, 0x72f584, 0x7cfa8d,
|
||||
0x87ff97, 0x9affa6, 0xadffb6, 0xadffb6,
|
||||
|
||||
0x0a4108, 0x0d540a, 0x10680d, 0x137d0f, // Green Blue
|
||||
0x169212, 0x19a514, 0x1cb917, 0x1ec919,
|
||||
0x21d91b, 0x47e42d, 0x6ef040, 0x78f74d,
|
||||
0x83ff5b, 0x9aff7a, 0xb2ff9a, 0xb2ff9a,
|
||||
|
||||
0x04410b, 0x05530e, 0x066611, 0x077714, // Green
|
||||
0x088817, 0x099b1a, 0x0baf1d, 0x48c41f,
|
||||
0x86d922, 0x8fe924, 0x99f927, 0xa8fc41,
|
||||
0xb7ff5b, 0xc9ff6e, 0xdcff81, 0xdcff81,
|
||||
|
||||
0x02350f, 0x073f15, 0x0c4a1c, 0x2d5f1e, // Yellow Green
|
||||
0x4f7420, 0x598324, 0x649228, 0x82a12e,
|
||||
0xa1b034, 0xa9c13a, 0xb2d241, 0xc4d945,
|
||||
0xd6e149, 0xe4f04e, 0xf2ff53, 0xf2ff53
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
using System;
|
||||
|
||||
using EMU7800.Core;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public class A7800HawkControl
|
||||
{
|
||||
private static readonly ControllerDefinition Joystick = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Joystick Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Paddles = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Paddle Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger",
|
||||
"P3 Trigger",
|
||||
"P4 Trigger"
|
||||
},
|
||||
FloatControls = // should be in [0..700000]
|
||||
{
|
||||
"P1 Paddle",
|
||||
"P2 Paddle",
|
||||
"P3 Paddle",
|
||||
"P4 Paddle"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
// what is the center point supposed to be here?
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Keypad = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Keypad Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Keypad1", "P1 Keypad2", "P1 Keypad3",
|
||||
"P1 Keypad4", "P1 Keypad5", "P1 Keypad6",
|
||||
"P1 Keypad7", "P1 Keypad8", "P1 Keypad9",
|
||||
"P1 KeypadA", "P1 Keypad0", "P1 KeypadP",
|
||||
"P2 Keypad1", "P2 Keypad2", "P2 Keypad3",
|
||||
"P2 Keypad4", "P2 Keypad5", "P2 Keypad6",
|
||||
"P2 Keypad7", "P2 Keypad8", "P2 Keypad9",
|
||||
"P2 KeypadA", "P2 Keypad0", "P2 KeypadP",
|
||||
"P3 Keypad1", "P3 Keypad2", "P3 Keypad3",
|
||||
"P3 Keypad4", "P3 Keypad5", "P3 Keypad6",
|
||||
"P3 Keypad7", "P3 Keypad8", "P3 Keypad9",
|
||||
"P3 KeypadA", "P3 Keypad0", "P3 KeypadP",
|
||||
"P4 Keypad1", "P4 Keypad2", "P4 Keypad3",
|
||||
"P4 Keypad4", "P4 Keypad5", "P4 Keypad6",
|
||||
"P4 Keypad7", "P4 Keypad8", "P4 Keypad9",
|
||||
"P4 KeypadA", "P4 Keypad0", "P4 KeypadP"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Driving = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Driving Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger"
|
||||
},
|
||||
FloatControls = // should be in [0..3]
|
||||
{
|
||||
"P1 Driving",
|
||||
"P2 Driving"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
new[] { 0.0f, 0.0f, 3.0f },
|
||||
new[] { 0.0f, 0.0f, 3.0f },
|
||||
new[] { 0.0f, 0.0f, 3.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition BoosterGrip = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Booster Grip Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
// NB: as referenced by the emu, p1t2 = p1t2, p1t3 = p2t2, p2t2 = p3t2, p2t3 = p4t2
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger", "P1 Trigger 2", "P1 Trigger 3",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger", "P2 Trigger 2", "P2 Trigger 3"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition ProLineJoystick = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 ProLine Joystick Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"Pause",
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger", "P1 Trigger 2",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger", "P2 Trigger 2"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Lightgun = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Light Gun Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"Pause",
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger"
|
||||
},
|
||||
FloatControls = // vpos should be actual scanline number. hpos should be in [0..319]??
|
||||
{
|
||||
"P1 VPos", "P1 HPos",
|
||||
"P2 VPos", "P2 HPos"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
// how many scanlines are there again??
|
||||
new[] { 0.0f, 0.0f, 240.0f },
|
||||
new[] { 0.0f, 0.0f, 319.0f },
|
||||
new[] { 0.0f, 0.0f, 240.0f },
|
||||
new[] { 0.0f, 0.0f, 319.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private struct ControlAdapter
|
||||
{
|
||||
public readonly ControllerDefinition Type;
|
||||
public readonly Controller Left;
|
||||
public readonly Controller Right;
|
||||
public readonly Action<IController, InputState> Convert;
|
||||
|
||||
public ControlAdapter(ControllerDefinition type, Controller left, Controller right, Action<IController, InputState> convert)
|
||||
{
|
||||
Type = type;
|
||||
Left = left;
|
||||
Right = right;
|
||||
Convert = convert;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ControlAdapter[] Adapters =
|
||||
{
|
||||
new ControlAdapter(Joystick, Controller.Joystick, Controller.Joystick, ConvertJoystick),
|
||||
new ControlAdapter(Paddles, Controller.Paddles, Controller.Paddles, ConvertPaddles),
|
||||
new ControlAdapter(Keypad, Controller.Keypad, Controller.Keypad, ConvertKeypad),
|
||||
new ControlAdapter(Driving, Controller.Driving, Controller.Driving, ConvertDriving),
|
||||
new ControlAdapter(BoosterGrip, Controller.BoosterGrip, Controller.BoosterGrip, ConvertBoosterGrip),
|
||||
new ControlAdapter(ProLineJoystick, Controller.ProLineJoystick, Controller.ProLineJoystick, ConvertProLineJoystick),
|
||||
new ControlAdapter(Lightgun, Controller.Lightgun, Controller.Lightgun, ConvertLightgun),
|
||||
};
|
||||
|
||||
private static void ConvertConsoleButtons(IController c, InputState s)
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.Reset, c.IsPressed("Reset"));
|
||||
s.RaiseInput(0, MachineInput.Select, c.IsPressed("Select"));
|
||||
s.RaiseInput(0, MachineInput.Color, c.IsPressed("BW"));
|
||||
if (c.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.LeftDifficulty, c.IsPressed("Toggle Left Difficulty"));
|
||||
}
|
||||
|
||||
if (c.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.RightDifficulty, c.IsPressed("Toggle Right Difficulty"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertConsoleButtons7800(IController c, InputState s)
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.Reset, c.IsPressed("Reset"));
|
||||
s.RaiseInput(0, MachineInput.Select, c.IsPressed("Select"));
|
||||
s.RaiseInput(0, MachineInput.Color, c.IsPressed("Pause"));
|
||||
if (c.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.LeftDifficulty, c.IsPressed("Toggle Left Difficulty"));
|
||||
}
|
||||
|
||||
if (c.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.RightDifficulty, c.IsPressed("Toggle Right Difficulty"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertDirections(IController c, InputState s, int p)
|
||||
{
|
||||
string ps = $"P{p + 1} ";
|
||||
s.RaiseInput(p, MachineInput.Up, c.IsPressed(ps + "Up"));
|
||||
s.RaiseInput(p, MachineInput.Down, c.IsPressed(ps + "Down"));
|
||||
s.RaiseInput(p, MachineInput.Left, c.IsPressed(ps + "Left"));
|
||||
s.RaiseInput(p, MachineInput.Right, c.IsPressed(ps + "Right"));
|
||||
}
|
||||
|
||||
private static void ConvertTrigger(IController c, InputState s, int p)
|
||||
{
|
||||
string ps = $"P{p + 1} ";
|
||||
s.RaiseInput(p, MachineInput.Fire, c.IsPressed(ps + "Trigger"));
|
||||
}
|
||||
|
||||
private static void ConvertJoystick(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
}
|
||||
|
||||
private static void ConvertPaddles(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
string ps = $"P{i + 1} ";
|
||||
ConvertTrigger(c, s, i);
|
||||
s.RaisePaddleInput(i, 700000, (int)c.GetFloat(ps + "Trigger"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertKeypad(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
string ps = $"P{i + 1} ";
|
||||
s.RaiseInput(i, MachineInput.NumPad1, c.IsPressed(ps + "Keypad1"));
|
||||
s.RaiseInput(i, MachineInput.NumPad2, c.IsPressed(ps + "Keypad2"));
|
||||
s.RaiseInput(i, MachineInput.NumPad3, c.IsPressed(ps + "Keypad3"));
|
||||
s.RaiseInput(i, MachineInput.NumPad4, c.IsPressed(ps + "Keypad4"));
|
||||
s.RaiseInput(i, MachineInput.NumPad5, c.IsPressed(ps + "Keypad5"));
|
||||
s.RaiseInput(i, MachineInput.NumPad6, c.IsPressed(ps + "Keypad6"));
|
||||
s.RaiseInput(i, MachineInput.NumPad7, c.IsPressed(ps + "Keypad7"));
|
||||
s.RaiseInput(i, MachineInput.NumPad8, c.IsPressed(ps + "Keypad8"));
|
||||
s.RaiseInput(i, MachineInput.NumPad9, c.IsPressed(ps + "Keypad9"));
|
||||
s.RaiseInput(i, MachineInput.NumPadMult, c.IsPressed(ps + "KeypadA"));
|
||||
s.RaiseInput(i, MachineInput.NumPad0, c.IsPressed(ps + "Keypad0"));
|
||||
s.RaiseInput(i, MachineInput.NumPadHash, c.IsPressed(ps + "KeypadP"));
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly MachineInput[] Drvlut =
|
||||
{
|
||||
MachineInput.Driving0,
|
||||
MachineInput.Driving1,
|
||||
MachineInput.Driving2,
|
||||
MachineInput.Driving3
|
||||
};
|
||||
|
||||
private static void ConvertDriving(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
s.RaiseInput(0, Drvlut[(int)c.GetFloat("P1 Driving")], true);
|
||||
s.RaiseInput(1, Drvlut[(int)c.GetFloat("P2 Driving")], true);
|
||||
}
|
||||
|
||||
private static void ConvertBoosterGrip(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
|
||||
// weird mapping is intentional
|
||||
s.RaiseInput(0, MachineInput.Fire, c.IsPressed("P1 Trigger"));
|
||||
s.RaiseInput(0, MachineInput.Fire2, c.IsPressed("P1 Trigger 2"));
|
||||
s.RaiseInput(1, MachineInput.Fire2, c.IsPressed("P1 Trigger 3"));
|
||||
s.RaiseInput(1, MachineInput.Fire, c.IsPressed("P2 Trigger"));
|
||||
s.RaiseInput(2, MachineInput.Fire2, c.IsPressed("P2 Trigger 2"));
|
||||
s.RaiseInput(3, MachineInput.Fire2, c.IsPressed("P2 Trigger 3"));
|
||||
}
|
||||
|
||||
private static void ConvertProLineJoystick(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons7800(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
s.RaiseInput(0, MachineInput.Fire, c.IsPressed("P1 Trigger"));
|
||||
s.RaiseInput(0, MachineInput.Fire2, c.IsPressed("P1 Trigger 2"));
|
||||
s.RaiseInput(1, MachineInput.Fire, c.IsPressed("P2 Trigger"));
|
||||
s.RaiseInput(1, MachineInput.Fire2, c.IsPressed("P2 Trigger 2"));
|
||||
}
|
||||
|
||||
private static void ConvertLightgun(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons7800(c, s);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
s.RaiseLightgunPos(0, (int)c.GetFloat("P1 VPos"), (int)c.GetFloat("P1 HPos"));
|
||||
s.RaiseLightgunPos(1, (int)c.GetFloat("P2 VPos"), (int)c.GetFloat("P2 HPos"));
|
||||
}
|
||||
|
||||
public Action<IController, InputState> Convert { get; private set; }
|
||||
|
||||
public ControllerDefinition ControlType { get; private set; }
|
||||
|
||||
public A7800HawkControl(MachineBase mac)
|
||||
{
|
||||
var l = mac.InputState.LeftControllerJack;
|
||||
var r = mac.InputState.RightControllerJack;
|
||||
|
||||
foreach (var a in Adapters)
|
||||
{
|
||||
if (a.Left == l && a.Right == r)
|
||||
{
|
||||
Convert = a.Convert;
|
||||
ControlType = a.Type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Couldn't connect Atari 7800 controls \"{l}\" and \"{r}\"");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
// Emulates the M6532 RIOT Chip
|
||||
public class M6532
|
||||
{
|
||||
private byte _ddRa = 0x00;
|
||||
private byte _ddRb = 0x00;
|
||||
private byte _outputA = 0x00;
|
||||
|
||||
public TimerData Timer;
|
||||
|
||||
public M6532()
|
||||
{
|
||||
|
||||
// arbitrary value to start with.
|
||||
Timer.Value = 0x73;
|
||||
Timer.PrescalerShift = 10;
|
||||
Timer.PrescalerCount = 1 << Timer.PrescalerShift;
|
||||
}
|
||||
|
||||
public byte ReadMemory(ushort addr, bool peek)
|
||||
{
|
||||
if ((addr & 0x0200) == 0) // If not register select, read Ram
|
||||
{
|
||||
//return _core.Ram[(ushort)(addr & 0x007f)];
|
||||
return 0;
|
||||
}
|
||||
|
||||
var registerAddr = (ushort)(addr & 0x0007);
|
||||
if (registerAddr == 0x00)
|
||||
{
|
||||
// Read Output reg A
|
||||
// Combine readings from player 1 and player 2
|
||||
// actually depends on setting in SWCHCNTA (aka DDRa)
|
||||
byte temp = 0;// (byte)(_core.ReadControls1(peek) & 0xF0 | ((_core.ReadControls2(peek) >> 4) & 0x0F));
|
||||
temp = (byte)(temp & ~_ddRa);
|
||||
temp = (byte)(temp + (_outputA & _ddRa));
|
||||
return temp;
|
||||
}
|
||||
|
||||
if (registerAddr == 0x01)
|
||||
{
|
||||
// Read DDRA
|
||||
return _ddRa;
|
||||
}
|
||||
|
||||
if (registerAddr == 0x02)
|
||||
{
|
||||
// Read Output reg B
|
||||
byte temp = 0;// _core.ReadConsoleSwitches(peek);
|
||||
temp = (byte)(temp & ~_ddRb);
|
||||
return temp;
|
||||
}
|
||||
|
||||
if (registerAddr == 0x03) // Read DDRB
|
||||
{
|
||||
return _ddRb;
|
||||
}
|
||||
|
||||
if ((registerAddr & 0x5) == 0x4)
|
||||
{
|
||||
// Bit 0x0080 contains interrupt enable/disable
|
||||
Timer.InterruptEnabled = (addr & 0x0080) != 0;
|
||||
|
||||
// The interrupt flag will be reset whenever the Timer is access by a read or a write
|
||||
// However, the reading of the timer at the same time the interrupt occurs will not reset the interrupt flag
|
||||
// (M6532 Datasheet)
|
||||
if (!(Timer.PrescalerCount == 0 && Timer.Value == 0))
|
||||
{
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
|
||||
return Timer.Value;
|
||||
}
|
||||
|
||||
// TODO: fix this to match real behaviour
|
||||
// This is an undocumented instruction whose behaviour is more dynamic then indicated here
|
||||
if ((registerAddr & 0x5) == 0x5)
|
||||
{
|
||||
// Read interrupt flag
|
||||
if (Timer.InterruptFlag) // Timer.InterruptEnabled && )
|
||||
{
|
||||
return 0xC0;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
return 0x3A;
|
||||
}
|
||||
|
||||
public void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if ((addr & 0x0200) == 0) // If the RS bit is not set, this is a ram write
|
||||
{
|
||||
//_core.Ram[(ushort)(addr & 0x007f)] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If bit 0x0010 is set, and bit 0x0004 is set, this is a timer write
|
||||
if ((addr & 0x0014) == 0x0014)
|
||||
{
|
||||
var registerAddr = (ushort)(addr & 0x0007);
|
||||
|
||||
// Bit 0x0080 contains interrupt enable/disable
|
||||
Timer.InterruptEnabled = (addr & 0x0080) != 0;
|
||||
|
||||
// The interrupt flag will be reset whenever the Timer is access by a read or a write
|
||||
// (M6532 datasheet)
|
||||
if (registerAddr == 0x04)
|
||||
{
|
||||
// Write to Timer/1
|
||||
Timer.PrescalerShift = 0;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
else if (registerAddr == 0x05)
|
||||
{
|
||||
// Write to Timer/8
|
||||
Timer.PrescalerShift = 3;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
else if (registerAddr == 0x06)
|
||||
{
|
||||
// Write to Timer/64
|
||||
Timer.PrescalerShift = 6;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
else if (registerAddr == 0x07)
|
||||
{
|
||||
// Write to Timer/1024
|
||||
Timer.PrescalerShift = 10;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If bit 0x0004 is not set, bit 0x0010 is ignored and
|
||||
// these are register writes
|
||||
else if ((addr & 0x0004) == 0)
|
||||
{
|
||||
var registerAddr = (ushort)(addr & 0x0007);
|
||||
|
||||
if (registerAddr == 0x00)
|
||||
{
|
||||
// Write Output reg A
|
||||
_outputA = value;
|
||||
}
|
||||
else if (registerAddr == 0x01)
|
||||
{
|
||||
// Write DDRA
|
||||
_ddRa = value;
|
||||
}
|
||||
else if (registerAddr == 0x02)
|
||||
{
|
||||
// Write Output reg B
|
||||
// But is read only
|
||||
}
|
||||
else if (registerAddr == 0x03)
|
||||
{
|
||||
// Write DDRB
|
||||
_ddRb = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("M6532");
|
||||
ser.Sync("ddra", ref _ddRa);
|
||||
ser.Sync("ddrb", ref _ddRb);
|
||||
ser.Sync("OutputA", ref _outputA);
|
||||
Timer.SyncState(ser);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
public struct TimerData
|
||||
{
|
||||
public int PrescalerCount;
|
||||
public byte PrescalerShift;
|
||||
|
||||
public byte Value;
|
||||
|
||||
public bool InterruptEnabled;
|
||||
public bool InterruptFlag;
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if (PrescalerCount == 0)
|
||||
{
|
||||
Value--;
|
||||
PrescalerCount = 1 << PrescalerShift;
|
||||
}
|
||||
|
||||
PrescalerCount--;
|
||||
if (PrescalerCount == 0)
|
||||
{
|
||||
if (Value == 0)
|
||||
{
|
||||
InterruptFlag = true;
|
||||
PrescalerShift = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("prescalerCount", ref PrescalerCount);
|
||||
ser.Sync("prescalerShift", ref PrescalerShift);
|
||||
ser.Sync("value", ref Value);
|
||||
ser.Sync("interruptEnabled", ref InterruptEnabled);
|
||||
ser.Sync("interruptFlag", ref InterruptFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
// Emulates the Atari 7800 Maria graphics chip
|
||||
public class Maria : IVideoProvider
|
||||
{
|
||||
public int _frameHz;
|
||||
|
||||
public int[] _vidbuffer;
|
||||
public int[] _palette;
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _vidbuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 275;
|
||||
public int VirtualHeight => BufferHeight;
|
||||
public int BufferWidth { get; private set; }
|
||||
public int BufferHeight { get; private set; }
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
public int VsyncNumerator => _frameHz;
|
||||
public int VsyncDenominator => 1;
|
||||
|
||||
public void FrameAdvance()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue