Atari 2600 - a round of code cleanup and check in some files I neglected to in the past few commits, remove oldTIA.cs

This commit is contained in:
adelikat 2014-04-05 14:13:05 +00:00
parent 43d58e3441
commit 27daa82464
32 changed files with 621 additions and 1142 deletions

View File

@ -206,7 +206,6 @@
<Compile Include="Consoles\Atari\2600\Mappers\mUA.cs" />
<Compile Include="Consoles\Atari\2600\Mappers\Multicart.cs" />
<Compile Include="Consoles\Atari\2600\Mappers\mX07.cs" />
<Compile Include="Consoles\Atari\2600\oldTIA.cs" />
<Compile Include="Consoles\Atari\2600\M6532.cs" />
<Compile Include="Consoles\Atari\2600\TIA.cs">
<SubType>Code</SubType>

View File

@ -4,75 +4,33 @@ using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components.M6502;
namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
partial class Atari2600
public partial class Atari2600
{
public byte[] rom;
public MOS6502X cpu;
public M6532 m6532;
public TIA tia;
public DCFilter dcfilter;
public byte[] ram = new byte[128];
public MapperBase mapper;
private TIA _tia;
private DCFilter _dcfilter;
private MapperBase _mapper;
public byte[] Ram;
// The Atari 2600 memory mapper looks something like this...usually
public byte[] Rom { get; private set; }
public MOS6502X Cpu { get; private set; }
public M6532 M6532 { get; private set; }
// N/A Page #
// 000 0000000 000000
// 0x0000-0x003F - TIA Registers
// 0x0040-0x007F - TIA Registers (mirror)
// 0x0080-0x00FF - 6532 RAM
// 0x0100-0x01FF - Mirror of 0x00FF
// 0x0200-0x023F - TIA Registers (mirror)
// 0x0240-0x027F - TIA Registers (mirror)
// 0x0280-0x029F - 6532 Registers
// 0x02A0-0x02BF - 6532 Registers (mirror)
// 0x02C0-0x02DF - 6532 Registers (mirror)
// 0x02E0-0x02FF - 6532 Registers (mirror)
// 0x0300-0x033F - TIA Registers (mirror)
// 0x0340-0x037F - TIA Registers (mirror)
// 0x0380-0x039F - 6532 Registers (mirror)
// 0x03A0-0x03BF - 6532 Registers (mirror)
// 0x03C0-0x03DF - 6532 Registers (mirror)
// 0x03E0-0x03FF - 6532 Registers (mirror)
// 0x0400-0x07FF - Mirror of 0x0000-0x03FF
// 0x0800-0x0BFF - Mirror of 0x0000-0x03FF
// 0x0C00-0x0FFF - Mirror of 0x0000-0x03FF
// 0x1000-0x1FFF - ROM
// If page# % 4 == 0 or 1, TIA
// If page# % 4 == 2 or 3, 6532
// if (addr & 0x0200 == 0x0000 && addr & 0x1080 == 0x0080)
// RAM
// else
// registers
// else
// ROM
public byte BaseReadMemory(ushort addr)
{
addr = (ushort)(addr & 0x1FFF);
if ((addr & 0x1080) == 0)
{
return tia.ReadMemory(addr, false);
return _tia.ReadMemory(addr, false);
}
else if ((addr & 0x1080) == 0x0080)
if ((addr & 0x1080) == 0x0080)
{
return m6532.ReadMemory(addr, false);
}
else
{
return rom[addr & 0x0FFF];
return M6532.ReadMemory(addr, false);
}
return Rom[addr & 0x0FFF];
}
public byte BasePeekMemory(ushort addr)
@ -80,16 +38,15 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
addr = (ushort)(addr & 0x1FFF);
if ((addr & 0x1080) == 0)
{
return tia.ReadMemory(addr, true);
return _tia.ReadMemory(addr, true);
}
else if ((addr & 0x1080) == 0x0080)
if ((addr & 0x1080) == 0x0080)
{
return m6532.ReadMemory(addr, true);
}
else
{
return rom[addr & 0x0FFF];
return M6532.ReadMemory(addr, true);
}
return Rom[addr & 0x0FFF];
}
public void BaseWriteMemory(ushort addr, byte value)
@ -97,11 +54,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
addr = (ushort)(addr & 0x1FFF);
if ((addr & 0x1080) == 0)
{
tia.WriteMemory(addr, value);
_tia.WriteMemory(addr, value);
}
else if ((addr & 0x1080) == 0x0080)
{
m6532.WriteMemory(addr, value);
M6532.WriteMemory(addr, value);
}
else
{
@ -111,7 +68,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public byte ReadMemory(ushort addr)
{
byte temp = mapper.ReadMemory((ushort)(addr&0x1FFF));
var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF));
CoreComm.MemoryCallbackSystem.CallRead(addr);
@ -120,16 +77,16 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public byte PeekMemory(ushort addr)
{
byte temp = mapper.ReadMemory((ushort)(addr & 0x1FFF));
var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF));
return temp;
}
public void WriteMemory(ushort addr, byte value)
{
mapper.WriteMemory((ushort)(addr & 0x1FFF), value);
_mapper.WriteMemory((ushort)(addr & 0x1FFF), value);
CoreComm.MemoryCallbackSystem.CallWrite((uint)addr);
CoreComm.MemoryCallbackSystem.CallWrite(addr);
}
public void ExecFetch(ushort addr)
@ -139,166 +96,164 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public void HardReset()
{
//regenerate mapper here to make sure its state is entirely clean
switch (game.GetOptionsDict()["m"])
// Regenerate mapper here to make sure its state is entirely clean
switch (this._game.GetOptionsDict()["m"])
{
case "2IN1":
case "4IN1":
case "8IN1":
case "16IN1":
case "32IN1":
mapper = new Multicart();
_mapper = new Multicart();
break;
case "AR":
mapper = new mAR();
_mapper = new mAR();
break;
case "4K":
mapper = new m4K();
_mapper = new m4K();
break;
case "2K":
mapper = new m2K();
_mapper = new m2K();
break;
case "CV":
mapper = new mCV();
_mapper = new mCV();
break;
case "DPC":
mapper = new mDPC();
_mapper = new mDPC();
break;
case "DPC+":
mapper = new mDPCPlus();
_mapper = new mDPCPlus();
break;
case "F8":
mapper = new mF8();
_mapper = new mF8();
break;
case "F8SC":
mapper = new mF8SC();
_mapper = new mF8SC();
break;
case "F6":
mapper = new mF6();
_mapper = new mF6();
break;
case "F6SC":
mapper = new mF6SC();
_mapper = new mF6SC();
break;
case "F4":
mapper = new mF4();
_mapper = new mF4();
break;
case "F4SC":
mapper = new mF4SC();
_mapper = new mF4SC();
break;
case "FE":
mapper = new mFE();
_mapper = new mFE();
break;
case "E0":
mapper = new mE0();
_mapper = new mE0();
break;
case "3F":
mapper = new m3F();
_mapper = new m3F();
break;
case "FA":
mapper = new mFA();
_mapper = new mFA();
break;
case "FA2":
mapper = new mFA2();
_mapper = new mFA2();
break;
case "E7":
mapper = new mE7();
_mapper = new mE7();
break;
case "F0":
mapper = new mF0();
_mapper = new mF0();
break;
case "UA":
mapper = new mUA();
_mapper = new mUA();
break;
//Homebrew mappers
// Homebrew mappers
case "3E":
mapper = new m3E();
_mapper = new m3E();
break;
case "0840":
mapper = new m0840();
_mapper = new m0840();
break;
case "MC":
mapper = new mMC();
_mapper = new mMC();
break;
case "EF":
mapper = new mEF();
_mapper = new mEF();
break;
case "EFSC":
mapper = new mEFSC();
_mapper = new mEFSC();
break;
case "X07":
mapper = new mX07();
_mapper = new mX07();
break;
case "4A50":
mapper = new m4A50();
_mapper = new m4A50();
break;
case "SB":
mapper = new mSB();
_mapper = new mSB();
break;
default: throw new InvalidOperationException("mapper not supported: " + game.GetOptionsDict()["m"]);
default: throw new InvalidOperationException("mapper not supported: " + this._game.GetOptionsDict()["m"]);
}
mapper.core = this;
_mapper.Core = this;
_lagcount = 0;
cpu = new MOS6502X();
//cpu.debug = true;
cpu.ReadMemory = ReadMemory;
cpu.WriteMemory = WriteMemory;
cpu.PeekMemory = PeekMemory;
cpu.DummyReadMemory = ReadMemory;
cpu.OnExecFetch = ExecFetch;
// Setup TIA
//tia = new TIA(this, frameBuffer);
tia = new TIA(this);
Cpu = new MOS6502X
{
ReadMemory = this.ReadMemory,
WriteMemory = this.WriteMemory,
PeekMemory = this.PeekMemory,
DummyReadMemory = this.ReadMemory,
OnExecFetch = this.ExecFetch
};
_tia = new TIA(this);
// dcfilter coefficent is from real observed hardware behavior: a latched "1" will fully decay by ~170 or so tia sound cycles
dcfilter = DCFilter.AsISoundProvider(tia, 256);
// Setup 6532
m6532 = new M6532(this);
_dcfilter = DCFilter.AsISoundProvider(_tia, 256);
//setup the system state here. for instance..
M6532 = new M6532(this);
// Set up the system state here. for instance..
// Read from the reset vector for where to start
cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); //set the initial PC
//cpu.PC = 0x0000; //set the initial PC
Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC
// show mapper class on romstatusdetails
// Show mapper class on romstatusdetails
CoreComm.RomStatusDetails =
string.Format("{0}\r\nSHA1:{1}\r\nMD5:{2}\r\nMapper Impl \"{3}\"",
game.Name,
Util.Hash_SHA1(rom), Util.Hash_MD5(rom),
mapper.GetType());
string.Format(
"{0}\r\nSHA1:{1}\r\nMD5:{2}\r\nMapper Impl \"{3}\"",
this._game.Name,
Util.Hash_SHA1(Rom),
Util.Hash_MD5(Rom),
_mapper.GetType());
}
public void FrameAdvance(bool render, bool rendersound)
{
_frame++;
_islag = true;
tia.frameComplete = false;
while (tia.frameComplete == false)
_tia.FrameComplete = false;
while (_tia.FrameComplete == false)
{
tia.execute(1);
tia.execute(1);
tia.execute(1);
_tia.Execute(1);
_tia.Execute(1);
_tia.Execute(1);
m6532.timer.tick();
M6532.timer.tick();
if (CoreComm.Tracer.Enabled)
CoreComm.Tracer.Put(cpu.TraceState());
cpu.ExecuteOne();
mapper.ClockCpu();
//if (cpu.PendingCycles <= 0)
//{
// //Console.WriteLine("Tia clocks: " + tia.scanlinePos + " CPU pending: " + cpu.PendingCycles);
//}
//if (cpu.PendingCycles < 0)
//{
// Console.WriteLine("------------Something went wrong------------");
//}
{
CoreComm.Tracer.Put(Cpu.TraceState());
}
Cpu.ExecuteOne();
_mapper.ClockCpu();
}
if (_islag)
{
LagCount++;
//if (render == false) return;
}
}
public byte ReadControls1(bool peek)
@ -306,12 +261,17 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
CoreComm.InputCallback.Call();
byte value = 0xFF;
if (Controller["P1 Up"]) value &= 0xEF;
if (Controller["P1 Down"]) value &= 0xDF;
if (Controller["P1 Left"]) value &= 0xBF;
if (Controller["P1 Right"]) value &= 0x7F;
if (Controller["P1 Button"]) value &= 0xF7;
if(!peek) _islag = false;
if (Controller["P1 Up"]) { value &= 0xEF; }
if (Controller["P1 Down"]) { value &= 0xDF; }
if (Controller["P1 Left"]) { value &= 0xBF; }
if (Controller["P1 Right"]) { value &= 0x7F; }
if (Controller["P1 Button"]) { value &= 0xF7; }
if (!peek)
{
_islag = false;
}
return value;
}
@ -320,22 +280,19 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
CoreComm.InputCallback.Call();
byte value = 0xFF;
if (Controller["P2 Up"]) value &= 0xEF;
if (Controller["P2 Down"]) value &= 0xDF;
if (Controller["P2 Left"]) value &= 0xBF;
if (Controller["P2 Right"]) value &= 0x7F;
if (Controller["P2 Button"]) value &= 0xF7;
if (!peek) _islag = false;
return value;
if (Controller["P2 Up"]) { value &= 0xEF; }
if (Controller["P2 Down"]) { value &= 0xDF; }
if (Controller["P2 Left"]) { value &= 0xBF; }
if (Controller["P2 Right"]) { value &= 0x7F; }
if (Controller["P2 Button"]) { value &= 0xF7; }
if (!peek)
{
_islag = false;
}
//private bool bw;
//private bool p0difficulty = true;
//private bool p1difficulty = true;
//public void SetBw(bool setting) { bw = setting; }
//public void SetP0Diff(bool setting) { p0difficulty = setting; }
//public void SetP1Diff(bool setting) { p1difficulty = setting; }
return value;
}
public byte ReadConsoleSwitches(bool peek)
{
@ -343,24 +300,44 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
bool select = Controller["Select"];
bool reset = Controller["Reset"];
if (reset) value &= 0xFE;
if (select) value &= 0xFD;
if (SyncSettings.BW) value &= 0xF7;
if (SyncSettings.LeftDifficulty) value &= 0xBF;
if (SyncSettings.RightDifficulty) value &= 0x7F;
if(!peek) _islag = false;
if (reset) { value &= 0xFE; }
if (select) { value &= 0xFD; }
if (SyncSettings.BW) { value &= 0xF7; }
if (SyncSettings.LeftDifficulty) { value &= 0xBF; }
if (SyncSettings.RightDifficulty) { value &= 0x7F; }
if (!peek)
{
_islag = false;
}
return value;
}
}
public class MapperBase
{
public Atari2600 core;
public virtual byte ReadMemory(ushort addr) { return core.BaseReadMemory(addr); }
public virtual byte PeekMemory(ushort addr) { return core.BasePeekMemory(addr); }
public virtual void WriteMemory(ushort addr, byte value) { core.BaseWriteMemory(addr, value); }
public Atari2600 Core { get; set; }
public virtual byte ReadMemory(ushort addr)
{
return Core.BaseReadMemory(addr);
}
public virtual byte PeekMemory(ushort addr)
{
return Core.BasePeekMemory(addr);
}
public virtual void WriteMemory(ushort addr, byte value)
{
Core.BaseWriteMemory(addr, value);
}
public virtual void SyncState(Serializer ser) { }
public virtual void Dispose() { }
public virtual void ClockCpu() { }
}
}

View File

@ -1,46 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using System.ComponentModel;
namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
public partial class Atari2600 : IEmulator
{
public string SystemId { get { return "A26"; } }
public GameInfo game;
private readonly GameInfo _game;
private bool _islag = true;
private int _lagcount;
private int _frame;
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 bool StartAsyncSound() { return true; }
public void EndAsyncSound() { }
public Atari2600(CoreComm comm, GameInfo game, byte[] rom, object Settings, object SyncSettings)
public Atari2600(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
{
Ram = new byte[128];
CoreComm = comm;
this.Settings = (A2600Settings)Settings ?? A2600Settings.GetDefaults();
this.SyncSettings = (A2600SyncSettings)SyncSettings ?? A2600SyncSettings.GetDefaults();
Settings = (A2600Settings)settings ?? A2600Settings.GetDefaults();
SyncSettings = (A2600SyncSettings)syncSettings ?? A2600SyncSettings.GetDefaults();
var domains = new List<MemoryDomain>(1)
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) => 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) => { })
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) => { })
};
memoryDomains = new MemoryDomainList(domains);
MemoryDomains = new MemoryDomainList(domains);
CoreComm.CpuTraceAvailable = true;
this.rom = rom;
this.game = game;
Rom = rom;
_game = game;
if (!game.GetOptionsDict().ContainsKey("m"))
{
@ -51,32 +63,39 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
HardReset();
}
public List<KeyValuePair<string, int>> GetCpuFlagsAndRegisters()
{
return new List<KeyValuePair<string, int>>
{
new KeyValuePair<string, int>("A", cpu.A),
new KeyValuePair<string, int>("X", cpu.X),
new KeyValuePair<string, int>("Y", cpu.Y),
new KeyValuePair<string, int>("S", cpu.S),
new KeyValuePair<string, int>("PC", cpu.PC),
new KeyValuePair<string, int>("Flag C", cpu.FlagC ? 1 : 0),
new KeyValuePair<string, int>("Flag Z", cpu.FlagZ ? 1 : 0),
new KeyValuePair<string, int>("Flag I", cpu.FlagI ? 1 : 0),
new KeyValuePair<string, int>("Flag D", cpu.FlagD ? 1 : 0),
new KeyValuePair<string, int>("Flag B", cpu.FlagB ? 1 : 0),
new KeyValuePair<string, int>("Flag V", cpu.FlagV ? 1 : 0),
new KeyValuePair<string, int>("Flag N", cpu.FlagN ? 1 : 0),
new KeyValuePair<string, int>("Flag T", cpu.FlagT ? 1 : 0)
};
}
public string SystemId { get { return "A26"; } }
public void ResetCounters()
{
_frame = 0;
_lagcount = 0;
_islag = false;
}
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
{
@ -89,65 +108,114 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
};
void SyncState(Serializer ser)
public List<KeyValuePair<string, int>> GetCpuFlagsAndRegisters()
{
return new List<KeyValuePair<string, int>>
{
new KeyValuePair<string, int>("A", Cpu.A),
new KeyValuePair<string, int>("X", Cpu.X),
new KeyValuePair<string, int>("Y", Cpu.Y),
new KeyValuePair<string, int>("S", Cpu.S),
new KeyValuePair<string, int>("PC", Cpu.PC),
new KeyValuePair<string, int>("Flag C", Cpu.FlagC ? 1 : 0),
new KeyValuePair<string, int>("Flag Z", Cpu.FlagZ ? 1 : 0),
new KeyValuePair<string, int>("Flag I", Cpu.FlagI ? 1 : 0),
new KeyValuePair<string, int>("Flag D", Cpu.FlagD ? 1 : 0),
new KeyValuePair<string, int>("Flag B", Cpu.FlagB ? 1 : 0),
new KeyValuePair<string, int>("Flag V", Cpu.FlagV ? 1 : 0),
new KeyValuePair<string, int>("Flag N", Cpu.FlagN ? 1 : 0),
new KeyValuePair<string, int>("Flag T", Cpu.FlagT ? 1 : 0)
};
}
public bool StartAsyncSound() { return true; }
public void EndAsyncSound() { }
public void ResetCounters()
{
_frame = 0;
_lagcount = 0;
_islag = false;
}
private void SyncState(Serializer ser)
{
ser.BeginSection("A2600");
cpu.SyncState(ser);
ser.Sync("ram", ref ram, false);
Cpu.SyncState(ser);
ser.Sync("ram", ref this.Ram, false);
ser.Sync("Lag", ref _lagcount);
ser.Sync("Frame", ref _frame);
ser.Sync("IsLag", ref _islag);
tia.SyncState(ser);
m6532.SyncState(ser);
_tia.SyncState(ser);
M6532.SyncState(ser);
ser.BeginSection("Mapper");
mapper.SyncState(ser);
_mapper.SyncState(ser);
ser.EndSection();
ser.EndSection();
}
public ControllerDefinition ControllerDefinition { get { return Atari2600ControllerDefinition; } }
public IController Controller { get; set; }
public byte[] ReadSaveRam()
{
return null;
}
public int Frame { get { return _frame; } set { _frame = value; } }
public int LagCount { get { return _lagcount; } set { _lagcount = value; } }
public bool IsLagFrame { get { return _islag; } }
private bool _islag = true;
private int _lagcount;
private int _frame;
public byte[] ReadSaveRam() { return null; }
public void StoreSaveRam(byte[] data) { }
public void ClearSaveRam() { }
public bool SaveRamModified { get; set; }
public bool DeterministicEmulation { get; set; }
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)); }
public void ClearSaveRam() { }
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));
}
public byte[] SaveStateBinary()
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
var ms = new MemoryStream();
var bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
return ms.ToArray();
}
public bool BinarySaveStatesPreferred { get { return false; } }
private readonly MemoryDomainList memoryDomains;
public MemoryDomainList MemoryDomains { get { return memoryDomains; } }
public void Dispose() { }
public object GetSettings() { return Settings.Clone(); }
public object GetSyncSettings() { return SyncSettings.Clone(); }
public bool PutSettings(object o) { Settings = (A2600Settings)o; return false; }
public bool PutSyncSettings(object o) { SyncSettings = (A2600SyncSettings)o; return false; }
public object GetSettings()
{
return Settings.Clone();
}
public A2600Settings Settings { get; private set; }
public A2600SyncSettings SyncSettings { get; private set; }
public object GetSyncSettings()
{
return SyncSettings.Clone();
}
public bool PutSettings(object o)
{
Settings = (A2600Settings)o;
return false;
}
public bool PutSyncSettings(object o)
{
SyncSettings = (A2600SyncSettings)o;
return false;
}
public class A2600Settings
{
@ -164,6 +232,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
return (A2600Settings)MemberwiseClone();
}
public static A2600Settings GetDefaults()
{
return new A2600Settings
@ -183,8 +252,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
[Description("Set the TV Type switch on the console to B&W or Color")]
public bool BW { get; set; }
[Description("Set the Left Difficulty switch on the console")]
public bool LeftDifficulty { get; set; }
[Description("Set the Right Difficulty switch on the console")]
public bool RightDifficulty { get; set; }
@ -192,6 +263,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
return (A2600SyncSettings)MemberwiseClone();
}
public static A2600SyncSettings GetDefaults()
{
return new A2600SyncSettings
@ -203,5 +275,4 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
}
}

View File

@ -72,7 +72,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
// Read Ram
ushort maskedAddr = (ushort)(addr & 0x007f);
return core.ram[maskedAddr];
return core.Ram[maskedAddr];
}
else
{
@ -150,7 +150,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (!RS)
{
ushort maskedAddr = (ushort)(addr & 0x007f);
core.ram[maskedAddr] = value;
core.Ram[maskedAddr] = value;
}
else
{

View File

@ -0,0 +1,30 @@
using System;
namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
/*
Mapper used for multi-cart mappers
*/
internal class Multicart : MapperBase
{
public Multicart()
{
throw new NotImplementedException();
}
public override byte ReadMemory(ushort addr)
{
if (addr < 0x1000)
{
return base.ReadMemory(addr);
}
return Core.Rom[addr & 0xFFF];
}
public override byte PeekMemory(ushort addr)
{
return ReadMemory(addr);
}
}
}

View File

@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_bank4K << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank4K << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -9,7 +9,7 @@
return base.ReadMemory(addr);
}
return core.rom[addr & 0x7FF];
return this.Core.Rom[addr & 0x7FF];
}
public override byte PeekMemory(ushort addr)

View File

@ -61,12 +61,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _ram[(addr & 0x03FF) + (_rambank_1K << 10)] = 0xFF; // Reading from the write port triggers an unwanted write
}
return core.rom[(_lowbank_2K << 11) + (addr & 0x07FF)];
return Core.Rom[(_lowbank_2K << 11) + (addr & 0x07FF)];
}
if (addr < 0x2000) // High bank fixed to last 2k of ROM
{
return core.rom[(core.rom.Length - 2048) + (addr & 0x07FF)];
return Core.Rom[(Core.Rom.Length - 2048) + (addr & 0x07FF)];
}
return base.ReadMemory(addr);
@ -91,12 +91,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _ram[(addr & 0x03FF) + (_rambank_1K << 10)]; // Reading from the write port triggers an unwanted write
}
return core.rom[(_lowbank_2K << 11) + (addr & 0x07FF)];
return Core.Rom[(_lowbank_2K << 11) + (addr & 0x07FF)];
}
if (addr < 0x2000) // High bank fixed to last 2k of ROM
{
return core.rom[(core.rom.Length - 2048) + (addr & 0x07FF)];
return Core.Rom[(Core.Rom.Length - 2048) + (addr & 0x07FF)];
}
return base.ReadMemory(addr);
@ -114,13 +114,13 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
else if (addr == 0x003F)
{
_hasRam = false;
if ((value << 11) < core.rom.Length)
if ((value << 11) < Core.Rom.Length)
{
_lowbank_2K = value;
}
else
{
_lowbank_2K = value & (core.rom.Length >> 11);
_lowbank_2K = value & (Core.Rom.Length >> 11);
}
}

View File

@ -40,12 +40,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (addr < 0x17FF) // Low 2k Bank
{
return core.rom[(_lowbank_2K << 11) + (addr & 0x07FF)];
return Core.Rom[(_lowbank_2K << 11) + (addr & 0x07FF)];
}
if (addr < 0x2000) // High bank fixed to last 2k of ROM
{
return core.rom[(core.rom.Length - 2048) + (addr & 0x07FF)];
return Core.Rom[(Core.Rom.Length - 2048) + (addr & 0x07FF)];
}
return base.ReadMemory(addr);
@ -60,13 +60,13 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
if (addr < 0x0040)
{
if ((value << 11) < core.rom.Length)
if ((value << 11) < Core.Rom.Length)
{
_lowbank_2K = value;
}
else
{
_lowbank_2K = value & (core.rom.Length >> 11);
_lowbank_2K = value & (Core.Rom.Length >> 11);
}
}

View File

@ -54,23 +54,23 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
if ((addr & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff
{
val = _myIsRomLow ? core.rom[(addr & 0x7ff) + _mySliceLow]
val = _myIsRomLow ? Core.Rom[(addr & 0x7ff) + _mySliceLow]
: _myRam[(addr & 0x7ff) + _mySliceLow];
}
else if (((addr & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff
((addr & 0x1fff) <= 0x1dff))
{
val = _myIsRomMiddle ? core.rom[(addr & 0x7ff) + _mySliceMiddle]
val = _myIsRomMiddle ? Core.Rom[(addr & 0x7ff) + _mySliceMiddle]
: _myRam[(addr & 0x7ff) + _mySliceMiddle];
}
else if ((addr & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff
{
val = _myIsRomHigh ? core.rom[(addr & 0xff) + _mySliceHigh]
val = _myIsRomHigh ? Core.Rom[(addr & 0xff) + _mySliceHigh]
: _myRam[(addr & 0xff) + _mySliceHigh];
}
else if ((addr & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff
{
val = core.rom[(addr & 0xff) + (core.rom.Length - 256)];
val = Core.Rom[(addr & 0xff) + (Core.Rom.Length - 256)];
if (((_myLastData & 0xe0) == 0x60) && ((_myLastAddress >= 0x1000) ||
(_myLastAddress < 0x200)))
{

View File

@ -9,7 +9,7 @@
return base.ReadMemory(addr);
}
return core.rom[addr & 0xFFF];
return Core.Rom[addr & 0xFFF];
}
public override byte PeekMemory(ushort addr)

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_bank4k << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank4k << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (addr >= 0x1800 && addr < 0x2000)
{
return core.rom[(addr & 0x7FF)];
return Core.Rom[(addr & 0x7FF)];
}
return base.ReadMemory(addr);

View File

@ -329,7 +329,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
Address(addr);
return core.rom[(bank_4k << 12) + addr];
return Core.Rom[(bank_4k << 12) + addr];
}
public override void WriteMemory(ushort addr, byte value)

View File

@ -43,20 +43,20 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (addr < 0x1400)
{
return core.rom[(_toggle1 << 10) + (addr & 0x3FF)];
return Core.Rom[(_toggle1 << 10) + (addr & 0x3FF)];
}
if (addr < 0x1800)
{
return core.rom[(_toggle2 << 10) + (addr & 0x3FF)];
return Core.Rom[(_toggle2 << 10) + (addr & 0x3FF)];
}
if (addr < 0x1C00)
{
return core.rom[(_toggle3 << 10) + (addr & 0x3FF)];
return Core.Rom[(_toggle3 << 10) + (addr & 0x3FF)];
}
return core.rom[(7 * 1024) + (addr & 0x3FF)]; // 7 because final bank is always set to last
return Core.Rom[(7 * 1024) + (addr & 0x3FF)]; // 7 because final bank is always set to last
}
public override byte ReadMemory(ushort addr)

View File

@ -59,7 +59,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _rambank0[addr & 0x3FF];
}
return core.rom[(_rombank_1K * 0x800) + (addr & 0x7FF)];
return Core.Rom[(_rombank_1K * 0x800) + (addr & 0x7FF)];
}
if (addr < 0x1900) // Ram 1 Read port
@ -76,8 +76,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
addr -= 0x1800;
addr &= 0x7FF;
int offset = core.rom.Length - 0x0800;
return core.rom[offset + addr]; // Fixed to last 1.5K
int offset = Core.Rom.Length - 0x0800;
return Core.Rom[offset + addr]; // Fixed to last 1.5K
}
return base.ReadMemory(addr);

View File

@ -28,7 +28,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_toggle << 12) + (addr & 0xFFF)];
return Core.Rom[(_toggle << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _ram[(addr & 0x7F)];
}
return core.rom[(_bank4k << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank4k << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_bank << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -26,7 +26,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_toggle << 12) + (addr & 0xFFF)];
return Core.Rom[(_toggle << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _ram[(addr & 0x7F)];
}
return core.rom[(_bank4k << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank4k << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_toggle << 12) + (addr & 0xFFF)];
return Core.Rom[(_toggle << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _ram[(addr & 0x7F)];
}
return core.rom[(_bank4k << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank4k << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_bank_4K << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank_4K << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _ram[(addr & 0x7F)];
}
return core.rom[(_bank_4K << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank_4K << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -41,7 +41,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _auxRam[addr & 0xFF];
}
return core.rom[(_toggle << 12) + (addr & 0xFFF)];
return Core.Rom[(_toggle << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return _auxRam[addr & 0xFF];
}
return core.rom[(_bank4k << 12) + (addr & 0xFFF)];
return Core.Rom[(_bank4k << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)
@ -82,7 +82,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (addr == 0x1FF8) _bank4k = 3;
if (addr == 0x1FF9) _bank4k = 4;
if (addr == 0x1FFA) _bank4k = 5;
if (addr == 0x1FFB && core.rom.Length == 28 * 1024) // Only available on 28k Roms
if (addr == 0x1FFB && Core.Rom.Length == 28 * 1024) // Only available on 28k Roms
{
_bank4k = 6;
}

View File

@ -0,0 +1,16 @@
using System;
namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
/*
Cartridge class used for SB "SUPERbanking" 128k-256k bankswitched games.
There are either 32 or 64 4K banks.
*/
internal class mSB : MapperBase
{
public mSB()
{
throw new NotImplementedException();
}
}
}

View File

@ -28,7 +28,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_toggle << 12) + (addr & 0xFFF)];
return Core.Rom[(_toggle << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -49,7 +49,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return base.ReadMemory(addr);
}
return core.rom[(_rombank_2K << 12) + (addr & 0xFFF)];
return Core.Rom[(_rombank_2K << 12) + (addr & 0xFFF)];
}
public override byte ReadMemory(ushort addr)

View File

@ -9,13 +9,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Emulates the TIA
public class TIA : IVideoProvider, ISoundProvider
{
public bool frameComplete;
private readonly Atari2600 core;
private byte hsyncCnt;
private int capChargeStart;
private bool capCharging;
private const byte CXP0 = 0x01;
private const byte CXP1 = 0x02;
private const byte CXM0 = 0x04;
@ -23,7 +16,32 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
private const byte CXPF = 0x10;
private const byte CXBL = 0x20;
struct missileData
private readonly Atari2600 _core;
private byte _hsyncCnt;
private int _capChargeStart;
private bool _capCharging;
private PlayerData player0;
private PlayerData player1;
private PlayfieldData playField;
private HmoveData hmove;
private BallData ball;
private bool vblankEnabled;
private bool vsyncEnabled;
private uint[] scanline = new uint[160];
public TIA(Atari2600 core)
{
_core = core;
player0.scanCnt = 8;
player1.scanCnt = 8;
}
public bool FrameComplete { get; set; }
private struct MissileData
{
public bool Enabled;
public bool ResetToPlayer;
@ -35,7 +53,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public bool Tick()
{
bool result = false;
var result = false;
// At hPosCnt == 0, start drawing the missile, if enabled
if (HPosCnt < (1 << Size))
@ -59,7 +77,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
if (((Number & 0x07) == 0x02 || ((Number & 0x07) == 0x03) || ((Number & 0x07) == 0x06)))
if ((Number & 0x07) == 0x02 || ((Number & 0x07) == 0x03) || ((Number & 0x07) == 0x06))
{
if (HPosCnt >= 32 && HPosCnt <= (32 + (1 << Size) - 1) )
{
@ -85,6 +103,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Increment the counter
HPosCnt++;
// Counter loops at 160
HPosCnt %= 160;
@ -105,9 +124,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
struct playerData
private struct PlayerData
{
public missileData missile;
public MissileData Missile;
public byte grp;
public byte dgrp;
public byte color;
@ -122,9 +141,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public byte resetCnt;
public byte collisions;
public bool tick()
public bool Tick()
{
bool result = false;
var result = false;
if (scanCnt < 8)
{
// Make the mask to check the graphic
@ -133,7 +152,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Reflect it if needed
if (reflect)
{
playerMask = (byte)reverseBits(playerMask, 8);
playerMask = (byte)ReverseBits(playerMask, 8);
}
// Check the graphic (depending on delay)
@ -153,9 +172,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
// Reset missile, if desired
if (scanCnt == 0x04 && hPosCnt <= 16 && missile.ResetToPlayer)
if (scanCnt == 0x04 && hPosCnt <= 16 && Missile.ResetToPlayer)
{
missile.HPosCnt = 0;
Missile.HPosCnt = 0;
}
// Increment counter
@ -170,12 +189,14 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
scanStrchCnt++;
scanStrchCnt %= 2;
}
// Quad size player
else if ((nusiz & 0x07) == 0x07)
{
scanStrchCnt++;
scanStrchCnt %= 4;
}
// Single size player
else
{
@ -186,7 +207,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
scanCnt++;
}
}
// At counter position 0 we should start drawing, a pixel late
@ -217,8 +237,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Reset is no longer in effect
reset = false;
// Increment the counter
hPosCnt++;
// Counter loops at 160
hPosCnt %= 160;
@ -239,7 +261,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public void SyncState(Serializer ser)
{
missile.SyncState(ser);
Missile.SyncState(ser);
ser.Sync("grp", ref grp);
ser.Sync("dgrp", ref dgrp);
ser.Sync("color", ref color);
@ -254,9 +276,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
ser.Sync("resetCnt", ref resetCnt);
ser.Sync("collisions", ref collisions);
}
};
}
struct ballData
private struct BallData
{
public bool enabled;
public bool denabled;
@ -264,10 +286,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public byte size;
public byte HM;
public byte hPosCnt;
public byte collisions;
public bool tick()
public bool Tick()
{
bool result = false;
if (hPosCnt < (1 << size))
@ -286,6 +307,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Increment the counter
hPosCnt++;
// Counter loops at 160
hPosCnt %= 160;
@ -304,12 +326,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
ser.Sync("collisions", ref collisions);
ser.EndSection();
}
}
};
struct playfieldData
private struct PlayfieldData
{
public UInt32 grp;
public uint grp;
public byte pfColor;
public byte bkColor;
public bool reflect;
@ -326,9 +347,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
ser.Sync("priority", ref priority);
ser.EndSection();
}
};
}
struct hmoveData
private struct HmoveData
{
public bool hmoveEnabled;
public bool hmoveJustStarted;
@ -374,20 +395,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
};
playerData player0;
playerData player1;
playfieldData playField;
hmoveData hmove;
ballData ball;
bool vblankEnabled;
bool vsyncEnabled;
private readonly List<uint[]> scanlinesBuffer = new List<uint[]>();
uint[] scanline = new uint[160];
private readonly UInt32[] palette = new UInt32[]{
private readonly uint[] palette = new uint[]
{
0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0,
0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0,
0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0,
@ -422,13 +433,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0
};
public TIA(Atari2600 core)
{
this.core = core;
player0.scanCnt = 8;
player1.scanCnt = 8;
}
public int[] frameBuffer = new int[320 * 262];
public int[] GetVideoBuffer() { return frameBuffer; }
public int VirtualWidth { get { return 320; } }
@ -436,31 +440,37 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public int BufferHeight { get { return 262; } }
public int BackgroundColor { get { return 0; } }
public class audio
public class Audio
{
/// <summary>noise/division control</summary>
// noise/division control
public byte AUDC = 0;
/// <summary>frequency divider</summary>
// frequency divider
public byte AUDF = 1;
/// <summary>volume</summary>
// volume
public byte AUDV = 0;
/// <summary>2 state counter</summary>
// 2 state counter
bool sr1 = true;
/// <summary>4 bit shift register</summary>
// 4 bit shift register
int sr4 = 0x0f;
/// <summary>5 bit shift register</summary>
// 5 bit shift register
int sr5 = 0x1f;
/// <summary>3 state counter</summary>
// 3 state counter
int sr3 = 2;
/// <summary>counter based off AUDF</summary>
// counter based off AUDF
byte freqcnt;
/// <summary>latched audio value</summary>
bool on = true;
// latched audio value
private bool on = true;
bool run_3()
private bool run_3()
{
sr3++;
if (sr3 == 3)
@ -468,10 +478,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
sr3 = 0;
return true;
}
return false;
}
bool run_4()
private bool run_4()
{
bool ret = (sr4 & 1) != 0;
bool c = (sr4 & 1) != 0 ^ (sr4 & 2) != 0;
@ -479,7 +490,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return ret;
}
bool run_5()
private bool run_5()
{
bool ret = (sr5 & 1) != 0;
bool c = (sr5 & 1) != 0 ^ (sr5 & 4) != 0;
@ -487,26 +498,27 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return ret;
}
bool one_4()
private bool one_4()
{
bool ret = (sr4 & 1) != 0;
sr4 = (sr4 >> 1) | 8;
return ret;
}
bool one_5()
private bool one_5()
{
bool ret = (sr5 & 1) != 0;
sr5 = (sr5 >> 1) | 16;
return ret;
}
bool run_1()
private bool run_1()
{
sr1 = !sr1;
return !sr1;
}
bool run_9()
private bool run_9()
{
bool ret = (sr4 & 1) != 0;
bool c = (sr5 & 1) != 0 ^ (sr4 & 1) != 0;
@ -519,7 +531,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
/// call me approx 31k times a second
/// </summary>
/// <returns>16 bit audio sample</returns>
public short cycle()
public short Cycle()
{
if (++freqcnt == AUDF)
{
@ -618,32 +630,23 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
public audio[] AUD = { new audio(), new audio() };
public Audio[] AUD = { new Audio(), new Audio() };
public void GetSamples(short[] samples)
{
short[] moreSamples = new short[523];
var moreSamples = new short[523];
for (int i = 0; i < moreSamples.Length; i++)
{
for (int snd = 0; snd < 2; snd++)
{
moreSamples[i] += AUD[snd].cycle();
//moreSamples[i] += (short)(((AUD[snd].sr4 & 0x08) != 0) ? AUD[snd].AUDV * 1092 : 0);
moreSamples[i] += AUD[snd].Cycle();
}
/*if (++freqDiv == (audioFreqDiv * 2))
{
freqDiv = 0;
myP4 = (byte)(((myP4 & 0x0f) != 0) ? ((myP4 << 1) | ((((myP4 & 0x08) != 0) ? 1 : 0) ^ (((myP4 & 0x04) != 0) ? 1 : 0))) : 1);
}
moreSamples[i] = (short)(((myP4 & 0x08) != 0) ? 32767 : 0);
*/
}
for (int i = 0; i < samples.Length / 2; i++)
{
samples[i * 2] = moreSamples[(int)(((double)moreSamples.Length / (double)(samples.Length / 2)) * i)];
samples[i * 2 + 1] = samples[i * 2];
samples[(i * 2) + 1] = samples[i * 2];
}
}
public void DiscardSamples() { }
@ -651,7 +654,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Execute TIA cycles
public void execute(int cycles)
public void Execute(int cycles)
{
// Still ignoring cycles...
@ -660,16 +663,16 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// ---- Things that happen only in the drawing section ----
// TODO: Remove this magic number (17). It depends on the HMOVE
if ((hsyncCnt / 4) >= (hmove.lateHBlankReset ? 19 : 17))
if ((_hsyncCnt / 4) >= (hmove.lateHBlankReset ? 19 : 17))
{
// TODO: Remove this magic number
if ((hsyncCnt / 4) >= 37)
if ((_hsyncCnt / 4) >= 37)
{
rightSide = true;
}
// The bit number of the PF data which we want
int pfBit = ((hsyncCnt / 4) - 17) % 20;
int pfBit = ((_hsyncCnt / 4) - 17) % 20;
// Create the mask for the bit we want
// Note that bits are arranged 0 1 2 3 4 .. 19
@ -678,7 +681,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Reverse the mask if on the right and playfield is reflected
if (rightSide && playField.reflect)
{
pfMask = reverseBits(pfMask, 20);
pfMask = ReverseBits(pfMask, 20);
}
// Calculate collisions
@ -691,29 +694,29 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// ---- Player 0 ----
collisions |= (player0.tick() ? CXP0 : (byte)0x00);
collisions |= (player0.Tick() ? CXP0 : (byte)0x00);
// ---- Missile 0 ----
collisions |= (player0.missile.Tick() ? CXM0 : (byte)0x00);
collisions |= (player0.Missile.Tick() ? CXM0 : (byte)0x00);
// ---- Player 1 ----
collisions |= (player1.tick() ? CXP1 : (byte)0x00);
collisions |= (player1.Tick() ? CXP1 : (byte)0x00);
// ---- Missile 0 ----
collisions |= (player1.missile.Tick() ? CXM1 : (byte)0x00);
collisions |= (player1.Missile.Tick() ? CXM1 : (byte)0x00);
// ---- Ball ----
collisions |= (ball.tick() ? CXBL : (byte)0x00);
collisions |= (ball.Tick() ? CXBL : (byte)0x00);
// Pick the pixel color from collisions
uint pixelColor = 0x000000;
if (core.Settings.ShowBG)
if (_core.Settings.ShowBG)
{
pixelColor = palette[playField.bkColor];
}
if ((collisions & CXPF) != 0 && core.Settings.ShowPlayfield)
if ((collisions & CXPF) != 0 && _core.Settings.ShowPlayfield)
{
if (playField.score)
{
@ -735,7 +738,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if ((collisions & CXBL) != 0)
{
ball.collisions |= collisions;
if (core.Settings.ShowBall)
if (_core.Settings.ShowBall)
{
pixelColor = palette[playField.pfColor];
}
@ -743,8 +746,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if ((collisions & CXM1) != 0)
{
player1.missile.Collisions |= collisions;
if (core.Settings.ShowMissle2)
player1.Missile.Collisions |= collisions;
if (_core.Settings.ShowMissle2)
{
pixelColor = palette[player1.color];
}
@ -753,7 +756,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if ((collisions & CXP1) != 0)
{
player1.collisions |= collisions;
if (core.Settings.ShowPlayer2)
if (_core.Settings.ShowPlayer2)
{
pixelColor = palette[player1.color];
}
@ -761,8 +764,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if ((collisions & CXM0) != 0)
{
player0.missile.Collisions |= collisions;
if (core.Settings.ShowMissle1)
player0.Missile.Collisions |= collisions;
if (_core.Settings.ShowMissle1)
{
pixelColor = palette[player0.color];
}
@ -771,24 +774,17 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if ((collisions & CXP0) != 0)
{
player0.collisions |= collisions;
if (core.Settings.ShowPlayer1)
if (_core.Settings.ShowPlayer1)
{
pixelColor = palette[player0.color];
}
}
if (playField.priority && (collisions & CXPF) != 0 && core.Settings.ShowPlayfield)
if (playField.priority && (collisions & CXPF) != 0 && _core.Settings.ShowPlayfield)
{
if (playField.score)
{
if (!rightSide)
{
pixelColor = palette[player0.color];
}
else
{
pixelColor = palette[player1.color];
}
pixelColor = !rightSide ? palette[player0.color] : palette[player1.color];
}
else
{
@ -804,7 +800,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Add the pixel to the scanline
// TODO: Remove this magic number (68)
scanline[hsyncCnt - 68] = pixelColor;
scanline[_hsyncCnt - 68] = pixelColor;
}
@ -833,7 +829,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
hmove.hmoveCnt = 0;
//hmove.hmoveCnt++;
hmove.hmoveJustStarted = false;
hmove.lateHBlankReset = true;
hmove.decCntEnabled = false;
@ -851,7 +846,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (((15 - hmove.player0Cnt) ^ ((player0.HM & 0x07) | ((~(player0.HM & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
player0.tick();
player0.Tick();
// Increase by 1, max of 15
hmove.player0Cnt++;
@ -869,10 +864,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{ }
// If the move counter still has a bit in common with the HM register
if (((15 - hmove.missile0Cnt) ^ ((player0.missile.Hm & 0x07) | ((~(player0.missile.Hm & 0x08)) & 0x08))) != 0x0F)
if (((15 - hmove.missile0Cnt) ^ ((player0.Missile.Hm & 0x07) | ((~(player0.Missile.Hm & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
player0.missile.Tick();
player0.Missile.Tick();
// Increase by 1, max of 15
hmove.missile0Cnt++;
@ -891,7 +886,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (((15 - hmove.player1Cnt) ^ ((player1.HM & 0x07) | ((~(player1.HM & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
player1.tick();
player1.Tick();
// Increase by 1, max of 15
hmove.player1Cnt++;
@ -906,10 +901,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (hmove.missile1Latch)
{
// If the move counter still has a bit in common with the HM register
if (((15 - hmove.missile1Cnt) ^ ((player1.missile.Hm & 0x07) | ((~(player1.missile.Hm & 0x08)) & 0x08))) != 0x0F)
if (((15 - hmove.missile1Cnt) ^ ((player1.Missile.Hm & 0x07) | ((~(player1.Missile.Hm & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
player1.missile.Tick();
player1.Missile.Tick();
// Increase by 1, max of 15
hmove.missile1Cnt++;
@ -927,7 +922,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (((15 - hmove.ballCnt) ^ ((ball.HM & 0x07) | ((~(ball.HM & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
ball.tick();
ball.Tick();
// Increase by 1, max of 15
hmove.ballCnt++;
@ -946,7 +941,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
hmove.hmoveDelayCnt = 0;
}
}
//hmove.hmoveJustStarted = false;
hmove.hmoveCnt++;
hmove.hmoveCnt %= 4;
}
@ -964,14 +959,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
// Increment the hsync counter
hsyncCnt++;
hsyncCnt %= 228;
_hsyncCnt++;
_hsyncCnt %= 228;
// End of the line? Add it to the buffer!
if (hsyncCnt == 0)
if (_hsyncCnt == 0)
{
hmove.lateHBlankReset = false;
scanlinesBuffer.Add(scanline);
@ -984,14 +977,14 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
* that need to be fixed; but it's preferable to not crash the emulator
* in such situations
*/
outputFrame();
OutputFrame();
scanlinesBuffer.Clear();
frameComplete = true;
FrameComplete = true;
}
}
// TODO: Remove the magic numbers from this function to allow for a variable height screen
public void outputFrame()
public void OutputFrame()
{
for (int row = 0; row < 262; row++)
{
@ -999,11 +992,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
if (scanlinesBuffer.Count > row)
{
frameBuffer[row * 320 + col] = (int)(scanlinesBuffer[row][col / 2] | 0xFF000000);
frameBuffer[(row * 320) + col] = (int)(scanlinesBuffer[row][col / 2] | 0xFF000000);
}
else
{
frameBuffer[row * 320 + col] = unchecked((int)0xFF000000);
frameBuffer[(row * 320) + col] = unchecked((int)0xFF000000);
}
}
}
@ -1014,41 +1007,49 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
ushort maskedAddr = (ushort)(addr & 0x000F);
if (maskedAddr == 0x00) // CXM0P
{
return (byte)((((player0.missile.Collisions & CXP1) != 0) ? 0x80 : 0x00) | (((player0.missile.Collisions & CXP0) != 0) ? 0x40 : 0x00));
return (byte)((((player0.Missile.Collisions & CXP1) != 0) ? 0x80 : 0x00) | (((player0.Missile.Collisions & CXP0) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x01) // CXM1P
if (maskedAddr == 0x01) // CXM1P
{
return (byte)((((player1.missile.Collisions & CXP0) != 0) ? 0x80 : 0x00) | (((player1.missile.Collisions & CXP1) != 0) ? 0x40 : 0x00));
return (byte)((((player1.Missile.Collisions & CXP0) != 0) ? 0x80 : 0x00) | (((player1.Missile.Collisions & CXP1) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x02) // CXP0FB
if (maskedAddr == 0x02) // CXP0FB
{
return (byte)((((player0.collisions & CXPF) != 0) ? 0x80 : 0x00) | (((player0.collisions & CXBL) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x03) // CXP1FB
if (maskedAddr == 0x03) // CXP1FB
{
return (byte)((((player1.collisions & CXPF) != 0) ? 0x80 : 0x00) | (((player1.collisions & CXBL) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x04) // CXM0FB
if (maskedAddr == 0x04) // CXM0FB
{
return (byte)((((player0.missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((player0.missile.Collisions & CXBL) != 0) ? 0x40 : 0x00));
return (byte)((((player0.Missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((player0.Missile.Collisions & CXBL) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x05) // CXM1FB
if (maskedAddr == 0x05) // CXM1FB
{
return (byte)((((player1.missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((player1.missile.Collisions & CXBL) != 0) ? 0x40 : 0x00));
return (byte)((((player1.Missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((player1.Missile.Collisions & CXBL) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x06) // CXBLPF
if (maskedAddr == 0x06) // CXBLPF
{
return (byte)(((ball.collisions & CXPF) != 0) ? 0x80 : 0x00);
}
else if (maskedAddr == 0x07) // CXPPMM
if (maskedAddr == 0x07) // CXPPMM
{
return (byte)((((player0.collisions & CXP1) != 0) ? 0x80 : 0x00) | (((player0.missile.Collisions & CXM1) != 0) ? 0x40 : 0x00));
return (byte)((((player0.collisions & CXP1) != 0) ? 0x80 : 0x00) | (((player0.Missile.Collisions & CXM1) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x08) // INPT0
if (maskedAddr == 0x08) // INPT0
{
// Changing the hard coded value will change the paddle position. The range seems to be roughly 0-56000 according to values from stella
// 6105 roughly centers the paddle in Breakout
if (capCharging && core.cpu.TotalExecutedCycles - capChargeStart >= 6105)
if (_capCharging && _core.Cpu.TotalExecutedCycles - _capChargeStart >= 6105)
{
return 0x80;
}
@ -1057,13 +1058,15 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return 0x00;
}
}
else if (maskedAddr == 0x0C) // INPT4
if (maskedAddr == 0x0C) // INPT4
{
return (byte)((core.ReadControls1(peek) & 0x08) != 0 ? 0x80 : 0x00);
return (byte)((_core.ReadControls1(peek) & 0x08) != 0 ? 0x80 : 0x00);
}
else if (maskedAddr == 0x0D) // INPT5
if (maskedAddr == 0x0D) // INPT5
{
return (byte)((core.ReadControls2(peek) & 0x08) != 0 ? 0x80 : 0x00);
return (byte)((_core.ReadControls2(peek) & 0x08) != 0 ? 0x80 : 0x00);
}
return 0x00;
@ -1085,53 +1088,55 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// When VSYNC is disabled, this will be the first line of the new frame
// write to frame buffer
outputFrame();
OutputFrame();
// Clear all from last frame
scanlinesBuffer.Clear();
//Frame is done
frameComplete = true;
// Frame is done
FrameComplete = true;
vsyncEnabled = false;
// Do not reset hsync, since we're on the first line of the new frame
//hsyncCnt = 0;
// hsyncCnt = 0;
}
}
else if (maskedAddr == 0x01) // VBLANK
{
vblankEnabled = (value & 0x02) != 0;
capCharging = (value & 0x80) == 0;
_capCharging = (value & 0x80) == 0;
if ((value & 0x80) == 0)
{
capChargeStart = core.cpu.TotalExecutedCycles;
_capChargeStart = _core.Cpu.TotalExecutedCycles;
}
}
else if (maskedAddr == 0x02) // WSYNC
{
int count = 0;
while (hsyncCnt > 0)
while (_hsyncCnt > 0)
{
count++;
execute(1);
Execute(1);
// Add a cycle to the cpu every 3 TIA clocks (corrects timer error in M6532)
if (count % 3 == 0)
{
core.m6532.timer.tick();
_core.M6532.timer.tick();
}
}
}
else if (maskedAddr == 0x04) // NUSIZ0
{
player0.nusiz = (byte)(value & 0x37);
player0.missile.Size = (byte)((value & 0x30) >> 4);
player0.missile.Number = (byte)(value & 0x07);
player0.Missile.Size = (byte)((value & 0x30) >> 4);
player0.Missile.Number = (byte)(value & 0x07);
}
else if (maskedAddr == 0x05) // NUSIZ1
{
player1.nusiz = (byte)(value & 0x37);
player1.missile.Size = (byte)((value & 0x30) >> 4);
player1.missile.Number = (byte)(value & 0x07);
player1.Missile.Size = (byte)((value & 0x30) >> 4);
player1.Missile.Number = (byte)(value & 0x07);
}
else if (maskedAddr == 0x06) // COLUP0
{
@ -1158,42 +1163,42 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
else if (maskedAddr == 0x0B) // REFP0
{
player0.reflect = ((value & 0x08) != 0);
player0.reflect = (value & 0x08) != 0;
}
else if (maskedAddr == 0x0C) // REFP1
{
player1.reflect = ((value & 0x08) != 0);
player1.reflect = (value & 0x08) != 0;
}
else if (maskedAddr == 0x0D) // PF0
{
playField.grp = (UInt32)((playField.grp & 0x0FFFF) + ((reverseBits(value,8) & 0x0F) << 16));
playField.grp = (uint)((playField.grp & 0x0FFFF) + ((ReverseBits(value, 8) & 0x0F) << 16));
}
else if (maskedAddr == 0x0E) // PF1
{
playField.grp = (UInt32)((playField.grp & 0xF00FF) + (value << 8));
playField.grp = (uint)((playField.grp & 0xF00FF) + (value << 8));
}
else if (maskedAddr == 0x0F) // PF2
{
playField.grp = (UInt32)((playField.grp & 0xFFF00) + reverseBits(value,8));
playField.grp = (uint)((playField.grp & 0xFFF00) + ReverseBits(value,8));
}
else if (maskedAddr == 0x10) // RESP0
{
// Borrowed from EMU7800. Apparently resetting between 68 and 76 has strange results.
if (hsyncCnt < 69)
if (_hsyncCnt < 69)
{
player0.hPosCnt = 0;
player0.resetCnt = 0;
player0.reset = true;
}
else if (hsyncCnt == 69)
else if (_hsyncCnt == 69)
{
player0.resetCnt = 3;
}
else if (hsyncCnt == 72)
else if (_hsyncCnt == 72)
{
player0.resetCnt = 2;
}
else if (hsyncCnt == 75)
else if (_hsyncCnt == 75)
{
player0.resetCnt = 1;
}
@ -1201,27 +1206,26 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
player0.resetCnt = 0;
}
//player0.resetCnt = 0;
}
else if (maskedAddr == 0x11) // RESP1
{
// Borrowed from EMU7800. Apparently resetting between 68 and 76 has strange results.
// This fixes some graphic glitches with Frostbite
if (hsyncCnt < 69)
if (_hsyncCnt < 69)
{
player1.hPosCnt = 0;
player1.resetCnt = 0;
player1.reset = true;
}
else if (hsyncCnt == 69)
else if (_hsyncCnt == 69)
{
player1.resetCnt = 3;
}
else if (hsyncCnt == 72)
else if (_hsyncCnt == 72)
{
player1.resetCnt = 2;
}
else if (hsyncCnt == 75)
else if (_hsyncCnt == 75)
{
player1.resetCnt = 1;
}
@ -1229,19 +1233,18 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
player1.resetCnt = 0;
}
//player1.resetCnt = 0;
}
else if (maskedAddr == 0x12) // RESM0
{
player0.missile.HPosCnt = (byte)(hsyncCnt < 68 ? 160 - 2 : 160 - 4);
player0.Missile.HPosCnt = (byte)(_hsyncCnt < 68 ? 160 - 2 : 160 - 4);
}
else if (maskedAddr == 0x13) // RESM1
{
player1.missile.HPosCnt = (byte)(hsyncCnt < 68 ? 160 - 2 : 160 - 4);
player1.Missile.HPosCnt = (byte)(_hsyncCnt < 68 ? 160 - 2 : 160 - 4);
}
else if (maskedAddr == 0x14) // RESBL
{
ball.hPosCnt = (byte)(hsyncCnt < 68 ? 160 - 2 : 160 - 4);
ball.hPosCnt = (byte)(_hsyncCnt < 68 ? 160 - 2 : 160 - 4);
}
else if (maskedAddr == 0x15) // AUDC0
{
@ -1282,11 +1285,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
else if (maskedAddr == 0x1D) // ENAM0
{
player0.missile.Enabled = (value & 0x02) != 0;
player0.Missile.Enabled = (value & 0x02) != 0;
}
else if (maskedAddr == 0x1E) // ENAM1
{
player1.missile.Enabled = (value & 0x02) != 0;
player1.Missile.Enabled = (value & 0x02) != 0;
}
else if (maskedAddr == 0x1F) // ENABL
{
@ -1302,11 +1305,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
else if (maskedAddr == 0x22) // HMM0
{
player0.missile.Hm = (byte)((value & 0xF0) >> 4);
player0.Missile.Hm = (byte)((value & 0xF0) >> 4);
}
else if (maskedAddr == 0x23) // HMM1
{
player1.missile.Hm = (byte)((value & 0xF0) >> 4);
player1.Missile.Hm = (byte)((value & 0xF0) >> 4);
}
else if (maskedAddr == 0x24) // HMBL
{
@ -1326,11 +1329,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
else if (maskedAddr == 0x28) // RESMP0
{
player0.missile.ResetToPlayer = (value & 0x02) != 0;
player0.Missile.ResetToPlayer = (value & 0x02) != 0;
}
else if (maskedAddr == 0x29) // RESMP1
{
player1.missile.ResetToPlayer = (value & 0x02) != 0;
player1.Missile.ResetToPlayer = (value & 0x02) != 0;
}
else if (maskedAddr == 0x2A) // HMOVE
{
@ -1341,22 +1344,22 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
else if (maskedAddr == 0x2B) // HMCLR
{
player0.HM = 0;
player0.missile.Hm = 0;
player0.Missile.Hm = 0;
player1.HM = 0;
player1.missile.Hm = 0;
player1.Missile.Hm = 0;
ball.HM = 0;
}
else if (maskedAddr == 0x2C) // CXCLR
{
player0.collisions = 0;
player0.missile.Collisions = 0;
player0.Missile.Collisions = 0;
player1.collisions = 0;
player1.missile.Collisions = 0;
player1.Missile.Collisions = 0;
ball.collisions = 0;
}
}
static int reverseBits(int value, int bits)
private static int ReverseBits(int value, int bits)
{
int result = 0;
for (int i = 0; i < bits; i++)
@ -1371,7 +1374,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
ser.BeginSection("TIA");
ball.SyncState(ser);
hmove.SyncState(ser);
ser.Sync("hsyncCnt", ref hsyncCnt);
ser.Sync("hsyncCnt", ref _hsyncCnt);
ser.BeginSection("Player0");
player0.SyncState(ser);
ser.EndSection();
@ -1379,7 +1382,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
player1.SyncState(ser);
ser.EndSection();
playField.SyncState(ser);
//ser.Sync("scanline", ref scanline);
ser.EndSection();
}
}

View File

@ -1,616 +0,0 @@
using System;
using System.Collections.Generic;
namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
// Emulates the TIA
public class oldTIA
{
private readonly Atari2600 core;
public bool audioEnabled = false;
public byte audioFreqDiv = 0;
UInt32 PF; // PlayField data
byte BKcolor, PFcolor;
bool PFpriority;
bool PFreflect;
bool PFscore;
bool inpt_latching;
bool inpt4;
bool hmoveHappened;
struct playerData
{
public byte grp;
public byte dgrp;
public byte color;
public byte pos;
public byte HM;
public bool reflect;
public bool delay;
/*
public byte nusiz;
*/
};
struct ballMissileData
{
public bool enabled;
public byte pos;
public byte HM;
public byte size;
/*
public bool reset;
public bool delay;
*/
};
ballMissileData ball;
playerData player0;
playerData player1;
byte player0copies;
byte player0copy1;
byte player0copy2;
byte player1copies;
byte player1copy1;
byte player1copy2;
byte P0_collisions;
byte P1_collisions;
byte M0_collisions;
byte M1_collisions;
byte BL_collisions;
const byte COLP0 = 0x01;
const byte COLP1 = 0x02;
const byte COLM0 = 0x04;
const byte COLM1 = 0x08;
const byte COLPF = 0x10;
const byte COLBL = 0x20;
bool vblankEnabled;
readonly int[] frameBuffer;
public bool frameComplete;
readonly List<uint[]> scanlinesBuffer = new List<uint[]> ();
uint[] scanline = new uint[160];
public int scanlinePos;
readonly int[] hmove = new int[] { 0,-1,-2,-3,-4,-5,-6,-7,-8,7,6,5,4,3,2,1 };
UInt32[] palette = new UInt32[]{
0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0,
0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0,
0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0,
0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0,
0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0,
0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0,
0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0,
0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0,
0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0,
0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0,
0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0,
0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0,
0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0,
0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0,
0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0,
0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0,
0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0,
0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0,
0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0,
0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0,
0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0,
0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0,
0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0,
0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0,
0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0,
0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0,
0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0,
0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0,
0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0,
0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0,
0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0,
0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0
};
public oldTIA(Atari2600 core, int[] frameBuffer)
{
player1copy2 = 0;
player0copy2 = 0;
this.core = core;
BKcolor = 0x00;
this.frameBuffer = frameBuffer;
scanlinePos = 0;
frameComplete = false;
}
public void execute(int cycles)
{
// Ignore cycles for now, just do one cycle (three color counts/pixels)
if (scanlinePos < 68)
{
scanlinePos ++;
// HBLANK
return;
}
UInt32 PFmask;
int pixelPos = scanlinePos - 68;
// First half of screen
if (pixelPos < 80)
{
PFmask = (UInt32)(1 << ((20-1) - (byte)((pixelPos % 80) / 4)));
}
// Second half
else
{
if (PFreflect)
{
PFmask = (UInt32)(1 << ((byte)((pixelPos % 80) / 4)));
}
else
{
PFmask = (UInt32)(1 << ((20 - 1) - (byte)((pixelPos % 80) / 4)));
}
}
uint color = palette[BKcolor];
byte collisions = 0;
if ((PF & PFmask) != 0)
{
color = palette[PFcolor];
if (PFscore)
{
if (pixelPos < 80)
{
color = palette[player0.color];
}
else
{
color = palette[player1.color];
}
}
collisions |= COLPF;
}
// Ball
if (ball.enabled && pixelPos >= ball.pos && pixelPos < (ball.pos + (1 << ball.size)))
{
color = palette[PFcolor];
collisions |= COLBL;
}
// Player 1
if (pixelPos >= player1.pos && pixelPos < (player1.pos + 8))
{
byte mask = (byte)(0x80 >> (pixelPos - player1.pos));
if (player1.reflect)
{
mask = reverseBits(mask);
}
if (((player1.grp & mask) != 0 && !player1.delay) || ((player1.dgrp & mask) != 0 && player1.delay))
{
color = palette[player1.color];
collisions |= COLP1;
}
}
byte pos = (byte)(player1.pos + player1copy1);
// Player copy 1
if (player1copies >= 1 && pixelPos >= pos && pixelPos < (pos + 8))
{
byte mask = (byte)(0x80 >> (pixelPos - pos));
if (player1.reflect)
{
mask = reverseBits(mask);
}
if (((player1.grp & mask) != 0 && !player1.delay) || ((player1.dgrp & mask) != 0 && player1.delay))
{
color = palette[player1.color];
collisions |= COLP1;
}
}
pos = (byte)(player1.pos + player1copy2);
// Player copy 2
if (player1copies >=2 && pixelPos >= pos && pixelPos < (pos + 8))
{
byte mask = (byte)(0x80 >> (pixelPos - pos));
if (player1.reflect)
{
mask = reverseBits(mask);
}
if (((player1.grp & mask) != 0 && !player1.delay) || ((player1.dgrp & mask) != 0 && player1.delay))
{
color = palette[player1.color];
collisions |= COLP1;
}
}
// Player 0
if (pixelPos >= player0.pos && pixelPos < (player0.pos + 8))
{
byte mask = (byte)(0x80 >> (pixelPos - player0.pos));
if (player0.reflect)
{
mask = reverseBits(mask);
}
if (((player0.grp & mask) != 0 && !player0.delay) || ((player0.dgrp & mask) != 0 && player0.delay))
{
color = palette[player0.color];
collisions |= COLP0;
}
}
pos = (byte)(player0.pos + player0copy1);
// Player copy 1
if (player0copies >= 1 && pixelPos >= pos && pixelPos < (pos + 8))
{
byte mask = (byte)(0x80 >> (pixelPos - pos));
if (player0.reflect)
{
mask = reverseBits(mask);
}
if (((player0.grp & mask) != 0 && !player0.delay) || ((player0.dgrp & mask) != 0 && player0.delay))
{
color = palette[player0.color];
collisions |= COLP0;
}
}
pos = (byte)(player0.pos + player0copy2);
// Player copy 1
if (player0copies >= 2 && pixelPos >= pos && pixelPos < (pos + 8))
{
byte mask = (byte)(0x80 >> (pixelPos - pos));
if (player0.reflect)
{
mask = reverseBits(mask);
}
if (((player0.grp & mask) != 0 && !player0.delay) || ((player0.dgrp & mask) != 0 && player0.delay))
{
color = palette[player0.color];
collisions |= COLP0;
}
}
if ((PF & PFmask) != 0 && PFpriority)
{
color = palette[PFcolor];
if (PFscore)
{
if (pixelPos < 80)
{
color = palette[player0.color];
}
else
{
color = palette[player1.color];
}
}
collisions |= COLPF;
}
if (vblankEnabled)
{
color = 0x000000;
}
P0_collisions |= (((collisions & COLP0) != 0) ? collisions : P0_collisions);
P1_collisions |= (((collisions & COLP1) != 0) ? collisions : P1_collisions);
M0_collisions |= (((collisions & COLM0) != 0) ? collisions : M0_collisions);
M1_collisions |= (((collisions & COLM1) != 0) ? collisions : M1_collisions);
BL_collisions |= (((collisions & COLBL) != 0) ? collisions : BL_collisions);
if (hmoveHappened && pixelPos >= 0 && pixelPos < 8)
{
color = 0x000000;
}
if (pixelPos >= 8)
{
hmoveHappened = false;
}
scanline[pixelPos] = color;
scanlinePos++;
if (scanlinePos >= 228)
{
scanlinesBuffer.Add(scanline);
scanline = new uint[160];
}
scanlinePos %= 228;
}
public void outputFrame()
{
for (int row = 0; row < 262; row++)
{
for (int col = 0; col < 320; col++)
{
if (scanlinesBuffer.Count > row)
{
frameBuffer[row * 320 + col] = (int)(scanlinesBuffer[row][col / 2]);
}
else
{
frameBuffer[row * 320 + col] = 0x000000;
}
}
}
}
public byte ReadMemory(ushort addr, bool peek)
{
ushort maskedAddr = (ushort)(addr & 0x000F);
Console.WriteLine("TIA read: " + maskedAddr.ToString("x"));
if (maskedAddr == 0x02) // CXP0FB
{
return (byte)((((P0_collisions & COLPF) != 0) ? 0x80 : 0x00) | (((P0_collisions & COLBL) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x07) // CXPPMM
{
return (byte)((((P0_collisions & COLP1) != 0) ? 0x80 : 0x00) | (((M0_collisions & COLM1) != 0) ? 0x40 : 0x00));
}
else if (maskedAddr == 0x0C) // INPT4
{
if (inpt_latching)
{
if (inpt4)
{
inpt4 = ((core.ReadControls1(peek) & 0x08) != 0);
}
}
else
{
inpt4 = ((core.ReadControls1(peek) & 0x08) != 0);
}
return (byte)(inpt4 ? 0x80 : 0x00);
}
return 0x80;
}
public void WriteMemory(ushort addr, byte value)
{
ushort maskedAddr = (ushort)(addr & 0x3f);
Console.WriteLine("TIA write: " + maskedAddr.ToString("x"));
if (maskedAddr == 0x00)
{
if ((value & 0x02) != 0)
{
Console.WriteLine("TIA VSYNC On");
// Frame is complete, output to buffer
outputFrame();
scanlinesBuffer.Clear();
frameComplete = true;
scanlinePos = 0;
}
else
{
Console.WriteLine("TIA VSYNC Off");
}
}
else if (maskedAddr == 0x01)
{
vblankEnabled = (value & 0x02) != 0;
if ((value & 0x02) != 0)
{
Console.WriteLine("TIA Vblank On");
}
else
{
Console.WriteLine("TIA Vblank Off");
}
inpt_latching = (value & 0x40) != 0;
}
else if (maskedAddr == 0x02) // WSYNC
{
Console.WriteLine("TIA WSYNC");
while (scanlinePos > 0)
{
execute(1);
}
}
else if (maskedAddr == 0x04) // NUSIZ0
{
byte size = (byte)(value & 0x07);
switch (size)
{
case 0x00:
player0copies = 0;
break;
case 0x01:
player0copies = 1;
player0copy1 = 16;
break;
case 0x02:
player0copies = 1;
player0copy1 = 32;
break;
case 0x03:
player0copies = 2;
player0copy1 = 16;
player0copy2 = 32;
break;
case 0x06:
player0copies = 2;
player0copy1 = 32;
player0copy2 = 64;
break;
}
}
else if (maskedAddr == 0x05) // NUSIZ1
{
byte size = (byte)(value & 0x07);
switch (size)
{
case 0x00:
player1copies = 0;
break;
case 0x01:
player1copies = 1;
player1copy1 = 16;
break;
case 0x02:
player1copies = 1;
player1copy1 = 32;
break;
case 0x03:
player1copies = 2;
player1copy1 = 16;
player1copy2 = 32;
break;
case 0x06:
player1copies = 2;
player1copy1 = 32;
player1copy2 = 64;
break;
}
}
else if (maskedAddr == 0x06) // COLUP0
{
player0.color = (byte)(value & 0xFE);
}
else if (maskedAddr == 0x07) // COLUP1
{
player1.color = (byte)(value & 0xFE);
}
else if (maskedAddr == 0x08) // COLUPF
{
PFcolor = (byte)(value & 0xFE);
}
else if (maskedAddr == 0x09) // COLUBK
{
BKcolor = (byte)(value & 0xFE);
}
else if (maskedAddr == 0x0A) // CTRLPF
{
PFpriority = (value & 0x04) != 0;
PFreflect = (value & 0x01) != 0;
PFscore = (value & 0x02) != 0;
ball.size = (byte)((value & 0x30) >> 4);
}
else if (maskedAddr == 0x0B) // REFP0
{
player0.reflect = ((value & 0x08) != 0);
}
else if (maskedAddr == 0x0C) // REFP1
{
player1.reflect = ((value & 0x08) != 0);
}
else if (maskedAddr == 0x0D) // PF0
{
PF = (UInt32)((PF & 0x0FFFF) + ((reverseBits(value) & 0x0F) << 16));
}
else if (maskedAddr == 0x0E) // PF1
{
PF = (UInt32)((PF & 0xF00FF) + (value << 8));
}
else if (maskedAddr == 0x0F) // PF2
{
PF = (PF & 0xFFF00) + reverseBits(value);
}
else if (maskedAddr == 0x10) // RESP0
{
player0.pos = (byte)(scanlinePos - 68 + 5);
}
else if (maskedAddr == 0x11) // RESP1
{
player1.pos = (byte)(scanlinePos - 68 + 5);
}
else if (maskedAddr == 0x14) // RESBL
{
ball.pos = (byte)(scanlinePos - 68 + 4);
}
else if (maskedAddr == 0x15) // AUDC0
{
audioEnabled = value != 0;
}
else if (maskedAddr == 0x17) // AUDF0
{
audioFreqDiv = (byte)(value + 1);
}
else if (maskedAddr == 0x1B) // GRP0
{
player0.grp = value;
player1.dgrp = player1.grp;
}
else if (maskedAddr == 0x1C) // GRP1
{
player1.grp = value;
player0.dgrp = player0.grp;
}
else if (maskedAddr == 0x1F) // ENABL
{
ball.enabled = (value & 0x02) != 0;
}
else if (maskedAddr == 0x20) // HMP0
{
player0.HM = (byte)((value & 0xF0) >> 4);
}
else if (maskedAddr == 0x21) // HMP1
{
player1.HM = (byte)((value & 0xF0) >> 4);
}
else if (maskedAddr == 0x24) // HMBL
{
ball.HM = (byte)((value & 0xF0) >> 4);
}
else if (maskedAddr == 0x25) // VDELP0
{
player0.delay = (value & 0x01) != 0;
}
else if (maskedAddr == 0x26) // VDELP1
{
player1.delay = (value & 0x01) != 0;
}
else if (maskedAddr == 0x2A) // HMOVE
{
player0.pos = (byte)(player0.pos + hmove[player0.HM]);
player1.pos = (byte)(player1.pos + hmove[player1.HM]);
ball.pos = (byte)(ball.pos + hmove[ball.HM]);
player0.HM = 0;
player1.HM = 0;
ball.HM = 0;
hmoveHappened = true;
}
else if (maskedAddr == 0x2C) // CXCLR
{
P0_collisions = 0;
P1_collisions = 0;
M0_collisions = 0;
M1_collisions = 0;
BL_collisions = 0;
}
}
public byte reverseBits(byte value)
{
byte result = 0x00;
for (int i = 0; i < 8; i++)
{
result = (byte)(result | (((value >> i) & 0x01 ) << (7-i)));
}
return result;
}
}
}