Skip to content

Commit 1c69215

Browse files
committed
Add NeoWatch with pointer deref, also supporting every width+display
1 parent b2a0ad0 commit 1c69215

File tree

3 files changed

+217
-12
lines changed

3 files changed

+217
-12
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
using System.Collections.Generic;
2+
using System.Linq.Expressions;
3+
4+
using BizHawk.Emulation.Common;
5+
6+
namespace BizHawk.Client.Common
7+
{
8+
/// <summary>an extremely versatile implementation (pointers!), but with presumably lower performance</summary>
9+
public sealed class NeoWatch : Watch
10+
{
11+
private static long CollapseAddress(long address, MemoryDomain domain)
12+
=> address;
13+
14+
private Expression _addressAST;
15+
16+
private uint _previous;
17+
18+
private uint _value;
19+
20+
private Watch _wrapped;
21+
22+
public override string AddressString
23+
=> _addressAST.ToString();
24+
25+
public override string Diff
26+
=> $"{_value - (long) _previous:+#;-#;0}";
27+
28+
public override uint Previous
29+
=> _previous;
30+
31+
public override string PreviousStr
32+
=> Watch.FormatValue(_previous, Size, Type);
33+
34+
public override int Value
35+
=> _wrapped.Value;
36+
37+
public override string ValueString
38+
=> _wrapped.ValueString;
39+
40+
public int Width;
41+
42+
private NeoWatch(Watch wrapped)
43+
: base(
44+
wrapped.Domain,
45+
wrapped.Address,
46+
wrapped.Size,
47+
wrapped.Type,
48+
bigEndian: wrapped.BigEndian,
49+
note: wrapped.Notes)
50+
=> _wrapped = wrapped;
51+
52+
internal NeoWatch(
53+
MemoryDomain domain,
54+
long address,
55+
WatchSize size,
56+
WatchDisplayType type,
57+
bool bigEndian)
58+
: this(Watch.GenerateWatch(
59+
domain,
60+
CollapseAddress(address, domain),
61+
size,
62+
type,
63+
bigEndian: bigEndian)) {}
64+
65+
public override IEnumerable<WatchDisplayType> AvailableTypes()
66+
=> Size switch
67+
{
68+
WatchSize.Byte => ByteWatch.ValidTypes,
69+
WatchSize.Word => WordWatch.ValidTypes,
70+
WatchSize.DWord => DWordWatch.ValidTypes,
71+
_ => [ ]
72+
};
73+
74+
private void CollapseAddress()
75+
{
76+
//TODO
77+
}
78+
79+
private uint CollapseAndPeek()
80+
{
81+
CollapseAddress();
82+
return Size switch
83+
{
84+
WatchSize.Byte => GetByte(),
85+
WatchSize.Word => GetWord(),
86+
_ => GetDWord()
87+
};
88+
}
89+
90+
public override bool Poke(string value)
91+
{
92+
CollapseAddress();
93+
try
94+
{
95+
var parsed = Watch.ParseValue(value, Size, Type);
96+
switch (Size)
97+
{
98+
case WatchSize.Byte:
99+
PokeByte(unchecked((byte) parsed));
100+
break;
101+
case WatchSize.Word:
102+
PokeWord(unchecked((ushort) parsed));
103+
break;
104+
case WatchSize.DWord:
105+
PokeDWord(parsed);
106+
break;
107+
}
108+
return true;
109+
}
110+
catch
111+
{
112+
return false;
113+
}
114+
}
115+
116+
public override void ResetPrevious()
117+
=> _previous = CollapseAndPeek();
118+
119+
public override void Update(PreviousType previousType)
120+
{
121+
switch (previousType)
122+
{
123+
case PreviousType.Original:
124+
CollapseAddress();
125+
// no-op
126+
break;
127+
case PreviousType.LastSearch:
128+
CollapseAddress();
129+
//TODO no-op?
130+
break;
131+
case PreviousType.LastFrame:
132+
_previous = _value;
133+
_value = CollapseAndPeek();
134+
if (_value != _previous) ChangeCount++;
135+
break;
136+
case PreviousType.LastChange:
137+
var newValue = CollapseAndPeek();
138+
if (newValue != _value)
139+
{
140+
_previous = _value;
141+
ChangeCount++;
142+
}
143+
_value = newValue;
144+
break;
145+
}
146+
}
147+
}
148+
}

src/BizHawk.Client.Common/tools/Watch/Watch.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ public virtual bool IsValid
558558
/// <summary>
559559
/// Gets the address in the <see cref="MemoryDomain"/> formatted as string
560560
/// </summary>
561-
public string AddressString => Address.ToString(AddressFormatStr);
561+
public virtual string AddressString => Address.ToString(AddressFormatStr);
562562

563563
/// <summary>
564564
/// Gets or sets a value indicating the endianess of current <see cref="Watch"/>

src/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public enum Mode { New, Duplicate, Edit }
2020
private Mode _mode = Mode.New;
2121
private bool _loading = true;
2222

23+
private string _sysBusDomainName = null!;
24+
2325
private bool _changedSize;
2426
private bool _changedDisplayType;
2527

@@ -29,6 +31,8 @@ public enum Mode { New, Duplicate, Edit }
2931

3032
private readonly HexTextBox AddressBox;
3133

34+
private readonly TextBox AddressWithPointersBox;
35+
3236
private readonly CheckBox BigEndianCheckBox;
3337

3438
private readonly ComboBox DisplayTypeDropDown;
@@ -49,6 +53,8 @@ private int SelectedWidth
4953

5054
private readonly ComboBox SizeDropDown;
5155

56+
private readonly CheckBoxEx UsePointerSyntaxCheckbox;
57+
5258
public WatchEditor()
5359
{
5460
_changedDisplayType = false;
@@ -89,8 +95,40 @@ public WatchEditor()
8995
{
9096
Controls = { new LabelEx { Text = "0x" }, AddressBox },
9197
};
98+
AddressWithPointersBox = new() { Size = new(100, 20), Visible = false };
99+
SingleColumnFLP flpAddrOptions = new()
100+
{
101+
Controls = { flpAddr, AddressWithPointersBox },
102+
};
92103
tlpMain.Controls.Add(label1, row: row, column: 0);
93-
tlpMain.Controls.Add(flpAddr, row: row, column: 1);
104+
tlpMain.Controls.Add(flpAddrOptions, row: row, column: 1);
105+
row++;
106+
107+
UsePointerSyntaxCheckbox = new() { Enabled = MemoryDomains.HasSystemBus, Text = "Use pointer syntax" };
108+
UsePointerSyntaxCheckbox.CheckedChanged += (checkedChangedSender, _) =>
109+
{
110+
var isChecked = ((CheckBox) checkedChangedSender).Checked;
111+
flpAddr.Visible = !(AddressWithPointersBox.Visible = isChecked);
112+
if (isChecked)
113+
{
114+
if ((string) DomainDropDown.SelectedItem == _sysBusDomainName!)
115+
{
116+
AddressWithPointersBox.Text = $"0x{AddressBox.Text}";
117+
}
118+
else
119+
{
120+
DomainDropDown.SelectedItem = _sysBusDomainName;
121+
AddressWithPointersBox.Text = string.Empty;
122+
}
123+
AddressBox.Text = string.Empty;
124+
}
125+
else
126+
{
127+
//TODO eval and copy back
128+
AddressWithPointersBox.Text = string.Empty;
129+
}
130+
};
131+
tlpMain.Controls.Add(UsePointerSyntaxCheckbox, row: row, column: 1);
94132
row++;
95133

96134
LocLabelEx label3 = new() { Anchor = AnchorStyles.Right, Text = "Size:" };
@@ -182,6 +220,7 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e)
182220
}
183221

184222
_loading = false;
223+
_sysBusDomainName = MemoryDomains.SystemBus.ToString();
185224
SetAddressBoxProperties();
186225

187226
switch (_mode)
@@ -201,7 +240,9 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e)
201240
NotesBox.Enabled = false;
202241
NotesBox.Text = "";
203242

204-
AddressBox.Enabled = false;
243+
AddressBox.Enabled = AddressWithPointersBox.Enabled
244+
= UsePointerSyntaxCheckbox.Enabled
245+
= false;
205246
AddressBox.Text = Watches.Select(a => a.AddressString).Aggregate((addrStr, nextStr) => $"{addrStr},{nextStr}");
206247

207248
BigEndianCheckBox.ThreeState = true;
@@ -215,7 +256,15 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e)
215256
{
216257
NotesBox.Text = Watches[0].Notes;
217258
NotesBox.Select();
218-
AddressBox.SetFromLong(Watches[0].Address);
259+
if (Watches[0] is NeoWatch neo)
260+
{
261+
UsePointerSyntaxCheckbox.Checked = true;
262+
AddressWithPointersBox.Text = neo.AddressString;
263+
}
264+
else
265+
{
266+
AddressBox.SetFromLong(Watches[0].Address);
267+
}
219268
}
220269

221270
SetBigEndianCheckBox();
@@ -316,17 +365,25 @@ private void Ok_Click(object sender, EventArgs e)
316365
default:
317366
case Mode.New:
318367
var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString());
319-
var address = AddressBox.ToLong() ?? 0;
320368
var notes = NotesBox.Text;
321369
var type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString());
322370
var bigEndian = BigEndianCheckBox.Checked;
323-
Watches.Add(Watch.GenerateWatch(
324-
domain,
325-
address,
326-
(WatchSize) SelectedWidth,
327-
type,
328-
bigEndian: bigEndian,
329-
note: notes));
371+
var addrWithPointers = AddressWithPointersBox.Text;
372+
if (addrWithPointers.Length is not 0)
373+
{
374+
//TODO
375+
}
376+
else
377+
{
378+
var address = AddressBox.ToLong() ?? 0;
379+
Watches.Add(Watch.GenerateWatch(
380+
domain,
381+
address,
382+
(WatchSize) SelectedWidth,
383+
type,
384+
bigEndian: bigEndian,
385+
note: notes));
386+
}
330387
break;
331388
case Mode.Edit:
332389
DoEdit();

0 commit comments

Comments
 (0)