diff --git a/CommonUtil/Misc.cs b/CommonUtil/Misc.cs
index 97e59b1..3bc7332 100644
--- a/CommonUtil/Misc.cs
+++ b/CommonUtil/Misc.cs
@@ -42,10 +42,10 @@ namespace CommonUtil {
///
///
/// Usage:
- /// AppDomain.CurrentDomain.UnhandledException +=
- /// new UnhandledExceptionEventHandler(CommonUtil.Misc.CrashReporter);
+ /// AppDomain.CurrentDomain.UnhandledException +=
+ /// new UnhandledExceptionEventHandler(CommonUtil.Misc.CrashReporter);
///
- /// Thanks: https://stackoverflow.com/a/21308327/294248
+ /// Thanks: .
///
public static void CrashReporter(object sender, UnhandledExceptionEventArgs e) {
const string CRASH_PATH = @"CrashLog.txt";
@@ -80,7 +80,7 @@ namespace CommonUtil {
/// faster than setting array elements individually.
///
///
- /// From https://stackoverflow.com/a/18659408/294248
+ /// From .
///
/// Invokes Array.Copy() on overlapping elements. Other approaches involve using
/// Buffer.BlockCopy or unsafe code. Apparently .NET Core has an Array.Fill(), but
diff --git a/SourceGen/AppSettings.cs b/SourceGen/AppSettings.cs
index e700d0e..41fc265 100644
--- a/SourceGen/AppSettings.cs
+++ b/SourceGen/AppSettings.cs
@@ -124,7 +124,7 @@ namespace SourceGen {
// Source generation settings.
public const string SRCGEN_DEFAULT_ASM = "srcgen-default-asm";
public const string SRCGEN_ADD_IDENT_COMMENT = "srcgen-add-ident-comment";
- public const string SRCGEN_LONG_LABEL_NEW_LINE = "srcgen-long-label-new-line";
+ public const string SRCGEN_LABEL_NEW_LINE = "srcgen-label-new-line";
public const string SRCGEN_SHOW_CYCLE_COUNTS = "srcgen-show-cycle-counts";
// Label file generation settings.
@@ -291,21 +291,20 @@ namespace SourceGen {
///
/// Retrieves an enumerated value setting.
///
+ /// Enumerated type.
/// 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) {
+ /// name exists, or the stored value is not a member of the enumeration.
+ public T GetEnum(string name, T defaultValue) {
if (!mSettings.TryGetValue(name, out string valueStr)) {
return defaultValue;
}
try {
- object o = Enum.Parse(enumType, valueStr);
- return (int)o;
+ object o = Enum.Parse(typeof(T), valueStr);
+ return (T)o;
} catch (ArgumentException ae) {
- Debug.WriteLine("Failed to parse " + valueStr + " (enum " + enumType + "): " +
+ Debug.WriteLine("Failed to parse '" + valueStr + "' (enum " + typeof(T) + "): " +
ae.Message);
return defaultValue;
}
@@ -314,14 +313,20 @@ namespace SourceGen {
///
/// Sets an enumerated setting.
///
+ ///
+ /// The value is output to the settings file as a string, rather than an integer, allowing
+ /// the correct handling even if the enumerated values are renumbered.
+ ///
+ /// Enumerated type.
/// Setting name.
- /// Enum type.
/// Setting value (integer enum index).
- public void SetEnum(string name, Type enumType, int value) {
- string newVal = Enum.GetName(enumType, value);
+ public void SetEnum(string name, T value) {
+ if (value == null) {
+ throw new NotImplementedException("Can't handle a null-valued enum type");
+ }
+ string newVal = Enum.GetName(typeof(T), value);
if (newVal == null) {
- // Shouldn't be possible if an enum value of the correct type is passed in.
- Debug.WriteLine("Unable to get enum name type=" + enumType + " value=" + value);
+ Debug.WriteLine("Unable to get enum name type=" + typeof(T) + " value=" + value);
return;
}
if (!mSettings.TryGetValue(name, out string oldValue) || oldValue != newVal) {
diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs
index 24b3777..d3c56c0 100644
--- a/SourceGen/AsmGen/AsmAcme.cs
+++ b/SourceGen/AsmGen/AsmAcme.cs
@@ -62,9 +62,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
///
- /// If set, long labels get their own line.
+ /// Influences whether labels are put on their own line.
///
- private bool mLongLabelNewLine;
+ private GenCommon.LabelPlacement mLabelNewLine;
///
/// Output column widths.
@@ -198,7 +198,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
- mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
+ mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Acme);
@@ -667,7 +668,9 @@ namespace SourceGen.AsmGen {
!string.Equals(opcode, sDataOpNames.EquDirective,
StringComparison.InvariantCultureIgnoreCase)) {
- if (mLongLabelNewLine && label.Length >= mColumnWidths[0]) {
+ if (mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
+ (mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
+ label.Length >= mColumnWidths[0])) {
mOutStream.WriteLine(label);
label = string.Empty;
}
diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs
index f64a5ae..5292529 100644
--- a/SourceGen/AsmGen/AsmCc65.cs
+++ b/SourceGen/AsmGen/AsmCc65.cs
@@ -57,9 +57,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
///
- /// If set, long labels get their own line.
+ /// Influences whether labels are put on their own line.
///
- private bool mLongLabelNewLine;
+ private GenCommon.LabelPlacement mLabelNewLine;
///
/// Output column widths.
@@ -188,7 +188,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
- mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
+ mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Cc65);
@@ -659,7 +660,9 @@ namespace SourceGen.AsmGen {
StringComparison.InvariantCultureIgnoreCase)) {
label += ':';
- if (mLongLabelNewLine && label.Length >= mColumnWidths[0]) {
+ if (mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
+ (mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
+ label.Length >= mColumnWidths[0])) {
mOutStream.WriteLine(label);
label = string.Empty;
}
diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs
index 08d843a..da74dea 100644
--- a/SourceGen/AsmGen/AsmMerlin32.cs
+++ b/SourceGen/AsmGen/AsmMerlin32.cs
@@ -57,9 +57,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
///
- /// If set, long labels get their own line.
+ /// Influences whether labels are put on their own line.
///
- private bool mLongLabelNewLine;
+ private GenCommon.LabelPlacement mLabelNewLine;
///
/// Output column widths.
@@ -174,7 +174,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
- mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
+ mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Merlin32);
@@ -606,11 +607,14 @@ namespace SourceGen.AsmGen {
// IGenerator
public void OutputLine(string label, string opcode, string operand, string comment) {
// Split long label, but not on EQU directives (confuses the assembler).
- if (mLongLabelNewLine && label.Length >= mColumnWidths[0] &&
- !string.Equals(opcode, sDataOpNames.EquDirective,
+ if (!string.IsNullOrEmpty(label) && !string.Equals(opcode, sDataOpNames.EquDirective,
StringComparison.InvariantCultureIgnoreCase)) {
- mOutStream.WriteLine(label);
- label = string.Empty;
+ if (mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
+ (mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
+ label.Length >= mColumnWidths[0])) {
+ mOutStream.WriteLine(label);
+ label = string.Empty;
+ }
}
mLineBuilder.Clear();
diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs
index 5c02c34..7e685c2 100644
--- a/SourceGen/AsmGen/AsmTass64.cs
+++ b/SourceGen/AsmGen/AsmTass64.cs
@@ -73,9 +73,9 @@ namespace SourceGen.AsmGen {
private string mWorkDirectory;
///
- /// If set, long labels get their own line.
+ /// Influences whether labels are put on their own line.
///
- private bool mLongLabelNewLine;
+ private GenCommon.LabelPlacement mLabelNewLine;
///
/// Output column widths.
@@ -201,7 +201,8 @@ namespace SourceGen.AsmGen {
mFileNameBase = fileNameBase;
Settings = settings;
- mLongLabelNewLine = Settings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
+ mLabelNewLine = Settings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ GenCommon.LabelPlacement.SplitIfTooLong);
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Tass64);
@@ -777,7 +778,9 @@ namespace SourceGen.AsmGen {
!string.Equals(opcode, sDataOpNames.VarDirective,
StringComparison.InvariantCultureIgnoreCase)) {
- if (mLongLabelNewLine && label.Length >= mColumnWidths[0]) {
+ if (mLabelNewLine == GenCommon.LabelPlacement.PreferSeparateLine ||
+ (mLabelNewLine == GenCommon.LabelPlacement.SplitIfTooLong &&
+ label.Length >= mColumnWidths[0])) {
mOutStream.WriteLine(label);
label = string.Empty;
}
diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs
index 5754518..10f1abb 100644
--- a/SourceGen/AsmGen/GenCommon.cs
+++ b/SourceGen/AsmGen/GenCommon.cs
@@ -23,11 +23,19 @@ using Asm65;
using CommonUtil;
namespace SourceGen.AsmGen {
+ ///
+ /// Code common to all assembly source generators.
+ ///
public class GenCommon {
+ public enum LabelPlacement {
+ Unknown = 0,
+ PreferSameLine,
+ SplitIfTooLong,
+ PreferSeparateLine,
+ }
+
///
/// Generates assembly source.
- ///
- /// This code is common to all generators.
///
/// Reference to generator object (presumably the caller).
/// Text output sink.
diff --git a/SourceGen/Exporter.cs b/SourceGen/Exporter.cs
index 1e2a48b..4f978df 100644
--- a/SourceGen/Exporter.cs
+++ b/SourceGen/Exporter.cs
@@ -550,10 +550,8 @@ namespace SourceGen {
// but we're only doing this on the template file, which should be small.
tmplStr = tmplStr.Replace("$ProjectName$", mProject.DataFileName);
tmplStr = tmplStr.Replace("$AppVersion$", App.ProgramVersion.ToString());
- string expModeStr = ((Formatter.FormatConfig.ExpressionMode)
- AppSettings.Global.GetEnum(AppSettings.FMT_EXPRESSION_MODE,
- typeof(Formatter.FormatConfig.ExpressionMode),
- (int)Formatter.FormatConfig.ExpressionMode.Unknown)).ToString();
+ string expModeStr = AppSettings.Global.GetEnum(AppSettings.FMT_EXPRESSION_MODE,
+ Formatter.FormatConfig.ExpressionMode.Unknown).ToString();
tmplStr = tmplStr.Replace("$ExpressionStyle$", expModeStr);
string dateStr = DateTime.Now.ToString("yyyy/MM/dd");
string timeStr = DateTime.Now.ToString("HH:mm:ss zzz");
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index db2401e..59bb1e8 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -345,7 +345,8 @@ namespace SourceGen {
settings.SetString(AppSettings.FMT_OPERAND_PREFIX_LONG, "f:");
settings.SetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, true);
- settings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, true);
+ settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ AsmGen.GenCommon.LabelPlacement.SplitIfTooLong);
#if DEBUG
settings.SetBool(AppSettings.DEBUG_MENU_ENABLED, true);
@@ -1462,10 +1463,8 @@ namespace SourceGen {
return;
}
- ClipLineFormat format = (ClipLineFormat)AppSettings.Global.GetEnum(
- AppSettings.CLIP_LINE_FORMAT,
- typeof(ClipLineFormat),
- (int)ClipLineFormat.AssemblerSource);
+ ClipLineFormat format = AppSettings.Global.GetEnum(AppSettings.CLIP_LINE_FORMAT,
+ ClipLineFormat.AssemblerSource);
int[] rightWidths = new int[] { 16, 6, 16, 80 };
diff --git a/SourceGen/SGTestData/20280-label-placement b/SourceGen/SGTestData/20280-label-placement
new file mode 100644
index 0000000..236cc60
Binary files /dev/null and b/SourceGen/SGTestData/20280-label-placement differ
diff --git a/SourceGen/SGTestData/20280-label-placement.dis65 b/SourceGen/SGTestData/20280-label-placement.dis65
new file mode 100644
index 0000000..ec1189a
--- /dev/null
+++ b/SourceGen/SGTestData/20280-label-placement.dis65
@@ -0,0 +1,175 @@
+### 6502bench SourceGen dis65 v1.0 ###
+{
+"_ContentVersion":5,
+"FileDataLength":25,
+"FileDataCrc32":646072439,
+"ProjectProps":{
+"CpuName":"6502",
+"IncludeUndocumentedInstr":false,
+"TwoByteBrk":false,
+"EntryFlags":32702671,
+"AutoLabelStyle":"Simple",
+"AnalysisParams":{
+"AnalyzeUncategorizedData":true,
+"DefaultTextScanMode":"LowHighAscii",
+"MinCharsForString":4,
+"SeekNearbyTargets":true,
+"UseRelocData":false,
+"SmartPlpHandling":false,
+"SmartPlbHandling":true},
+
+"PlatformSymbolFileIdentifiers":[],
+"ExtensionScriptFileIdentifiers":[],
+"ProjectSyms":{
+"__ENABLE_ALL_LABEL_NEWLINE":{
+"DataDescriptor":{
+"Length":1,
+"Format":"NumericLE",
+"SubFormat":"Decimal",
+"SymbolRef":null},
+
+"Comment":"",
+"HasWidth":false,
+"Direction":"ReadWrite",
+"MultiMask":null,
+"Label":"__ENABLE_ALL_LABEL_NEWLINE",
+"Value":1,
+"Source":"Project",
+"Type":"ExternalAddr",
+"LabelAnno":"None"},
+
+"shortnm":{
+"DataDescriptor":{
+"Length":1,
+"Format":"NumericLE",
+"SubFormat":"Hex",
+"SymbolRef":null},
+
+"Comment":"short label",
+"HasWidth":false,
+"Direction":"ReadWrite",
+"MultiMask":null,
+"Label":"shortnm",
+"Value":16384,
+"Source":"Project",
+"Type":"ExternalAddr",
+"LabelAnno":"None"},
+
+"SomewhatLongName":{
+"DataDescriptor":{
+"Length":1,
+"Format":"NumericLE",
+"SubFormat":"Hex",
+"SymbolRef":null},
+
+"Comment":"somewhat longer label",
+"HasWidth":false,
+"Direction":"ReadWrite",
+"MultiMask":null,
+"Label":"SomewhatLongName",
+"Value":16385,
+"Source":"Project",
+"Type":"ExternalAddr",
+"LabelAnno":"None"}}},
+
+"AddressMap":[{
+"Offset":0,
+"Addr":4096,
+"Length":25,
+"PreLabel":"",
+"IsRelative":false}],
+"TypeHints":[{
+"Low":0,
+"High":0,
+"Hint":"Code"}],
+"StatusFlagOverrides":{
+},
+
+"Comments":{
+},
+
+"LongComments":{
+},
+
+"Notes":{
+},
+
+"UserLabels":{
+"9":{
+"Label":"data",
+"Value":4105,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"},
+
+"20":{
+"Label":"shortb",
+"Value":4116,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"},
+
+"10":{
+"Label":"BranchTargetLongName",
+"Value":4106,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"},
+
+"24":{
+"Label":"done",
+"Value":4120,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"}},
+
+"OperandFormats":{
+},
+
+"LvTables":{
+"10":{
+"Variables":[{
+"DataDescriptor":{
+"Length":2,
+"Format":"NumericLE",
+"SubFormat":"Hex",
+"SymbolRef":null},
+
+"Comment":"local var with short name",
+"HasWidth":true,
+"Direction":"ReadWrite",
+"MultiMask":null,
+"Label":"ptr",
+"Value":0,
+"Source":"Variable",
+"Type":"ExternalAddr",
+"LabelAnno":"None"},
+
+{
+"DataDescriptor":{
+"Length":2,
+"Format":"NumericLE",
+"SubFormat":"Hex",
+"SymbolRef":null},
+
+"Comment":"local var with longer name",
+"HasWidth":true,
+"Direction":"ReadWrite",
+"MultiMask":null,
+"Label":"PointerWithLongName",
+"Value":2,
+"Source":"Variable",
+"Type":"ExternalAddr",
+"LabelAnno":"None"}],
+"ClearPrevious":false}},
+
+"Visualizations":[],
+"VisualizationAnimations":[],
+"VisualizationSets":{
+},
+
+"RelocList":{
+},
+
+"DbrValues":{
+}}
diff --git a/SourceGen/SGTestData/Expected/20280-label-placement_64tass.S b/SourceGen/SGTestData/Expected/20280-label-placement_64tass.S
new file mode 100644
index 0000000..ef49d60
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20280-label-placement_64tass.S
@@ -0,0 +1,28 @@
+ .cpu "6502"
+shortnm = $4000 ;short label
+SomewhatLongName = $4001 ;somewhat longer label
+
+* = $1000
+ lda shortnm
+ ldx SomewhatLongName
+ clc
+ bcc BranchTargetLongName
+
+data
+ .byte $cc
+
+ptr .var $00 ;local var with short name
+PointerWithLongName .var $02 ;local var with longer name
+BranchTargetLongName
+ sta ptr
+ stx PointerWithLongName
+ ldy data
+ lsr a
+ bcc shortb
+shortb
+ nop
+ jmp done
+
+done
+ rts
+
diff --git a/SourceGen/SGTestData/Expected/20280-label-placement_acme.S b/SourceGen/SGTestData/Expected/20280-label-placement_acme.S
new file mode 100644
index 0000000..6fa1f69
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20280-label-placement_acme.S
@@ -0,0 +1,29 @@
+ !cpu 6502
+shortnm = $4000 ;short label
+SomewhatLongName = $4001 ;somewhat longer label
+
+* = $1000
+ lda shortnm
+ ldx SomewhatLongName
+ clc
+ bcc BranchTargetLongName
+
+data
+ !byte $cc
+
+ !zone Z00000a
+.ptr = $00 ;local var with short name
+.PointerWithLongName = $02 ;local var with longer name
+BranchTargetLongName
+ sta .ptr
+ stx .PointerWithLongName
+ ldy data
+ lsr
+ bcc shortb
+shortb
+ nop
+ jmp done
+
+done
+ rts
+
diff --git a/SourceGen/SGTestData/Expected/20280-label-placement_cc65.S b/SourceGen/SGTestData/Expected/20280-label-placement_cc65.S
new file mode 100644
index 0000000..2b18133
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20280-label-placement_cc65.S
@@ -0,0 +1,28 @@
+ .setcpu "6502"
+shortnm = $4000 ;short label
+SomewhatLongName = $4001 ;somewhat longer label
+
+ .org $1000
+ lda shortnm
+ ldx SomewhatLongName
+ clc
+ bcc BranchTargetLongName
+
+data:
+ .byte $cc
+
+ptr .set $00 ;local var with short name
+PointerWithLongName .set $02 ;local var with longer name
+BranchTargetLongName:
+ sta ptr
+ stx PointerWithLongName
+ ldy data
+ lsr A
+ bcc shortb
+shortb:
+ nop
+ jmp done
+
+done:
+ rts
+
diff --git a/SourceGen/SGTestData/Expected/20280-label-placement_cc65.cfg b/SourceGen/SGTestData/Expected/20280-label-placement_cc65.cfg
new file mode 100644
index 0000000..80dbdea
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20280-label-placement_cc65.cfg
@@ -0,0 +1,9 @@
+# 6502bench SourceGen generated linker script for 20280-label-placement
+MEMORY {
+ MAIN: file=%O, start=%S, size=65536;
+}
+SEGMENTS {
+ CODE: load=MAIN, type=rw;
+}
+FEATURES {}
+SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20280-label-placement_merlin32.S b/SourceGen/SGTestData/Expected/20280-label-placement_merlin32.S
new file mode 100644
index 0000000..5246d87
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20280-label-placement_merlin32.S
@@ -0,0 +1,27 @@
+shortnm equ $4000 ;short label
+SomewhatLongName equ $4001 ;somewhat longer label
+
+ org $1000
+ lda shortnm
+ ldx SomewhatLongName
+ clc
+ bcc BranchTargetLongName
+
+data
+ dfb $cc
+
+]ptr equ $00 ;local var with short name
+]PointerWithLongName equ $02 ;local var with longer name
+BranchTargetLongName
+ sta ]ptr
+ stx ]PointerWithLongName
+ ldy data
+ lsr A
+ bcc shortb
+shortb
+ nop
+ jmp done
+
+done
+ rts
+
diff --git a/SourceGen/SGTestData/README.md b/SourceGen/SGTestData/README.md
index 2bf8417..ec1cdae 100644
--- a/SourceGen/SGTestData/README.md
+++ b/SourceGen/SGTestData/README.md
@@ -34,17 +34,19 @@ be opened as the project file.
### Overriding Settings ###
All tests are run with a fixed set of app settings, so that the tests look
-the same regardless of how the assemblers are configured. For example,
-upper-case conversion is disabled, and cycle counts are not shown.
+the same regardless of how the assemblers are configured in the app settings
+file. For example, upper-case conversion is disabled, and cycle counts are
+not shown.
Sometimes a test will want to exercise one of these settings, so we need
a way to tell the test harness to override the default. We do this by
-creating project symbols.
+creating project symbols:
-| Name | Value | Description
-| ---------------------- | ----- | -------------------------------------------|
-| __ENABLE_LABEL_NEWLINE | any | Puts long labels on their own line |
-| __ENABLE_CYCLE_COUNTS | any | Adds cycle count to end-of-line comments |
+| Name | Value | Description
+| -------------------------- | ----- | -------------------------------------------|
+| __ENABLE_LABEL_NEWLINE | any | Puts long labels on their own line |
+| __ENABLE_ALL_LABEL_NEWLINE | any | Puts all labels on their own line |
+| __ENABLE_CYCLE_COUNTS | any | Adds cycle count to end-of-line comments |
### Execution ###
@@ -74,7 +76,7 @@ the "retain output" box in the test harness, the directory and its contents
will remain. This allows you to examine the outputs when investigating
failures.
-As a safety measure, the directory will NOT be removed if it contains files
+As a safety measure, a directory will NOT be removed if it contains files
that the test harness doesn't recognize.
### Updating Tests ###
@@ -115,4 +117,3 @@ for a full explanation.
Some test projects and data files for exercising the visualization generators.
Not part of a formal test; load the projects and eyeball the results.
-
diff --git a/SourceGen/SGTestData/Source/20280-label-placement.S b/SourceGen/SGTestData/Source/20280-label-placement.S
new file mode 100644
index 0000000..eff9a9a
--- /dev/null
+++ b/SourceGen/SGTestData/Source/20280-label-placement.S
@@ -0,0 +1,32 @@
+; Copyright 2024 faddenSoft. All Rights Reserved.
+; See the LICENSE.txt file for distribution terms (Apache 2.0).
+;
+; The symbol __ENABLE_ALL_LABEL_NEWLINE must be defined in the project
+; symbols, so that labels are placed on their own lines whenever possible.
+;
+; Assembler: Merlin 32
+
+ org $1000
+shortnm equ $4000
+SomewhatLongName equ $4001
+
+ lda shortnm
+ ldx SomewhatLongName
+ clc
+ bcc BranchTargetLongName
+data dfb $cc
+
+]ptr equ $00
+]PointerWithLongName equ $02
+
+BranchTargetLongName
+ sta ]ptr
+ stx ]PointerWithLongName
+ ldy data
+ lsr A
+ bcc shortb
+shortb nop
+
+ jmp done
+
+done rts
diff --git a/SourceGen/Tests/GenTest.cs b/SourceGen/Tests/GenTest.cs
index 09fa24e..91488cb 100644
--- a/SourceGen/Tests/GenTest.cs
+++ b/SourceGen/Tests/GenTest.cs
@@ -430,7 +430,8 @@ namespace SourceGen.Tests {
// Don't break lines with long labels. That way we can redefine "long"
// without breaking our tests. (This is purely cosmetic.)
- settings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false);
+ settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ GenCommon.LabelPlacement.PreferSameLine);
// This could be on or off. Off seems less distracting.
settings.SetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
@@ -455,17 +456,23 @@ namespace SourceGen.Tests {
}
///
- /// Applies app setting overrides that were specified in the project settings.
+ /// Applies app setting overrides that were specified in the project properties.
///
private void ApplyProjectSettings(AppSettings settings, DisasmProject project) {
// We could probably make this a more general mechanism, but that would strain
// things a bit, since we need to know the settings name, bool/int/string, and
// desired value. Easier to just have a set of named features.
const string ENABLE_LABEL_NEWLINE = "__ENABLE_LABEL_NEWLINE";
+ const string ENABLE_ALL_LABEL_NEWLINE = "__ENABLE_ALL_LABEL_NEWLINE";
const string ENABLE_CYCLE_COUNTS = "__ENABLE_CYCLE_COUNTS";
if (project.ProjectProps.ProjectSyms.ContainsKey(ENABLE_LABEL_NEWLINE)) {
- settings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, true);
+ settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ GenCommon.LabelPlacement.SplitIfTooLong);
+ }
+ if (project.ProjectProps.ProjectSyms.ContainsKey(ENABLE_ALL_LABEL_NEWLINE)) {
+ settings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ GenCommon.LabelPlacement.PreferSeparateLine);
}
if (project.ProjectProps.ProjectSyms.ContainsKey(ENABLE_CYCLE_COUNTS)) {
settings.SetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, true);
diff --git a/SourceGen/Tools/WpfGui/Apple2ScreenChart.xaml.cs b/SourceGen/Tools/WpfGui/Apple2ScreenChart.xaml.cs
index 8b552ef..10623b7 100644
--- a/SourceGen/Tools/WpfGui/Apple2ScreenChart.xaml.cs
+++ b/SourceGen/Tools/WpfGui/Apple2ScreenChart.xaml.cs
@@ -75,8 +75,7 @@ namespace SourceGen.Tools.WpfGui {
public void Window_Loaded(object sender, RoutedEventArgs e) {
// Restore chart mode setting.
- ChartMode mode = (ChartMode)AppSettings.Global.GetEnum(
- AppSettings.A2SC_MODE, typeof(ChartMode), (int)ChartMode.HiRes1_L);
+ ChartMode mode = AppSettings.Global.GetEnum(AppSettings.A2SC_MODE, ChartMode.HiRes1_L);
int index = 0;
for (int i = 0; i < ChartModeItems.Length; i++) {
if (ChartModeItems[i].Mode == mode) {
@@ -107,7 +106,7 @@ namespace SourceGen.Tools.WpfGui {
return;
}
- AppSettings.Global.SetEnum(AppSettings.A2SC_MODE, typeof(ChartMode), (int)item.Mode);
+ AppSettings.Global.SetEnum(AppSettings.A2SC_MODE, item.Mode);
string text;
switch (item.Mode) {
diff --git a/SourceGen/Tools/WpfGui/AsciiChart.xaml.cs b/SourceGen/Tools/WpfGui/AsciiChart.xaml.cs
index f4ffdaa..57f9dea 100644
--- a/SourceGen/Tools/WpfGui/AsciiChart.xaml.cs
+++ b/SourceGen/Tools/WpfGui/AsciiChart.xaml.cs
@@ -55,8 +55,7 @@ namespace SourceGen.Tools.WpfGui {
public void Window_Loaded(object sender, RoutedEventArgs e) {
// Restore chart mode setting.
- ChartMode mode = (ChartMode)AppSettings.Global.GetEnum(
- AppSettings.ASCCH_MODE, typeof(ChartMode), (int)ChartMode.Standard);
+ ChartMode mode = AppSettings.Global.GetEnum(AppSettings.ASCCH_MODE, ChartMode.Standard);
int index = 0;
for (int i = 0; i < ChartModeItems.Length; i++) {
if (ChartModeItems[i].Mode == mode) {
@@ -87,7 +86,7 @@ namespace SourceGen.Tools.WpfGui {
return;
}
- AppSettings.Global.SetEnum(AppSettings.ASCCH_MODE, typeof(ChartMode), (int)item.Mode);
+ AppSettings.Global.SetEnum(AppSettings.ASCCH_MODE, item.Mode);
//
// Draw box contents.
diff --git a/SourceGen/Tools/WpfGui/HexDumpViewer.xaml.cs b/SourceGen/Tools/WpfGui/HexDumpViewer.xaml.cs
index 0e98762..87c854f 100644
--- a/SourceGen/Tools/WpfGui/HexDumpViewer.xaml.cs
+++ b/SourceGen/Tools/WpfGui/HexDumpViewer.xaml.cs
@@ -111,8 +111,8 @@ namespace SourceGen.Tools.WpfGui {
AsciiOnlyDump = AppSettings.Global.GetBool(AppSettings.HEXD_ASCII_ONLY, false);
// Restore conv mode setting.
- CharConvMode mode = (CharConvMode)AppSettings.Global.GetEnum(
- AppSettings.HEXD_CHAR_CONV, typeof(CharConvMode), (int)CharConvMode.Ascii);
+ CharConvMode mode =
+ AppSettings.Global.GetEnum(AppSettings.HEXD_CHAR_CONV, CharConvMode.Ascii);
int index = 0;
for (int i = 0; i < CharConvItems.Length; i++) {
if (CharConvItems[i].Mode == mode) {
@@ -156,8 +156,7 @@ namespace SourceGen.Tools.WpfGui {
// Keep app settings up to date.
AppSettings.Global.SetBool(AppSettings.HEXD_ASCII_ONLY, mAsciiOnlyDump);
- AppSettings.Global.SetEnum(AppSettings.HEXD_CHAR_CONV, typeof(CharConvMode),
- (int)item.Mode);
+ AppSettings.Global.SetEnum(AppSettings.HEXD_CHAR_CONV, item.Mode);
mFormatter = new Formatter(config);
HexDumpLines.Reformat(mFormatter);
diff --git a/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs b/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs
index e5892c5..c737609 100644
--- a/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs
+++ b/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs
@@ -112,8 +112,8 @@ namespace SourceGen.Tools.WpfGui {
public void Window_Loaded(object sender, RoutedEventArgs e) {
// Restore chart settings.
- CpuDef.CpuType type = (CpuDef.CpuType)AppSettings.Global.GetEnum(
- AppSettings.INSTCH_MODE, typeof(CpuDef.CpuType), (int)CpuDef.CpuType.Cpu6502);
+ CpuDef.CpuType type =
+ AppSettings.Global.GetEnum(AppSettings.INSTCH_MODE, CpuDef.CpuType.Cpu6502);
ShowUndocumented = AppSettings.Global.GetBool(AppSettings.INSTCH_SHOW_UNDOC, true);
int index = 0;
@@ -146,8 +146,7 @@ namespace SourceGen.Tools.WpfGui {
}
// Push current choice to settings.
- AppSettings.Global.SetEnum(AppSettings.INSTCH_MODE, typeof(CpuDef.CpuType),
- (int)item.Type);
+ AppSettings.Global.SetEnum(AppSettings.INSTCH_MODE, item.Type);
AppSettings.Global.SetBool(AppSettings.INSTCH_SHOW_UNDOC, mShowUndocumented);
// Populate the items source.
diff --git a/SourceGen/WpfGui/EditAppSettings.xaml b/SourceGen/WpfGui/EditAppSettings.xaml
index 30398de..7d57a49 100644
--- a/SourceGen/WpfGui/EditAppSettings.xaml
+++ b/SourceGen/WpfGui/EditAppSettings.xaml
@@ -820,10 +820,20 @@ limitations under the License.
-
-
+
+
+
+
+
+
diff --git a/SourceGen/WpfGui/EditAppSettings.xaml.cs b/SourceGen/WpfGui/EditAppSettings.xaml.cs
index c7fe5f7..1f0d622 100644
--- a/SourceGen/WpfGui/EditAppSettings.xaml.cs
+++ b/SourceGen/WpfGui/EditAppSettings.xaml.cs
@@ -31,6 +31,7 @@ using CommonUtil;
using AssemblerInfo = SourceGen.AsmGen.AssemblerInfo;
using AssemblerConfig = SourceGen.AsmGen.AssemblerConfig;
using ExpressionMode = Asm65.Formatter.FormatConfig.ExpressionMode;
+using LabelPlacement = SourceGen.AsmGen.GenCommon.LabelPlacement;
namespace SourceGen.WpfGui {
///
@@ -280,8 +281,8 @@ namespace SourceGen.WpfGui {
UpperOperandXY = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_XY, false);
Debug.Assert(clipboardFormatComboBox.Items.Count == sClipboardFormatItems.Length);
- int clipIndex = mSettings.GetEnum(AppSettings.CLIP_LINE_FORMAT,
- typeof(MainController.ClipLineFormat), 0);
+ int clipIndex = (int)mSettings.GetEnum(AppSettings.CLIP_LINE_FORMAT,
+ MainController.ClipLineFormat.AssemblerSource);
if (clipIndex >= 0 && clipIndex < sClipboardFormatItems.Length) {
// require Value == clipIndex because we're lazy and don't want to search
Debug.Assert((int)sClipboardFormatItems[clipIndex].Value == clipIndex);
@@ -414,8 +415,7 @@ namespace SourceGen.WpfGui {
private void ClipboardFormatComboBox_SelectionChanged(object sender,
SelectionChangedEventArgs e) {
ClipboardFormatItem item = (ClipboardFormatItem)clipboardFormatComboBox.SelectedItem;
- mSettings.SetEnum(AppSettings.CLIP_LINE_FORMAT, typeof(MainController.ClipLineFormat),
- (int)item.Value);
+ mSettings.SetEnum(AppSettings.CLIP_LINE_FORMAT, item.Value);
IsDirty = true;
}
@@ -757,14 +757,6 @@ namespace SourceGen.WpfGui {
IsDirty = true;
}
}
- public bool LongLabelNewLine {
- get { return mSettings.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); }
- set {
- mSettings.SetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, value);
- OnPropertyChanged();
- IsDirty = true;
- }
- }
public bool AddIdentComment {
get { return mSettings.GetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, false); }
set {
@@ -774,6 +766,58 @@ namespace SourceGen.WpfGui {
}
}
+ // label placement radio buttons
+ public bool LabelPlacement_PreferSameLine {
+ get {
+ LabelPlacement place = mSettings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ LabelPlacement.SplitIfTooLong);
+ return place == LabelPlacement.PreferSameLine;
+ }
+ set {
+ if (value) {
+ mSettings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ LabelPlacement.PreferSameLine);
+ LabelPlacementChanged();
+ IsDirty = true;
+ }
+ }
+ }
+ public bool LabelPlacement_SplitIfTooLong {
+ get {
+ LabelPlacement place = mSettings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ LabelPlacement.SplitIfTooLong);
+ return place == LabelPlacement.SplitIfTooLong;
+ }
+ set {
+ if (value) {
+ mSettings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ LabelPlacement.SplitIfTooLong);
+ LabelPlacementChanged();
+ IsDirty = true;
+ }
+ }
+ }
+ public bool LabelPlacement_PreferSeparateLine {
+ get {
+ LabelPlacement place = mSettings.GetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ LabelPlacement.SplitIfTooLong);
+ return place == LabelPlacement.PreferSeparateLine;
+ }
+ set {
+ if (value) {
+ mSettings.SetEnum(AppSettings.SRCGEN_LABEL_NEW_LINE,
+ LabelPlacement.PreferSeparateLine);
+ LabelPlacementChanged();
+ IsDirty = true;
+ }
+ }
+ }
+ private void LabelPlacementChanged() {
+ OnPropertyChanged(nameof(LabelPlacement_PreferSameLine));
+ OnPropertyChanged(nameof(LabelPlacement_SplitIfTooLong));
+ OnPropertyChanged(nameof(LabelPlacement_PreferSeparateLine));
+ }
+
private void Loaded_AsmConfig() {
asmConfigComboBox.SelectedItem = AssemblerInfo.GetAssemblerInfo(mInitialAsmId);
if (asmConfigComboBox.SelectedIndex < 0) {
diff --git a/SourceGen/WpfGui/EditDataOperand.xaml.cs b/SourceGen/WpfGui/EditDataOperand.xaml.cs
index d88981f..6eef077 100644
--- a/SourceGen/WpfGui/EditDataOperand.xaml.cs
+++ b/SourceGen/WpfGui/EditDataOperand.xaml.cs
@@ -293,8 +293,7 @@ namespace SourceGen.WpfGui {
AnalyzeStringRanges(item.Mode);
UpdateControls();
- AppSettings.Global.SetEnum(AppSettings.OPED_DEFAULT_STRING_ENCODING,
- typeof(TextScanMode), (int)item.Mode);
+ AppSettings.Global.SetEnum(AppSettings.OPED_DEFAULT_STRING_ENCODING, item.Mode);
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
@@ -780,9 +779,8 @@ namespace SourceGen.WpfGui {
// Get the previous mode selected in the combo box. If the format descriptor
// doesn't specify a string, we'll use this.
- TextScanMode textMode = (TextScanMode)AppSettings.Global.GetEnum(
- AppSettings.OPED_DEFAULT_STRING_ENCODING, typeof(TextScanMode),
- (int)TextScanMode.LowHighAscii);
+ TextScanMode textMode = AppSettings.Global.GetEnum(
+ AppSettings.OPED_DEFAULT_STRING_ENCODING, TextScanMode.LowHighAscii);
if (dfd == null) {
radioDefaultFormat.IsChecked = true;
diff --git a/SourceGen/WpfGui/Export.xaml.cs b/SourceGen/WpfGui/Export.xaml.cs
index f82453c..8de731c 100644
--- a/SourceGen/WpfGui/Export.xaml.cs
+++ b/SourceGen/WpfGui/Export.xaml.cs
@@ -235,8 +235,8 @@ namespace SourceGen.WpfGui {
AsmCommentColWidth = colWidths[3];
}
- TextMode mode = (TextMode)AppSettings.Global.GetEnum(AppSettings.EXPORT_TEXT_MODE,
- typeof(TextMode), (int)TextMode.PlainText);
+ TextMode mode = AppSettings.Global.GetEnum(AppSettings.EXPORT_TEXT_MODE,
+ TextMode.PlainText);
if (mode == TextMode.PlainText) {
TextModePlain = true;
} else {
@@ -273,7 +273,7 @@ namespace SourceGen.WpfGui {
} else {
mode = TextMode.Csv;
}
- AppSettings.Global.SetEnum(AppSettings.EXPORT_TEXT_MODE, typeof(TextMode), (int)mode);
+ AppSettings.Global.SetEnum(AppSettings.EXPORT_TEXT_MODE, mode);
}
///
diff --git a/SourceGen/WpfGui/GenerateLabels.xaml.cs b/SourceGen/WpfGui/GenerateLabels.xaml.cs
index 05862a3..f4ce2d2 100644
--- a/SourceGen/WpfGui/GenerateLabels.xaml.cs
+++ b/SourceGen/WpfGui/GenerateLabels.xaml.cs
@@ -55,17 +55,15 @@ namespace SourceGen.WpfGui {
Owner = owner;
DataContext = this;
- Format =
- (LabelFileGenerator.LabelFmt)AppSettings.Global.GetEnum(AppSettings.LABGEN_FORMAT,
- typeof(LabelFileGenerator.LabelFmt), (int)LabelFileGenerator.LabelFmt.VICE);
+ Format = AppSettings.Global.GetEnum(AppSettings.LABGEN_FORMAT,
+ LabelFileGenerator.LabelFmt.VICE);
UpdateFormats();
mIncludeAutoLabels = AppSettings.Global.GetBool(AppSettings.LABGEN_INCLUDE_AUTO, false);
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
// Save settings.
- AppSettings.Global.SetEnum(AppSettings.LABGEN_FORMAT,
- typeof(LabelFileGenerator.LabelFmt), (int)Format);
+ AppSettings.Global.SetEnum(AppSettings.LABGEN_FORMAT, Format);
AppSettings.Global.SetBool(AppSettings.LABGEN_INCLUDE_AUTO, mIncludeAutoLabels);
DialogResult = true;
}