mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-29 10:50:28 +00:00
Add selectable auto-label styles
SourceGen creates "auto" labels when it finds a reference to an address that doesn't have a label associated with it. The label for address $1234 would be "L1234". This change allows the project to specify alternative label naming conventions, annotating them with information from the cross-reference data. For example, a subroutine entry point (i.e. the target of a JSR) would be "S_1234". (The underscore was added to avoid confusion when an annotation letter is the same as a hex digit.) Also, tweaked the way the preferred clipboard line format is stored in the settings file (was an integer, now an enumeration string).
This commit is contained in:
parent
47b1363738
commit
97a372a884
40
SourceGen/AppForms/EditAppSettings.Designer.cs
generated
40
SourceGen/AppForms/EditAppSettings.Designer.cs
generated
@ -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;
|
||||
|
@ -37,6 +37,15 @@ namespace SourceGen.AppForms {
|
||||
PseudoOp = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clipboard format enumeration. Numbers must match order of items in combo box.
|
||||
/// </summary>
|
||||
public enum ClipLineFormat {
|
||||
Unknown = -1,
|
||||
AssemblerSource = 0,
|
||||
Disassembly = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
44
SourceGen/AppForms/EditProjectProperties.Designer.cs
generated
44
SourceGen/AppForms/EditProjectProperties.Designer.cs
generated
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -243,6 +243,40 @@ namespace SourceGen {
|
||||
Dirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an enumerated value setting.
|
||||
/// </summary>
|
||||
/// <param name="name">Setting name.</param>
|
||||
/// <param name="enumType">Enum type that the value is part of.</param>
|
||||
/// <param name="defaultValue">Setting default value.</param>
|
||||
/// <returns>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.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an enumerated setting.
|
||||
/// </summary>
|
||||
/// <param name="name">Setting name.</param>
|
||||
/// <param name="enumType">Enum type.</param>
|
||||
/// <param name="value">Setting value (integer enum index).</param>
|
||||
public void SetEnum(string name, Type enumType, int value) {
|
||||
mSettings[name] = Enum.GetName(enumType, value);
|
||||
Dirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a string setting. The default value will be returned if the key
|
||||
/// is not found, or if the value is null.
|
||||
|
@ -20,7 +20,7 @@ using System.Diagnostics;
|
||||
namespace SourceGen.AsmGen {
|
||||
public class AssemblerVersion {
|
||||
/// <summary>
|
||||
/// Version string reported by the assembler.
|
||||
/// Version string reported by the assembler. Retained mostly for debugging.
|
||||
/// </summary>
|
||||
public string VersionStr { get; private set; }
|
||||
|
||||
@ -49,7 +49,7 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "[" + VersionStr + "/" + Version + "]";
|
||||
return "['" + VersionStr + "'/" + Version + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
164
SourceGen/AutoLabel.cs
Normal file
164
SourceGen/AutoLabel.cs
Normal file
@ -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 {
|
||||
/// <summary>
|
||||
/// Functions for generation of "auto" labels.
|
||||
/// </summary>
|
||||
public static class AutoLabel {
|
||||
/// <summary>
|
||||
/// Auto-label style enumeration. Values were chosen to map directly to a combo box.
|
||||
/// </summary>
|
||||
public enum Style {
|
||||
Unknown = -1,
|
||||
Simple = 0,
|
||||
Annotated = 1,
|
||||
FullyAnnotated = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="addr">Address that label will be applied to.</param>
|
||||
/// <param name="symbols">Symbol table, for uniqueness check.</param>
|
||||
/// <param name="prefix">Prefix to use; must start with a letter.</param>
|
||||
/// <returns>Newly-created, unique symbol.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Source reference type.
|
||||
///
|
||||
/// The enum is in priority order, i.e. the lowest-valued item "wins" in situations
|
||||
/// where only one value is used.
|
||||
/// </summary>
|
||||
[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' };
|
||||
|
||||
/// <summary>
|
||||
/// Generates an auto-label with a prefix string based on the XrefSet.
|
||||
/// </summary>
|
||||
/// <param name="addr">Address that label will be applied to.</param>
|
||||
/// <param name="symbols">Symbol table, for uniqueness check.</param>
|
||||
/// <param name="xset">Cross-references for this location.</param>
|
||||
/// <returns>Newly-created, unique symbol.</returns>
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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.
|
||||
/// </summary>
|
||||
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.
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces generic auto-labels with fancier versions generated from xrefs.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the list of project/platform symbols that are being used. Any
|
||||
/// DefSymbol with a non-empty Xrefs is included. Previous contents are cleared.
|
||||
|
@ -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<string> PlatformSymbolFileIdentifiers { get; set; }
|
||||
public List<string> 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<AutoLabel.Style>(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;
|
||||
|
@ -26,6 +26,12 @@ namespace SourceGen {
|
||||
/// All fields are explicitly handled by the ProjectFile serializer.
|
||||
/// </summary>
|
||||
public class ProjectProperties {
|
||||
//
|
||||
// NOTE:
|
||||
// If you add or modify a member, make sure to update the copy constructor and
|
||||
// add serialization code to ProjectFile.
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Some parameters we feed to the analyzers.
|
||||
/// </summary>
|
||||
@ -61,6 +67,11 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
public Asm65.StatusFlags EntryFlags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Naming style for auto-generated labels.
|
||||
/// </summary>
|
||||
public AutoLabel.Style AutoLabelStyle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Configurable parameters for the analyzers.
|
||||
/// </summary>
|
||||
@ -101,6 +112,7 @@ namespace SourceGen {
|
||||
CpuType = src.CpuType;
|
||||
IncludeUndocumentedInstr = src.IncludeUndocumentedInstr;
|
||||
EntryFlags = src.EntryFlags;
|
||||
AutoLabelStyle = src.AutoLabelStyle;
|
||||
|
||||
AnalysisParams = new AnalysisParameters(src.AnalysisParams);
|
||||
|
||||
|
@ -227,9 +227,12 @@ data operand, and provides an indication of the nature of the reference:</p>
|
||||
<li>data - address referenced by data (e.g. .DD2 addr)</li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
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>.</p>
|
||||
|
||||
<p>Double-clicking on a reference moves the code list selection to that
|
||||
reference, and adds the previous selection to the navigation stack.</p>
|
||||
|
@ -131,6 +131,7 @@
|
||||
<Compile Include="AsmGen\IGenerator.cs" />
|
||||
<Compile Include="AsmGen\LabelLocalizer.cs" />
|
||||
<Compile Include="AsmGen\StringGather.cs" />
|
||||
<Compile Include="AutoLabel.cs" />
|
||||
<Compile Include="NavStack.cs" />
|
||||
<Compile Include="ChangeSet.cs" />
|
||||
<Compile Include="CodeAnalysis.cs" />
|
||||
|
@ -211,42 +211,5 @@ namespace SourceGen {
|
||||
mSymbolsByValue.Remove(sym);
|
||||
ChangeSerial++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a unique address symbol. Does not add the symbol to the list.
|
||||
/// </summary>
|
||||
/// <param name="addr">Address that label will be applied to.</param>
|
||||
/// <param name="symbols">Symbol table.</param>
|
||||
/// <param name="prefix">Prefix to use; must start with a letter.</param>
|
||||
/// <returns>Newly-created, unique symbol.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,6 @@ namespace SourceGen {
|
||||
public class XrefSet : IEnumerable<XrefSet.Xref> {
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public enum XrefType {
|
||||
Unknown = 0,
|
||||
|
Loading…
Reference in New Issue
Block a user