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)
This commit is contained in:
Andy McFadden 2020-10-17 16:10:48 -07:00
parent ae4c90d838
commit 99cd0d3ac1
27 changed files with 1296 additions and 405 deletions

View File

@ -38,6 +38,19 @@ namespace CommonUtil {
return Enumerable.SequenceEqual<string>(l1, l2, comparer);
}
/// <summary>
/// Makes a deep copy of a string list.
/// </summary>
/// <param name="src">String list to copy.</param>
/// <returns>New string list.</returns>
public static List<string> CopyStringList(IList<string> src) {
List<string> dst = new List<string>(src.Count);
foreach (string str in src) {
dst.Add(str);
}
return dst;
}
/// <summary>
/// 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

View File

@ -54,6 +54,9 @@ namespace SourceGen.AsmGen {
// IGenerator
public LabelLocalizer Localizer { get { return mLocalizer; } }
// IGenerator
public int StartOffset { get { return 0; } }
/// <summary>
/// Working directory, i.e. where we write our output file(s).
/// </summary>
@ -207,7 +210,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
public List<string> GenerateSource(BackgroundWorker worker) {
public GenerationResults GenerateSource(BackgroundWorker worker) {
List<string> pathNames = new List<string>(1);
string fileName = mFileNameBase + ASM_FILE_SUFFIX;
@ -256,7 +259,7 @@ namespace SourceGen.AsmGen {
}
mOutStream = null;
return pathNames;
return new GenerationResults(pathNames, string.Empty);
}
/// <summary>
@ -741,13 +744,9 @@ namespace SourceGen.AsmGen {
}
// IAssembler
public void Configure(List<string> pathNames, string workDirectory) {
public void Configure(GenerationResults results, string workDirectory) {
// Clone pathNames, in case the caller decides to modify the original.
mPathNames = new List<string>(pathNames.Count);
foreach (string str in pathNames) {
mPathNames.Add(str);
}
mPathNames = CommonUtil.Container.CopyStringList(results.PathNames);
mWorkDirectory = workDirectory;
}

View File

@ -48,6 +48,9 @@ namespace SourceGen.AsmGen {
// IGenerator
public LabelLocalizer Localizer { get { return mLocalizer; } }
// IGenerator
public int StartOffset { get { return 0; } }
/// <summary>
/// Working directory, i.e. where we write our output file(s).
/// </summary>
@ -202,7 +205,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
public List<string> GenerateSource(BackgroundWorker worker) {
public GenerationResults GenerateSource(BackgroundWorker worker) {
List<string> pathNames = new List<string>(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<string> pathNames, string workDirectory) {
public void Configure(GenerationResults results, string workDirectory) {
// Clone pathNames, in case the caller decides to modify the original.
mPathNames = new List<string>(pathNames.Count);
foreach (string str in pathNames) {
mPathNames.Add(str);
}
mPathNames = CommonUtil.Container.CopyStringList(results.PathNames);
mWorkDirectory = workDirectory;
}

View File

@ -48,6 +48,9 @@ namespace SourceGen.AsmGen {
// IGenerator
public LabelLocalizer Localizer { get { return mLocalizer; } }
// IGenerator
public int StartOffset { get { return 0; } }
/// <summary>
/// Working directory, i.e. where we write our output file(s).
/// </summary>
@ -176,7 +179,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator; executes on background thread
public List<string> GenerateSource(BackgroundWorker worker) {
public GenerationResults GenerateSource(BackgroundWorker worker) {
List<string> pathNames = new List<string>(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<string> pathNames, string workDirectory) {
public void Configure(GenerationResults results, string workDirectory) {
// Clone pathNames, in case the caller decides to modify the original.
mPathNames = new List<string>(pathNames.Count);
foreach (string str in pathNames) {
mPathNames.Add(str);
}
mPathNames = CommonUtil.Container.CopyStringList(results.PathNames);
mWorkDirectory = workDirectory;
}

View File

@ -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;
}
}
/// <summary>
/// Working directory, i.e. where we write our output file(s).
@ -81,16 +87,16 @@ namespace SourceGen.AsmGen {
/// </summary>
private string mFileNameBase;
/// <summary>
/// True if the first two bytes look like the header of a PRG file.
/// </summary>
private bool mHasPrgHeader;
/// <summary>
/// StringBuilder to use when composing a line. Held here to reduce allocations.
/// </summary>
private StringBuilder mLineBuilder = new StringBuilder(100);
/// <summary>
/// Label localization helper.
/// </summary>
private LabelLocalizer mLocalizer;
/// <summary>
/// Stream to send the output to.
/// </summary>
@ -176,6 +182,8 @@ namespace SourceGen.AsmGen {
AssemblerConfig config = AssemblerConfig.GetConfig(settings,
AssemblerInfo.Id.Tass64);
mColumnWidths = (int[])config.ColumnWidths.Clone();
mHasPrgHeader = HasPrgHeader(project);
}
/// <summary>
@ -207,7 +215,7 @@ namespace SourceGen.AsmGen {
}
// IGenerator
public List<string> GenerateSource(BackgroundWorker worker) {
public GenerationResults GenerateSource(BackgroundWorker worker) {
List<string> pathNames = new List<string>(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 <addr> 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<string> 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<string> pathNames, string workDirectory) {
// Clone pathNames, in case the caller decides to modify the original.
mPathNames = new List<string>(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();

View File

@ -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);

View File

@ -44,12 +44,12 @@ namespace SourceGen.AsmGen {
AssemblerVersion QueryVersion();
/// <summary>
/// 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.
/// </summary>
/// <param name="pathNames">Assembler source pathnames.</param>
/// <param name="pathNames">Source generation results.</param>
/// <param name="workDirectory">Working directory for shell command.</param>
void Configure(List<string> pathNames, string workDirectory);
void Configure(GenerationResults results, string workDirectory);
/// <summary>
/// Executes the assembler. Must call Configure() first. Executed on background thread.

View File

@ -77,13 +77,19 @@ namespace SourceGen.AsmGen {
/// </summary>
LabelLocalizer Localizer { get; }
/// <summary>
/// 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).
/// </summary>
int StartOffset { get; }
/// <summary>
/// Generates source files on a background thread. Method must not make any UI calls.
/// </summary>
/// <param name="worker">Async work object, used to report progress updates and
/// check for cancellation.</param>
/// <returns>List of pathnames of generated files.</returns>
List<string> GenerateSource(BackgroundWorker worker);
/// <returns>Object with list of pathnames of generated files.</returns>
GenerationResults GenerateSource(BackgroundWorker worker);
/// <summary>
/// Provides an opportunity for the assembler to replace a mnemonic with another, or
@ -262,4 +268,17 @@ namespace SourceGen.AsmGen {
/// </summary>
public bool TracksSepRepNotEmu { get; set; }
}
/// <summary>
/// Holds metadata generated by the assembly source generator.
/// </summary>
public class GenerationResults {
public List<string> PathNames { get; private set; }
public string ExtraOptions { get; private set; }
public GenerationResults(List<string> pathNames, string extraOptions) {
PathNames = CommonUtil.Container.CopyStringList(pathNames);
ExtraOptions = extraOptions;
}
}
}

View File

@ -82,7 +82,7 @@ namespace SourceGen.AsmGen.WpfGui {
/// <summary>
/// Results from last source generation.
/// </summary>
private List<string> mGenerationResults;
private GenerationResults mGenerationResults;
/// <summary>
/// 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<string> 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<string>)results;
Results = (GenerationResults)results;
}
}
@ -279,17 +279,16 @@ namespace SourceGen.AsmGen.WpfGui {
dlg.ShowDialog();
//Debug.WriteLine("Dialog returned: " + dlg.DialogResult);
List<string> 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

View File

@ -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.</p>
<p>The localizer is somewhat experimental at this time, and can be
disabled from the
<a href="settings.html#app-settings">application settings</a>.</p>
<h3><a name="reserved-labels">Reserved Label Names</a></h3>
@ -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 <code>jmp jmp jmp</code>).</p>
<p>If a label doesn't appear to be legal, the generated code will have
<p>If a label doesn't appear to be legal, the generated code will use
a suitable replacement (e.g. <code>jmp_1 jmp jmp_1</code>).</p>
<h3><a name="platform-features">Platform-Specific Features</a></h3>
<p>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.</p>
<p>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.</p>
<p>A file is treated as a PRG if:</p>
<ul>
<li>it is between 3 and 65536 bytes long (inclusive)</li>
<li>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.)</li>
<li>the 16-bit value at +000000 is equal to the address of the
byte at +000002</li>
<li>there is no label at offset +000000 (explicit or auto-generated)</li>
</ul>
<p>If a file is being treated as PRG and you'd rather it wasn't, you
can add a label or reformat the bytes.</p>
<h2><a name="assemble">Cross-Assembling Generated Code</a></h2>
<p>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.</p>
there's no way to do that, so instead we occasionally generate
additional width directives.</li>
<li>Non-unique local labels should cause an error, but don't.</li>
<li>No undocumented opcodes are supported.</li>
<li>No undocumented opcodes are supported, nor are the Rockwell
65C02 instructions.</li>
</ul>

View File

@ -106,6 +106,8 @@ and 65816 code. The official web site is
<li><a href="codegen.html#generate">Generating Source Code</a>
<ul>
<li><a href="codegen.html#localizer">Label Localizer</a></li>
<li><a href="codegen.html#reserved-labels">Reserved Label Names</a></li>
<li><a href="codegen.html#platform-features">Platform-Specific Features</a></li>
</ul></li>
<li><a href="codegen.html#assemble">Cross-Assembling Generated Code</a></li>
<li><a href="codegen.html#quirks">Assembler-Specific Bugs &amp; Quirks</a>

Binary file not shown.

View File

@ -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":{
}}

View File

@ -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":{
}}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -2,6 +2,7 @@
; See the LICENSE.txt file for distribution terms (Apache 2.0).
;
; Assembler: Merlin 32
; 65816 version
org $1000
clc

View File

@ -269,7 +269,7 @@ namespace SourceGen.Tests {
timer.StartTask("Generate Source");
gen.Configure(project, workDir, fileName,
AssemblerVersionCache.GetVersion(asmId), settings);
List<string> 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) {