From 0929077fda984683314b42b3e02f11cf88340a2d Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Thu, 9 Jul 2020 19:36:22 -0700 Subject: [PATCH] Data Bank Register management, part 4 Implemented "smart" PLB handling. If we see PHK/PLB, or 8-bit LDA imm/PHA/PLB, we create a data bank change item. The feature can be disabled with a project property. --- SourceGen/CodeAnalysis.cs | 99 +++++++++++++------ SourceGen/LineListGen.cs | 22 +++-- SourceGen/ProjectFile.cs | 11 ++- SourceGen/ProjectProperties.cs | 3 + SourceGen/Res/Strings.xaml | 2 +- SourceGen/Res/Strings.xaml.cs | 4 +- SourceGen/RuntimeData/Help/settings.html | 5 + SourceGen/WpfGui/EditProjectProperties.xaml | 2 + .../WpfGui/EditProjectProperties.xaml.cs | 8 ++ 9 files changed, 111 insertions(+), 45 deletions(-) diff --git a/SourceGen/CodeAnalysis.cs b/SourceGen/CodeAnalysis.cs index 1f40095..7734c68 100644 --- a/SourceGen/CodeAnalysis.cs +++ b/SourceGen/CodeAnalysis.cs @@ -1295,47 +1295,34 @@ namespace SourceGen { /// Determines the value of the Data Bank Register (DBR, register 'B') for relevant /// instructions, and updates the Anattrib OperandOffset value. /// + /// + /// This is of questionable value when we have reliable relocation data. OTOH it's + /// pretty quick even on very large files. + /// public void ApplyDataBankRegister(Dictionary userValues, Dictionary dbrChanges) { Debug.Assert(!mCpuDef.HasAddr16); // 65816 only dbrChanges.Clear(); - short[] bval = new short[mAnattribs.Length]; - - // Initialize all entries to "unknown". - Misc.Memset(bval, DbrValue.UNKNOWN); - - // Set B=K every time we cross an address boundary and the program bank changes. - short prevBank = DbrValue.UNKNOWN; - foreach (AddressMap.AddressMapEntry ent in mAddrMap) { - short mapBank = (short)(ent.Addr >> 16); - if (mapBank != prevBank) { - bval[ent.Offset] = mapBank; - prevBank = mapBank; - dbrChanges.Add(ent.Offset, new DbrValue(false, (byte)mapBank, - DbrValue.Source.Auto)); - } + if (mAnalysisParameters.SmartPlbHandling) { + GenerateSmartPlbChanges(dbrChanges); } - // Apply the user-specified values, overwriting existing values. + // Apply the user-specified values, overwriting auto-generated values. foreach (KeyValuePair kvp in userValues) { dbrChanges[kvp.Key] = kvp.Value; + } + + // Create an array for fast access. + short[] bval = new short[mAnattribs.Length]; + Misc.Memset(bval, DbrValue.UNKNOWN); + foreach (KeyValuePair kvp in dbrChanges) { bval[kvp.Key] = kvp.Value.AsShort; } - // Run through the file, looking for PHK/PLB pairs. When we find one, set an - // entry for the PLB instruction unless an entry already exists there. - - // add to dbrChanges with "Auto" or "smart" - - // ? look for LDA #imm8 / PHA / PLB? - - // ... - - // Run through file, updating instructions as needed. - short curVal = 0; + short curVal = (byte)(mAddrMap.Get(0) >> 16); // start with B=K for (int offset = 0; offset < mAnattribs.Length; offset++) { if (bval[offset] != DbrValue.UNKNOWN) { curVal = bval[offset]; @@ -1358,15 +1345,65 @@ namespace SourceGen { int newOffset = mAddrMap.AddressToOffset(offset, newAddr); if (newAddr != mAnattribs[offset].OperandAddress || newOffset != mAnattribs[offset].OperandOffset) { - Debug.WriteLine("DBR rewrite at +" + offset.ToString("x6") + ": $" + - mAnattribs[offset].OperandAddress.ToString("x6") + "/+" + - mAnattribs[offset].OperandOffset.ToString("x6") + " --> $" + - newAddr.ToString("x6") + "/+" + newOffset.ToString("x6")); + //Debug.WriteLine("DBR rewrite at +" + offset.ToString("x6") + ": $" + + // mAnattribs[offset].OperandAddress.ToString("x6") + "/+" + + // mAnattribs[offset].OperandOffset.ToString("x6") + " --> $" + + // newAddr.ToString("x6") + "/+" + newOffset.ToString("x6")); mAnattribs[offset].OperandAddress = newAddr; mAnattribs[offset].OperandOffset = newOffset; } } } + + private void GenerateSmartPlbChanges(Dictionary dbrChanges) { +#if false + // Set B=K every time we cross an address boundary and the program bank changes. + short prevBank = DbrValue.UNKNOWN; + foreach (AddressMap.AddressMapEntry ent in mAddrMap) { + short mapBank = (short)(ent.Addr >> 16); + if (mapBank != prevBank) { + prevBank = mapBank; + dbrChanges.Add(ent.Offset, new DbrValue(false, (byte)mapBank, + DbrValue.Source.Auto)); + } + } +#endif + + // Run through the file, looking for PLB. If the preceding code was something + // we can reliably pull a value out of, create an entry for it. + for (int offset = 0; offset < mAnattribs.Length; offset++) { + if (!mAnattribs[offset].IsInstructionStart) { + continue; + } + OpDef op = mCpuDef.GetOpDef(mFileData[offset]); + if (op != OpDef.OpPLB_StackPull) { + continue; + } + if (offset < 1) { + continue; + } + if (!mAnattribs[offset - 1].IsInstructionStart) { + continue; + } + op = mCpuDef.GetOpDef(mFileData[offset - 1]); + if (op == OpDef.OpPHK_StackPush) { + // output B=K + dbrChanges.Add(offset, new DbrValue(true, 0, DbrValue.Source.Auto)); + } else if (op == OpDef.OpPHA_StackPush && offset >= 4) { + // check for LDA imm + if (!mAnattribs[offset - 3].IsInstructionStart) { + continue; + } + op = mCpuDef.GetOpDef(mFileData[offset - 3]); + if (!(op == OpDef.OpLDA_ImmLongA || op == OpDef.OpLDA_Imm)) { + continue; + } + + byte bank = mFileData[offset - 2]; + dbrChanges.Add(offset, new DbrValue(false, bank, DbrValue.Source.Auto)); + } + } + } } } \ No newline at end of file diff --git a/SourceGen/LineListGen.cs b/SourceGen/LineListGen.cs index d8ce02e..8b72449 100644 --- a/SourceGen/LineListGen.cs +++ b/SourceGen/LineListGen.cs @@ -1056,19 +1056,21 @@ namespace SourceGen { // behavior is unwise.) if (mProject.DbrChanges.TryGetValue(offset, out CodeAnalysis.DbrValue dbrValue)) { - string operandStr; + string bankStr; if (dbrValue.FollowPbr) { - operandStr = Res.Strings.DATA_BANK_USER_K; + bankStr = Res.Strings.DATA_BANK_K; } else { - string fmt; - if (dbrValue.ValueSource == CodeAnalysis.DbrValue.Source.Auto) { - fmt = Res.Strings.DATA_BANK_AUTO_FMT; - } else { - fmt = Res.Strings.DATA_BANK_USER_FMT; - } - operandStr = string.Format(fmt, - mFormatter.FormatHexValue(dbrValue.Bank, 2)); + bankStr = mFormatter.FormatHexValue(dbrValue.Bank, 2); } + + string fmt; + if (dbrValue.ValueSource == CodeAnalysis.DbrValue.Source.Auto) { + fmt = Res.Strings.DATA_BANK_AUTO_FMT; + } else { + fmt = Res.Strings.DATA_BANK_USER_FMT; + } + string operandStr = string.Format(fmt, bankStr); + Line dbrLine = new Line(offset, 0, Line.Type.DataBankDirective); dbrLine.Parts = FormattedParts.CreateDirective( mFormatter.FormatPseudoOp(mPseudoOpNames.DataBankDirective), diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs index 1e15c4e..a3efe64 100644 --- a/SourceGen/ProjectFile.cs +++ b/SourceGen/ProjectFile.cs @@ -225,6 +225,7 @@ namespace SourceGen { public bool SeekNearbyTargets { get; set; } public bool UseRelocData { get; set; } public bool SmartPlpHandling { get; set; } + public bool SmartPlbHandling { get; set; } public SerAnalysisParameters() { } public SerAnalysisParameters(ProjectProperties.AnalysisParameters src) { @@ -234,6 +235,7 @@ namespace SourceGen { SeekNearbyTargets = src.SeekNearbyTargets; UseRelocData = src.UseRelocData; SmartPlpHandling = src.SmartPlpHandling; + SmartPlbHandling = src.SmartPlbHandling; } } public class SerAddressMap { @@ -632,12 +634,19 @@ namespace SourceGen { proj.ProjectProps.AnalysisParams.UseRelocData = spf.ProjectProps.AnalysisParams.UseRelocData; if (spf._ContentVersion < 2) { - // This was made optional in v1.3. Default it to true for older projects. + // This was made optional in v1.3 (#2). Default it to true for older projects. proj.ProjectProps.AnalysisParams.SmartPlpHandling = true; } else { proj.ProjectProps.AnalysisParams.SmartPlpHandling = spf.ProjectProps.AnalysisParams.SmartPlpHandling; } + if (spf._ContentVersion < 4) { + // Introduced in v1.7 (#4). Default it to true for older projects. + proj.ProjectProps.AnalysisParams.SmartPlbHandling = true; + } else { + proj.ProjectProps.AnalysisParams.SmartPlbHandling = + spf.ProjectProps.AnalysisParams.SmartPlbHandling; + } // Deserialize ProjectProperties: external file identifiers. Debug.Assert(proj.ProjectProps.PlatformSymbolFileIdentifiers.Count == 0); diff --git a/SourceGen/ProjectProperties.cs b/SourceGen/ProjectProperties.cs index d188621..4d77412 100644 --- a/SourceGen/ProjectProperties.cs +++ b/SourceGen/ProjectProperties.cs @@ -54,6 +54,7 @@ namespace SourceGen { public bool SeekNearbyTargets { get; set; } public bool UseRelocData { get; set; } public bool SmartPlpHandling { get; set; } + public bool SmartPlbHandling { get; set; } public AnalysisParameters() { // Set default values. @@ -63,6 +64,7 @@ namespace SourceGen { SeekNearbyTargets = true; UseRelocData = false; SmartPlpHandling = true; + SmartPlbHandling = true; } public AnalysisParameters(AnalysisParameters src) { AnalyzeUncategorizedData = src.AnalyzeUncategorizedData; @@ -71,6 +73,7 @@ namespace SourceGen { SeekNearbyTargets = src.SeekNearbyTargets; UseRelocData = src.UseRelocData; SmartPlpHandling = src.SmartPlpHandling; + SmartPlbHandling = src.SmartPlbHandling; } } diff --git a/SourceGen/Res/Strings.xaml b/SourceGen/Res/Strings.xaml index 1e03bb6..80e5481 100644 --- a/SourceGen/Res/Strings.xaml +++ b/SourceGen/Res/Strings.xaml @@ -36,7 +36,7 @@ limitations under the License. Disassembly {0} (auto) {0} - K + K 6502bench SourceGen v{0} ‘#’ “#” diff --git a/SourceGen/Res/Strings.xaml.cs b/SourceGen/Res/Strings.xaml.cs index 9be977e..3a354a4 100644 --- a/SourceGen/Res/Strings.xaml.cs +++ b/SourceGen/Res/Strings.xaml.cs @@ -47,8 +47,8 @@ namespace SourceGen.Res { (string)Application.Current.FindResource("str_DataBankAutoFmt"); public static string DATA_BANK_USER_FMT = (string)Application.Current.FindResource("str_DataBankUserFmt"); - public static string DATA_BANK_USER_K = - (string)Application.Current.FindResource("str_DataBankUserK"); + public static string DATA_BANK_K = + (string)Application.Current.FindResource("str_DataBankK"); public static string DEFAULT_HEADER_COMMENT_FMT = (string)Application.Current.FindResource("str_DefaultHeaderCommentFmt"); public static string DEFAULT_ASCII_DELIM_PAT = diff --git a/SourceGen/RuntimeData/Help/settings.html b/SourceGen/RuntimeData/Help/settings.html index b71ee14..6669d26 100644 --- a/SourceGen/RuntimeData/Help/settings.html +++ b/SourceGen/RuntimeData/Help/settings.html @@ -262,6 +262,11 @@ improve automatic operand formatting.

the processor status flags from a nearby PHP when a PLP is encountered. If not enabled, all flags are set to "indeterminate" following a PLP.

+

If "smart PLB handling" is checked, the analyzer will watch for +code patterns like PLB preceded by PHK, +and generate appropriate Data Bank Register changes. If not enabled, +the DBR is set to the bank of the address of the start of the file, +and does not change unless explicitly set. Only useful for 65816 code.

The "default text encoding" setting has two effects. First, it specifies which character encoding to use when searching for strings in diff --git a/SourceGen/WpfGui/EditProjectProperties.xaml b/SourceGen/WpfGui/EditProjectProperties.xaml index ec001cf..4554e7c 100644 --- a/SourceGen/WpfGui/EditProjectProperties.xaml +++ b/SourceGen/WpfGui/EditProjectProperties.xaml @@ -107,6 +107,8 @@ limitations under the License. IsChecked="{Binding UseRelocData}" IsEnabled="{Binding IsRelocDataAvailable}"/> + diff --git a/SourceGen/WpfGui/EditProjectProperties.xaml.cs b/SourceGen/WpfGui/EditProjectProperties.xaml.cs index a1c3d44..0aa941e 100644 --- a/SourceGen/WpfGui/EditProjectProperties.xaml.cs +++ b/SourceGen/WpfGui/EditProjectProperties.xaml.cs @@ -364,6 +364,14 @@ namespace SourceGen.WpfGui { IsDirty = true; } } + public bool SmartPlbHandling { + get { return mWorkProps.AnalysisParams.SmartPlbHandling; } + set { + mWorkProps.AnalysisParams.SmartPlbHandling = value; + OnPropertyChanged(); + IsDirty = true; + } + } private void Loaded_General() { for (int i = 0; i < CpuItems.Length; i++) {