using System; using System.Text; namespace Mesen.GUI.Debugger { public class Breakpoint { private SnesMemoryType _memoryType = SnesMemoryType.CpuMemory; private bool _isCpuBreakpoint = true; public bool BreakOnRead = false; public bool BreakOnWrite = false; public bool BreakOnExec = true; public bool Enabled = true; public bool MarkEvent = false; public UInt32 Address = UInt32.MaxValue; public UInt32 StartAddress; public UInt32 EndAddress; public BreakpointAddressType AddressType = BreakpointAddressType.SingleAddress; public string Condition = ""; public SnesMemoryType MemoryType { get { return _memoryType; } set { _memoryType = value; _isCpuBreakpoint = IsTypeCpuBreakpoint(value); } } public string GetAddressString(bool showLabel) { string addr = ""; switch(AddressType) { case BreakpointAddressType.AnyAddress: return ""; case BreakpointAddressType.SingleAddress: if(IsAbsoluteAddress) { addr += $"[${Address.ToString("X6")}]"; } else { addr = $"${Address.ToString("X6")}"; } break; case BreakpointAddressType.AddressRange: if(IsAbsoluteAddress) { addr = $"[${StartAddress.ToString("X6")}] - [${EndAddress.ToString("X6")}]"; } else { addr = $"${StartAddress.ToString("X6")} - ${EndAddress.ToString("X6")}"; } break; } //TODO LABELS /*string label = GetAddressLabel(); if(showLabel && !string.IsNullOrWhiteSpace(label)) { addr = label + $", {addr}"; }*/ return addr; } public static bool IsTypeCpuBreakpoint(SnesMemoryType type) { return ( type == SnesMemoryType.CpuMemory || type == SnesMemoryType.WorkRam || type == SnesMemoryType.SaveRam || type == SnesMemoryType.PrgRom ); } public void SetEnabled(bool enabled) { Enabled = enabled; BreakpointManager.RefreshBreakpoints(this); } public void SetMarked(bool marked) { MarkEvent = marked; BreakpointManager.RefreshBreakpoints(this); } public bool IsAbsoluteAddress { get { return MemoryType != SnesMemoryType.CpuMemory; } } public bool IsCpuBreakpoint { get { return this._isCpuBreakpoint; } } private BreakpointTypeFlags Type { get { BreakpointTypeFlags type = BreakpointTypeFlags.None; if(BreakOnRead) { type |= BreakpointTypeFlags.Read; } if(BreakOnWrite) { type |= BreakpointTypeFlags.Write; } if(BreakOnExec && IsCpuBreakpoint) { type |= BreakpointTypeFlags.Execute; } return type; } } public string ToReadableType() { string type; switch(MemoryType) { default: throw new Exception("invalid type"); case SnesMemoryType.CpuMemory: type = "CPU"; break; case SnesMemoryType.PrgRom: type = "PRG"; break; case SnesMemoryType.WorkRam: type = "WRAM"; break; case SnesMemoryType.SaveRam: type = "SRAM"; break; case SnesMemoryType.VideoRam: type = "VRAM"; break; case SnesMemoryType.SpriteRam: type = "OAM"; break; case SnesMemoryType.CGRam: type = "CG"; break; } type += ":"; type += BreakOnRead ? "R" : "‒"; type += BreakOnWrite ? "W" : "‒"; if(IsCpuBreakpoint) { type += BreakOnExec ? "X" : "‒"; } return type; } public int GetRelativeAddress() { UInt32 address = AddressType == BreakpointAddressType.SingleAddress ? this.Address : this.StartAddress; if(IsCpuBreakpoint && this.IsAbsoluteAddress) { //TODO //return InteropEmu.DebugGetRelativeAddress(address, this.MemoryType.ToAddressType()); return -1; } else { return (int)address; } } private int GetRelativeAddressEnd() { if(this.AddressType == BreakpointAddressType.AddressRange){ if(IsCpuBreakpoint && this.IsAbsoluteAddress) { //TODO //return InteropEmu.DebugGetRelativeAddress(this.EndAddress, this.MemoryType.ToAddressType()); } else { return (int)this.EndAddress; } } return -1; } public bool Matches(UInt32 address, SnesMemoryType type) { if(IsTypeCpuBreakpoint(type) != this.IsCpuBreakpoint) { return false; } bool isRelativeMemory = type == SnesMemoryType.CpuMemory; if(this.AddressType == BreakpointAddressType.SingleAddress) { return address == this.Address && type == this.MemoryType; } else if(this.AddressType == BreakpointAddressType.AddressRange) { return address >= this.StartAddress && address <= this.EndAddress && type == this.MemoryType; } return false; } public InteropBreakpoint ToInteropBreakpoint(int breakpointId) { InteropBreakpoint bp = new InteropBreakpoint() { Id = breakpointId, MemoryType = MemoryType, Type = Type, MarkEvent = MarkEvent, Enabled = Enabled }; switch(AddressType) { case BreakpointAddressType.AnyAddress: bp.StartAddress = -1; bp.EndAddress = -1; break; case BreakpointAddressType.SingleAddress: bp.StartAddress = (Int32)Address; bp.EndAddress = -1; break; case BreakpointAddressType.AddressRange: bp.StartAddress = (Int32)StartAddress; bp.EndAddress = (Int32)EndAddress; break; } bp.Condition = new byte[1000]; byte[] condition = Encoding.UTF8.GetBytes(Condition.Replace(Environment.NewLine, " ")); Array.Copy(condition, bp.Condition, condition.Length); return bp; } } public enum BreakpointAddressType { AnyAddress, SingleAddress, AddressRange, } [Flags] public enum BreakpointTypeFlags { None = 0, Execute = 1, Read = 2, Write = 4, } }