Atari 2600
-Recast to run single cycle -Remove frame buffer from state -Always end frames on vsync boundary
This commit is contained in:
parent
0574013bd0
commit
30f1d61f7f
|
@ -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)
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue