diff --git a/src/BizHawk.Client.Common/tools/Cheat.cs b/src/BizHawk.Client.Common/tools/Cheat.cs index bae019699e3..227c0b56264 100644 --- a/src/BizHawk.Client.Common/tools/Cheat.cs +++ b/src/BizHawk.Client.Common/tools/Cheat.cs @@ -91,35 +91,20 @@ public MemoryDomain Domain public string AddressStr => _watch.AddressString; - public string ValueStr => - _watch.Size switch - { - WatchSize.Byte => ((ByteWatch) _watch).FormatValue((byte)_val), - WatchSize.Word => ((WordWatch) _watch).FormatValue((ushort)_val), - WatchSize.DWord => ((DWordWatch) _watch).FormatValue((uint)_val), - WatchSize.Separator => "", - _ => string.Empty, - }; + public string ValueStr + => _watch.Size is WatchSize.Byte or WatchSize.Word or WatchSize.DWord + ? _watch.IsValid + ? Watch.FormatValue(unchecked((uint) _val), _watch.Size, _watch.Type) + : "-" + : string.Empty; public string CompareStr - { - get - { - if (_compare.HasValue) - { - return _watch.Size switch - { - WatchSize.Byte => ((ByteWatch) _watch).FormatValue((byte)_compare.Value), - WatchSize.Word => ((WordWatch) _watch).FormatValue((ushort)_compare.Value), - WatchSize.DWord => ((DWordWatch) _watch).FormatValue((uint)_compare.Value), - WatchSize.Separator => "", - _ => string.Empty, - }; - } - - return ""; - } - } + => _compare.Value is int compareValue + && _watch.Size is WatchSize.Byte or WatchSize.Word or WatchSize.DWord + ? _watch.IsValid + ? Watch.FormatValue(unchecked((uint) compareValue), _watch.Size, _watch.Type) + : "-" + : string.Empty; public CompareType ComparisonType { get; } @@ -167,17 +152,24 @@ public void Pulse() { if (ShouldPoke()) { - switch (_watch.Size) + try + { + switch (_watch.Size) + { + case WatchSize.Byte: + _watch.PokeByte(unchecked((byte) _val)); + break; + case WatchSize.Word: + _watch.PokeWord(unchecked((ushort) _val)); + break; + case WatchSize.DWord: + _watch.PokeDWord(unchecked((uint) _val)); + break; + } + } + catch { - case WatchSize.Byte: - _watch.Poke(((ByteWatch)_watch).FormatValue((byte)_val)); - break; - case WatchSize.Word: - _watch.Poke(((WordWatch)_watch).FormatValue((ushort)_val)); - break; - case WatchSize.DWord: - _watch.Poke(((DWordWatch)_watch).FormatValue((uint)_val)); - break; + // ignore (matches `*Watch.Poke` implementations) } } diff --git a/src/BizHawk.Client.Common/tools/Watch/ByteWatch.cs b/src/BizHawk.Client.Common/tools/Watch/ByteWatch.cs index 5aacf977aeb..224e1a4e990 100644 --- a/src/BizHawk.Client.Common/tools/Watch/ByteWatch.cs +++ b/src/BizHawk.Client.Common/tools/Watch/ByteWatch.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using System.Globalization; + using BizHawk.Emulation.Common; namespace BizHawk.Client.Common @@ -42,43 +42,21 @@ internal ByteWatch(MemoryDomain domain, long address, WatchDisplayType type, boo WatchDisplayType.Binary, ]; - /// - /// Get a list a that can be used for this - /// - /// An enumeration that contains all valid public override IEnumerable AvailableTypes() { return ValidTypes; } - /// - /// Reset the previous value; set it to the current one - /// public override void ResetPrevious() { _previous = GetByte(); } - /// - /// Try to sets the value into the - /// at the current address - /// - /// Value to set - /// True if value successfully sets; otherwise, false public override bool Poke(string value) { try { - byte val = Type switch - { - WatchDisplayType.Unsigned => byte.Parse(value), - WatchDisplayType.Signed => (byte)sbyte.Parse(value), - WatchDisplayType.Hex => byte.Parse(value, NumberStyles.HexNumber), - WatchDisplayType.Binary => Convert.ToByte(value, 2), - _ => 0, - }; - - PokeByte(val); + PokeByte(unchecked((byte) Watch.ParseValue(value, Size, Type))); return true; } catch @@ -87,9 +65,6 @@ public override bool Poke(string value) } } - /// - /// Update the Watch (read it from - /// public override void Update(PreviousType previousType) { switch (previousType) @@ -120,52 +95,16 @@ public override void Update(PreviousType previousType) // TODO: Implements IFormattable public string FormatValue(byte val) - { - return Type switch - { - _ when !IsValid => "-", - WatchDisplayType.Unsigned => val.ToString(), - WatchDisplayType.Signed => ((sbyte) val).ToString(), - WatchDisplayType.Hex => $"{val:X2}", - WatchDisplayType.Binary => Convert.ToString(val, 2).PadLeft(8, '0').Insert(4, " "), - _ => val.ToString(), - }; - } + => IsValid ? Watch.FormatValue(val, Size, Type) : "-"; - /// - /// Get a string representation of difference - /// between current value and the previous one - /// public override string Diff => $"{_value - _previous:+#;-#;0}"; - /// - /// Returns true if the Watch is valid, false otherwise - /// - public override bool IsValid => Domain.Size == 0 || Address < Domain.Size; - - /// - /// Get the maximum possible value - /// - public override uint MaxValue => byte.MaxValue; - - /// - /// Get the current value - /// public override int Value => GetByte(); - /// - /// Get a string representation of the current value - /// public override string ValueString => FormatValue(GetByte()); - /// - /// Get the previous value - /// public override uint Previous => _previous; - /// - /// Get a string representation of the previous value - /// public override string PreviousStr => FormatValue(_previous); } } diff --git a/src/BizHawk.Client.Common/tools/Watch/DWordWatch.cs b/src/BizHawk.Client.Common/tools/Watch/DWordWatch.cs index f64bd59639e..986b6022ab7 100644 --- a/src/BizHawk.Client.Common/tools/Watch/DWordWatch.cs +++ b/src/BizHawk.Client.Common/tools/Watch/DWordWatch.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; -using System.Globalization; -using BizHawk.Common.NumberExtensions; + using BizHawk.Emulation.Common; namespace BizHawk.Client.Common @@ -46,44 +45,19 @@ internal DWordWatch(MemoryDomain domain, long address, WatchDisplayType type, bo WatchDisplayType.Float, ]; - /// - /// Get a list of that can be used for a - /// - /// An enumeration that contains all valid public override IEnumerable AvailableTypes() { return ValidTypes; } - /// - /// Reset the previous value; set it to the current one - /// public override void ResetPrevious() => _previous = GetDWord(); - /// - /// Try to sets the value into the - /// at the current address - /// - /// Value to set - /// True if value successfully sets; otherwise, false public override bool Poke(string value) { try { - uint val = Type switch - { - WatchDisplayType.Unsigned => uint.Parse(value), - WatchDisplayType.Signed => (uint)int.Parse(value), - WatchDisplayType.Hex => uint.Parse(value, NumberStyles.HexNumber), - WatchDisplayType.FixedPoint_20_12 => (uint)(double.Parse(value, NumberFormatInfo.InvariantInfo) * 4096.0), - WatchDisplayType.FixedPoint_16_16 => (uint)(double.Parse(value, NumberFormatInfo.InvariantInfo) * 65536.0), - WatchDisplayType.Float => NumberExtensions.ReinterpretAsUInt32(float.Parse(value, NumberFormatInfo.InvariantInfo)), - WatchDisplayType.Binary => Convert.ToUInt32(value, 2), - _ => 0, - }; - - PokeDWord(val); + PokeDWord(Watch.ParseValue(value, Size, Type)); return true; } catch @@ -92,9 +66,6 @@ public override bool Poke(string value) } } - /// - /// Update the Watch (read it from - /// public override void Update(PreviousType previousType) { switch (previousType) @@ -125,71 +96,16 @@ public override void Update(PreviousType previousType) // TODO: Implements IFormattable public string FormatValue(uint val) - { - string FormatFloat() - { - var _float = NumberExtensions.ReinterpretAsF32(val); - return _float.ToString(NumberFormatInfo.InvariantInfo); - } - - string FormatBinary() - { - var str = Convert.ToString(val, 2).PadLeft(32, '0'); - for (var i = 28; i > 0; i -= 4) - { - str = str.Insert(i, " "); - } - return str; - } - - return Type switch - { - _ when !IsValid => "-", - WatchDisplayType.Unsigned => val.ToString(), - WatchDisplayType.Signed => ((int)val).ToString(), - WatchDisplayType.Hex => $"{val:X8}", - WatchDisplayType.FixedPoint_20_12 => ((int)val / 4096.0).ToString("0.######", NumberFormatInfo.InvariantInfo), - WatchDisplayType.FixedPoint_16_16 => ((int)val / 65536.0).ToString("0.######", NumberFormatInfo.InvariantInfo), - WatchDisplayType.Float => FormatFloat(), - WatchDisplayType.Binary => FormatBinary(), - _ => val.ToString(), - }; - } + => IsValid ? Watch.FormatValue(val, Size, Type) : "-"; - /// - /// Get a string representation of difference - /// between current value and the previous one - /// public override string Diff => $"{_value - (long)_previous:+#;-#;0}"; - /// - /// Returns true if the Watch is valid, false otherwise - /// - public override bool IsValid => Domain.Size == 0 || Address < (Domain.Size - 3); - - /// - /// Get the maximum possible value - /// - public override uint MaxValue => uint.MaxValue; - - /// - /// Get the current value - /// public override int Value => (int)GetDWord(); - /// - /// Get a string representation of the current value - /// public override string ValueString => FormatValue(GetDWord()); - /// - /// Get the previous value - /// public override uint Previous => _previous; - /// - /// Get a string representation of the previous value - /// public override string PreviousStr => FormatValue(_previous); } } diff --git a/src/BizHawk.Client.Common/tools/Watch/NeoWatch.cs b/src/BizHawk.Client.Common/tools/Watch/NeoWatch.cs new file mode 100644 index 00000000000..78b66a8d1f6 --- /dev/null +++ b/src/BizHawk.Client.Common/tools/Watch/NeoWatch.cs @@ -0,0 +1,148 @@ +using System.Collections.Generic; +using System.Linq.Expressions; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + /// an extremely versatile implementation (pointers!), but with presumably lower performance + 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 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; + } + } + } +} diff --git a/src/BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs b/src/BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs index 50497f3e7d5..4cc21bb0fbb 100644 --- a/src/BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs +++ b/src/BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs @@ -56,11 +56,6 @@ public override IEnumerable AvailableTypes() /// public override string PreviousStr => ""; - /// - /// TTransform the current instance into a displayable (short representation) string - /// It's used by the "Display on screen" option in the RamWatch window - /// - /// A well formatted string representation public override string ToDisplayString() { return string.IsNullOrEmpty(Notes) @@ -68,10 +63,6 @@ public override string ToDisplayString() : Notes; } - /// - /// Transforms the current instance into a string - /// - /// A representation of the current public override string ToString() { return $"0\tS\t_\t1\t\t{Notes.Trim('\r', '\n')}"; @@ -99,11 +90,6 @@ public override void ResetPrevious() /// public override string Diff => ""; - /// - /// Ignore that stuff - /// - public override uint MaxValue => 0; - /// /// Ignore that stuff /// diff --git a/src/BizHawk.Client.Common/tools/Watch/Watch.cs b/src/BizHawk.Client.Common/tools/Watch/Watch.cs index f1f0d24e35f..fbe50899eaf 100644 --- a/src/BizHawk.Client.Common/tools/Watch/Watch.cs +++ b/src/BizHawk.Client.Common/tools/Watch/Watch.cs @@ -19,6 +19,78 @@ public abstract class Watch IEquatable, IComparable { + private const string ERR_MSG_INVALID_WIDTH = "can only parse numeric strings for 1-, 2-, or 4-octet watches"; + + public static string FormatValue(uint value, WatchSize width, WatchDisplayType dispType) + => width switch + { + WatchSize.Byte => dispType switch + { + WatchDisplayType.Signed => unchecked((sbyte) value).ToString(), + WatchDisplayType.Unsigned => value.ToString(), + WatchDisplayType.Hex => $"{value:X2}", + WatchDisplayType.Binary => Convert.ToString(unchecked((byte) value), toBase: 2).PadLeft(8, '0').Insert(4, " "), + _ => value.ToString(), //TODO throw instead? + }, + WatchSize.Word => dispType switch + { + WatchDisplayType.Signed => unchecked((short) value).ToString(), + WatchDisplayType.Unsigned => value.ToString(), + WatchDisplayType.Hex => $"{value:X4}", + WatchDisplayType.Binary => Convert.ToString(unchecked((ushort) value), toBase: 2).PadLeft(16, '0') + .Insert(8, " ").Insert(4, " ").Insert(14, " "), + WatchDisplayType.FixedPoint_12_4 => $"{unchecked((short) value) / 16.0:F4}", + _ => value.ToString(), //TODO throw instead? + }, + WatchSize.DWord => dispType switch + { + WatchDisplayType.Signed => unchecked((int) value).ToString(), + WatchDisplayType.Unsigned => value.ToString(), + WatchDisplayType.Hex => $"{value:X8}", + WatchDisplayType.Binary => Convert.ToString(value, toBase: 2).PadLeft(32, '0') + .Insert(28, " ").Insert(24, " ").Insert(20, " ").Insert(16, " ").Insert(12, " ").Insert(8, " ").Insert(4, " "), + WatchDisplayType.FixedPoint_20_12 => $"{unchecked((int) value) / 4096.0:0.######}", + WatchDisplayType.FixedPoint_16_16 => $"{unchecked((int) value) / 65536.0:0.######}", + WatchDisplayType.Float => NumberExtensions.ReinterpretAsF32(value).ToString(NumberFormatInfo.InvariantInfo), + _ => value.ToString(), //TODO throw instead? + }, + _ => throw new ArgumentOutOfRangeException(paramName: nameof(width), width, message: ERR_MSG_INVALID_WIDTH), + }; + + public static uint ParseValue(string value, WatchSize width, WatchDisplayType dispType) + => width switch + { + WatchSize.Byte => dispType switch + { + WatchDisplayType.Signed => unchecked((byte) sbyte.Parse(value)), + WatchDisplayType.Unsigned => byte.Parse(value), + WatchDisplayType.Hex => byte.Parse(value, NumberStyles.HexNumber), + WatchDisplayType.Binary => Convert.ToByte(value, fromBase: 2), + _ => 0, //TODO throw instead? + }, + WatchSize.Word => dispType switch + { + WatchDisplayType.Signed => unchecked((ushort) short.Parse(value)), + WatchDisplayType.Unsigned => ushort.Parse(value), + WatchDisplayType.Hex => ushort.Parse(value, NumberStyles.HexNumber), + WatchDisplayType.Binary => Convert.ToUInt16(value, fromBase: 2), + WatchDisplayType.FixedPoint_12_4 => unchecked((ushort) (16.0 * double.Parse(value, NumberFormatInfo.InvariantInfo))), + _ => 0, //TODO throw instead? + }, + WatchSize.DWord => dispType switch + { + WatchDisplayType.Signed => unchecked((uint) int.Parse(value)), + WatchDisplayType.Unsigned => uint.Parse(value), + WatchDisplayType.Hex => uint.Parse(value, NumberStyles.HexNumber), + WatchDisplayType.Binary => Convert.ToUInt32(value, fromBase: 2), + WatchDisplayType.FixedPoint_20_12 => unchecked((uint) (4096.0 * double.Parse(value, NumberFormatInfo.InvariantInfo))), + WatchDisplayType.FixedPoint_16_16 => unchecked((uint) (65536.0 * double.Parse(value, NumberFormatInfo.InvariantInfo))), + WatchDisplayType.Float => NumberExtensions.ReinterpretAsUInt32(float.Parse(value, NumberFormatInfo.InvariantInfo)), + _ => 0, //TODO throw instead? + }, + _ => throw new ArgumentOutOfRangeException(paramName: nameof(width), width, message: ERR_MSG_INVALID_WIDTH), + }; + private MemoryDomain _domain; private WatchDisplayType _type; @@ -285,7 +357,7 @@ protected uint GetDWord() : 0; } - protected void PokeByte(byte val) + protected internal void PokeByte(byte val) { if (IsValid) { @@ -293,7 +365,7 @@ protected void PokeByte(byte val) } } - protected void PokeWord(ushort val) + protected internal void PokeWord(ushort val) { if (IsValid) { @@ -301,7 +373,7 @@ protected void PokeWord(ushort val) } } - protected void PokeDWord(uint val) + protected internal void PokeDWord(uint val) { if (IsValid) { @@ -430,7 +502,15 @@ public override string ToString() /// /// Gets the maximum possible value /// - public abstract uint MaxValue { get; } + public uint MaxValue + => Size switch + { + WatchSize.Separator => 0, + WatchSize.Byte => byte.MaxValue, + WatchSize.Word => ushort.MaxValue, + WatchSize.DWord => uint.MaxValue, + _ => throw new InvalidOperationException(), + }; /// /// Gets the current value @@ -445,7 +525,8 @@ public override string ToString() /// /// Returns true if the Watch is valid, false otherwise /// - public abstract bool IsValid { get; } + public virtual bool IsValid + => Domain.Size is 0 || Address <= Domain.Size - unchecked((long) Size); /// /// Try to sets the value into the @@ -477,7 +558,7 @@ public override string ToString() /// /// Gets the address in the formatted as string /// - public string AddressString => Address.ToString(AddressFormatStr); + public virtual string AddressString => Address.ToString(AddressFormatStr); /// /// Gets or sets a value indicating the endianess of current diff --git a/src/BizHawk.Client.Common/tools/Watch/WordWatch.cs b/src/BizHawk.Client.Common/tools/Watch/WordWatch.cs index f5fd8c0ae99..10fcaa6bd0e 100644 --- a/src/BizHawk.Client.Common/tools/Watch/WordWatch.cs +++ b/src/BizHawk.Client.Common/tools/Watch/WordWatch.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using System.Globalization; + using BizHawk.Emulation.Common; namespace BizHawk.Client.Common @@ -43,41 +43,18 @@ internal WordWatch(MemoryDomain domain, long address, WatchDisplayType type, boo WatchDisplayType.FixedPoint_12_4, ]; - /// - /// Get a list a that can be used for this - /// - /// An enumeration that contains all valid public override IEnumerable AvailableTypes() => ValidTypes; - /// - /// Reset the previous value; set it to the current one - /// public override void ResetPrevious() { _previous = GetWord(); } - /// - /// Try to sets the value into the - /// at the current address - /// - /// Value to set - /// True if value successfully sets; otherwise, false public override bool Poke(string value) { try { - ushort val = Type switch - { - WatchDisplayType.Unsigned => ushort.Parse(value), - WatchDisplayType.Signed => (ushort)short.Parse(value), - WatchDisplayType.Hex => ushort.Parse(value, NumberStyles.HexNumber), - WatchDisplayType.Binary => Convert.ToUInt16(value, 2), - WatchDisplayType.FixedPoint_12_4 => (ushort)(double.Parse(value, NumberFormatInfo.InvariantInfo) * 16.0), - _ => 0, - }; - - PokeWord(val); + PokeWord(unchecked((ushort) Watch.ParseValue(value, Size, Type))); return true; } catch @@ -86,9 +63,6 @@ public override bool Poke(string value) } } - /// - /// Update the Watch (read it from - /// public override void Update(PreviousType previousType) { switch (previousType) @@ -120,57 +94,16 @@ public override void Update(PreviousType previousType) // TODO: Implements IFormattable public string FormatValue(ushort val) - { - return Type switch - { - _ when !IsValid => "-", - WatchDisplayType.Unsigned => val.ToString(), - WatchDisplayType.Signed => ((short) val).ToString(), WatchDisplayType.Hex => $"{val:X4}", - WatchDisplayType.FixedPoint_12_4 => ((short)val / 16.0).ToString("F4", NumberFormatInfo.InvariantInfo), - WatchDisplayType.Binary => Convert - .ToString(val, 2) - .PadLeft(16, '0') - .Insert(8, " ") - .Insert(4, " ") - .Insert(14, " "), - _ => val.ToString(), - }; - } + => IsValid ? Watch.FormatValue(val, Size, Type) : "-"; - /// - /// Get a string representation of difference - /// between current value and the previous one - /// public override string Diff => $"{_value - _previous:+#;-#;0}"; - /// - /// Returns true if the Watch is valid, false otherwise - /// - public override bool IsValid => Domain.Size == 0 || Address < (Domain.Size - 1); - - /// - /// Get the maximum possible value - /// - public override uint MaxValue => ushort.MaxValue; - - /// - /// Gets the current value - /// public override int Value => GetWord(); - /// - /// Get a string representation of the current value - /// public override string ValueString => FormatValue(GetWord()); - /// - /// Get the previous value - /// public override uint Previous => _previous; - /// - /// Get a string representation of the previous value - /// public override string PreviousStr => FormatValue(_previous); } } diff --git a/src/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs b/src/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs index 88e6c05b9ac..da7cc06fde9 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs @@ -25,6 +25,8 @@ public enum Mode private Mode _mode = Mode.New; private bool _loading = true; + private string _sysBusDomainName = null!; + private bool _changedSize; private bool _changedDisplayType; @@ -34,6 +36,8 @@ public enum Mode private readonly HexTextBox AddressBox; + private readonly TextBox AddressWithPointersBox; + private readonly CheckBox BigEndianCheckBox; private readonly ComboBox DisplayTypeDropDown; @@ -54,6 +58,8 @@ private int SelectedWidth private readonly ComboBox SizeDropDown; + private readonly CheckBoxEx UsePointerSyntaxCheckbox; + public WatchEditor() { _changedDisplayType = false; @@ -94,8 +100,40 @@ public WatchEditor() { 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:" }; @@ -187,6 +225,7 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e) } _loading = false; + _sysBusDomainName = MemoryDomains.SystemBus.ToString(); SetAddressBoxProperties(); switch (_mode) @@ -206,7 +245,9 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e) 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; @@ -220,7 +261,15 @@ private void RamWatchNewWatch_Load(object sender, EventArgs e) { 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(); @@ -321,17 +370,25 @@ private void Ok_Click(object sender, EventArgs e) 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();