diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 5d26ad5bae..d3a8627e57 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -177,6 +177,7 @@ + diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs index 141f1c916d..0b3b964b1c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs @@ -11,6 +11,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private TIA _tia; private DCFilter _dcfilter; private MapperBase _mapper; + private bool _hardResetSignal; + public byte[] Ram; public byte[] Rom { get; private set; } @@ -117,7 +119,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private static MapperBase SetMultiCartMapper(int romLength, int gameTotal) { - switch(romLength / gameTotal) + switch (romLength / gameTotal) { case 1024 * 2: // 2K return new Multicart2K(gameTotal); @@ -296,8 +298,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC } - private bool _hardResetSignal; - public void FrameAdvance(bool render, bool rendersound) { _frame++; @@ -308,6 +308,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { CycleAdvance(); } + _tia.CompleteAudioFrame(); if (_hardResetSignal) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Settings.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Settings.cs new file mode 100644 index 0000000000..5796820805 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Settings.cs @@ -0,0 +1,141 @@ +using System; +using System.ComponentModel; + +using Newtonsoft.Json; + +namespace BizHawk.Emulation.Cores.Atari.Atari2600 +{ + public partial class Atari2600 + { + 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 class A2600Settings + { + [JsonIgnore] + private int _ntscTopLine = 24; + + [JsonIgnore] + private int _ntscBottomLine = 248; + + [JsonIgnore] + private int _palTopLine = 24; + + [JsonIgnore] + private int _palBottomLine = 296; + + [Description("Sets whether or not the Background layer will be displayed")] + public bool ShowBG { get; set; } + + [Description("Sets whether or not the Player 1 layer will be displayed")] + public bool ShowPlayer1 { get; set; } + + [Description("Sets whether or not the Player 2 layer will be displayed")] + public bool ShowPlayer2 { get; set; } + + [Description("Sets whether or not the Missle 1 layer will be displayed")] + public bool ShowMissle1 { get; set; } + + [Description("Sets whether or not the Missle 2 layer will be displayed")] + public bool ShowMissle2 { get; set; } + + [Description("Sets whether or not the Ball layer will be displayed")] + public bool ShowBall { get; set; } + + [Description("Sets whether or not the Playfield layer will be displayed")] + public bool ShowPlayfield { get; set; } + + public int NTSCTopLine + { + get { return this._ntscTopLine; } + set { _ntscTopLine = Math.Min(64, Math.Max(value, 0)); } + } + + public int NTSCBottomLine + { + get { return _ntscBottomLine; } + set { _ntscBottomLine = Math.Min(260, Math.Max(value, 192)); } + } + + public int PALTopLine + { + get { return this._palTopLine; } + set { this._palTopLine = Math.Min(64, Math.Max(value, 0)); } + } + + public int PALBottomLine + { + get { return this._palBottomLine; } + set { this._palBottomLine = Math.Min(310, Math.Max(value, 192)); } + } + + public int BackgroundColor { get; set; } + + public A2600Settings Clone() + { + return (A2600Settings)MemberwiseClone(); + } + + public static A2600Settings GetDefaults() + { + return new A2600Settings + { + ShowBG = true, + ShowPlayer1 = true, + ShowPlayer2 = true, + ShowMissle1 = true, + ShowMissle2 = true, + ShowBall = true, + ShowPlayfield = true, + BackgroundColor = 0 + }; + } + } + + public class A2600SyncSettings + { + [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; } + + public A2600SyncSettings Clone() + { + return (A2600SyncSettings)MemberwiseClone(); + } + + public static A2600SyncSettings GetDefaults() + { + return new A2600SyncSettings + { + BW = false, + LeftDifficulty = true, + RightDifficulty = true + }; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs index bf1b1bcccc..02bc0f3427 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs @@ -1,14 +1,11 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IO; using System.Linq; using BizHawk.Common; using BizHawk.Emulation.Common; -using Newtonsoft.Json; - namespace BizHawk.Emulation.Cores.Atari.Atari2600 { [CoreAttributes( @@ -167,7 +164,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 }; } - // TODO: rewrite GetCpuFlagsAndRegisters this way public Dictionary GetCpuFlagsAndRegisters() { return new Dictionary @@ -256,118 +252,5 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } 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 class A2600Settings - { - // todo: descriptions - public bool ShowBG { get; set; } - public bool ShowPlayer1 { get; set; } - public bool ShowPlayer2 { get; set; } - public bool ShowMissle1 { get; set; } - public bool ShowMissle2 { get; set; } - public bool ShowBall { get; set; } - public bool ShowPlayfield { get; set; } - - public int NTSCTopLine - { - get { return _NTSCTopLine; } - set { _NTSCTopLine = Math.Min(64, Math.Max(value, 0)); } - } - public int NTSCBottomLine - { - get { return _NTSCBottomLine; } - set { _NTSCBottomLine = Math.Min(260, Math.Max(value, 192)); } - } - [JsonIgnore] - private int _NTSCTopLine = 24; - [JsonIgnore] - private int _NTSCBottomLine = 248; - - public int PALTopLine - { - get { return _PALTopLine; } - set { _PALTopLine = Math.Min(64, Math.Max(value, 0)); } - } - public int PALBottomLine - { - get { return _PALBottomLine; } - set { _PALBottomLine = Math.Min(310, Math.Max(value, 192)); } - } - [JsonIgnore] - private int _PALTopLine = 24; - [JsonIgnore] - private int _PALBottomLine = 296; - - public int BackgroundColor { get; set; } - - public A2600Settings Clone() - { - return (A2600Settings)MemberwiseClone(); - } - - public static A2600Settings GetDefaults() - { - return new A2600Settings - { - ShowBG = true, - ShowPlayer1 = true, - ShowPlayer2 = true, - ShowMissle1 = true, - ShowMissle2 = true, - ShowBall = true, - ShowPlayfield = true, - BackgroundColor = 0 - }; - } - } - - public class A2600SyncSettings - { - [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; } - - public A2600SyncSettings Clone() - { - return (A2600SyncSettings)MemberwiseClone(); - } - - public static A2600SyncSettings GetDefaults() - { - return new A2600SyncSettings - { - BW = false, - LeftDifficulty = true, - RightDifficulty = true - }; - } - } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs index 1e3660d77f..bd79a7f975 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs @@ -8,6 +8,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // Emulates the TIA public partial class TIA : IVideoProvider, ISoundProvider { + private const int ScreenWidth = 160; + private const int MaxScreenHeight = 312; + private const byte CXP0 = 0x01; private const byte CXP1 = 0x02; private const byte CXM0 = 0x04; @@ -90,25 +93,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 get { return _vsyncEnabled; } } - public void Reset() - { - _hsyncCnt = 0; - _capChargeStart = 0; - _capCharging = false; - _vblankEnabled = false; - _vsyncEnabled = false; - _scanline = new uint[160]; - - _player0 = new PlayerData(); - _player1 = new PlayerData(); - _playField = new PlayfieldData(); - _hmove = new HMoveData(); - _ball = new BallData(); - - _player0.ScanCnt = 8; - _player1.ScanCnt = 8; - } - public bool FrameComplete { get; set; } public int MaxVolume { get; set; } @@ -148,6 +132,25 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 return FrameBuffer; } + public void Reset() + { + _hsyncCnt = 0; + _capChargeStart = 0; + _capCharging = false; + _vblankEnabled = false; + _vsyncEnabled = false; + _scanline = new uint[160]; + + _player0 = new PlayerData(); + _player1 = new PlayerData(); + _playField = new PlayfieldData(); + _hmove = new HMoveData(); + _ball = new BallData(); + + _player0.ScanCnt = 8; + _player1.ScanCnt = 8; + } + // Execute TIA cycles public void Execute(int cycles) { @@ -480,9 +483,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public int[] FrameBuffer = new int[ScreenWidth * MaxScreenHeight]; - private const int ScreenWidth = 160; - private const int MaxScreenHeight = 312; - public void OutputFrame() { var topLine = _core.Settings.NTSCTopLine; @@ -870,12 +870,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 return result; } - // ========================================================================= - // Audio bits - // ========================================================================= + #region Audio bits - enum AudioRegister : byte { AUDC, AUDF, AUDV } - struct QueuedCommand + private enum AudioRegister : byte { AUDC, AUDF, AUDV } + private struct QueuedCommand { public int Time; public byte Channel; @@ -883,8 +881,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public byte Value; } - int frameStartCycles, frameEndCycles; - Queue commands = new Queue(4096); + private int frameStartCycles, frameEndCycles; + private Queue commands = new Queue(4096); public void BeginAudioFrame() { @@ -896,18 +894,24 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 frameEndCycles = _core.Cpu.TotalExecutedCycles; } - void WriteAudio(byte channel, AudioRegister register, byte value) + private void WriteAudio(byte channel, AudioRegister register, byte value) { commands.Enqueue(new QueuedCommand { Channel = channel, Register = register, Value = value, Time = _core.Cpu.TotalExecutedCycles - frameStartCycles }); } - void ApplyAudioCommand(QueuedCommand cmd) + private void ApplyAudioCommand(QueuedCommand cmd) { switch (cmd.Register) { - case AudioRegister.AUDC: AUD[cmd.Channel].AUDC = cmd.Value; break; - case AudioRegister.AUDF: AUD[cmd.Channel].AUDF = cmd.Value; break; - case AudioRegister.AUDV: AUD[cmd.Channel].AUDV = cmd.Value; break; + case AudioRegister.AUDC: + AUD[cmd.Channel].AUDC = cmd.Value; + break; + case AudioRegister.AUDF: + AUD[cmd.Channel].AUDF = cmd.Value; + break; + case AudioRegister.AUDV: + AUD[cmd.Channel].AUDV = cmd.Value; + break; } } @@ -917,22 +921,25 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 int elapsedCycles = frameEndCycles - frameStartCycles; if (elapsedCycles == 0) + { elapsedCycles = 1; // better than diving by zero + } int start = 0; while (commands.Count > 0) { var cmd = commands.Dequeue(); - int pos = ((cmd.Time * samples31khz.Length) / elapsedCycles); + int pos = (cmd.Time * samples31khz.Length) / elapsedCycles; pos = Math.Min(pos, samples31khz.Length); // sometimes the cpu timestamp of the write is > frameEndCycles GetSamplesImmediate(samples31khz, start, pos - start); start = pos; ApplyAudioCommand(cmd); } + GetSamplesImmediate(samples31khz, start, samples31khz.Length - start); // convert from 31khz to 44khz - for (int i = 0; i < samples.Length / 2; i++) + for (var i = 0; i < samples.Length / 2; i++) { samples[i * 2] = samples31khz[(int)(((double)samples31khz.Length / (double)(samples.Length / 2)) * i)]; samples[(i * 2) + 1] = samples[i * 2]; @@ -941,7 +948,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public void GetSamplesImmediate(short[] samples, int start, int len) { - for (int i = start; i < start + len; i++) + for (var i = start; i < start + len; i++) { samples[i] += AUD[0].Cycle(); samples[i] += AUD[1].Cycle(); @@ -953,8 +960,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 commands.Clear(); } - // ========================================================================= - + #endregion + public void SyncState(Serializer ser) { ser.BeginSection("TIA");