Add `NeoWatch` with pointer deref, also supporting every width+display
This commit is contained in:
parent
b2a0ad0857
commit
1c69215815
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"/>
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue