diff --git a/SourceGen/AppForms/EditAppSettings.Designer.cs b/SourceGen/AppForms/EditAppSettings.Designer.cs index 251af8a..d325672 100644 --- a/SourceGen/AppForms/EditAppSettings.Designer.cs +++ b/SourceGen/AppForms/EditAppSettings.Designer.cs @@ -91,6 +91,8 @@ namespace SourceGen.AppForms { this.showAsmIdentCheckBox = new System.Windows.Forms.CheckBox(); this.disableLabelLocalizationCheckBox = new System.Windows.Forms.CheckBox(); this.displayFormatTabPage = new System.Windows.Forms.TabPage(); + this.expressionStyleComboBox = new System.Windows.Forms.ComboBox(); + this.expressionStyleLabel = new System.Windows.Forms.Label(); this.fmtExplanationLabel = new System.Windows.Forms.Label(); this.quickDisplayFormatGroup = new System.Windows.Forms.GroupBox(); this.displayFmtQuickComboBox = new System.Windows.Forms.ComboBox(); @@ -157,8 +159,6 @@ namespace SourceGen.AppForms { this.defineData1Label = new System.Windows.Forms.Label(); this.equDirectiveTextBox = new System.Windows.Forms.TextBox(); this.equDirectiveLabel = new System.Windows.Forms.Label(); - this.expressionStyleLabel = new System.Windows.Forms.Label(); - this.expressionStyleComboBox = new System.Windows.Forms.ComboBox(); this.settingsTabControl.SuspendLayout(); this.codeViewTabPage.SuspendLayout(); this.codeViewMiscGroupBox.SuspendLayout(); @@ -752,6 +752,24 @@ namespace SourceGen.AppForms { this.displayFormatTabPage.Text = "Display Format"; this.displayFormatTabPage.UseVisualStyleBackColor = true; // + // expressionStyleComboBox + // + this.expressionStyleComboBox.FormattingEnabled = true; + this.expressionStyleComboBox.Location = new System.Drawing.Point(98, 153); + this.expressionStyleComboBox.Name = "expressionStyleComboBox"; + this.expressionStyleComboBox.Size = new System.Drawing.Size(121, 21); + this.expressionStyleComboBox.TabIndex = 5; + this.expressionStyleComboBox.SelectedIndexChanged += new System.EventHandler(this.expressionStyleComboBox_SelectedIndexChanged); + // + // expressionStyleLabel + // + this.expressionStyleLabel.AutoSize = true; + this.expressionStyleLabel.Location = new System.Drawing.Point(7, 156); + this.expressionStyleLabel.Name = "expressionStyleLabel"; + this.expressionStyleLabel.Size = new System.Drawing.Size(85, 13); + this.expressionStyleLabel.TabIndex = 4; + this.expressionStyleLabel.Text = "Expression style:"; + // // fmtExplanationLabel // this.fmtExplanationLabel.AutoSize = true; @@ -1468,24 +1486,6 @@ namespace SourceGen.AppForms { this.equDirectiveLabel.Text = "Equate:"; this.equDirectiveLabel.TextAlign = System.Drawing.ContentAlignment.TopRight; // - // expressionStyleLabel - // - this.expressionStyleLabel.AutoSize = true; - this.expressionStyleLabel.Location = new System.Drawing.Point(7, 156); - this.expressionStyleLabel.Name = "expressionStyleLabel"; - this.expressionStyleLabel.Size = new System.Drawing.Size(85, 13); - this.expressionStyleLabel.TabIndex = 4; - this.expressionStyleLabel.Text = "Expression style:"; - // - // expressionStyleComboBox - // - this.expressionStyleComboBox.FormattingEnabled = true; - this.expressionStyleComboBox.Location = new System.Drawing.Point(98, 153); - this.expressionStyleComboBox.Name = "expressionStyleComboBox"; - this.expressionStyleComboBox.Size = new System.Drawing.Size(121, 21); - this.expressionStyleComboBox.TabIndex = 5; - this.expressionStyleComboBox.SelectedIndexChanged += new System.EventHandler(this.expressionStyleComboBox_SelectedIndexChanged); - // // EditAppSettings // this.AcceptButton = this.okButton; diff --git a/SourceGen/AppForms/EditAppSettings.cs b/SourceGen/AppForms/EditAppSettings.cs index ec4b891..d777523 100644 --- a/SourceGen/AppForms/EditAppSettings.cs +++ b/SourceGen/AppForms/EditAppSettings.cs @@ -37,6 +37,15 @@ namespace SourceGen.AppForms { PseudoOp = 3 } + /// + /// Clipboard format enumeration. Numbers must match order of items in combo box. + /// + public enum ClipLineFormat { + Unknown = -1, + AssemblerSource = 0, + Disassembly = 1 + } + /// /// ProjectView reference. When the user hits Apply, the object's ApplyAppSettings /// method will be invoked. @@ -140,7 +149,7 @@ namespace SourceGen.AppForms { showCol5, showCol6, showCol7, showCol8 }; Debug.Assert(NUM_COLUMNS == 9); - // Extract formats from column-width button labels. + // Extract format strings from column-width button labels. for (int i = 0; i < NUM_COLUMNS; i++) { mColButtons[i].Click += ColumnVisibilityButtonClick; mColumnFormats[i] = mColButtons[i].Text; @@ -230,7 +239,8 @@ namespace SourceGen.AppForms { upperSCheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_S, false); upperXYCheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_XY, false); - int clipIndex = mSettings.GetInt(AppSettings.CLIP_LINE_FORMAT, 0); + int clipIndex = mSettings.GetEnum(AppSettings.CLIP_LINE_FORMAT, + typeof(ClipLineFormat), 0); if (clipIndex >= 0 && clipIndex < clipboardFormatComboBox.Items.Count) { clipboardFormatComboBox.SelectedIndex = clipIndex; } @@ -422,7 +432,8 @@ namespace SourceGen.AppForms { } private void clipboardFormatComboBox_SelectedIndexChanged(object sender, EventArgs e) { - mSettings.SetInt(AppSettings.CLIP_LINE_FORMAT, clipboardFormatComboBox.SelectedIndex); + mSettings.SetEnum(AppSettings.CLIP_LINE_FORMAT, typeof(ClipLineFormat), + clipboardFormatComboBox.SelectedIndex); SetDirty(true); } diff --git a/SourceGen/AppForms/EditProjectProperties.Designer.cs b/SourceGen/AppForms/EditProjectProperties.Designer.cs index 37d9481..ce5b848 100644 --- a/SourceGen/AppForms/EditProjectProperties.Designer.cs +++ b/SourceGen/AppForms/EditProjectProperties.Designer.cs @@ -45,6 +45,9 @@ namespace SourceGen.AppForms { "This is a test to gauge column widths"}, -1); this.tabControl1 = new System.Windows.Forms.TabControl(); this.generalTab = new System.Windows.Forms.TabPage(); + this.miscGroupBox = new System.Windows.Forms.GroupBox(); + this.autoLabelStyleComboBox = new System.Windows.Forms.ComboBox(); + this.autoLabelStyleLabel = new System.Windows.Forms.Label(); this.analysisGroupBox = new System.Windows.Forms.GroupBox(); this.seekAltTargetCheckBox = new System.Windows.Forms.CheckBox(); this.minStringCharsComboBox = new System.Windows.Forms.ComboBox(); @@ -86,6 +89,7 @@ namespace SourceGen.AppForms { this.applyButton = new System.Windows.Forms.Button(); this.tabControl1.SuspendLayout(); this.generalTab.SuspendLayout(); + this.miscGroupBox.SuspendLayout(); this.analysisGroupBox.SuspendLayout(); this.entryFlagsGroupBox.SuspendLayout(); this.cpuGroupBox.SuspendLayout(); @@ -112,6 +116,7 @@ namespace SourceGen.AppForms { // // generalTab // + this.generalTab.Controls.Add(this.miscGroupBox); this.generalTab.Controls.Add(this.analysisGroupBox); this.generalTab.Controls.Add(this.entryFlagsGroupBox); this.generalTab.Controls.Add(this.cpuGroupBox); @@ -123,6 +128,40 @@ namespace SourceGen.AppForms { this.generalTab.Text = "General"; this.generalTab.UseVisualStyleBackColor = true; // + // miscGroupBox + // + this.miscGroupBox.Controls.Add(this.autoLabelStyleComboBox); + this.miscGroupBox.Controls.Add(this.autoLabelStyleLabel); + this.miscGroupBox.Location = new System.Drawing.Point(7, 177); + this.miscGroupBox.Name = "miscGroupBox"; + this.miscGroupBox.Size = new System.Drawing.Size(422, 100); + this.miscGroupBox.TabIndex = 3; + this.miscGroupBox.TabStop = false; + this.miscGroupBox.Text = "Miscellaneous"; + // + // autoLabelStyleComboBox + // + this.autoLabelStyleComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.autoLabelStyleComboBox.FormattingEnabled = true; + this.autoLabelStyleComboBox.Items.AddRange(new object[] { + "Simple (\"L1234\")", + "Annotated (\"W_1234\")", + "Fully Annotated (\"DWR_1234\")"}); + this.autoLabelStyleComboBox.Location = new System.Drawing.Point(98, 19); + this.autoLabelStyleComboBox.Name = "autoLabelStyleComboBox"; + this.autoLabelStyleComboBox.Size = new System.Drawing.Size(318, 21); + this.autoLabelStyleComboBox.TabIndex = 1; + this.autoLabelStyleComboBox.SelectedIndexChanged += new System.EventHandler(this.autoLabelStyleComboBox_SelectedIndexChanged); + // + // autoLabelStyleLabel + // + this.autoLabelStyleLabel.AutoSize = true; + this.autoLabelStyleLabel.Location = new System.Drawing.Point(6, 22); + this.autoLabelStyleLabel.Name = "autoLabelStyleLabel"; + this.autoLabelStyleLabel.Size = new System.Drawing.Size(81, 13); + this.autoLabelStyleLabel.TabIndex = 0; + this.autoLabelStyleLabel.Text = "Auto-label style:"; + // // analysisGroupBox // this.analysisGroupBox.Controls.Add(this.seekAltTargetCheckBox); @@ -568,6 +607,8 @@ namespace SourceGen.AppForms { this.Load += new System.EventHandler(this.EditProperties_Load); this.tabControl1.ResumeLayout(false); this.generalTab.ResumeLayout(false); + this.miscGroupBox.ResumeLayout(false); + this.miscGroupBox.PerformLayout(); this.analysisGroupBox.ResumeLayout(false); this.analysisGroupBox.PerformLayout(); this.entryFlagsGroupBox.ResumeLayout(false); @@ -628,5 +669,8 @@ namespace SourceGen.AppForms { private System.Windows.Forms.Label configuredScriptsLabel; private System.Windows.Forms.Button importSymbolsButton; private System.Windows.Forms.CheckBox seekAltTargetCheckBox; + private System.Windows.Forms.GroupBox miscGroupBox; + private System.Windows.Forms.ComboBox autoLabelStyleComboBox; + private System.Windows.Forms.Label autoLabelStyleLabel; } } \ No newline at end of file diff --git a/SourceGen/AppForms/EditProjectProperties.cs b/SourceGen/AppForms/EditProjectProperties.cs index 0c16c79..0d355cf 100644 --- a/SourceGen/AppForms/EditProjectProperties.cs +++ b/SourceGen/AppForms/EditProjectProperties.cs @@ -112,6 +112,13 @@ namespace SourceGen.AppForms { } minStringCharsComboBox.SelectedIndex = selIndex; + selIndex = (int) mWorkProps.AutoLabelStyle; + if (selIndex < 0 || selIndex >= autoLabelStyleComboBox.Items.Count) { + Debug.Assert(false, "bad AutoLabelStyle " + mWorkProps.AutoLabelStyle); + selIndex = 0; + } + autoLabelStyleComboBox.SelectedIndex = selIndex; + LoadProjectSymbols(); LoadPlatformSymbolFiles(); LoadExtensionScriptNames(); @@ -245,6 +252,7 @@ namespace SourceGen.AppForms { } private void minStringCharsComboBox_SelectedIndexChanged(object sender, EventArgs e) { + // ComboBox must be the value 0, then N+2 in each subsequent entry (3, 4, 5, ...). int index = minStringCharsComboBox.SelectedIndex; int newVal; if (index == 0) { @@ -260,6 +268,15 @@ namespace SourceGen.AppForms { } } + private void autoLabelStyleComboBox_SelectedIndexChanged(object sender, EventArgs e) { + AutoLabel.Style newStyle = (AutoLabel.Style)autoLabelStyleComboBox.SelectedIndex; + if (newStyle != mWorkProps.AutoLabelStyle) { + mWorkProps.AutoLabelStyle = newStyle; + mDirty = true; + UpdateControls(); + } + } + #endregion General diff --git a/SourceGen/AppForms/FormatSplitAddress.cs b/SourceGen/AppForms/FormatSplitAddress.cs index dc8feeb..b2a15f7 100644 --- a/SourceGen/AppForms/FormatSplitAddress.cs +++ b/SourceGen/AppForms/FormatSplitAddress.cs @@ -385,7 +385,7 @@ namespace SourceGen.AppForms { // won't generate identical labels for different addresses, and we do // want to generate a single label if more than one table entry refers // to the same target. - Symbol tmpSym = SymbolTable.GenerateUniqueForAddress(addr, + Symbol tmpSym = AutoLabel.GenerateUniqueForAddress(addr, mProject.SymbolTable, "T"); // tmpSym was returned as an auto-label, make it a user label instead tmpSym = new Symbol(tmpSym.Label, tmpSym.Value, Symbol.Source.User, diff --git a/SourceGen/AppForms/ProjectView.cs b/SourceGen/AppForms/ProjectView.cs index 3ddb606..dc04f04 100644 --- a/SourceGen/AppForms/ProjectView.cs +++ b/SourceGen/AppForms/ProjectView.cs @@ -1731,11 +1731,13 @@ namespace SourceGen.AppForms { // Edit > Copy (Ctrl+C) private void copyToolStripMenuItem_Click(object sender, EventArgs e) { - const int AssemblerSource = 0; - const int Disassembly = 1; const bool addCsv = true; - int format = AppSettings.Global.GetInt(AppSettings.CLIP_LINE_FORMAT, AssemblerSource); + EditAppSettings.ClipLineFormat format = + (EditAppSettings.ClipLineFormat) AppSettings.Global.GetEnum( + AppSettings.CLIP_LINE_FORMAT, + typeof(EditAppSettings.ClipLineFormat), + (int) EditAppSettings.ClipLineFormat.AssemblerSource); StringBuilder fullText = new StringBuilder(codeListView.SelectedIndices.Count * 50); StringBuilder csv = new StringBuilder(codeListView.SelectedIndices.Count * 40); StringBuilder sb = new StringBuilder(100); @@ -1743,7 +1745,7 @@ namespace SourceGen.AppForms { int addrAdj = mProject.CpuDef.HasAddr16 ? 6 : 9; int disAdj = 0; int bytesWidth = 0; - if (format == Disassembly) { + if (format == EditAppSettings.ClipLineFormat.Disassembly) { // A limit of 8 gets us 4 bytes from dense display ("20edfd60") and 3 if spaces // are included ("20 ed fd") with no excess. We want to increase it to 11 so // we can always show 4 bytes. @@ -1766,7 +1768,7 @@ namespace SourceGen.AppForms { case DisplayList.Line.Type.EquDirective: case DisplayList.Line.Type.RegWidthDirective: case DisplayList.Line.Type.OrgDirective: - if (format == Disassembly) { + if (format == EditAppSettings.ClipLineFormat.Disassembly) { if (!string.IsNullOrEmpty(parts.Addr)) { sb.Append(parts.Addr); sb.Append(": "); @@ -1791,7 +1793,7 @@ namespace SourceGen.AppForms { sb.Append("\r\n"); break; case DisplayList.Line.Type.LongComment: - if (format == Disassembly) { + if (format == EditAppSettings.ClipLineFormat.Disassembly) { TextUtil.AppendPaddedString(sb, string.Empty, disAdj); } sb.Append(parts.Comment); diff --git a/SourceGen/AppSettings.cs b/SourceGen/AppSettings.cs index 38f6c0e..7d46b78 100644 --- a/SourceGen/AppSettings.cs +++ b/SourceGen/AppSettings.cs @@ -243,6 +243,40 @@ namespace SourceGen { Dirty = true; } + /// + /// Retrieves an enumerated value setting. + /// + /// Setting name. + /// Enum type that the value is part of. + /// Setting default value. + /// The value found, or the default value if no setting with the specified + /// name exists, or the stored value is not a member of the specified enumerated + /// type. + public int GetEnum(string name, Type enumType, int defaultValue) { + if (!mSettings.TryGetValue(name, out string valueStr)) { + return defaultValue; + } + try { + object o = Enum.Parse(enumType, valueStr); + return (int)o; + } catch (ArgumentException ae) { + Debug.WriteLine("Failed to parse " + valueStr + " (enum " + enumType + "): " + + ae.Message); + return defaultValue; + } + } + + /// + /// Sets an enumerated setting. + /// + /// Setting name. + /// Enum type. + /// Setting value (integer enum index). + public void SetEnum(string name, Type enumType, int value) { + mSettings[name] = Enum.GetName(enumType, value); + Dirty = true; + } + /// /// Retrieves a string setting. The default value will be returned if the key /// is not found, or if the value is null. diff --git a/SourceGen/AsmGen/AssemblerVersion.cs b/SourceGen/AsmGen/AssemblerVersion.cs index f52a1ae..3102ffa 100644 --- a/SourceGen/AsmGen/AssemblerVersion.cs +++ b/SourceGen/AsmGen/AssemblerVersion.cs @@ -20,7 +20,7 @@ using System.Diagnostics; namespace SourceGen.AsmGen { public class AssemblerVersion { /// - /// Version string reported by the assembler. + /// Version string reported by the assembler. Retained mostly for debugging. /// public string VersionStr { get; private set; } @@ -49,7 +49,7 @@ namespace SourceGen.AsmGen { } public override string ToString() { - return "[" + VersionStr + "/" + Version + "]"; + return "['" + VersionStr + "'/" + Version + "]"; } } diff --git a/SourceGen/AutoLabel.cs b/SourceGen/AutoLabel.cs new file mode 100644 index 0000000..b3053b6 --- /dev/null +++ b/SourceGen/AutoLabel.cs @@ -0,0 +1,164 @@ +/* + * Copyright 2019 faddenSoft + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace SourceGen { + /// + /// Functions for generation of "auto" labels. + /// + public static class AutoLabel { + /// + /// Auto-label style enumeration. Values were chosen to map directly to a combo box. + /// + public enum Style { + Unknown = -1, + Simple = 0, + Annotated = 1, + FullyAnnotated = 2 + } + + /// + /// Generates a unique address symbol. Does not add the symbol to the table. + /// + /// This does not follow any Formatter rules -- labels are always entirely upper-case. + /// + /// Address that label will be applied to. + /// Symbol table, for uniqueness check. + /// Prefix to use; must start with a letter. + /// Newly-created, unique symbol. + public static Symbol GenerateUniqueForAddress(int addr, SymbolTable symbols, + string prefix) { + // $1234 == L1234, $05/1234 == L51234. + string label = prefix + addr.ToString("X4"); // always upper-case + if (symbols.TryGetValue(label, out Symbol unused)) { + const int MAX_RENAME = 999; + string baseLabel = label; + StringBuilder sb = new StringBuilder(baseLabel.Length + 8); + int index = -1; + + do { + // This is expected to be unlikely and infrequent, so a simple linear + // probe for uniqueness is fine. Labels are based on the address, not + // the offset, so even without user-created labels there's still an + // opportunity for duplication. + index++; + sb.Clear(); + sb.Append(baseLabel); + sb.Append('_'); + sb.Append(index); + label = sb.ToString(); + } while (index <= MAX_RENAME && symbols.TryGetValue(label, out unused)); + if (index > MAX_RENAME) { + // I give up + throw new Exception("Too many identical symbols: " + label); + } + } + Symbol sym = new Symbol(label, addr, Symbol.Source.Auto, + Symbol.Type.LocalOrGlobalAddr); + return sym; + } + + /// + /// Source reference type. + /// + /// The enum is in priority order, i.e. the lowest-valued item "wins" in situations + /// where only one value is used. + /// + [Flags] + private enum RefTypes { + None = 0, + SubCall = 1 << 0, + Branch = 1 << 1, + DataRef = 1 << 2, + Write = 1 << 3, + Read = 1 << 4, + } + private static readonly char[] TAGS = { 'S', 'B', 'D', 'W', 'R' }; + + /// + /// Generates an auto-label with a prefix string based on the XrefSet. + /// + /// Address that label will be applied to. + /// Symbol table, for uniqueness check. + /// Cross-references for this location. + /// Newly-created, unique symbol. + public static Symbol GenerateAnnotatedLabel(int addr, SymbolTable symbols, + XrefSet xset, Style style) { + Debug.Assert(xset != null); + Debug.Assert(style != Style.Simple); + + RefTypes rtypes = RefTypes.None; + foreach (XrefSet.Xref xr in xset) { + switch (xr.Type) { + case XrefSet.XrefType.SubCallOp: + rtypes |= RefTypes.SubCall; + break; + case XrefSet.XrefType.BranchOp: + rtypes |= RefTypes.Branch; + break; + case XrefSet.XrefType.RefFromData: + rtypes |= RefTypes.DataRef; + break; + case XrefSet.XrefType.MemAccessOp: + switch (xr.AccType) { + case Asm65.OpDef.MemoryEffect.Read: + rtypes |= RefTypes.Read; + break; + case Asm65.OpDef.MemoryEffect.Write: + rtypes |= RefTypes.Write; + break; + case Asm65.OpDef.MemoryEffect.ReadModifyWrite: + rtypes |= RefTypes.Read; + rtypes |= RefTypes.Write; + break; + case Asm65.OpDef.MemoryEffect.None: + case Asm65.OpDef.MemoryEffect.Unknown: + break; + default: + Debug.Assert(false); + break; + } + break; + default: + Debug.Assert(false); + break; + } + } + + if (rtypes == RefTypes.None) { + // unexpected + Debug.Assert(false); + return GenerateUniqueForAddress(addr, symbols, "X_"); + } + + StringBuilder sb = new StringBuilder(8); + for (int i = 0; i < TAGS.Length; i++) { + if (((int) rtypes & (1 << i)) != 0) { + sb.Append(TAGS[i]); + + if (style == Style.Annotated) { + break; + } + } + } + sb.Append('_'); + return GenerateUniqueForAddress(addr, symbols, sb.ToString()); + } + } +} diff --git a/SourceGen/DataAnalysis.cs b/SourceGen/DataAnalysis.cs index 6148151..5714ba6 100644 --- a/SourceGen/DataAnalysis.cs +++ b/SourceGen/DataAnalysis.cs @@ -311,7 +311,7 @@ namespace SourceGen { // incorporates the address. It's possible through various means to end // up with a user or platform label that matches an auto label, so we // need to do some renaming in that case. Shouldn't happen often. - Symbol sym = SymbolTable.GenerateUniqueForAddress(mAnattribs[targetOffset].Address, + Symbol sym = AutoLabel.GenerateUniqueForAddress(mAnattribs[targetOffset].Address, mProject.SymbolTable, "L"); mAnattribs[targetOffset].Symbol = sym; // This will throw if the symbol already exists. That is the desired diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs index 338531f..69c9038 100644 --- a/SourceGen/DisasmProject.cs +++ b/SourceGen/DisasmProject.cs @@ -477,6 +477,13 @@ namespace SourceGen { GenerateXrefs(); reanalysisTimer.EndTask("GenerateXrefs"); + // replace simple auto-labels ("L1234") with annotated versions ("WR_1234") + if (ProjectProps.AutoLabelStyle != AutoLabel.Style.Simple) { + reanalysisTimer.StartTask("AnnotateAutoLabels"); + AnnotateAutoLabels(); + reanalysisTimer.EndTask("AnnotateAutoLabels"); + } + reanalysisTimer.StartTask("GenerateActiveDefSymbolList"); // Generate the list of project/platform symbols that are being used. This forms // the list of EQUates at the top of the file. @@ -676,7 +683,7 @@ namespace SourceGen { /// Call this after the code and data analysis passes have completed. This doesn't /// interact with labels, so the ordering there doesn't matter. /// - public void GeneratePlatformSymbolRefs() { + private void GeneratePlatformSymbolRefs() { bool checkNearby = ProjectProps.AnalysisParams.SeekNearbyTargets; for (int offset = 0; offset < mAnattribs.Length; ) { @@ -738,7 +745,7 @@ namespace SourceGen { /// /// Call this after the code and data analysis passes have completed. /// - public void GenerateXrefs() { + private void GenerateXrefs() { // Xref generation. There are two general categories of references: // (1) Numeric reference. Comes from instructions (e.g. "LDA $1000" or "BRA $1000") // and Numeric/Address data items. @@ -901,6 +908,39 @@ namespace SourceGen { return xset; // will be null if not found } + /// + /// Replaces generic auto-labels with fancier versions generated from xrefs. + /// + private void AnnotateAutoLabels() { + AutoLabel.Style style = ProjectProps.AutoLabelStyle; + Debug.Assert(style != AutoLabel.Style.Simple); + + for (int offset = 0; offset < mAnattribs.Length; offset++) { + Anattrib attr = mAnattribs[offset]; + if (attr.Symbol != null && attr.Symbol.SymbolSource == Symbol.Source.Auto) { + XrefSet xset = GetXrefSet(offset); + if (xset == null) { + // Nothing useful to do here. This is unexpected, since auto-labels + // should only exist because something referenced the offset. + continue; + } + Symbol newSym = + AutoLabel.GenerateAnnotatedLabel(attr.Address, SymbolTable, xset, style); + if (!newSym.Equals(attr.Symbol)) { + //Debug.WriteLine("Replace " + attr.Symbol.Label + " with " +newSym.Label); + + // Replace the symbol in Anattribs, update the symbol table, then + // call Refactor to update everything that referenced it. + Symbol oldSym = mAnattribs[offset].Symbol; + mAnattribs[offset].Symbol = newSym; + SymbolTable.Remove(oldSym); + SymbolTable.Add(newSym); + RefactorLabel(offset, oldSym.Label); + } + } + } + } + /// /// Generates the list of project/platform symbols that are being used. Any /// DefSymbol with a non-empty Xrefs is included. Previous contents are cleared. diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs index 9a77fa4..1968b87 100644 --- a/SourceGen/ProjectFile.cs +++ b/SourceGen/ProjectFile.cs @@ -185,6 +185,7 @@ namespace SourceGen { public string CpuName { get; set; } public bool IncludeUndocumentedInstr { get; set; } public int EntryFlags { get; set; } + public string AutoLabelStyle { get; set; } public SerAnalysisParameters AnalysisParams { get; set; } public List PlatformSymbolFileIdentifiers { get; set; } public List ExtensionScriptFileIdentifiers { get; set; } @@ -195,6 +196,7 @@ namespace SourceGen { CpuName = Asm65.CpuDef.GetCpuNameFromType(props.CpuType); IncludeUndocumentedInstr = props.IncludeUndocumentedInstr; EntryFlags = props.EntryFlags.AsInt; + AutoLabelStyle = props.AutoLabelStyle.ToString(); AnalysisParams = new SerAnalysisParameters(props.AnalysisParams); // External file identifiers require no conversion. @@ -461,6 +463,12 @@ namespace SourceGen { proj.ProjectProps.CpuType = Asm65.CpuDef.GetCpuTypeFromName(spf.ProjectProps.CpuName); proj.ProjectProps.IncludeUndocumentedInstr = spf.ProjectProps.IncludeUndocumentedInstr; proj.ProjectProps.EntryFlags = Asm65.StatusFlags.FromInt(spf.ProjectProps.EntryFlags); + if (Enum.TryParse(spf.ProjectProps.AutoLabelStyle, + out AutoLabel.Style als)) { + proj.ProjectProps.AutoLabelStyle = als; + } else { + // unknown value, leave as default + } proj.ProjectProps.AnalysisParams = new ProjectProperties.AnalysisParameters(); proj.ProjectProps.AnalysisParams.AnalyzeUncategorizedData = spf.ProjectProps.AnalysisParams.AnalyzeUncategorizedData; diff --git a/SourceGen/ProjectProperties.cs b/SourceGen/ProjectProperties.cs index bfc276a..eaf6251 100644 --- a/SourceGen/ProjectProperties.cs +++ b/SourceGen/ProjectProperties.cs @@ -26,6 +26,12 @@ namespace SourceGen { /// All fields are explicitly handled by the ProjectFile serializer. /// public class ProjectProperties { + // + // NOTE: + // If you add or modify a member, make sure to update the copy constructor and + // add serialization code to ProjectFile. + // + /// /// Some parameters we feed to the analyzers. /// @@ -61,6 +67,11 @@ namespace SourceGen { /// public Asm65.StatusFlags EntryFlags { get; set; } + /// + /// Naming style for auto-generated labels. + /// + public AutoLabel.Style AutoLabelStyle { get; set; } + /// /// Configurable parameters for the analyzers. /// @@ -101,6 +112,7 @@ namespace SourceGen { CpuType = src.CpuType; IncludeUndocumentedInstr = src.IncludeUndocumentedInstr; EntryFlags = src.EntryFlags; + AutoLabelStyle = src.AutoLabelStyle; AnalysisParams = new AnalysisParameters(src.AnalysisParams); diff --git a/SourceGen/RuntimeData/Help/mainwin.html b/SourceGen/RuntimeData/Help/mainwin.html index c5dd301..7006bed 100644 --- a/SourceGen/RuntimeData/Help/mainwin.html +++ b/SourceGen/RuntimeData/Help/mainwin.html @@ -227,9 +227,12 @@ data operand, and provides an indication of the nature of the reference:

  • data - address referenced by data (e.g. .DD2 addr)
  • In addition, the source will be identified as a symbolic ("Sym") or -numeric ("Num") reference. Symbolic references may be offset from the -actual operand value; if this is the case, the adjustment will be shown -as well.

    +numeric ("Num") reference. Most will be symbolic, because SourceGen +generates symbols automatically. However, references to addresses that +are offset from a symbol will also create a numeric reference entry. +For example, "LDA addr+1" will create a symbolic reference at <addr> +(shown in the table with an adjustment of "+1") and a numeric reference +at <addr+1>.

    Double-clicking on a reference moves the code list selection to that reference, and adds the previous selection to the navigation stack.

    diff --git a/SourceGen/SourceGen.csproj b/SourceGen/SourceGen.csproj index 14090d1..79a0444 100644 --- a/SourceGen/SourceGen.csproj +++ b/SourceGen/SourceGen.csproj @@ -131,6 +131,7 @@ + diff --git a/SourceGen/SymbolTable.cs b/SourceGen/SymbolTable.cs index 1d4926f..a162fc9 100644 --- a/SourceGen/SymbolTable.cs +++ b/SourceGen/SymbolTable.cs @@ -211,42 +211,5 @@ namespace SourceGen { mSymbolsByValue.Remove(sym); ChangeSerial++; } - - /// - /// Generates a unique address symbol. Does not add the symbol to the list. - /// - /// Address that label will be applied to. - /// Symbol table. - /// Prefix to use; must start with a letter. - /// Newly-created, unique symbol. - public static Symbol GenerateUniqueForAddress(int addr, SymbolTable symbols, - string prefix) { - // $1234 == L1234, $05/1234 == L51234. - string label = prefix + addr.ToString("X4"); // always upper-case - if (symbols.TryGetValue(label, out Symbol unused)) { - const int MAX_RENAME = 999; - string baseLabel = label; - StringBuilder sb = new StringBuilder(baseLabel.Length + 8); - int index = -1; - - do { - // This is expected to be unlikely and infrequent, so a simple linear - // probe for uniqueness is fine. - index++; - sb.Clear(); - sb.Append(baseLabel); - sb.Append('_'); - sb.Append(index); - label = sb.ToString(); - } while (index <= MAX_RENAME && symbols.TryGetValue(label, out unused)); - if (index > MAX_RENAME) { - // I give up - throw new Exception("Too many identical symbols"); - } - } - Symbol sym = new Symbol(label, addr, Symbol.Source.Auto, - Symbol.Type.LocalOrGlobalAddr); - return sym; - } } } diff --git a/SourceGen/XrefSet.cs b/SourceGen/XrefSet.cs index 3fa602e..c138767 100644 --- a/SourceGen/XrefSet.cs +++ b/SourceGen/XrefSet.cs @@ -28,9 +28,6 @@ namespace SourceGen { public class XrefSet : IEnumerable { /// /// Reference type. This is mostly useful for display to the user. - /// - /// The enum is in priority order, i.e. the lowest-valued - /// item "wins" in situations where only one value is used. /// public enum XrefType { Unknown = 0,