Add `NeoWatch` with pointer deref, also supporting every width+display

This commit is contained in:
YoshiRulz 2025-03-27 04:14:48 +10:00
parent b2a0ad0857
commit 1c69215815
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
3 changed files with 217 additions and 12 deletions

View File

@ -0,0 +1,148 @@
using System.Collections.Generic;
using System.Linq.Expressions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
/// <summary>an extremely versatile implementation (pointers!), but with presumably lower performance</summary>
public sealed class NeoWatch : Watch
{
private static long CollapseAddress(long address, MemoryDomain domain)
=> address;
private Expression _addressAST;
private uint _previous;
private uint _value;
private Watch _wrapped;
public override string AddressString
=> _addressAST.ToString();
public override string Diff
=> $"{_value - (long) _previous:+#;-#;0}";
public override uint Previous
=> _previous;
public override string PreviousStr
=> Watch.FormatValue(_previous, Size, Type);
public override int Value
=> _wrapped.Value;
public override string ValueString
=> _wrapped.ValueString;
public int Width;
private NeoWatch(Watch wrapped)
: base(
wrapped.Domain,
wrapped.Address,
wrapped.Size,
wrapped.Type,
bigEndian: wrapped.BigEndian,
note: wrapped.Notes)
=> _wrapped = wrapped;
internal NeoWatch(
MemoryDomain domain,
long address,
WatchSize size,
WatchDisplayType type,
bool bigEndian)
: this(Watch.GenerateWatch(
domain,
CollapseAddress(address, domain),
size,
type,
bigEndian: bigEndian)) {}
public override IEnumerable<WatchDisplayType> AvailableTypes()
=> Size switch
{
WatchSize.Byte => ByteWatch.ValidTypes,
WatchSize.Word => WordWatch.ValidTypes,
WatchSize.DWord => DWordWatch.ValidTypes,
_ => [ ]
};
private void CollapseAddress()
{
//TODO
}
private uint CollapseAndPeek()
{
CollapseAddress();
return Size switch
{
WatchSize.Byte => GetByte(),
WatchSize.Word => GetWord(),
_ => GetDWord()
};
}
public override bool Poke(string value)
{
CollapseAddress();
try
{
var parsed = Watch.ParseValue(value, Size, Type);
switch (Size)
{
case WatchSize.Byte:
PokeByte(unchecked((byte) parsed));
break;
case WatchSize.Word:
PokeWord(unchecked((ushort) parsed));
break;
case WatchSize.DWord:
PokeDWord(parsed);
break;
}
return true;
}
catch
{
return false;
}
}
public override void ResetPrevious()
=> _previous = CollapseAndPeek();
public override void Update(PreviousType previousType)
{
switch (previousType)
{
case PreviousType.Original:
CollapseAddress();
// no-op
break;
case PreviousType.LastSearch:
CollapseAddress();
//TODO no-op?
break;
case PreviousType.LastFrame:
_previous = _value;
_value = CollapseAndPeek();
if (_value != _previous) ChangeCount++;
break;
case PreviousType.LastChange:
var newValue = CollapseAndPeek();
if (newValue != _value)
{
_previous = _value;
ChangeCount++;
}
_value = newValue;
break;
}
}
}
}

View File

@ -558,7 +558,7 @@ namespace BizHawk.Client.Common
/// <summary>
/// Gets the address in the <see cref="MemoryDomain"/> formatted as string
/// </summary>
public string AddressString => Address.ToString(AddressFormatStr);
public virtual string AddressString => Address.ToString(AddressFormatStr);
/// <summary>
/// Gets or sets a value indicating the endianess of current <see cref="Watch"/>

View File

@ -20,6 +20,8 @@ namespace BizHawk.Client.EmuHawk
private Mode _mode = Mode.New;
private bool _loading = true;
private string _sysBusDomainName = null!;
private bool _changedSize;
private bool _changedDisplayType;
@ -29,6 +31,8 @@ namespace BizHawk.Client.EmuHawk
private readonly HexTextBox AddressBox;
private readonly TextBox AddressWithPointersBox;
private readonly CheckBox BigEndianCheckBox;
private readonly ComboBox DisplayTypeDropDown;
@ -49,6 +53,8 @@ namespace BizHawk.Client.EmuHawk
private readonly ComboBox SizeDropDown;
private readonly CheckBoxEx UsePointerSyntaxCheckbox;
public WatchEditor()
{
_changedDisplayType = false;
@ -89,8 +95,40 @@ namespace BizHawk.Client.EmuHawk
{
Controls = { new LabelEx { Text = "0x" }, AddressBox },
};
AddressWithPointersBox = new() { Size = new(100, 20), Visible = false };
SingleColumnFLP flpAddrOptions = new()
{
Controls = { flpAddr, AddressWithPointersBox },
};
tlpMain.Controls.Add(label1, row: row, column: 0);
tlpMain.Controls.Add(flpAddr, row: row, column: 1);
tlpMain.Controls.Add(flpAddrOptions, row: row, column: 1);
row++;
UsePointerSyntaxCheckbox = new() { Enabled = MemoryDomains.HasSystemBus, Text = "Use pointer syntax" };
UsePointerSyntaxCheckbox.CheckedChanged += (checkedChangedSender, _) =>
{
var isChecked = ((CheckBox) checkedChangedSender).Checked;
flpAddr.Visible = !(AddressWithPointersBox.Visible = isChecked);
if (isChecked)
{
if ((string) DomainDropDown.SelectedItem == _sysBusDomainName!)
{
AddressWithPointersBox.Text = $"0x{AddressBox.Text}";
}
else
{
DomainDropDown.SelectedItem = _sysBusDomainName;
AddressWithPointersBox.Text = string.Empty;
}
AddressBox.Text = string.Empty;
}
else
{
//TODO eval and copy back
AddressWithPointersBox.Text = string.Empty;
}
};
tlpMain.Controls.Add(UsePointerSyntaxCheckbox, row: row, column: 1);
row++;
LocLabelEx label3 = new() { Anchor = AnchorStyles.Right, Text = "Size:" };
@ -182,6 +220,7 @@ namespace BizHawk.Client.EmuHawk
}
_loading = false;
_sysBusDomainName = MemoryDomains.SystemBus.ToString();
SetAddressBoxProperties();
switch (_mode)
@ -201,7 +240,9 @@ namespace BizHawk.Client.EmuHawk
NotesBox.Enabled = false;
NotesBox.Text = "";
AddressBox.Enabled = false;
AddressBox.Enabled = AddressWithPointersBox.Enabled
= UsePointerSyntaxCheckbox.Enabled
= false;
AddressBox.Text = Watches.Select(a => a.AddressString).Aggregate((addrStr, nextStr) => $"{addrStr},{nextStr}");
BigEndianCheckBox.ThreeState = true;
@ -215,7 +256,15 @@ namespace BizHawk.Client.EmuHawk
{
NotesBox.Text = Watches[0].Notes;
NotesBox.Select();
AddressBox.SetFromLong(Watches[0].Address);
if (Watches[0] is NeoWatch neo)
{
UsePointerSyntaxCheckbox.Checked = true;
AddressWithPointersBox.Text = neo.AddressString;
}
else
{
AddressBox.SetFromLong(Watches[0].Address);
}
}
SetBigEndianCheckBox();
@ -316,17 +365,25 @@ namespace BizHawk.Client.EmuHawk
default:
case Mode.New:
var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString());
var address = AddressBox.ToLong() ?? 0;
var notes = NotesBox.Text;
var type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString());
var bigEndian = BigEndianCheckBox.Checked;
Watches.Add(Watch.GenerateWatch(
domain,
address,
(WatchSize) SelectedWidth,
type,
bigEndian: bigEndian,
note: notes));
var addrWithPointers = AddressWithPointersBox.Text;
if (addrWithPointers.Length is not 0)
{
//TODO
}
else
{
var address = AddressBox.ToLong() ?? 0;
Watches.Add(Watch.GenerateWatch(
domain,
address,
(WatchSize) SelectedWidth,
type,
bigEndian: bigEndian,
note: notes));
}
break;
case Mode.Edit:
DoEdit();