Skip to content

Commit 07e896c

Browse files
committed
Add NeoWatch with pointer deref, also supporting every width+display
1 parent a313e5c commit 07e896c

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
@@ -25,6 +25,8 @@ public enum Mode
2525
private Mode _mode = Mode.New;
2626
private bool _loading = true;
2727

28+
private string _sysBusDomainName = null!;
29+
2830
private bool _changedSize;
2931
private bool _changedDisplayType;
3032

@@ -34,6 +36,8 @@ public enum Mode
3436

3537
private readonly HexTextBox AddressBox;
3638

39+
private readonly TextBox AddressWithPointersBox;
40+
3741
private readonly CheckBox BigEndianCheckBox;
3842

3943
private readonly ComboBox DisplayTypeDropDown;
@@ -54,6 +58,8 @@ private int SelectedWidth
5458

5559
private readonly ComboBox SizeDropDown;
5660

61+
private readonly CheckBoxEx UsePointerSyntaxCheckbox;
62+
5763
public WatchEditor()
5864
{
5965
_changedDisplayType = false;
@@ -94,8 +100,40 @@ public WatchEditor()
94100
{
95101
Controls = { new LabelEx { Text = "0x" }, AddressBox },
96102
};
103+
AddressWithPointersBox = new() { Size = new(100, 20), Visible = false };
104+
SingleColumnFLP flpAddrOptions = new()
105+
{
106+
Controls = { flpAddr, AddressWithPointersBox },
107+
};
97108
tlpMain.Controls.Add(label1, row: row, column: 0);
98-
tlpMain.Controls.Add(flpAddr, row: row, column: 1);
109+
tlpMain.Controls.Add(flpAddrOptions, row: row, column: 1);
110+
row++;
111+
112+
UsePointerSyntaxCheckbox = new() { Enabled = MemoryDomains.HasSystemBus, Text = "Use pointer syntax" };
113+
UsePointerSyntaxCheckbox.CheckedChanged += (checkedChangedSender, _) =>
114+
{
115+
var isChecked = ((CheckBox) checkedChangedSender).Checked;
116+
flpAddr.Visible = !(AddressWithPointersBox.Visible = isChecked);
117+
if (isChecked)
118+
{
119+
if ((string) DomainDropDown.SelectedItem == _sysBusDomainName!)
120+
{
121+
AddressWithPointersBox.Text = $"0x{AddressBox.Text}";
122+
}
123+
else
124+
{
125+
DomainDropDown.SelectedItem = _sysBusDomainName;
126+
AddressWithPointersBox.Text = string.Empty;
127+
}
128+
AddressBox.Text = string.Empty;
129+
}
130+
else
131+
{
132+
//TODO eval and copy back
133+
AddressWithPointersBox.Text = string.Empty;
134+
}
135+
};
136+
tlpMain.Controls.Add(UsePointerSyntaxCheckbox, row: row, column: 1);
99137
row++;
100138

101139
LocLabelEx label3 = new() { Anchor = AnchorStyles.Right, Text = "Size:" };
@@ -187,6 +225,7 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e)
187225
}
188226

189227
_loading = false;
228+
_sysBusDomainName = MemoryDomains.SystemBus.ToString();
190229
SetAddressBoxProperties();
191230

192231
switch (_mode)
@@ -206,7 +245,9 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e)
206245
NotesBox.Enabled = false;
207246
NotesBox.Text = "";
208247

209-
AddressBox.Enabled = false;
248+
AddressBox.Enabled = AddressWithPointersBox.Enabled
249+
= UsePointerSyntaxCheckbox.Enabled
250+
= false;
210251
AddressBox.Text = Watches.Select(a => a.AddressString).Aggregate((addrStr, nextStr) => $"{addrStr},{nextStr}");
211252

212253
BigEndianCheckBox.ThreeState = true;
@@ -220,7 +261,15 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e)
220261
{
221262
NotesBox.Text = Watches[0].Notes;
222263
NotesBox.Select();
223-
AddressBox.SetFromLong(Watches[0].Address);
264+
if (Watches[0] is NeoWatch neo)
265+
{
266+
UsePointerSyntaxCheckbox.Checked = true;
267+
AddressWithPointersBox.Text = neo.AddressString;
268+
}
269+
else
270+
{
271+
AddressBox.SetFromLong(Watches[0].Address);
272+
}
224273
}
225274

226275
SetBigEndianCheckBox();
@@ -321,17 +370,25 @@ private void Ok_Click(object sender, EventArgs e)
321370
default:
322371
case Mode.New:
323372
var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString());
324-
var address = AddressBox.ToLong() ?? 0;
325373
var notes = NotesBox.Text;
326374
var type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString());
327375
var bigEndian = BigEndianCheckBox.Checked;
328-
Watches.Add(Watch.GenerateWatch(
329-
domain,
330-
address,
331-
(WatchSize) SelectedWidth,
332-
type,
333-
bigEndian: bigEndian,
334-
note: notes));
376+
var addrWithPointers = AddressWithPointersBox.Text;
377+
if (addrWithPointers.Length is not 0)
378+
{
379+
//TODO
380+
}
381+
else
382+
{
383+
var address = AddressBox.ToLong() ?? 0;
384+
Watches.Add(Watch.GenerateWatch(
385+
domain,
386+
address,
387+
(WatchSize) SelectedWidth,
388+
type,
389+
bigEndian: bigEndian,
390+
note: notes));
391+
}
335392
break;
336393
case Mode.Edit:
337394
DoEdit();

0 commit comments

Comments
 (0)