2015-08-02 22:19:12 -04:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Drawing;
|
2017-09-08 15:56:14 -04:00
|
|
|
|
using System.Globalization;
|
2015-08-02 22:19:12 -04:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using Mesen.GUI.Forms;
|
|
|
|
|
|
|
|
|
|
namespace Mesen.GUI.Debugger
|
|
|
|
|
{
|
|
|
|
|
public partial class frmBreakpoint : BaseConfigForm
|
|
|
|
|
{
|
|
|
|
|
public frmBreakpoint(Breakpoint breakpoint)
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
Entity = breakpoint;
|
|
|
|
|
|
2016-01-09 13:15:43 -05:00
|
|
|
|
if(breakpoint.Type >= BreakpointType.ReadVram) {
|
|
|
|
|
radPpu.Checked = true;
|
|
|
|
|
} else {
|
|
|
|
|
radCpu.Checked = true;
|
|
|
|
|
}
|
2015-08-02 22:19:12 -04:00
|
|
|
|
|
2016-12-04 12:21:20 -05:00
|
|
|
|
switch(breakpoint.AddressType) {
|
|
|
|
|
case BreakpointAddressType.AnyAddress: radAnyAddress.Checked = true; break;
|
|
|
|
|
case BreakpointAddressType.SingleAddress: radSpecificAddress.Checked = true; break;
|
|
|
|
|
case BreakpointAddressType.AddressRange: radRange.Checked = true; break;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-02 22:19:12 -04:00
|
|
|
|
AddBinding("Enabled", chkEnabled);
|
2016-01-09 13:15:43 -05:00
|
|
|
|
AddBinding("IsAbsoluteAddress", chkAbsolute);
|
2015-08-02 22:19:12 -04:00
|
|
|
|
AddBinding("Address", txtAddress);
|
2016-12-04 12:21:20 -05:00
|
|
|
|
AddBinding("StartAddress", txtFrom);
|
|
|
|
|
AddBinding("EndAddress", txtTo);
|
2016-01-09 13:15:43 -05:00
|
|
|
|
AddBinding("BreakOnRead", chkRead);
|
|
|
|
|
AddBinding("BreakOnWrite", chkWrite);
|
|
|
|
|
AddBinding("BreakOnExec", chkExec);
|
|
|
|
|
AddBinding("BreakOnReadVram", chkReadVram);
|
|
|
|
|
AddBinding("BreakOnWriteVram", chkWriteVram);
|
|
|
|
|
AddBinding("Condition", txtCondition);
|
|
|
|
|
|
2016-12-04 11:40:31 -05:00
|
|
|
|
this.toolTip.SetToolTip(this.picExpressionWarning, "Condition contains invalid syntax or symbols.");
|
|
|
|
|
|
2016-01-09 13:15:43 -05:00
|
|
|
|
this.toolTip.SetToolTip(this.chkAbsolute, "Check to set an absolute address based on the exact address in PRG/CHR ROM (not CPU/PPU memory)");
|
2017-08-05 12:13:53 -04:00
|
|
|
|
this.toolTip.SetToolTip(this.picHelp, frmBreakpoint.GetConditionTooltip(false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string GetConditionTooltip(bool forWatch)
|
|
|
|
|
{
|
|
|
|
|
string tooltip =
|
2016-06-05 11:51:46 -04:00
|
|
|
|
"Most expressions/operators are accepted (C++ syntax)." + Environment.NewLine +
|
2017-08-05 12:13:53 -04:00
|
|
|
|
"Note: Use the $ prefix to denote hexadecimal values." + Environment.NewLine +
|
2016-11-22 18:28:59 -05:00
|
|
|
|
"Note 2: Labels assigned to the code can be used (their value will match the label's address in CPU memory)." + Environment.NewLine + Environment.NewLine +
|
2016-06-05 11:51:46 -04:00
|
|
|
|
"A/X/Y/PS/SP: Value of registers" + Environment.NewLine +
|
2017-04-30 20:40:09 -04:00
|
|
|
|
"PC: Program Counter" + Environment.NewLine +
|
|
|
|
|
"OpPC: Address of the current instruction's first byte" + Environment.NewLine +
|
2016-06-05 11:51:46 -04:00
|
|
|
|
"Irq/Nmi: True if the Irq/Nmi flags are set" + Environment.NewLine +
|
|
|
|
|
"Cycle/Scanline: Current cycle (0-340)/scanline(-1 to 260) of the PPU" + Environment.NewLine +
|
2017-04-30 20:40:09 -04:00
|
|
|
|
"Frame: PPU frame number (since power on/reset)" + Environment.NewLine +
|
2016-06-05 11:51:46 -04:00
|
|
|
|
"Value: Current value being read/written from/to memory" + Environment.NewLine +
|
2017-08-05 12:13:53 -04:00
|
|
|
|
"IsRead: True if the CPU is reading from a memory address" + Environment.NewLine +
|
|
|
|
|
"IsWrite: True if the CPU is writing to a memory address" + Environment.NewLine;
|
|
|
|
|
|
|
|
|
|
if(!forWatch) {
|
|
|
|
|
tooltip +=
|
|
|
|
|
"Address: Current CPU memory address being read/written" + Environment.NewLine +
|
|
|
|
|
"RomAddress: Current ROM address being read/written" + Environment.NewLine;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tooltip +=
|
2016-11-22 16:56:23 -05:00
|
|
|
|
"[<address>]: (Byte) Memory value at <address> (CPU)" + Environment.NewLine +
|
|
|
|
|
"{<address>}: (Word) Memory value at <address> (CPU)" + Environment.NewLine + Environment.NewLine +
|
2016-06-05 11:51:46 -04:00
|
|
|
|
|
|
|
|
|
"Examples:" + Environment.NewLine +
|
|
|
|
|
"a == 10 || x == $23" + Environment.NewLine +
|
|
|
|
|
"scanline == 10 && (cycle >= 55 && cycle <= 100)" + Environment.NewLine +
|
|
|
|
|
"x == [$150] || y == [10]" + Environment.NewLine +
|
2016-12-04 10:29:36 -05:00
|
|
|
|
"[[$15] + y] -> Reads the value at address $15, adds Y to it and reads the value at the resulting address." + Environment.NewLine +
|
2017-08-05 12:13:53 -04:00
|
|
|
|
"{$FFFA} -> Returns the NMI handler's address.";
|
|
|
|
|
|
|
|
|
|
return tooltip;
|
2016-01-09 13:15:43 -05:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-04 12:21:20 -05:00
|
|
|
|
protected override void UpdateConfig()
|
|
|
|
|
{
|
|
|
|
|
base.UpdateConfig();
|
|
|
|
|
|
|
|
|
|
if(radAnyAddress.Checked) {
|
|
|
|
|
((Breakpoint)Entity).AddressType = BreakpointAddressType.AnyAddress;
|
|
|
|
|
} else if(radSpecificAddress.Checked) {
|
|
|
|
|
((Breakpoint)Entity).AddressType = BreakpointAddressType.SingleAddress;
|
|
|
|
|
} else if(radRange.Checked) {
|
|
|
|
|
((Breakpoint)Entity).AddressType = BreakpointAddressType.AddressRange;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-09 13:15:43 -05:00
|
|
|
|
protected override bool ValidateInput()
|
|
|
|
|
{
|
2016-12-04 11:40:31 -05:00
|
|
|
|
if(txtCondition.Text.Length > 0) {
|
|
|
|
|
EvalResultType resultType;
|
|
|
|
|
InteropEmu.DebugEvaluateExpression(txtCondition.Text, out resultType);
|
|
|
|
|
if(resultType == EvalResultType.Invalid) {
|
|
|
|
|
picExpressionWarning.Visible = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
picExpressionWarning.Visible = false;
|
|
|
|
|
|
2017-09-08 15:56:14 -04:00
|
|
|
|
if(radRange.Checked) {
|
|
|
|
|
int start = 0, end = 0;
|
|
|
|
|
int.TryParse(txtFrom.Text, NumberStyles.HexNumber, null, out start);
|
|
|
|
|
int.TryParse(txtTo.Text, NumberStyles.HexNumber, null, out end);
|
|
|
|
|
if(end < start) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-09 13:15:43 -05:00
|
|
|
|
return chkRead.Checked || chkWrite.Checked || chkExec.Checked || chkReadVram.Checked || chkWriteVram.Checked || txtCondition.Text.Length > 0;
|
2015-08-02 22:19:12 -04:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-09 13:15:43 -05:00
|
|
|
|
private void txtAddress_Enter(object sender, EventArgs e)
|
2015-08-02 22:19:12 -04:00
|
|
|
|
{
|
2016-01-09 13:15:43 -05:00
|
|
|
|
radSpecificAddress.Checked = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void chkWriteVram_Enter(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
radPpu.Checked = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void chkRead_Enter(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
radCpu.Checked = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void radCpu_CheckedChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if(radCpu.Checked) {
|
|
|
|
|
chkReadVram.Checked = false;
|
|
|
|
|
chkWriteVram.Checked = false;
|
2015-08-02 22:19:12 -04:00
|
|
|
|
}
|
2016-01-09 13:15:43 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void radPpu_CheckedChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if(radPpu.Checked) {
|
|
|
|
|
chkRead.Checked = false;
|
|
|
|
|
chkWrite.Checked = false;
|
|
|
|
|
chkExec.Checked = false;
|
2015-08-02 22:19:12 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-04 12:21:20 -05:00
|
|
|
|
|
|
|
|
|
private void txtFrom_Enter(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
radRange.Checked = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void txtTo_Enter(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
radRange.Checked = true;
|
|
|
|
|
}
|
2015-08-02 22:19:12 -04:00
|
|
|
|
}
|
|
|
|
|
}
|