From 973d162edb83cbaa9fb2ad86e108ca0a92813d4d Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Thu, 9 Jul 2020 11:10:39 -0700 Subject: [PATCH] Data Bank Register management, part 2 Changed basic data item from an "extended enum" to a class, so we can keep track of where things come from (useful for the display list). Finished edit dialog. Added serialization to project file. --- Asm65/Number.cs | 27 +++++ SourceGen/CodeAnalysis.cs | 95 ++++++++++++---- SourceGen/DisasmProject.cs | 6 +- SourceGen/MainController.cs | 11 +- SourceGen/ProjectFile.cs | 33 ++++++ SourceGen/Res/Strings.xaml | 1 + SourceGen/Res/Strings.xaml.cs | 2 + SourceGen/WpfGui/EditDataBank.xaml | 27 +++-- SourceGen/WpfGui/EditDataBank.xaml.cs | 154 +++++++++++++++++++------- 9 files changed, 273 insertions(+), 83 deletions(-) diff --git a/Asm65/Number.cs b/Asm65/Number.cs index 67adc84..4741516 100644 --- a/Asm65/Number.cs +++ b/Asm65/Number.cs @@ -58,6 +58,33 @@ namespace Asm65 { return true; } + /// + /// Parses a hexadecimal integer. Leading '$' or "0x" will be ignored. + /// + /// Trim whitespace before calling here. + /// + /// String to parse. + /// Integer value of string. + /// True if the parsing was successful. + public static bool TryParseIntHex(string str, out int val) { + if (str.Length == 0) { + val = 0; + return false; + } + if (str[0] == '$') { + str = str.Substring(1); + } + // leading "0x" will be handled by Convert + + try { + val = Convert.ToInt32(str, 16); + } catch (Exception) { + val = 0; + return false; + } + return true; + } + /// /// Parses a long integer in a variety of formats (hex, decimal, binary). We allow /// hex to be identified with a leading '$' as well as "0x". diff --git a/SourceGen/CodeAnalysis.cs b/SourceGen/CodeAnalysis.cs index 08cbeca..d2b2a4a 100644 --- a/SourceGen/CodeAnalysis.cs +++ b/SourceGen/CodeAnalysis.cs @@ -1224,16 +1224,73 @@ namespace SourceGen { /// /// Data Bank Register value. /// - /// - /// This is primarily a value from $00-ff, but we also want to encode the B=K special - /// mode. - /// - public enum DbrValue : short { - // $00-ff is bank number - Unknown = -1, // unknown / do-nothing - ProgramBankReg = -2 // set B=K + public class DbrValue { + public const short UNKNOWN = -1; + public const short USE_PBR = -2; + + /// + /// If true, ignore Bank, use Program Bank Register instead. + /// + public bool FollowPbr; + + /// + /// Bank number (0-255). + /// + public byte Bank { get; private set; } + + public enum Source { Unknown = 0, User, Auto, Smart }; + /// + /// From whence this value originates. + /// + public Source ValueSource { get; private set; } + + /// + /// Representation of the object state as a short integer. 0-255 specifies the + /// bank, while negative values are used for special conditions. + /// + public short AsShort { + get { + if (FollowPbr) { + return USE_PBR; + } else { + return Bank; + } + } + } + + public DbrValue(bool followPbr, byte bank, Source source) { + FollowPbr = followPbr; + Bank = bank; + ValueSource = source; + } + + public override string ToString() { + return "DBR:" + (FollowPbr ? "K" : "$" + Bank.ToString("x2")); + } + + public static bool operator ==(DbrValue a, DbrValue b) { + if (ReferenceEquals(a, b)) { + return true; // same object, or both null + } + if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) { + return false; // one is null + } + // All fields must be equal. + return a.Bank == b.Bank && a.FollowPbr == b.FollowPbr && + a.ValueSource == b.ValueSource; + } + public static bool operator !=(DbrValue a, DbrValue b) { + return !(a == b); + } + public override bool Equals(object obj) { + return obj is Symbol && this == (DbrValue)obj; + } + public override int GetHashCode() { + return Bank + (FollowPbr ? 0x100 : 0); + } } + /// /// Determines the value of the Data Bank Register (DBR, register 'B') for relevant /// instructions, and updates the Anattrib OperandOffset value. @@ -1244,21 +1301,21 @@ namespace SourceGen { short[] bval = new short[mAnattribs.Length]; // Initialize all entries to "unknown". - Misc.Memset(bval, (short)DbrValue.Unknown); + Misc.Memset(bval, DbrValue.UNKNOWN); // Set B=K every time we cross an address boundary and the program bank changes. - DbrValue prevBank = DbrValue.Unknown; + short prevBank = DbrValue.UNKNOWN; foreach (AddressMap.AddressMapEntry ent in mAddrMap) { - int mapBank = ent.Addr >> 16; - if (mapBank != (int)prevBank) { - bval[ent.Offset] = (short)mapBank; - prevBank = (DbrValue)mapBank; + short mapBank = (short)(ent.Addr >> 16); + if (mapBank != prevBank) { + bval[ent.Offset] = mapBank; + prevBank = mapBank; } } // Apply the user-specified values. foreach (KeyValuePair kvp in userValues) { - bval[kvp.Key] = (short)kvp.Value; + bval[kvp.Key] = kvp.Value.AsShort; } // Run through the file, looking for PHK/PLB pairs. When we find one, set an @@ -1270,19 +1327,19 @@ namespace SourceGen { // Run through file, updating instructions as needed. - short curVal = (short)DbrValue.Unknown; + short curVal = DbrValue.UNKNOWN; for (int offset = 0; offset < mAnattribs.Length; offset++) { - if (bval[offset] != (short)DbrValue.Unknown) { + if (bval[offset] != DbrValue.UNKNOWN) { curVal = bval[offset]; } if (!mAnattribs[offset].UsesDataBankReg) { continue; } Debug.Assert(mAnattribs[offset].IsInstructionStart); - Debug.Assert(curVal != (short)DbrValue.Unknown); + Debug.Assert(curVal != DbrValue.UNKNOWN); int bank; - if (curVal == (short)DbrValue.ProgramBankReg) { + if (curVal == DbrValue.USE_PBR) { bank = mAnattribs[offset].Address >> 16; } else { Debug.Assert(curVal >= 0 && curVal < 256); diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs index f618a59..5daee47 100644 --- a/SourceGen/DisasmProject.cs +++ b/SourceGen/DisasmProject.cs @@ -2120,15 +2120,13 @@ namespace SourceGen { break; case UndoableChange.ChangeType.SetDataBank: { // If there's no entry, treat it as an entry with value = Unknown. - if (!DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue current)) { - current = CodeAnalysis.DbrValue.Unknown; - } + DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue current); if (current != (CodeAnalysis.DbrValue)oldValue) { Debug.WriteLine("GLITCH: old DBR value mismatch (" + current + " vs " + oldValue + ")"); Debug.Assert(false); } - if ((CodeAnalysis.DbrValue)newValue == CodeAnalysis.DbrValue.Unknown) { + if (newValue == null) { DbrValues.Remove(offset); } else { DbrValues[offset] = (CodeAnalysis.DbrValue)newValue; diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index f315839..62f3a0f 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -1873,19 +1873,16 @@ namespace SourceGen { int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex(); int offset = CodeLineList[selIndex].FileOffset; - CodeAnalysis.DbrValue curValue; - if (!mProject.DbrValues.TryGetValue(offset, out curValue)) { - curValue = CodeAnalysis.DbrValue.Unknown; - } + // Get current user-specified value, or null. + mProject.DbrValues.TryGetValue(offset, out CodeAnalysis.DbrValue curValue); - EditDataBank dlg = new EditDataBank(mMainWin, mProject.AddrMap, mFormatter, curValue); + EditDataBank dlg = new EditDataBank(mMainWin, mProject, mFormatter, curValue); if (dlg.ShowDialog() != true) { return; } if (dlg.Result != curValue) { - Debug.WriteLine("Changing DBR at +" + offset.ToString("x6") + " to $" + - ((int)(dlg.Result)).ToString("x2")); + Debug.WriteLine("Changing DBR at +" + offset.ToString("x6") + " to $" + dlg.Result); UndoableChange uc = UndoableChange.CreateDataBankChange(offset, curValue, dlg.Result); ChangeSet cs = new ChangeSet(uc); diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs index 4438e03..c8634c6 100644 --- a/SourceGen/ProjectFile.cs +++ b/SourceGen/ProjectFile.cs @@ -401,6 +401,18 @@ namespace SourceGen { } } } + public class SerDbrValue { + // Skip the ValueSource property; should always be User in project file. + public bool FollowPbr; + public byte Bank; + + public SerDbrValue() { } + public SerDbrValue(CodeAnalysis.DbrValue dbrValue) { + FollowPbr = dbrValue.FollowPbr; + Bank = dbrValue.Bank; + Debug.Assert(dbrValue.ValueSource == CodeAnalysis.DbrValue.Source.User); + } + } // Fields are serialized to/from JSON. DO NOT change the field names. public int _ContentVersion { get; set; } @@ -420,6 +432,7 @@ namespace SourceGen { public List VisualizationAnimations { get; set; } public Dictionary VisualizationSets { get; set; } public Dictionary RelocList { get; set; } + public Dictionary DbrValues { get; set; } /// /// Serializes a DisasmProject into an augmented JSON string. @@ -534,6 +547,13 @@ namespace SourceGen { spf.RelocList.Add(kvp.Key.ToString(), kvp.Value); } + // We could output the value as a short, using DbrValue.AsShort, but it doesn't + // save much space and could make life harder down the road. + spf.DbrValues = new Dictionary(proj.DbrValues.Count); + foreach (KeyValuePair kvp in proj.DbrValues) { + spf.DbrValues.Add(kvp.Key.ToString(), new SerDbrValue(kvp.Value)); + } + JavaScriptSerializer ser = new JavaScriptSerializer(); string cereal = ser.Serialize(spf); sb.Append(cereal); @@ -854,6 +874,19 @@ namespace SourceGen { } } + // Deserialize data bank register values. This was added in v1.7. + if (spf.DbrValues != null) { + foreach (KeyValuePair kvp in spf.DbrValues) { + if (!ParseValidateKey(kvp.Key, spf.FileDataLength, + Res.Strings.PROJECT_FIELD_DBR_VALUE, report, out int intKey)) { + continue; + } + CodeAnalysis.DbrValue newDbr = new CodeAnalysis.DbrValue(kvp.Value.FollowPbr, + kvp.Value.Bank, CodeAnalysis.DbrValue.Source.User); + proj.DbrValues.Add(intKey, newDbr); + } + } + return true; } diff --git a/SourceGen/Res/Strings.xaml b/SourceGen/Res/Strings.xaml index ffddd09..fbd2e03 100644 --- a/SourceGen/Res/Strings.xaml +++ b/SourceGen/Res/Strings.xaml @@ -152,6 +152,7 @@ limitations under the License. Executing assembler... Generating {0}... comment + DBR value long comment local variable table note diff --git a/SourceGen/Res/Strings.xaml.cs b/SourceGen/Res/Strings.xaml.cs index 3b3317c..f7d16e1 100644 --- a/SourceGen/Res/Strings.xaml.cs +++ b/SourceGen/Res/Strings.xaml.cs @@ -285,6 +285,8 @@ namespace SourceGen.Res { (string)Application.Current.FindResource("str_ProgressGeneratingFmt"); public static string PROJECT_FIELD_COMMENT = (string)Application.Current.FindResource("str_ProjectFieldComment"); + public static string PROJECT_FIELD_DBR_VALUE = + (string)Application.Current.FindResource("str_ProjectFieldDbrValue"); public static string PROJECT_FIELD_LONG_COMMENT = (string)Application.Current.FindResource("str_ProjectFieldLongComment"); public static string PROJECT_FIELD_LV_TABLE = diff --git a/SourceGen/WpfGui/EditDataBank.xaml b/SourceGen/WpfGui/EditDataBank.xaml index e1ec974..daa6b76 100644 --- a/SourceGen/WpfGui/EditDataBank.xaml +++ b/SourceGen/WpfGui/EditDataBank.xaml @@ -20,12 +20,17 @@ limitations under the License. xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SourceGen.WpfGui" + xmlns:system="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" Title="Set Data Bank" SizeToContent="WidthAndHeight" ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterOwner" ContentRendered="Window_ContentRendered"> + + (other) + + @@ -33,25 +38,25 @@ limitations under the License. + - - + - + - - - - + + - +