Atari 2600

-Recast to run single cycle
-Remove frame buffer from state
-Always end frames on vsync boundary
This commit is contained in:
alyosha-tas 2017-09-20 10:27:27 -04:00 committed by GitHub
parent 0574013bd0
commit 30f1d61f7f
5 changed files with 73 additions and 199 deletions

View File

@ -21,7 +21,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
private IController _controller;
private int _frame;
private int _lastAddress;
private bool _frameStartPending = true;
private bool _leftDifficultySwitchPressed;
private bool _rightDifficultySwitchPressed;
@ -34,6 +33,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
internal byte[] Rom { get; }
internal int DistinctAccessCount { get; private set; }
// keeps track of tia cycles, 3 cycles per CPU cycle
private int cyc_counter;
private static MapperBase SetMultiCartMapper(int romLength, int gameTotal)
{
switch (romLength / gameTotal)
@ -319,17 +321,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
_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
HardReset();
// Show mapper class on romstatusdetails
CoreComm.RomStatusDetails = $"{this._game.Name}\r\nSHA1:{Rom.HashSHA1()}\r\nMD5:{Rom.HashMD5()}\r\nMapper Impl \"{_mapper.GetType()}\"";
// as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves.
// some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532
// executing a reset sequence at power on, but it's needed so let's hard code it for now
Cpu.S = 0xFD;
}
private bool _pal;
@ -349,96 +344,28 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
};
_tia.Reset();
_m6532 = new M6532(this);
Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC
// as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves.
// some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532
// executing a reset sequence at power on, but it's needed so let's hard code it for now
Cpu.S = 0xFD;
SetupMemoryDomains();
}
private void VFrameAdvance() // advance up to 500 lines looking for end of video frame
// after vsync falling edge, continues to end of next line
{
bool frameend = false;
_tia.FrameEndCallBack = (n) => frameend = true;
for (int i = 0; i < 500 && !frameend; i++)
{
ScanlineAdvance();
}
_tia.FrameEndCallBack = null;
}
private void StartFrameCond()
{
if (_frameStartPending)
{
_frame++;
_islag = true;
if (_controller.IsPressed("Power"))
{
HardReset();
}
if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld)
{
_leftDifficultySwitchPressed ^= true;
_leftDifficultySwitchHeld = true;
}
else if (!_controller.IsPressed("Toggle Left Difficulty"))
{
_leftDifficultySwitchHeld = false;
}
if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld)
{
_rightDifficultySwitchPressed ^= true;
_rightDifficultySwitchHeld = true;
}
else if (!_controller.IsPressed("Toggle Right Difficulty"))
{
_rightDifficultySwitchHeld = false;
}
_tia.BeginAudioFrame();
_frameStartPending = false;
}
}
private void FinishFrameCond()
{
if (_tia.LineCount >= _tia.NominalNumScanlines)
{
_tia.CompleteAudioFrame();
if (_islag)
{
_lagcount++;
}
_tia.LineCount = 0;
_frameStartPending = true;
}
cyc_counter = 0;
}
private void Cycle()
{
_tia.Execute(1);
_tia.Execute(1);
_tia.Execute(1);
_m6532.Timer.Tick();
if (Tracer.Enabled)
_tia.Execute();
cyc_counter++;
if (cyc_counter == 3)
{
Tracer.Put(Cpu.TraceState());
}
_m6532.Timer.Tick();
if (Tracer.Enabled)
{
Tracer.Put(Cpu.TraceState());
}
Cpu.ExecuteOne();
_mapper.ClockCpu();
Cpu.ExecuteOne();
_mapper.ClockCpu();
cyc_counter = 0;
}
}
internal byte ReadControls1(bool peek)

View File

@ -60,97 +60,18 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public bool CanStep(StepType type)
{
switch (type)
{
case StepType.Into:
case StepType.Out:
case StepType.Over:
return true;
default:
return false;
}
return false;
}
[FeatureNotImplemented]
public void Step(StepType type)
{
switch (type)
{
case StepType.Into:
StepInto();
break;
case StepType.Out:
StepOut();
break;
case StepType.Over:
StepOver();
break;
}
throw new NotImplementedException();
}
public int TotalExecutedCycles => Cpu.TotalExecutedCycles;
private void StepInto()
{
do
{
CycleAdvance();
} while (!Cpu.AtStart);
}
private void StepOver()
{
var instruction = Cpu.PeekMemory(Cpu.PC);
if (instruction == JSR)
{
var destination = Cpu.PC + opsize[JSR];
while (Cpu.PC != destination)
{
StepInto();
}
}
else
{
StepInto();
}
}
private void StepOut()
{
var instruction = Cpu.PeekMemory(Cpu.PC);
JSRCount = instruction == JSR ? 1 : 0;
var bailOutFrame = Frame + 1;
while (true)
{
StepInto();
var instr = Cpu.PeekMemory(Cpu.PC);
if (instr == JSR)
{
JSRCount++;
}
else if (instr == RTS && JSRCount <= 0)
{
StepInto();
JSRCount = 0;
break;
}
else if (instr == RTS)
{
JSRCount--;
}
else // Emergency bail out logic
{
if (Frame == bailOutFrame)
{
break;
}
}
}
}
private int JSRCount = 0;
private const byte JSR = 0x20;
@ -212,22 +133,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
#region Currently Unused Debug hooks
private void ScanlineAdvance()
{
StartFrameCond();
int currentLine = _tia.LineCount;
while (_tia.LineCount == currentLine)
Cycle();
FinishFrameCond();
}
private void CycleAdvance()
{
StartFrameCond();
Cycle();
FinishFrameCond();
}
private int CurrentScanLine
{
get { return _tia.LineCount; }

View File

@ -12,18 +12,53 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
_controller = controller;
StartFrameCond();
while (_tia.LineCount < _tia.NominalNumScanlines)
_frame++;
_islag = true;
// Handle all the console controls here
if (_controller.IsPressed("Power"))
{
HardReset();
}
if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld)
{
_leftDifficultySwitchPressed ^= true;
_leftDifficultySwitchHeld = true;
}
else if (!_controller.IsPressed("Toggle Left Difficulty"))
{
_leftDifficultySwitchHeld = false;
}
if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld)
{
_rightDifficultySwitchPressed ^= true;
_rightDifficultySwitchHeld = true;
}
else if (!_controller.IsPressed("Toggle Right Difficulty"))
{
_rightDifficultySwitchHeld = false;
}
while (!_tia.New_Frame)
{
Cycle();
}
_tia.New_Frame = false;
if (rendersound == false)
{
_tia.AudioClocks = 0; // we need this here since the async sound provider won't check in this case
}
FinishFrameCond();
if (_islag)
{
_lagcount++;
}
_tia.LineCount = 0;
}
public int Frame => _frame;

View File

@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
ser.Sync("Lag", ref _lagcount);
ser.Sync("Frame", ref _frame);
ser.Sync("IsLag", ref _islag);
ser.Sync("frameStartPending", ref _frameStartPending);
ser.Sync("cyc_counter", ref cyc_counter);
ser.Sync("leftDifficultySwitchPressed", ref _leftDifficultySwitchPressed);
ser.Sync("rightDifficultySwitchPressed", ref _rightDifficultySwitchPressed);
ser.Sync("leftDifficultySwitchHeld", ref _leftDifficultySwitchHeld);

View File

@ -102,18 +102,25 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// give the emu a minimal of input\output connections so it doesn't crash
var comm = new CoreComm(null, null);
// here we advance past start up irregularities to see how long a frame is based on calls to Vsync
// we run 72 frames, then run 270 scanlines worth of cycles.
// if we don't hit a new frame, we can be pretty confident we are in PAL
using (Atari2600 emu = new Atari2600(new CoreComm(null, null), newgame, rom, null, null))
{
List<int> framecounts = new List<int>();
emu._tia.FrameEndCallBack = (i) => framecounts.Add(i);
for (int i = 0; i < 71; i++) // run for 71 * 262 lines, since we're in NTSC mode
for (int i = 0; i < 72; i++)
{
emu.FrameAdvance(NullController.Instance, false, false);
}
int numpal = framecounts.Count((i) => i > 287);
bool pal = numpal >= 25;
Console.WriteLine("PAL Detection: {0} lines, {1}", numpal, pal);
for (int i = 0; i < 61560; i++)
{
emu.Cycle();
}
bool pal = !emu._tia.New_Frame;
Console.WriteLine("PAL Detection: {0}", pal);
return pal;
}
}