BizHawk/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IDebuggable.cs

211 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Computers.AppleII
{
public partial class AppleII : IDebuggable
{
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
{
var regs = _machine.GetCpuFlagsAndRegisters();
var dic = new Dictionary<string, RegisterValue>();
foreach (var reg in regs)
{
dic.Add(
reg.Key,
reg.Key.Contains("Flag")
? reg.Value > 0
: getRegisterValue(reg));
}
return dic;
}
private RegisterValue getRegisterValue(KeyValuePair<string, int> reg)
{
switch (reg.Key)
{
case "A":
case "X":
case "Y":
case "S":
return (byte)reg.Value;
case "PC":
return (ushort)reg.Value;
default:
return reg.Value;
}
}
public void SetCpuRegister(string register, int value)
{
switch (register)
{
default:
throw new InvalidOperationException();
case "A":
_machine.Cpu.RA = (byte)value;
break;
case "X":
_machine.Cpu.RX = (byte)value;
break;
case "Y":
_machine.Cpu.RY = (byte)value;
break;
case "S":
_machine.Cpu.RS = (byte)value;
break;
case "PC":
_machine.Cpu.RPC = (ushort)value;
break;
case "Flag C":
_machine.Cpu.FlagC = value > 0;
break;
case "Flag Z":
_machine.Cpu.FlagZ = value > 0;
break;
case "Flag I":
_machine.Cpu.FlagI = value > 0;
break;
case "Flag D":
_machine.Cpu.FlagD = value > 0;
break;
case "Flag B":
_machine.Cpu.FlagB = value > 0;
break;
case "Flag T":
_machine.Cpu.FlagT = value > 0;
break;
case "Flag V":
_machine.Cpu.FlagV = value > 0;
break;
case "Flag N":
_machine.Cpu.FlagV = value > 0;
break;
}
}
public bool CanStep(StepType type)
{
switch (type)
{
case StepType.Into:
case StepType.Over:
case StepType.Out:
return true;
default:
return false;
}
}
public void Step(StepType type)
{
switch (type)
{
case StepType.Into:
StepInto();
break;
case StepType.Out:
StepOut();
break;
case StepType.Over:
StepOver();
break;
}
}
private void StepInto()
{
if (Tracer.Enabled)
_machine.Cpu.TraceCallback = (s) => TracerWrapper(s);
else
_machine.Cpu.TraceCallback = null;
var machineInVblank = _machine.Video.IsVBlank;
_machine.Events.HandleEvents(_machine.Cpu.Execute());
if (!machineInVblank && _machine.Video.IsVBlank) // Check if a frame has passed while stepping
{
Frame++;
if (_machine.Lagged)
{
LagCount++;
}
_machine.Lagged = true;
_machine.DriveLight = false;
}
}
private void StepOver()
{
var instruction = _machine.Memory.Read(_machine.Cpu.RPC);
if (instruction == JSR)
{
var destination = _machine.Cpu.RPC + JSRSize;
while (_machine.Cpu.RPC != destination)
{
StepInto();
}
}
else
{
StepInto();
}
}
private void StepOut()
{
var instr = _machine.Memory.Read(_machine.Cpu.RPC);
JSRCount = instr == JSR ? 1 : 0;
var bailOutFrame = Frame + 1;
while (true)
{
StepInto();
instr = _machine.Memory.Read(_machine.Cpu.RPC);
if (instr == JSR)
{
JSRCount++;
}
else if (instr == RTS && JSRCount <= 0)
{
StepInto();
JSRCount = 0;
break;
}
else if (instr == RTS)
{
JSRCount--;
}
else //Emergency Bailout Logic
{
if (Frame == bailOutFrame)
{
break;
}
}
}
}
private int JSRCount = 0;
private const byte JSR = 0x20;
private const byte RTS = 0x60;
private const byte JSRSize = 3;
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
}
}