From 99cd0d3ac1e4a0ae627007741282f0fb5136c31f Mon Sep 17 00:00:00 2001
From: Andy McFadden
Date: Sat, 17 Oct 2020 16:10:48 -0700
Subject: [PATCH] Improve handling of C64 PRG header
C64 PRG files are pretty common. Their salient feature is that they
start with a 16-bit value that is used as the load address. The
value is commonly generated by the assembler itself, rather than
explicitly added to the source file.
Not all assemblers know what a PRG file is, and some of them handle
it in ways that are difficult to guarantee in SourceGen. ACME adds
the 16-bit header when the output file name ends in ".prg", cc65
uses a modified config file, 64tass uses a different command-line
option, and Merlin 32 has no idea what they are.
This change adds PRG file detection and handling to the 64tass code
generator. Doing so required making a few changes to the gen/asm
interfaces, because we now need to have the generator pass additional
flags to the assembler, and sometimes we need code generation to
start somewhere other than offset zero. Overall the changes were
pretty minor.
The 20042-address-changes test needed a 6502-only variant. A new test
(20040-address-changes) has been added and given a PRG header. As
part of this change the 65816 variant was changed to use addresses
in bank 2, which uncovered a code generation bug that this change
also fixes.
The 64tass --long-address flag doesn't appear to be necessary for
files <= 65536 bytes long, so we no longer emit it for those.
(issue #90)
---
CommonUtil/Container.cs | 13 ++
SourceGen/AsmGen/AsmAcme.cs | 15 +-
SourceGen/AsmGen/AsmCc65.cs | 15 +-
SourceGen/AsmGen/AsmMerlin32.cs | 15 +-
SourceGen/AsmGen/AsmTass64.cs | 97 +++++++---
SourceGen/AsmGen/GenCommon.cs | 10 +-
SourceGen/AsmGen/IAssembler.cs | 6 +-
SourceGen/AsmGen/IGenerator.cs | 23 ++-
SourceGen/AsmGen/WpfGui/GenAndAsm.xaml.cs | 15 +-
SourceGen/RuntimeData/Help/codegen.html | 33 +++-
SourceGen/RuntimeData/Help/index.html | 2 +
SourceGen/SGTestData/20040-address-changes | Bin 0 -> 194 bytes
.../SGTestData/20040-address-changes.dis65 | 170 ++++++++++++++++++
.../SGTestData/20042-address-changes.dis65 | 161 ++++++++++++++---
.../Expected/20040-address-changes_64tass.S | 119 ++++++++++++
.../Expected/20040-address-changes_Merlin32.S | 107 +++++++++++
.../Expected/20040-address-changes_acme.S | 124 +++++++++++++
.../Expected/20040-address-changes_cc65.S | 123 +++++++++++++
.../Expected/20040-address-changes_cc65.cfg | 39 ++++
.../Expected/20042-address-changes_64tass.S | 116 ++++++------
.../Expected/20042-address-changes_Merlin32.S | 98 +++++-----
.../Expected/20042-address-changes_acme.S | 132 +-------------
.../Expected/20042-address-changes_cc65.S | 116 ++++++------
.../Expected/20042-address-changes_cc65.cfg | 28 +--
.../SGTestData/Source/20040-address-changes.S | 117 ++++++++++++
.../SGTestData/Source/20042-address-changes.S | 1 +
SourceGen/Tests/GenTest.cs | 6 +-
27 files changed, 1296 insertions(+), 405 deletions(-)
create mode 100644 SourceGen/SGTestData/20040-address-changes
create mode 100644 SourceGen/SGTestData/20040-address-changes.dis65
create mode 100644 SourceGen/SGTestData/Expected/20040-address-changes_64tass.S
create mode 100644 SourceGen/SGTestData/Expected/20040-address-changes_Merlin32.S
create mode 100644 SourceGen/SGTestData/Expected/20040-address-changes_acme.S
create mode 100644 SourceGen/SGTestData/Expected/20040-address-changes_cc65.S
create mode 100644 SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg
create mode 100644 SourceGen/SGTestData/Source/20040-address-changes.S
diff --git a/CommonUtil/Container.cs b/CommonUtil/Container.cs
index 069fdea..49dd3df 100644
--- a/CommonUtil/Container.cs
+++ b/CommonUtil/Container.cs
@@ -38,6 +38,19 @@ namespace CommonUtil {
return Enumerable.SequenceEqual(l1, l2, comparer);
}
+ ///
+ /// Makes a deep copy of a string list.
+ ///
+ /// String list to copy.
+ /// New string list.
+ public static List CopyStringList(IList src) {
+ List dst = new List(src.Count);
+ foreach (string str in src) {
+ dst.Add(str);
+ }
+ return dst;
+ }
+
///
/// Compares two Dictionaries to see if their contents are equal. Key and value types
/// must have correctly-implemented equality checks. (I contend this works incorrectly
diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs
index 4e9f348..6bfff8b 100644
--- a/SourceGen/AsmGen/AsmAcme.cs
+++ b/SourceGen/AsmGen/AsmAcme.cs
@@ -54,6 +54,9 @@ namespace SourceGen.AsmGen {
// IGenerator
public LabelLocalizer Localizer { get { return mLocalizer; } }
+ // IGenerator
+ public int StartOffset { get { return 0; } }
+
///
/// Working directory, i.e. where we write our output file(s).
///
@@ -207,7 +210,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public List GenerateSource(BackgroundWorker worker) {
+ public GenerationResults GenerateSource(BackgroundWorker worker) {
List pathNames = new List(1);
string fileName = mFileNameBase + ASM_FILE_SUFFIX;
@@ -256,7 +259,7 @@ namespace SourceGen.AsmGen {
}
mOutStream = null;
- return pathNames;
+ return new GenerationResults(pathNames, string.Empty);
}
///
@@ -741,13 +744,9 @@ namespace SourceGen.AsmGen {
}
// IAssembler
- public void Configure(List pathNames, string workDirectory) {
+ public void Configure(GenerationResults results, string workDirectory) {
// Clone pathNames, in case the caller decides to modify the original.
- mPathNames = new List(pathNames.Count);
- foreach (string str in pathNames) {
- mPathNames.Add(str);
- }
-
+ mPathNames = CommonUtil.Container.CopyStringList(results.PathNames);
mWorkDirectory = workDirectory;
}
diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs
index 9118d68..a4d6e0a 100644
--- a/SourceGen/AsmGen/AsmCc65.cs
+++ b/SourceGen/AsmGen/AsmCc65.cs
@@ -48,6 +48,9 @@ namespace SourceGen.AsmGen {
// IGenerator
public LabelLocalizer Localizer { get { return mLocalizer; } }
+ // IGenerator
+ public int StartOffset { get { return 0; } }
+
///
/// Working directory, i.e. where we write our output file(s).
///
@@ -202,7 +205,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public List GenerateSource(BackgroundWorker worker) {
+ public GenerationResults GenerateSource(BackgroundWorker worker) {
List pathNames = new List(1);
string pathName = Path.Combine(mWorkDirectory, mFileNameBase + ASM_FILE_SUFFIX);
@@ -251,7 +254,7 @@ namespace SourceGen.AsmGen {
}
mOutStream = null;
- return pathNames;
+ return new GenerationResults(pathNames, string.Empty);
}
private void GenerateLinkerScript(StreamWriter sw) {
@@ -832,13 +835,9 @@ namespace SourceGen.AsmGen {
}
// IAssembler
- public void Configure(List pathNames, string workDirectory) {
+ public void Configure(GenerationResults results, string workDirectory) {
// Clone pathNames, in case the caller decides to modify the original.
- mPathNames = new List(pathNames.Count);
- foreach (string str in pathNames) {
- mPathNames.Add(str);
- }
-
+ mPathNames = CommonUtil.Container.CopyStringList(results.PathNames);
mWorkDirectory = workDirectory;
}
diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs
index 7990046..77f89c9 100644
--- a/SourceGen/AsmGen/AsmMerlin32.cs
+++ b/SourceGen/AsmGen/AsmMerlin32.cs
@@ -48,6 +48,9 @@ namespace SourceGen.AsmGen {
// IGenerator
public LabelLocalizer Localizer { get { return mLocalizer; } }
+ // IGenerator
+ public int StartOffset { get { return 0; } }
+
///
/// Working directory, i.e. where we write our output file(s).
///
@@ -176,7 +179,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator; executes on background thread
- public List GenerateSource(BackgroundWorker worker) {
+ public GenerationResults GenerateSource(BackgroundWorker worker) {
List pathNames = new List(1);
string fileName = mFileNameBase + ASM_FILE_SUFFIX;
@@ -211,7 +214,7 @@ namespace SourceGen.AsmGen {
}
mOutStream = null;
- return pathNames;
+ return new GenerationResults(pathNames, string.Empty);
}
// IGenerator
@@ -751,13 +754,9 @@ namespace SourceGen.AsmGen {
}
// IAssembler
- public void Configure(List pathNames, string workDirectory) {
+ public void Configure(GenerationResults results, string workDirectory) {
// Clone pathNames, in case the caller decides to modify the original.
- mPathNames = new List(pathNames.Count);
- foreach (string str in pathNames) {
- mPathNames.Add(str);
- }
-
+ mPathNames = CommonUtil.Container.CopyStringList(results.PathNames);
mWorkDirectory = workDirectory;
}
diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs
index 4860ed9..65730b5 100644
--- a/SourceGen/AsmGen/AsmTass64.cs
+++ b/SourceGen/AsmGen/AsmTass64.cs
@@ -59,7 +59,13 @@ namespace SourceGen.AsmGen {
public AssemblerQuirks Quirks { get; private set; }
// IGenerator
- public LabelLocalizer Localizer { get { return mLocalizer; } }
+ public LabelLocalizer Localizer { get; private set; }
+
+ public int StartOffset {
+ get {
+ return mHasPrgHeader ? 2 : 0;
+ }
+ }
///
/// Working directory, i.e. where we write our output file(s).
@@ -81,16 +87,16 @@ namespace SourceGen.AsmGen {
///
private string mFileNameBase;
+ ///
+ /// True if the first two bytes look like the header of a PRG file.
+ ///
+ private bool mHasPrgHeader;
+
///
/// StringBuilder to use when composing a line. Held here to reduce allocations.
///
private StringBuilder mLineBuilder = new StringBuilder(100);
- ///
- /// Label localization helper.
- ///
- private LabelLocalizer mLocalizer;
-
///
/// Stream to send the output to.
///
@@ -176,6 +182,8 @@ namespace SourceGen.AsmGen {
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Tass64);
mColumnWidths = (int[])config.ColumnWidths.Clone();
+
+ mHasPrgHeader = HasPrgHeader(project);
}
///
@@ -207,7 +215,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
- public List GenerateSource(BackgroundWorker worker) {
+ public GenerationResults GenerateSource(BackgroundWorker worker) {
List pathNames = new List(1);
string fileName = mFileNameBase + ASM_FILE_SUFFIX;
@@ -233,10 +241,14 @@ namespace SourceGen.AsmGen {
string msg = string.Format(Res.Strings.PROGRESS_GENERATING_FMT, pathName);
worker.ReportProgress(0, msg);
- mLocalizer = new LabelLocalizer(Project);
- mLocalizer.LocalPrefix = "_";
- mLocalizer.QuirkNoOpcodeMnemonics = true;
- mLocalizer.Analyze();
+ Localizer = new LabelLocalizer(Project);
+ Localizer.LocalPrefix = "_";
+ Localizer.QuirkNoOpcodeMnemonics = true;
+ Localizer.Analyze();
+
+ string extraOptions = string.Empty +
+ (Project.FileDataLength > 65536 ? AsmTass64.LONG_ADDRESS : string.Empty) +
+ (mHasPrgHeader ? string.Empty : AsmTass64.NOSTART);
// Use UTF-8 encoding, without a byte-order mark.
using (StreamWriter sw = new StreamWriter(pathName, false, new UTF8Encoding(false))) {
@@ -245,7 +257,7 @@ namespace SourceGen.AsmGen {
if (Settings.GetBool(AppSettings.SRCGEN_ADD_IDENT_COMMENT, false)) {
OutputLine(SourceFormatter.FullLineCommentDelimiter +
string.Format(Res.Strings.GENERATED_FOR_VERSION_FMT,
- "64tass", V1_53, AsmTass64.OPTIONS));
+ "64tass", V1_53, AsmTass64.BASE_OPTIONS + extraOptions));
}
GenCommon.Generate(this, sw, worker);
@@ -257,7 +269,7 @@ namespace SourceGen.AsmGen {
}
mOutStream = null;
- return pathNames;
+ return new GenerationResults(pathNames, extraOptions);
}
// IGenerator
@@ -330,6 +342,36 @@ namespace SourceGen.AsmGen {
}
}
+ private static bool HasPrgHeader(DisasmProject project) {
+ if (project.FileDataLength < 3 || project.FileDataLength > 65536) {
+ return false;
+ }
+ Anattrib attr0 = project.GetAnattrib(0);
+ Anattrib attr1 = project.GetAnattrib(1);
+ if (!(attr0.IsDataStart && attr1.IsData)) {
+ Debug.WriteLine("PRG test: 0/1 not data");
+ return false;
+ }
+ if (attr0.Length != 2) {
+ Debug.WriteLine("PRG test: 0/1 not 16-bit value");
+ return false;
+ }
+ if (attr0.Symbol != null || attr1.Symbol != null) {
+ Debug.WriteLine("PRG test: 0/1 has label");
+ return false;
+ }
+ // See if the address at offset 2 matches the value at 0/1.
+ int value01 = project.FileData[0] | (project.FileData[1] << 8);
+ int addr2 = project.AddrMap.OffsetToAddress(2);
+ if (value01 != addr2) {
+ Debug.WriteLine("PRG test: 0/1 value is " + value01.ToString("x4") +
+ ", address at 2 is " + addr2);
+ return false;
+ }
+
+ return true;
+ }
+
// IGenerator
public string ModifyOpcode(int offset, OpDef op) {
if (op.IsUndocumented) {
@@ -432,7 +474,7 @@ namespace SourceGen.AsmGen {
string labelStr = string.Empty;
if (attr.Symbol != null) {
- labelStr = mLocalizer.ConvLabel(attr.Symbol.Label);
+ labelStr = Localizer.ConvLabel(attr.Symbol.Label);
}
string commentStr = SourceFormatter.FormatEolComment(Project.Comments[offset]);
@@ -459,7 +501,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, false);
UpdateCharacterEncoding(dfd);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
- mLocalizer.LabelMap, dfd, operand, length,
+ Localizer.LabelMap, dfd, operand, length,
PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
break;
case FormatDescriptor.Type.NumericBE:
@@ -471,7 +513,7 @@ namespace SourceGen.AsmGen {
UpdateCharacterEncoding(dfd);
operand = RawData.GetWord(data, offset, length, true);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
- mLocalizer.LabelMap, dfd, operand, length,
+ Localizer.LabelMap, dfd, operand, length,
PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix);
}
break;
@@ -600,7 +642,7 @@ namespace SourceGen.AsmGen {
// Any subsequent ORG changes are made to the program counter, and take the form
// of a pair of ops (.logical to open, .here to end). Omitting the .here
// causes an error.
- if (offset == 0) {
+ if (offset == StartOffset) {
// Set the "compile offset" to the initial address.
OutputLine("*", "=", SourceFormatter.FormatHexValue(Project.AddrMap.Get(0), 4),
string.Empty);
@@ -818,7 +860,9 @@ namespace SourceGen.AsmGen {
// default "none" encoding from "raw" to something that converts characters to
// PETSCII, so if you want to output strings in another format (such as ASCII) an
// explicit encoding must be specified.
- public const string OPTIONS = "--ascii --case-sensitive --nostart --long-address -Wall";
+ public const string BASE_OPTIONS = "--ascii --case-sensitive -Wall";
+ public const string LONG_ADDRESS = " --long-address";
+ public const string NOSTART = " --nostart";
// Paths from generator.
private List mPathNames;
@@ -826,6 +870,9 @@ namespace SourceGen.AsmGen {
// Directory to make current before executing assembler.
private string mWorkDirectory;
+ // Additional options specified by the source generator.
+ private string mExtraOptions;
+
// IAssembler
public void GetExeIdentifiers(out string humanName, out string exeName) {
@@ -875,13 +922,10 @@ namespace SourceGen.AsmGen {
}
// IAssembler
- public void Configure(List pathNames, string workDirectory) {
- // Clone pathNames, in case the caller decides to modify the original.
- mPathNames = new List(pathNames.Count);
- foreach (string str in pathNames) {
- mPathNames.Add(str);
- }
-
+ public void Configure(GenerationResults results, string workDirectory) {
+ // Clone path names, in case the caller decides to modify the original.
+ mPathNames = CommonUtil.Container.CopyStringList(results.PathNames);
+ mExtraOptions = results.ExtraOptions;
mWorkDirectory = workDirectory;
}
@@ -911,7 +955,8 @@ namespace SourceGen.AsmGen {
// Wrap pathname in quotes in case it has spaces.
// (Do we need to shell-escape quotes in the pathName?)
ShellCommand cmd = new ShellCommand(config.ExecutablePath,
- OPTIONS + " \"" + pathName + "\"" + " -o \"" + outFileName + "\"",
+ BASE_OPTIONS + mExtraOptions +
+ " \"" + pathName + "\"" + " -o \"" + outFileName + "\"",
mWorkDirectory, null);
cmd.Execute();
diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs
index e55bfd7..d68b9e2 100644
--- a/SourceGen/AsmGen/GenCommon.cs
+++ b/SourceGen/AsmGen/GenCommon.cs
@@ -35,7 +35,7 @@ namespace SourceGen.AsmGen {
public static void Generate(IGenerator gen, StreamWriter sw, BackgroundWorker worker) {
DisasmProject proj = gen.Project;
Formatter formatter = gen.SourceFormatter;
- int offset = 0;
+ int offset = gen.StartOffset;
bool doAddCycles = gen.Settings.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
@@ -220,6 +220,8 @@ namespace SourceGen.AsmGen {
// Tweak branch instructions. We want to show the absolute address rather
// than the relative offset (which happens with the OperandAddress assignment
// below), and 1-byte branches should always appear as a 4-byte hex value.
+ // Unless we're outside bank 0 on 65816, in which case most assemblers require
+ // them to be 6-byte hex values.
if (op.AddrMode == OpDef.AddressMode.PCRel ||
op.AddrMode == OpDef.AddressMode.DPPCRel) {
Debug.Assert(attr.OperandAddress >= 0);
@@ -304,10 +306,12 @@ namespace SourceGen.AsmGen {
formattedOperand = formatter.FormatHexValue(operand & 0xff, 2) + "," +
formatter.FormatHexValue(operandForSymbol, operandLen * 2);
} else {
- if (operandLen == 2 && !(op.IsAbsolutePBR && gen.Quirks.Need24BitsForAbsPBR)) {
+ if (operandLen == 2 && !(op.IsAbsolutePBR && gen.Quirks.Need24BitsForAbsPBR) &&
+ (opFlags & PseudoOp.FormatNumericOpFlags.IsPcRel) == 0) {
// This is necessary for 16-bit operands, like "LDA abs" and "PEA val",
// when outside bank zero. The bank is included in the operand address,
- // but we don't want to show it here. We may need it for JSR/JMP though.
+ // but we don't want to show it here. We may need it for JSR/JMP though,
+ // and the bank is required for relative branch instructions.
operandForSymbol &= 0xffff;
}
formattedOperand = formatter.FormatHexValue(operandForSymbol, operandLen * 2);
diff --git a/SourceGen/AsmGen/IAssembler.cs b/SourceGen/AsmGen/IAssembler.cs
index 309bb9a..d08ed32 100644
--- a/SourceGen/AsmGen/IAssembler.cs
+++ b/SourceGen/AsmGen/IAssembler.cs
@@ -44,12 +44,12 @@ namespace SourceGen.AsmGen {
AssemblerVersion QueryVersion();
///
- /// Configures the object. Pass in the list of pathnames returned by IGenerator.Run(),
+ /// Configures the object. Pass in the result object from IGenerator.GenerateSource(),
/// and the working directory to use for the shell command.
///
- /// Assembler source pathnames.
+ /// Source generation results.
/// Working directory for shell command.
- void Configure(List pathNames, string workDirectory);
+ void Configure(GenerationResults results, string workDirectory);
///
/// Executes the assembler. Must call Configure() first. Executed on background thread.
diff --git a/SourceGen/AsmGen/IGenerator.cs b/SourceGen/AsmGen/IGenerator.cs
index e06265a..7603a47 100644
--- a/SourceGen/AsmGen/IGenerator.cs
+++ b/SourceGen/AsmGen/IGenerator.cs
@@ -77,13 +77,19 @@ namespace SourceGen.AsmGen {
///
LabelLocalizer Localizer { get; }
+ ///
+ /// File offset to start generating code from, usually zero. Will be nonzero for files
+ /// with a header that is supposed to be generated by the assembler (e.g. C64 PRG).
+ ///
+ int StartOffset { get; }
+
///
/// Generates source files on a background thread. Method must not make any UI calls.
///
/// Async work object, used to report progress updates and
/// check for cancellation.
- /// List of pathnames of generated files.
- List GenerateSource(BackgroundWorker worker);
+ /// Object with list of pathnames of generated files.
+ GenerationResults GenerateSource(BackgroundWorker worker);
///
/// Provides an opportunity for the assembler to replace a mnemonic with another, or
@@ -262,4 +268,17 @@ namespace SourceGen.AsmGen {
///
public bool TracksSepRepNotEmu { get; set; }
}
+
+ ///
+ /// Holds metadata generated by the assembly source generator.
+ ///
+ public class GenerationResults {
+ public List PathNames { get; private set; }
+ public string ExtraOptions { get; private set; }
+
+ public GenerationResults(List pathNames, string extraOptions) {
+ PathNames = CommonUtil.Container.CopyStringList(pathNames);
+ ExtraOptions = extraOptions;
+ }
+ }
}
\ No newline at end of file
diff --git a/SourceGen/AsmGen/WpfGui/GenAndAsm.xaml.cs b/SourceGen/AsmGen/WpfGui/GenAndAsm.xaml.cs
index 7cfbd5d..2f27509 100644
--- a/SourceGen/AsmGen/WpfGui/GenAndAsm.xaml.cs
+++ b/SourceGen/AsmGen/WpfGui/GenAndAsm.xaml.cs
@@ -82,7 +82,7 @@ namespace SourceGen.AsmGen.WpfGui {
///
/// Results from last source generation.
///
- private List mGenerationResults;
+ private GenerationResults mGenerationResults;
///
/// Holds an item for the pick-your-assembler combox box.
@@ -250,7 +250,7 @@ namespace SourceGen.AsmGen.WpfGui {
private class GenWorker : WorkProgress.IWorker {
IGenerator mGenerator;
- public List Results { get; private set; }
+ public GenerationResults Results { get; private set; }
public GenWorker(IGenerator gen) {
mGenerator = gen;
@@ -261,7 +261,7 @@ namespace SourceGen.AsmGen.WpfGui {
return mGenerator.GenerateSource(worker);
}
public void RunWorkerCompleted(object results) {
- Results = (List)results;
+ Results = (GenerationResults)results;
}
}
@@ -279,17 +279,16 @@ namespace SourceGen.AsmGen.WpfGui {
dlg.ShowDialog();
//Debug.WriteLine("Dialog returned: " + dlg.DialogResult);
- List pathNames = gw.Results;
-
- if (pathNames == null) {
+ GenerationResults res = gw.Results;
+ if (res == null) {
// error or cancelation; errors already reported
return;
}
ResetElements();
- mGenerationResults = pathNames;
+ mGenerationResults = res;
previewFileComboBox.Items.Clear();
- foreach (string str in pathNames) {
+ foreach (string str in res.PathNames) {
previewFileComboBox.Items.Add(new ComboPath(str));
}
previewFileComboBox.SelectedIndex = 0; // should trigger update
diff --git a/SourceGen/RuntimeData/Help/codegen.html b/SourceGen/RuntimeData/Help/codegen.html
index b7b8c31..4bef231 100644
--- a/SourceGen/RuntimeData/Help/codegen.html
+++ b/SourceGen/RuntimeData/Help/codegen.html
@@ -93,9 +93,6 @@ loops is easier to understand than giving each one a unique label) or
reduce the size of a generated link table. There are usually restrictions
on local labels, e.g. references to them may not be allowed to cross a
global label definition, which the localizer factors in automatically.
-The localizer is somewhat experimental at this time, and can be
-disabled from the
-application settings.
@@ -103,10 +100,35 @@ disabled from the
use of labels that begin with two underscores. Most assemblers will
also prevent you from using opcode mnemonics as labels (which means
you can't assemble jmp jmp jmp
).
-If a label doesn't appear to be legal, the generated code will have
+
If a label doesn't appear to be legal, the generated code will use
a suitable replacement (e.g. jmp_1 jmp jmp_1
).
+
+SourceGen needs to be able to assemble binaries for any system
+with any assembler, so it generally avoids platform-specific features.
+One exception to that is C64 PRG files.
+PRG files start with a 16-bit value that tells the OS where the
+rest of the file should be loaded. The value is not usually part of
+the source code, but rather is generated by the assembler, based on
+the address of the first byte generated. If SourceGen detects that
+a file is PRG, the source generators for some assemblers will suppress
+the first 2 bytes, and instead pass appropriate meta-data (such as
+an additional command-line option) to the assembler.
+A file is treated as a PRG if:
+
+ - it is between 3 and 65536 bytes long (inclusive)
+ - the format at offset +000000 is a 16-bit numeric data item
+ (not executable code, not two 8-byte values, not the first part
+ of a 24-bit value, etc.)
+ - the 16-bit value at +000000 is equal to the address of the
+ byte at +000002
+ - there is no label at offset +000000 (explicit or auto-generated)
+
+If a file is being treated as PRG and you'd rather it wasn't, you
+can add a label or reformat the bytes.
+
+
After generating sources, if you have a cross-assembler executable
@@ -313,7 +335,8 @@ code, but also needs to know how to handle the corner cases.
there's no way to do that, so instead we occasionally generate
additional width directives.
Non-unique local labels should cause an error, but don't.
- No undocumented opcodes are supported.
+ No undocumented opcodes are supported, nor are the Rockwell
+ 65C02 instructions.
diff --git a/SourceGen/RuntimeData/Help/index.html b/SourceGen/RuntimeData/Help/index.html
index 7eb63c0..389836a 100644
--- a/SourceGen/RuntimeData/Help/index.html
+++ b/SourceGen/RuntimeData/Help/index.html
@@ -106,6 +106,8 @@ and 65816 code. The official web site is
Generating Source Code
Cross-Assembling Generated Code
Assembler-Specific Bugs & Quirks
diff --git a/SourceGen/SGTestData/20040-address-changes b/SourceGen/SGTestData/20040-address-changes
new file mode 100644
index 0000000000000000000000000000000000000000..cb532bd8bf95ef4be24c6f25a678ae38a9d03132
GIT binary patch
literal 194
zcmajREe^sk7zW_C5Q5>aLE+xaY@(vw31jKf-EQv
z*-%=tR5-`D+e_*%E`*g+RDbt)(YHsO$o}}ojja8ouKSbx0DP@
Fs2?IiGbjK6
literal 0
HcmV?d00001
diff --git a/SourceGen/SGTestData/20040-address-changes.dis65 b/SourceGen/SGTestData/20040-address-changes.dis65
new file mode 100644
index 0000000..a0a0f19
--- /dev/null
+++ b/SourceGen/SGTestData/20040-address-changes.dis65
@@ -0,0 +1,170 @@
+### 6502bench SourceGen dis65 v1.0 ###
+{
+"_ContentVersion":4,
+"FileDataLength":194,
+"FileDataCrc32":452364300,
+"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":{
+}},
+
+"AddressMap":[{
+"Offset":0,
+"Addr":4096},
+
+{
+"Offset":2,
+"Addr":4096},
+
+{
+"Offset":11,
+"Addr":4352},
+
+{
+"Offset":23,
+"Addr":4352},
+
+{
+"Offset":35,
+"Addr":4352},
+
+{
+"Offset":47,
+"Addr":8192},
+
+{
+"Offset":54,
+"Addr":8224},
+
+{
+"Offset":62,
+"Addr":8320},
+
+{
+"Offset":94,
+"Addr":8448},
+
+{
+"Offset":99,
+"Addr":10240},
+
+{
+"Offset":115,
+"Addr":10272},
+
+{
+"Offset":133,
+"Addr":12288},
+
+{
+"Offset":147,
+"Addr":12544},
+
+{
+"Offset":170,
+"Addr":12672},
+
+{
+"Offset":189,
+"Addr":12800}],
+"TypeHints":[{
+"Low":2,
+"High":2,
+"Hint":"Code"},
+
+{
+"Low":23,
+"High":23,
+"Hint":"Code"},
+
+{
+"Low":35,
+"High":35,
+"Hint":"Code"},
+
+{
+"Low":168,
+"High":169,
+"Hint":"InlineData"},
+
+{
+"Low":192,
+"High":193,
+"Hint":"InlineData"}],
+"StatusFlagOverrides":{
+},
+
+"Comments":{
+"0":"PRG-style header",
+"193":"execution continues off end of file"},
+
+"LongComments":{
+},
+
+"Notes":{
+},
+
+"UserLabels":{
+"145":{
+"Label":"ulabel",
+"Value":12300,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"},
+
+"148":{
+"Label":"fwd",
+"Value":12545,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"},
+
+"187":{
+"Label":"label1",
+"Value":12689,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"},
+
+"61":{
+"Label":"offend",
+"Value":8231,
+"Source":"User",
+"Type":"GlobalAddr",
+"LabelAnno":"None"}},
+
+"OperandFormats":{
+"0":{
+"Length":2,
+"Format":"NumericLE",
+"SubFormat":"None",
+"SymbolRef":null}},
+
+"LvTables":{
+},
+
+"Visualizations":[],
+"VisualizationAnimations":[],
+"VisualizationSets":{
+},
+
+"RelocList":{
+},
+
+"DbrValues":{
+}}
diff --git a/SourceGen/SGTestData/20042-address-changes.dis65 b/SourceGen/SGTestData/20042-address-changes.dis65
index e24da80..1de8f86 100644
--- a/SourceGen/SGTestData/20042-address-changes.dis65
+++ b/SourceGen/SGTestData/20042-address-changes.dis65
@@ -1,64 +1,167 @@
### 6502bench SourceGen dis65 v1.0 ###
{
-"_ContentVersion":1,"FileDataLength":203,"FileDataCrc32":-2143569845,"ProjectProps":{
-"CpuName":"65816","IncludeUndocumentedInstr":false,"EntryFlags":33489103,"AnalysisParams":{
-"AnalyzeUncategorizedData":true,"MinCharsForString":4,"SeekNearbyTargets":true},
-"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":[],"ProjectSyms":{
+"_ContentVersion":4,
+"FileDataLength":203,
+"FileDataCrc32":-2143569845,
+"ProjectProps":{
+"CpuName":"65816",
+"IncludeUndocumentedInstr":false,
+"TwoByteBrk":false,
+"EntryFlags":33489103,
+"AutoLabelStyle":"Simple",
+"AnalysisParams":{
+"AnalyzeUncategorizedData":true,
+"DefaultTextScanMode":"LowHighAscii",
+"MinCharsForString":4,
+"SeekNearbyTargets":true,
+"UseRelocData":false,
+"SmartPlpHandling":true,
+"SmartPlbHandling":true},
+
+"PlatformSymbolFileIdentifiers":[],
+"ExtensionScriptFileIdentifiers":[],
+"ProjectSyms":{
}},
+
"AddressMap":[{
-"Offset":0,"Addr":4096},
+"Offset":0,
+"Addr":135168},
+
{
-"Offset":13,"Addr":4352},
+"Offset":13,
+"Addr":135424},
+
{
-"Offset":27,"Addr":4352},
+"Offset":27,
+"Addr":135424},
+
{
-"Offset":42,"Addr":4352},
+"Offset":42,
+"Addr":135424},
+
{
-"Offset":56,"Addr":8192},
+"Offset":56,
+"Addr":139264},
+
{
-"Offset":63,"Addr":8224},
+"Offset":63,
+"Addr":139296},
+
{
-"Offset":72,"Addr":8320},
+"Offset":72,
+"Addr":139392},
+
{
-"Offset":104,"Addr":8448},
+"Offset":104,
+"Addr":139520},
+
{
-"Offset":109,"Addr":10240},
+"Offset":109,
+"Addr":141312},
+
{
-"Offset":125,"Addr":10272},
+"Offset":125,
+"Addr":141344},
+
{
-"Offset":143,"Addr":12288},
+"Offset":143,
+"Addr":143360},
+
{
-"Offset":157,"Addr":12544},
+"Offset":157,
+"Addr":143616},
+
{
-"Offset":180,"Addr":12672},
+"Offset":180,
+"Addr":143744},
+
{
-"Offset":198,"Addr":12800}],"TypeHints":[{
-"Low":0,"High":0,"Hint":"Code"},
+"Offset":198,
+"Addr":143872}],
+"TypeHints":[{
+"Low":0,
+"High":0,
+"Hint":"Code"},
+
{
-"Low":27,"High":27,"Hint":"Code"},
+"Low":27,
+"High":27,
+"Hint":"Code"},
+
{
-"Low":42,"High":42,"Hint":"Code"},
+"Low":42,
+"High":42,
+"Hint":"Code"},
+
{
-"Low":178,"High":180,"Hint":"InlineData"},
+"Low":178,
+"High":180,
+"Hint":"InlineData"},
+
{
-"Low":201,"High":202,"Hint":"InlineData"}],"StatusFlagOverrides":{
+"Low":201,
+"High":202,
+"Hint":"InlineData"}],
+"StatusFlagOverrides":{
},
+
"Comments":{
},
+
"LongComments":{
},
+
"Notes":{
},
+
"UserLabels":{
"71":{
-"Label":"offend","Value":8232,"Source":"User","Type":"LocalOrGlobalAddr"},
+"Label":"offend",
+"Value":139304,
+"Source":"User",
+"Type":"LocalOrGlobalAddr",
+"LabelAnno":"None"},
+
"155":{
-"Label":"ulabel","Value":12300,"Source":"User","Type":"LocalOrGlobalAddr"},
+"Label":"ulabel",
+"Value":143372,
+"Source":"User",
+"Type":"LocalOrGlobalAddr",
+"LabelAnno":"None"},
+
"158":{
-"Label":"fwd","Value":12545,"Source":"User","Type":"LocalOrGlobalAddr"},
+"Label":"fwd",
+"Value":143617,
+"Source":"User",
+"Type":"LocalOrGlobalAddr",
+"LabelAnno":"None"},
+
"196":{
-"Label":"label1","Value":12688,"Source":"User","Type":"LocalOrGlobalAddr"}},
+"Label":"label1",
+"Value":143760,
+"Source":"User",
+"Type":"LocalOrGlobalAddr",
+"LabelAnno":"None"}},
+
"OperandFormats":{
"191":{
-"Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
-"Label":"label1","Part":"Low"}}}}
+"Length":3,
+"Format":"NumericLE",
+"SubFormat":"Symbol",
+"SymbolRef":{
+"Label":"label1",
+"Part":"Low"}}},
+
+"LvTables":{
+},
+
+"Visualizations":[],
+"VisualizationAnimations":[],
+"VisualizationSets":{
+},
+
+"RelocList":{
+},
+
+"DbrValues":{
+}}
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_64tass.S b/SourceGen/SGTestData/Expected/20040-address-changes_64tass.S
new file mode 100644
index 0000000..3c3476e
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_64tass.S
@@ -0,0 +1,119 @@
+ .cpu "6502"
+
+* = $1000
+ jsr L1100
+ jsr L1107
+ jmp L2000
+
+ .logical $1100
+L1100 bit L1100
+L1103 lda #$11
+ ldx #$11
+L1107 ldy #$11
+ clv
+ bvc L1103
+
+ .here
+ .logical $1100
+_L1100_0 bit _L1100_0
+ lda #$22
+_L1105 ldx #$22
+ ldy #$22
+ jmp _L1105
+
+ .here
+ .logical $1100
+_L1100_1 bit _L1100_1
+ lda #$33
+ ldx #$33
+_L1107_0 ldy #$33
+ sec
+ bcs _L1107_0
+
+ .here
+ .logical $2000
+L2000 bit L2000
+ beq $2018
+ bne _L2020
+
+ .here
+ .logical $2020
+_L2020 bit _L2020
+ beq $2028
+ bne L2080
+
+offend nop
+ .here
+ .logical $2080
+L2080 bit L2080
+ lda offend
+ jsr offend
+ lda $2028
+ jsr $2028
+ lda L2080-1
+ jsr L2080-1
+ lda L2080
+ jsr L2080
+ lda $00
+ beq _L2100
+ .byte $ad
+
+ .here
+ .logical $2100
+_L2100 nop
+ nop
+ jmp _L3000
+
+ .here
+ .logical $2800
+ .byte $00
+ .byte $28
+ .fill 14,$00
+ .here
+ .logical $2820
+ .fill 18,$00
+
+ .here
+ .logical $3000
+_L3000 bit _L3000
+ lda #$44
+ ldx #$44
+ ldy #$44
+ jmp fwd
+
+ulabel .byte $00
+ .byte $01
+ .here
+ .logical $3100
+ .byte $02
+
+fwd bit fwd
+ lda ulabel
+ lda ulabel+1
+ lda $300e
+ lda $300f
+ lda fwd-1
+ beq _L3182
+ .byte $ea
+ .byte $ea
+ .here
+ .logical $3180
+ .byte $00
+ .byte $01
+
+_L3182 bit _L3182
+ lda label1
+ lda label1+1
+ lda L3200
+ clv
+ bvc L3200
+
+label1 .byte $ea
+ .byte $ea
+
+ .here
+ .logical $3200
+L3200 bit L3200
+ .byte $00
+ .byte $01 ;execution continues off end of file
+ .here
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_Merlin32.S b/SourceGen/SGTestData/Expected/20040-address-changes_Merlin32.S
new file mode 100644
index 0000000..0e7a36c
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_Merlin32.S
@@ -0,0 +1,107 @@
+ org $1000
+ dw $1000 ;PRG-style header
+
+ org $1000
+ jsr L1100
+ jsr L1107
+ jmp L2000
+
+ org $1100
+L1100 bit L1100
+L1103 lda #$11
+ ldx #$11
+L1107 ldy #$11
+ clv
+ bvc L1103
+
+ org $1100
+:L1100_0 bit :L1100_0
+ lda #$22
+:L1105 ldx #$22
+ ldy #$22
+ jmp :L1105
+
+ org $1100
+:L1100_1 bit :L1100_1
+ lda #$33
+ ldx #$33
+:L1107_0 ldy #$33
+ sec
+ bcs :L1107_0
+
+ org $2000
+L2000 bit L2000
+ beq $2018
+ bne :L2020
+
+ org $2020
+:L2020 bit :L2020
+ beq $2028
+ bne L2080
+
+offend nop
+ org $2080
+L2080 bit L2080
+ lda offend
+ jsr offend
+ lda $2028
+ jsr $2028
+ lda L2080-1
+ jsr L2080-1
+ lda L2080
+ jsr L2080
+ lda $00
+ beq :L2100
+ dfb $ad
+
+ org $2100
+:L2100 nop
+ nop
+ jmp :L3000
+
+ org $2800
+ dfb $00
+ dfb $28
+ ds 14
+ org $2820
+ ds 18
+
+ org $3000
+:L3000 bit :L3000
+ lda #$44
+ ldx #$44
+ ldy #$44
+ jmp fwd
+
+ulabel dfb $00
+ dfb $01
+ org $3100
+ dfb $02
+
+fwd bit fwd
+ lda ulabel
+ lda ulabel+1
+ lda $300e
+ lda $300f
+ lda fwd-1
+ beq :L3182
+ dfb $ea
+ dfb $ea
+ org $3180
+ dfb $00
+ dfb $01
+
+:L3182 bit :L3182
+ lda label1
+ lda label1+1
+ lda L3200
+ clv
+ bvc L3200
+
+label1 dfb $ea
+ dfb $ea
+
+ org $3200
+L3200 bit L3200
+ dfb $00
+ dfb $01 ;execution continues off end of file
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_acme.S b/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
new file mode 100644
index 0000000..3aab4e6
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_acme.S
@@ -0,0 +1,124 @@
+ !cpu 6502
+* = $0000
+ !pseudopc $1000 {
+ !word $1000 ;PRG-style header
+
+ } ;!pseudopc
+ !pseudopc $1000 {
+ jsr L1100
+ jsr L1107
+ jmp L2000
+
+ } ;!pseudopc
+ !pseudopc $1100 {
+L1100 bit L1100
+L1103 lda #$11
+ ldx #$11
+L1107 ldy #$11
+ clv
+ bvc L1103
+
+ } ;!pseudopc
+ !pseudopc $1100 {
+@L1100_0 bit @L1100_0
+ lda #$22
+@L1105 ldx #$22
+ ldy #$22
+ jmp @L1105
+
+ } ;!pseudopc
+ !pseudopc $1100 {
+@L1100_1 bit @L1100_1
+ lda #$33
+ ldx #$33
+@L1107_0 ldy #$33
+ sec
+ bcs @L1107_0
+
+ } ;!pseudopc
+ !pseudopc $2000 {
+L2000 bit L2000
+ beq $2018
+ bne @L2020
+
+ } ;!pseudopc
+ !pseudopc $2020 {
+@L2020 bit @L2020
+ beq $2028
+ bne L2080
+
+offend nop
+ } ;!pseudopc
+ !pseudopc $2080 {
+L2080 bit L2080
+ lda offend
+ jsr offend
+ lda $2028
+ jsr $2028
+ lda L2080-1
+ jsr L2080-1
+ lda L2080
+ jsr L2080
+ lda $00
+ beq @L2100
+ !byte $ad
+
+ } ;!pseudopc
+ !pseudopc $2100 {
+@L2100 nop
+ nop
+ jmp @L3000
+
+ } ;!pseudopc
+ !pseudopc $2800 {
+ !byte $00
+ !byte $28
+ !fill 14,$00
+ } ;!pseudopc
+ !pseudopc $2820 {
+ !fill 18,$00
+
+ } ;!pseudopc
+ !pseudopc $3000 {
+@L3000 bit @L3000
+ lda #$44
+ ldx #$44
+ ldy #$44
+ jmp fwd
+
+ulabel !byte $00
+ !byte $01
+ } ;!pseudopc
+ !pseudopc $3100 {
+ !byte $02
+
+fwd bit fwd
+ lda ulabel
+ lda ulabel+1
+ lda $300e
+ lda $300f
+ lda fwd-1
+ beq @L3182
+ !byte $ea
+ !byte $ea
+ } ;!pseudopc
+ !pseudopc $3180 {
+ !byte $00
+ !byte $01
+
+@L3182 bit @L3182
+ lda label1
+ lda label1+1
+ lda L3200
+ clv
+ bvc L3200
+
+label1 !byte $ea
+ !byte $ea
+
+ } ;!pseudopc
+ !pseudopc $3200 {
+L3200 bit L3200
+ !byte $00
+ !byte $01 ;execution continues off end of file
+ } ;!pseudopc
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_cc65.S b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.S
new file mode 100644
index 0000000..6ca2af2
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.S
@@ -0,0 +1,123 @@
+ .setcpu "6502"
+; .segment "SEG000"
+ .org $1000
+ .word $1000 ;PRG-style header
+
+; .segment "SEG001"
+ .org $1000
+ jsr L1100
+ jsr L1107
+ jmp L2000
+
+; .segment "SEG002"
+ .org $1100
+L1100: bit L1100
+L1103: lda #$11
+ ldx #$11
+L1107: ldy #$11
+ clv
+ bvc L1103
+
+; .segment "SEG003"
+ .org $1100
+@L1100_0: bit @L1100_0
+ lda #$22
+@L1105: ldx #$22
+ ldy #$22
+ jmp @L1105
+
+; .segment "SEG004"
+ .org $1100
+@L1100_1: bit @L1100_1
+ lda #$33
+ ldx #$33
+@L1107_0: ldy #$33
+ sec
+ bcs @L1107_0
+
+; .segment "SEG005"
+ .org $2000
+L2000: bit L2000
+ beq $2018
+ bne @L2020
+
+; .segment "SEG006"
+ .org $2020
+@L2020: bit @L2020
+ beq $2028
+ bne L2080
+
+offend: nop
+; .segment "SEG007"
+ .org $2080
+L2080: bit L2080
+ lda offend
+ jsr offend
+ lda $2028
+ jsr $2028
+ lda L2080-1
+ jsr L2080-1
+ lda L2080
+ jsr L2080
+ lda $00
+ beq @L2100
+ .byte $ad
+
+; .segment "SEG008"
+ .org $2100
+@L2100: nop
+ nop
+ jmp @L3000
+
+; .segment "SEG009"
+ .org $2800
+ .byte $00
+ .byte $28
+ .res 14,$00
+; .segment "SEG010"
+ .org $2820
+ .res 18,$00
+
+; .segment "SEG011"
+ .org $3000
+@L3000: bit @L3000
+ lda #$44
+ ldx #$44
+ ldy #$44
+ jmp fwd
+
+ulabel: .byte $00
+ .byte $01
+; .segment "SEG012"
+ .org $3100
+ .byte $02
+
+fwd: bit fwd
+ lda ulabel
+ lda ulabel+1
+ lda $300e
+ lda $300f
+ lda fwd-1
+ beq @L3182
+ .byte $ea
+ .byte $ea
+; .segment "SEG013"
+ .org $3180
+ .byte $00
+ .byte $01
+
+@L3182: bit @L3182
+ lda label1
+ lda label1+1
+ lda L3200
+ clv
+ bvc L3200
+
+label1: .byte $ea
+ .byte $ea
+
+; .segment "SEG014"
+ .org $3200
+L3200: bit L3200
+ .byte $00
+ .byte $01 ;execution continues off end of file
diff --git a/SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg
new file mode 100644
index 0000000..31120e0
--- /dev/null
+++ b/SourceGen/SGTestData/Expected/20040-address-changes_cc65.cfg
@@ -0,0 +1,39 @@
+# 6502bench SourceGen generated linker script for 20040-address-changes
+MEMORY {
+ MAIN: file=%O, start=%S, size=65536;
+# MEM000: file=%O, start=$1000, size=2;
+# MEM001: file=%O, start=$1000, size=9;
+# MEM002: file=%O, start=$1100, size=12;
+# MEM003: file=%O, start=$1100, size=12;
+# MEM004: file=%O, start=$1100, size=12;
+# MEM005: file=%O, start=$2000, size=7;
+# MEM006: file=%O, start=$2020, size=8;
+# MEM007: file=%O, start=$2080, size=32;
+# MEM008: file=%O, start=$2100, size=5;
+# MEM009: file=%O, start=$2800, size=16;
+# MEM010: file=%O, start=$2820, size=18;
+# MEM011: file=%O, start=$3000, size=14;
+# MEM012: file=%O, start=$3100, size=23;
+# MEM013: file=%O, start=$3180, size=19;
+# MEM014: file=%O, start=$3200, size=5;
+}
+SEGMENTS {
+ CODE: load=MAIN, type=rw;
+# SEG000: load=MEM000, type=rw;
+# SEG001: load=MEM001, type=rw;
+# SEG002: load=MEM002, type=rw;
+# SEG003: load=MEM003, type=rw;
+# SEG004: load=MEM004, type=rw;
+# SEG005: load=MEM005, type=rw;
+# SEG006: load=MEM006, type=rw;
+# SEG007: load=MEM007, type=rw;
+# SEG008: load=MEM008, type=rw;
+# SEG009: load=MEM009, type=rw;
+# SEG010: load=MEM010, type=rw;
+# SEG011: load=MEM011, type=rw;
+# SEG012: load=MEM012, type=rw;
+# SEG013: load=MEM013, type=rw;
+# SEG014: load=MEM014, type=rw;
+}
+FEATURES {}
+SYMBOLS {}
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S b/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S
index de3b898..d071e95 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_64tass.S
@@ -1,86 +1,86 @@
.cpu "65816"
-* = $1000
+* = $021000
.as
.xs
clc
xce
sep #$ff
- jsr L1100
- jsr L1107
- jmp L2000
+ jsr L21100
+ jsr L21107
+ jmp L22000
- .logical $1100
-L1100 bit L1100
-L1103 lda #$11
+ .logical $021100
+L21100 bit L21100 & $ffff
+L21103 lda #$11
ldx #$11
-L1107 ldy #$11
- per L1103
- bra L1103
+L21107 ldy #$11
+ per L21103
+ bra L21103
.here
- .logical $1100
-_L1100_0 bit _L1100_0
+ .logical $021100
+_L21100_0 bit _L21100_0 & $ffff
lda #$22
-_L1105 ldx #$22
+_L21105 ldx #$22
ldy #$22
- per _L1105
- jmp _L1105
+ per _L21105
+ jmp _L21105
.here
- .logical $1100
-_L1100_1 bit _L1100_1
+ .logical $021100
+_L21100_1 bit _L21100_1 & $ffff
lda #$33
ldx #$33
-_L1107_0 ldy #$33
- per _L1107_0
- bra _L1107_0
+_L21107_0 ldy #$33
+ per _L21107_0
+ bra _L21107_0
.here
- .logical $2000
-L2000 bit L2000
- beq $2018
- bra _L2020
+ .logical $022000
+L22000 bit L22000 & $ffff
+ beq $022018
+ bra _L22020
.here
- .logical $2020
-_L2020 bit _L2020
- beq $2029
- brl _L2080
+ .logical $022020
+_L22020 bit _L22020 & $ffff
+ beq $022029
+ brl _L22080
_offend nop
.here
- .logical $2080
-_L2080 bit _L2080
- lda _offend
+ .logical $022080
+_L22080 bit _L22080 & $ffff
+ lda _offend & $ffff
jsr _offend
lda $2029
- jsr $2029
- lda _L2080-1
- jsr _L2080-1
- lda _L2080
- jsr _L2080
+ jsr $022029
+ lda 0+(_L22080 & $ffff)-1
+ jsr _L22080-1
+ lda _L22080 & $ffff
+ jsr _L22080
lda $00
- beq _L2100
+ beq _L22100
.byte $ad
.here
- .logical $2100
-_L2100 nop
+ .logical $022100
+_L22100 nop
nop
- jmp _L3000
+ jmp _L23000
.here
- .logical $2800
+ .logical $022800
.byte $00
.byte $28
.fill 14,$00
.here
- .logical $2820
+ .logical $022820
.fill 18,$00
.here
- .logical $3000
-_L3000 bit _L3000
+ .logical $023000
+_L23000 bit _L23000 & $ffff
lda #$44
ldx #$44
ldy #$44
@@ -89,35 +89,35 @@ _L3000 bit _L3000
_ulabel .byte $00
.byte $01
.here
- .logical $3100
+ .logical $023100
.byte $02
-_fwd bit _fwd
- lda _ulabel
- lda _ulabel+1
+_fwd bit _fwd & $ffff
+ lda _ulabel & $ffff
+ lda 0+(_ulabel & $ffff)+1
lda $300e
lda $300f
- lda _fwd-1
- beq _L3182
+ lda 0+(_fwd & $ffff)-1
+ beq _L23182
.byte $ea
.byte $ea
.here
- .logical $3180
+ .logical $023180
.byte $00
.byte $01
-_L3182 bit _L3182
- lda _label1
- lda _label1+1
- lda _label1+112
- bra _L3200
+_L23182 bit _L23182 & $ffff
+ lda _label1 & $ffff
+ lda 0+(_label1 & $ffff)+1
+ lda 0+(_label1 & $ffff)+112
+ bra _L23200
_label1 .byte $ea
.byte $ea
.here
- .logical $3200
-_L3200 bit _L3200
+ .logical $023200
+_L23200 bit _L23200 & $ffff
.byte $00
.byte $01
.here
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_Merlin32.S b/SourceGen/SGTestData/Expected/20042-address-changes_Merlin32.S
index 64ac625..ae5c1d6 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_Merlin32.S
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_Merlin32.S
@@ -1,74 +1,74 @@
- org $1000
+ org $021000
clc
xce
sep #$ff
- jsr L1100
- jsr L1107
- jmp L2000
+ jsr L21100
+ jsr L21107
+ jmp L22000
- org $1100
-L1100 bit L1100
-L1103 lda #$11
+ org $021100
+L21100 bit L21100
+L21103 lda #$11
ldx #$11
-L1107 ldy #$11
- per L1103
- bra L1103
+L21107 ldy #$11
+ per L21103
+ bra L21103
- org $1100
-:L1100_0 bit :L1100_0
+ org $021100
+:L21100_0 bit :L21100_0
lda #$22
-:L1105 ldx #$22
+:L21105 ldx #$22
ldy #$22
- per :L1105
- jmp :L1105
+ per :L21105
+ jmp :L21105
- org $1100
-:L1100_1 bit :L1100_1
+ org $021100
+:L21100_1 bit :L21100_1
lda #$33
ldx #$33
-:L1107_0 ldy #$33
- per :L1107_0
- bra :L1107_0
+:L21107_0 ldy #$33
+ per :L21107_0
+ bra :L21107_0
- org $2000
-L2000 bit L2000
- beq $2018
- bra :L2020
+ org $022000
+L22000 bit L22000
+ beq $022018
+ bra :L22020
- org $2020
-:L2020 bit :L2020
- beq $2029
- brl :L2080
+ org $022020
+:L22020 bit :L22020
+ beq $022029
+ brl :L22080
:offend nop
- org $2080
-:L2080 bit :L2080
+ org $022080
+:L22080 bit :L22080
lda :offend
jsr :offend
lda $2029
jsr $2029
- lda :L2080-1
- jsr :L2080-1
- lda :L2080
- jsr :L2080
+ lda :L22080-1
+ jsr :L22080-1
+ lda :L22080
+ jsr :L22080
lda $00
- beq :L2100
+ beq :L22100
dfb $ad
- org $2100
-:L2100 nop
+ org $022100
+:L22100 nop
nop
- jmp :L3000
+ jmp :L23000
- org $2800
+ org $022800
dfb $00
dfb $28
ds 14
- org $2820
+ org $022820
ds 18
- org $3000
-:L3000 bit :L3000
+ org $023000
+:L23000 bit :L23000
lda #$44
ldx #$44
ldy #$44
@@ -76,7 +76,7 @@ L2000 bit L2000
:ulabel dfb $00
dfb $01
- org $3100
+ org $023100
dfb $02
:fwd bit :fwd
@@ -85,23 +85,23 @@ L2000 bit L2000
lda $300e
lda $300f
lda :fwd-1
- beq :L3182
+ beq :L23182
dfb $ea
dfb $ea
- org $3180
+ org $023180
dfb $00
dfb $01
-:L3182 bit :L3182
+:L23182 bit :L23182
lda :label1
lda :label1+1
lda :label1+112
- bra :L3200
+ bra :L23200
:label1 dfb $ea
dfb $ea
- org $3200
-:L3200 bit :L3200
+ org $023200
+:L23200 bit :L23200
dfb $00
dfb $01
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_acme.S b/SourceGen/SGTestData/Expected/20042-address-changes_acme.S
index 2baae7f..26e1087 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_acme.S
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_acme.S
@@ -1,125 +1,11 @@
- !cpu 65816
+;ACME can't handle 65816 code that lives outside bank zero
* = $0000
- !pseudopc $1000 {
- !as
- !rs
- clc
- xce
- sep #$ff
- jsr L1100
- jsr L1107
- jmp L2000
-
- } ;!pseudopc
- !pseudopc $1100 {
-L1100 bit L1100
-L1103 lda #$11
- ldx #$11
-L1107 ldy #$11
- per L1103
- bra L1103
-
- } ;!pseudopc
- !pseudopc $1100 {
-@L1100_0 bit @L1100_0
- lda #$22
-@L1105 ldx #$22
- ldy #$22
- per @L1105
- jmp @L1105
-
- } ;!pseudopc
- !pseudopc $1100 {
-@L1100_1 bit @L1100_1
- lda #$33
- ldx #$33
-@L1107_0 ldy #$33
- per @L1107_0
- bra @L1107_0
-
- } ;!pseudopc
- !pseudopc $2000 {
-L2000 bit L2000
- beq $2018
- bra @L2020
-
- } ;!pseudopc
- !pseudopc $2020 {
-@L2020 bit @L2020
- beq $2029
- brl @L2080
-
-@offend nop
- } ;!pseudopc
- !pseudopc $2080 {
-@L2080 bit @L2080
- lda @offend
- jsr @offend
- lda $2029
- jsr $2029
- lda @L2080-1
- jsr @L2080-1
- lda @L2080
- jsr @L2080
- lda $00
- beq @L2100
- !byte $ad
-
- } ;!pseudopc
- !pseudopc $2100 {
-@L2100 nop
- nop
- jmp @L3000
-
- } ;!pseudopc
- !pseudopc $2800 {
- !byte $00
- !byte $28
- !fill 14,$00
- } ;!pseudopc
- !pseudopc $2820 {
- !fill 18,$00
-
- } ;!pseudopc
- !pseudopc $3000 {
-@L3000 bit @L3000
- lda #$44
- ldx #$44
- ldy #$44
- brl @fwd
-
-@ulabel !byte $00
- !byte $01
- } ;!pseudopc
- !pseudopc $3100 {
- !byte $02
-
-@fwd bit @fwd
- lda @ulabel
- lda @ulabel+1
- lda $300e
- lda $300f
- lda @fwd-1
- beq @L3182
- !byte $ea
- !byte $ea
- } ;!pseudopc
- !pseudopc $3180 {
- !byte $00
- !byte $01
-
-@L3182 bit @L3182
- lda @label1
- lda @label1+1
- lda @label1+112
- bra @L3200
-
-@label1 !byte $ea
- !byte $ea
-
- } ;!pseudopc
- !pseudopc $3200 {
-@L3200 bit @L3200
- !byte $00
- !byte $01
+ !pseudopc $021000 {
+ !hex 18fbe2ff2000112007114c00202c0011a911a211a01162f7ff80f52c0011a922
+ !hex a222a02262f9ff4c05112c0011a933a233a03362fbff80f92c0020f01380192c
+ !hex 2020f004825800ea2c8020ad2820202820ad2920202920ad7f20207f20ad8020
+ !hex 208020a500f061adeaea4c003000280000000000000000000000000000000000
+ !hex 0000000000000000000000000000002c0030a944a244a04482f5000001022c01
+ !hex 31ad0c30ad0d30ad0e30ad0f30ad0031f06deaea00012c8231ad9031ad9131ad
+ !hex 00328070eaea2c00320001
} ;!pseudopc
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S
index 909e102..d56d36a 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.S
@@ -1,88 +1,88 @@
.setcpu "65816"
; .segment "SEG000"
- .org $1000
+ .org $021000
.a8
.i8
clc
xce
sep #$ff
- jsr L1100
- jsr L1107
- jmp L2000
+ jsr L21100 & $ffff
+ jsr L21107 & $ffff
+ jmp L22000 & $ffff
; .segment "SEG001"
- .org $1100
-L1100: bit L1100
-L1103: lda #$11
+ .org $021100
+L21100: bit L21100 & $ffff
+L21103: lda #$11
ldx #$11
-L1107: ldy #$11
- per L1103
- bra L1103
+L21107: ldy #$11
+ per L21103
+ bra L21103
; .segment "SEG002"
- .org $1100
-@L1100_0: bit @L1100_0
+ .org $021100
+@L21100_0: bit @L21100_0 & $ffff
lda #$22
-@L1105: ldx #$22
+@L21105: ldx #$22
ldy #$22
- per @L1105
- jmp @L1105
+ per @L21105
+ jmp @L21105 & $ffff
; .segment "SEG003"
- .org $1100
-@L1100_1: bit @L1100_1
+ .org $021100
+@L21100_1: bit @L21100_1 & $ffff
lda #$33
ldx #$33
-@L1107_0: ldy #$33
- per @L1107_0
- bra @L1107_0
+@L21107_0: ldy #$33
+ per @L21107_0
+ bra @L21107_0
; .segment "SEG004"
- .org $2000
-L2000: bit L2000
- beq $2018
- bra @L2020
+ .org $022000
+L22000: bit L22000 & $ffff
+ beq $022018
+ bra @L22020
; .segment "SEG005"
- .org $2020
-@L2020: bit @L2020
- beq $2029
- brl @L2080
+ .org $022020
+@L22020: bit @L22020 & $ffff
+ beq $022029
+ brl @L22080
@offend: nop
; .segment "SEG006"
- .org $2080
-@L2080: bit @L2080
- lda @offend
- jsr @offend
+ .org $022080
+@L22080: bit @L22080 & $ffff
+ lda @offend & $ffff
+ jsr @offend & $ffff
lda $2029
jsr $2029
- lda @L2080-1
- jsr @L2080-1
- lda @L2080
- jsr @L2080
+ lda @L22080 & $ffff -1
+ jsr @L22080 & $ffff -1
+ lda @L22080 & $ffff
+ jsr @L22080 & $ffff
lda $00
- beq @L2100
+ beq @L22100
.byte $ad
; .segment "SEG007"
- .org $2100
-@L2100: nop
+ .org $022100
+@L22100: nop
nop
- jmp @L3000
+ jmp @L23000 & $ffff
; .segment "SEG008"
- .org $2800
+ .org $022800
.byte $00
.byte $28
.res 14,$00
; .segment "SEG009"
- .org $2820
+ .org $022820
.res 18,$00
; .segment "SEG010"
- .org $3000
-@L3000: bit @L3000
+ .org $023000
+@L23000: bit @L23000 & $ffff
lda #$44
ldx #$44
ldy #$44
@@ -91,34 +91,34 @@ L2000: bit L2000
@ulabel: .byte $00
.byte $01
; .segment "SEG011"
- .org $3100
+ .org $023100
.byte $02
-@fwd: bit @fwd
- lda @ulabel
- lda @ulabel+1
+@fwd: bit @fwd & $ffff
+ lda @ulabel & $ffff
+ lda @ulabel & $ffff +1
lda $300e
lda $300f
- lda @fwd-1
- beq @L3182
+ lda @fwd & $ffff -1
+ beq @L23182
.byte $ea
.byte $ea
; .segment "SEG012"
- .org $3180
+ .org $023180
.byte $00
.byte $01
-@L3182: bit @L3182
- lda @label1
- lda @label1+1
- lda @label1+112
- bra @L3200
+@L23182: bit @L23182 & $ffff
+ lda @label1 & $ffff
+ lda @label1 & $ffff +1
+ lda @label1 & $ffff +112
+ bra @L23200
@label1: .byte $ea
.byte $ea
; .segment "SEG013"
- .org $3200
-@L3200: bit @L3200
+ .org $023200
+@L23200: bit @L23200 & $ffff
.byte $00
.byte $01
diff --git a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg
index 282f00e..b8ef32f 100644
--- a/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg
+++ b/SourceGen/SGTestData/Expected/20042-address-changes_cc65.cfg
@@ -1,20 +1,20 @@
# 6502bench SourceGen generated linker script for 20042-address-changes
MEMORY {
MAIN: file=%O, start=%S, size=65536;
-# MEM000: file=%O, start=$1000, size=13;
-# MEM001: file=%O, start=$1100, size=14;
-# MEM002: file=%O, start=$1100, size=15;
-# MEM003: file=%O, start=$1100, size=14;
-# MEM004: file=%O, start=$2000, size=7;
-# MEM005: file=%O, start=$2020, size=9;
-# MEM006: file=%O, start=$2080, size=32;
-# MEM007: file=%O, start=$2100, size=5;
-# MEM008: file=%O, start=$2800, size=16;
-# MEM009: file=%O, start=$2820, size=18;
-# MEM010: file=%O, start=$3000, size=14;
-# MEM011: file=%O, start=$3100, size=23;
-# MEM012: file=%O, start=$3180, size=18;
-# MEM013: file=%O, start=$3200, size=5;
+# MEM000: file=%O, start=$21000, size=13;
+# MEM001: file=%O, start=$21100, size=14;
+# MEM002: file=%O, start=$21100, size=15;
+# MEM003: file=%O, start=$21100, size=14;
+# MEM004: file=%O, start=$22000, size=7;
+# MEM005: file=%O, start=$22020, size=9;
+# MEM006: file=%O, start=$22080, size=32;
+# MEM007: file=%O, start=$22100, size=5;
+# MEM008: file=%O, start=$22800, size=16;
+# MEM009: file=%O, start=$22820, size=18;
+# MEM010: file=%O, start=$23000, size=14;
+# MEM011: file=%O, start=$23100, size=23;
+# MEM012: file=%O, start=$23180, size=18;
+# MEM013: file=%O, start=$23200, size=5;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
diff --git a/SourceGen/SGTestData/Source/20040-address-changes.S b/SourceGen/SGTestData/Source/20040-address-changes.S
new file mode 100644
index 0000000..cf460f3
--- /dev/null
+++ b/SourceGen/SGTestData/Source/20040-address-changes.S
@@ -0,0 +1,117 @@
+; Copyright 2018 faddenSoft. All Rights Reserved.
+; See the LICENSE.txt file for distribution terms (Apache 2.0).
+;
+; Assembler: Merlin 32
+; 6502 version
+
+ dw $1000 ;PRG-style header
+
+ org $1000
+ jsr one
+ jsr three_p ;should land inside one
+ jmp nextthing
+
+ org $1100
+one bit one
+one_p lda #$11
+ ldx #$11
+ ldy #$11
+ clv
+ bvc one_p
+
+ org $1100
+two bit two
+ lda #$22
+two_p ldx #$22
+ ldy #$22
+ jmp two_p
+
+ org $1100
+three bit three
+ lda #$33
+ ldx #$33
+three_p ldy #$33
+ sec
+ bcs three_p
+
+
+ org $2000
+nextthing
+ bit nextthing
+ beq :fwd-8 ;should just appear as hex since it's outside
+ bne :fwd ;BNE across org segments (always)
+
+ org $2020
+:fwd bit :fwd
+ beq offend ;branch off the end of the address area into dead space
+ bne endcheck ; (which wouldn't be dead without the org)
+ nop
+offend
+
+ org $2080
+endcheck
+ bit endcheck
+ lda offend-1 ;touch bytes at the ends, and one byte before/after
+ jsr offend-1
+ lda offend
+ jsr offend
+ lda endcheck-1
+ jsr endcheck-1
+ lda endcheck
+ jsr endcheck
+
+ lda $00
+ beq :midinst
+ dfb $ad ;LDA abs
+ org $2100
+:midinst dfb $ea,$ea
+
+ jmp pastdata
+
+ org $2800
+ dw *
+ ds 16 ;EDIT: put an org change in the middle
+ org $2820
+ ds 16
+
+ org $3000
+pastdata
+ bit pastdata
+ lda #$44
+ ldx #$44
+ ldy #$44
+ jmp :fwd
+ dfb $00 ;put user label here or next inst
+:datend dfb $01
+
+ org $3100
+ dfb $02 ;data target should NOT get merged with previous user label
+:fwd
+ bit :fwd
+ lda :datend-1
+ lda :datend
+ lda :datend+1
+ lda :datend+2
+ lda :fwd-1
+ beq :more
+
+ dfb $ea,$ea ;EDIT: mark as inline data
+
+ org $3180
+ dfb $00,$01
+:more bit :more
+
+; xref edge case test: make sure adjustment shown is based on address
+ lda label1
+ lda label2 ;EDIT: set operand to sym=label1
+ lda label3 ;EDIT: set operand to sym=label1
+ clv
+ bvc label3
+label1 nop
+label2 nop
+ org $3200
+label3 bit label3
+
+ dfb $00,$01 ;EDIT: mark as inline data to test execution off end
+
+; add nothing here -- execution should run off end
diff --git a/SourceGen/SGTestData/Source/20042-address-changes.S b/SourceGen/SGTestData/Source/20042-address-changes.S
index 1285068..3c2b4de 100644
--- a/SourceGen/SGTestData/Source/20042-address-changes.S
+++ b/SourceGen/SGTestData/Source/20042-address-changes.S
@@ -2,6 +2,7 @@
; See the LICENSE.txt file for distribution terms (Apache 2.0).
;
; Assembler: Merlin 32
+; 65816 version
org $1000
clc
diff --git a/SourceGen/Tests/GenTest.cs b/SourceGen/Tests/GenTest.cs
index 7dcd575..cf82869 100644
--- a/SourceGen/Tests/GenTest.cs
+++ b/SourceGen/Tests/GenTest.cs
@@ -269,7 +269,7 @@ namespace SourceGen.Tests {
timer.StartTask("Generate Source");
gen.Configure(project, workDir, fileName,
AssemblerVersionCache.GetVersion(asmId), settings);
- List genPathNames = gen.GenerateSource(mWorker);
+ GenerationResults genResults = gen.GenerateSource(mWorker);
timer.EndTask("Generate Source");
if (mWorker.CancellationPending) {
// The generator will stop early if a cancellation is requested. If we
@@ -280,7 +280,7 @@ namespace SourceGen.Tests {
ReportProgress(" verify...");
timer.StartTask("Compare Source to Expected");
- bool match = CompareGeneratedToExpected(pathName, genPathNames);
+ bool match = CompareGeneratedToExpected(pathName, genResults.PathNames);
timer.EndTask("Compare Source to Expected");
if (match) {
ReportSuccess();
@@ -304,7 +304,7 @@ namespace SourceGen.Tests {
}
timer.StartTask("Assemble Source");
- asm.Configure(genPathNames, workDir);
+ asm.Configure(genResults, workDir);
AssemblerResults asmResults = asm.RunAssembler(mWorker);
timer.EndTask("Assemble Source");
if (asmResults == null) {