diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index a986e9fcda..1f9d4f18f4 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -636,6 +636,13 @@ Cheats.cs + + + UserControl + + + BreakpointControl.cs + Form @@ -643,6 +650,7 @@ GenericDebugger.cs + GenericDebugger.cs Form @@ -1227,6 +1235,9 @@ Cheats.cs + + BreakpointControl.cs + GenericDebugger.cs diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs b/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs new file mode 100644 index 0000000000..2e1b6c0351 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs @@ -0,0 +1,98 @@ +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Client.EmuHawk +{ + public class BreakpointList : List + { + public Action Callback { get; set; } + + public void Add(IDebuggable core, uint address, BreakpointType type) + { + Add(new Breakpoint(core, Callback, address, type)); + } + + public new void Clear() + { + foreach (var breakpoint in this) + { + breakpoint.Active = false; + } + + base.Clear(); + } + + // TODO: override all ways to remove + } + + public class Breakpoint + { + private bool _active; + private readonly IDebuggable _core; + + public Breakpoint(IDebuggable core, Action callBack, uint address, BreakpointType type, bool enabled = true) + { + _core = core; + + Callback = callBack; + Address = address; + Active = enabled; + + if (enabled) + { + AddCallback(); + } + } + + public Action Callback { get; set; } + public uint Address { get; set; } + public BreakpointType Type { get; set; } + + public bool Active + { + get + { + return _active; + } + + set + { + if (!value) + { + RemoveCallback(); + } + + if (!_active && value) // If inactive and changing to active + { + AddCallback(); + } + + _active = value; + } + } + + private void AddCallback() + { + switch (Type) + { + case BreakpointType.Read: + _core.MemoryCallbacks.AddRead(Callback, Address); + break; + case BreakpointType.Write: + _core.MemoryCallbacks.AddWrite(Callback, Address); + break; + case BreakpointType.Execute: + _core.MemoryCallbacks.AddExecute(Callback, Address); + break; + } + } + + private void RemoveCallback() + { + _core.MemoryCallbacks.Remove(Callback); + } + } +} diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.Designer.cs b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.Designer.cs new file mode 100644 index 0000000000..cb5935872f --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.Designer.cs @@ -0,0 +1,118 @@ +namespace BizHawk.Client.EmuHawk.tools.Debugger +{ + partial class BreakpointControl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.BreakpointView = new BizHawk.Client.EmuHawk.VirtualListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.AddBreakpointButton = new System.Windows.Forms.Button(); + this.RemoveBreakpointButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // BreakpointView + // + this.BreakpointView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BreakpointView.BlazingFast = false; + this.BreakpointView.CheckBoxes = true; + this.BreakpointView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2}); + this.BreakpointView.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.BreakpointView.FullRowSelect = true; + this.BreakpointView.GridLines = true; + this.BreakpointView.HideSelection = false; + this.BreakpointView.ItemCount = 0; + this.BreakpointView.Location = new System.Drawing.Point(0, 0); + this.BreakpointView.Name = "BreakpointView"; + this.BreakpointView.SelectAllInProgress = false; + this.BreakpointView.selectedItem = -1; + this.BreakpointView.Size = new System.Drawing.Size(193, 384); + this.BreakpointView.TabIndex = 5; + this.BreakpointView.TabStop = false; + this.BreakpointView.UseCompatibleStateImageBehavior = false; + this.BreakpointView.UseCustomBackground = true; + this.BreakpointView.View = System.Windows.Forms.View.Details; + // + // columnHeader1 + // + this.columnHeader1.Text = "Address"; + this.columnHeader1.Width = 85; + // + // columnHeader2 + // + this.columnHeader2.Text = "Type"; + this.columnHeader2.Width = 103; + // + // AddBreakpointButton + // + this.AddBreakpointButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.AddBreakpointButton.Location = new System.Drawing.Point(0, 387); + this.AddBreakpointButton.Name = "AddBreakpointButton"; + this.AddBreakpointButton.Size = new System.Drawing.Size(60, 23); + this.AddBreakpointButton.TabIndex = 6; + this.AddBreakpointButton.Text = "&Add"; + this.AddBreakpointButton.UseVisualStyleBackColor = true; + this.AddBreakpointButton.Click += new System.EventHandler(this.AddBreakpointButton_Click); + // + // RemoveBreakpointButton + // + this.RemoveBreakpointButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.RemoveBreakpointButton.Location = new System.Drawing.Point(130, 387); + this.RemoveBreakpointButton.Name = "RemoveBreakpointButton"; + this.RemoveBreakpointButton.Size = new System.Drawing.Size(60, 23); + this.RemoveBreakpointButton.TabIndex = 7; + this.RemoveBreakpointButton.Text = "&Remove"; + this.RemoveBreakpointButton.UseVisualStyleBackColor = true; + this.RemoveBreakpointButton.Click += new System.EventHandler(this.RemoveBreakpointButton_Click); + // + // BreakpointControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.RemoveBreakpointButton); + this.Controls.Add(this.AddBreakpointButton); + this.Controls.Add(this.BreakpointView); + this.Name = "BreakpointControl"; + this.Size = new System.Drawing.Size(193, 413); + this.Load += new System.EventHandler(this.BreakpointControl_Load); + this.ResumeLayout(false); + + } + + #endregion + + private VirtualListView BreakpointView; + public System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.Button AddBreakpointButton; + private System.Windows.Forms.Button RemoveBreakpointButton; + } +} diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs new file mode 100644 index 0000000000..32c4b0ef7f --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + +namespace BizHawk.Client.EmuHawk.tools.Debugger +{ + public partial class BreakpointControl : UserControl + { + public IDebuggable Core { get; set; } + public GenericDebugger ParentDebugger { get; set; } + private readonly BreakpointList Breakpoints = new BreakpointList(); + + public BreakpointControl() + { + InitializeComponent(); + BreakpointView.QueryItemText += BreakPointView_QueryItemText; + BreakpointView.VirtualMode = true; + Breakpoints.Callback = BreakpointCallback; + } + + private void BreakpointControl_Load(object sender, EventArgs e) + { + + } + + private void BreakPointView_QueryItemText(int index, int column, out string text) + { + text = string.Empty; + switch (column) + { + case 0: + text = string.Format("{0:X4}", Breakpoints[index].Address); + break; + case 1: + text = Breakpoints[index].Type.ToString(); + break; + } + } + + private void BreakpointCallback() + { + GlobalWin.MainForm.PauseEmulator(); + UpdateValues(); + } + + public void UpdateValues() + { + if (this.Enabled) + { + + } + } + + public void GenerateUI() + { + if (Core.MemoryCallbacksAvailable()) + { + // TODO: need a way to populate existing breakpoints + } + else + { + this.Enabled = false; + } + } + + public void Shutdown() + { + Breakpoints.Clear(); + } + + private void AddBreakpointButton_Click(object sender, EventArgs e) + { + var b = new AddBreakpointDialog(); // TODO: rename and move this widget + if (b.ShowDialog() == DialogResult.OK) + { + Breakpoints.Add(Core, b.Address, b.BreakType); + } + + BreakpointView.ItemCount = Breakpoints.Count; + UpdateBreakpointRemoveButton(); + } + + private IEnumerable SelectedIndices + { + get { return BreakpointView.SelectedIndices.Cast(); } + } + + private IEnumerable SelectedItems + { + get { return SelectedIndices.Select(index => Breakpoints[index]); } + } + + private void RemoveBreakpointButton_Click(object sender, EventArgs e) + { + if (BreakpointView.SelectedIndices.Count > 0) + { + var items = SelectedItems.ToList(); + if (items.Any()) + { + foreach (var item in items) + { + Breakpoints.Remove(item); + } + + BreakpointView.ItemCount = Breakpoints.Count; + UpdateBreakpointRemoveButton(); + } + } + } + + private void UpdateBreakpointRemoveButton() + { + RemoveBreakpointButton.Enabled = BreakpointView.SelectedIndices.Count > 0; + } + } +} diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.resx b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.resx new file mode 100644 index 0000000000..29dcb1b3a3 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs index d60c4720bb..0e68f2ef3e 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs @@ -45,9 +45,11 @@ this.RegistersGroupBox = new System.Windows.Forms.GroupBox(); this.RegisterPanel = new BizHawk.Client.EmuHawk.RegisterBoxControl(); this.BreakpointsGroupBox = new System.Windows.Forms.GroupBox(); + this.BreakPointControl1 = new BizHawk.Client.EmuHawk.tools.Debugger.BreakpointControl(); this.menuStrip1.SuspendLayout(); this.TracerBox.SuspendLayout(); this.RegistersGroupBox.SuspendLayout(); + this.BreakpointsGroupBox.SuspendLayout(); this.SuspendLayout(); // // menuStrip1 @@ -204,6 +206,7 @@ this.BreakpointsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.BreakpointsGroupBox.Controls.Add(this.BreakPointControl1); this.BreakpointsGroupBox.Location = new System.Drawing.Point(425, 267); this.BreakpointsGroupBox.Name = "BreakpointsGroupBox"; this.BreakpointsGroupBox.Size = new System.Drawing.Size(239, 281); @@ -211,6 +214,18 @@ this.BreakpointsGroupBox.TabStop = false; this.BreakpointsGroupBox.Text = "Breakpoints"; // + // BreakPointControl1 + // + this.BreakPointControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BreakPointControl1.Core = null; + this.BreakPointControl1.Location = new System.Drawing.Point(8, 19); + this.BreakPointControl1.Name = "BreakPointControl1"; + this.BreakPointControl1.ParentDebugger = null; + this.BreakPointControl1.Size = new System.Drawing.Size(225, 256); + this.BreakPointControl1.TabIndex = 0; + // // GenericDebugger // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -230,6 +245,7 @@ this.menuStrip1.PerformLayout(); this.TracerBox.ResumeLayout(false); this.RegistersGroupBox.ResumeLayout(false); + this.BreakpointsGroupBox.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -253,5 +269,6 @@ private System.Windows.Forms.GroupBox RegistersGroupBox; private RegisterBoxControl RegisterPanel; private System.Windows.Forms.GroupBox BreakpointsGroupBox; + private tools.Debugger.BreakpointControl BreakPointControl1; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs index 8fcb7bee35..9662511291 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs @@ -72,6 +72,10 @@ namespace BizHawk.Client.EmuHawk RegisterPanel.Core = Core; RegisterPanel.ParentDebugger = this; RegisterPanel.GenerateUI(); + + BreakPointControl1.Core = Core; + BreakPointControl1.ParentDebugger = this; + } catch (NotImplementedException) { @@ -82,6 +86,8 @@ namespace BizHawk.Client.EmuHawk private void DisengageDebugger() { SaveConfigSettings(); + + BreakPointControl1.Shutdown(); } private void UpdateTraceLog() @@ -103,13 +109,6 @@ namespace BizHawk.Client.EmuHawk } } - - - - - - - private void TraceView_QueryItemText(int index, int column, out string text) { text = index < _instructions.Count ? _instructions[index] : string.Empty;