1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-12-28 16:31:17 +00:00

Correct handling of no-op .ORG statements

These were being overlooked because they didn't actually cause
anything to happen (a no-op .ORG sets the address to what it would
already have been).  The assembly source generator works in a way
that causes them to be skipped, so everybody was happy.

This seemed like the sort of thing that was likely to cause problems
down the road, however, so we now split regions correctly when a
no-op .ORG is encountered.  This affects the uncategorized data
analyzer and selection grouping.

This changed the behavior of the 2004-numeric-types test, which was
visibly weird in the UI but generated correct output.

Added the 2024-ui-edge-cases test to provide a place to exercise
edge cases when testing the UI by hand.  It has some value for the
automated regression test, so it's included there.

Also, changed the AddressMapEntry objects to be immutable.  This
is handy when passing lists of them around.
This commit is contained in:
Andy McFadden 2020-02-28 14:43:03 -08:00
parent 07d477fc70
commit 0bbb307d4e
18 changed files with 472 additions and 97 deletions

View File

@ -24,13 +24,13 @@ namespace CommonUtil {
/// multiple ORG directives. /// multiple ORG directives.
/// ///
/// It's possible to generate code that would overlap once relocated at run time, /// It's possible to generate code that would overlap once relocated at run time,
/// which means a given address could map to multiple offsets. For this reason /// which means a given address can map to multiple offsets (overlays, bank-switched
/// it's useful to know the offset of the referring code when evaluating a /// RAM, etc). For this reason it's useful to know the offset of the referring code
/// reference, so that a "local" match can take priority. /// when evaluating a reference, so that "local" matches take priority.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This was part of the main SourceGen application, but I want to share it with /// This was part of the main SourceGen application, but I want to share it with
/// script extensions. /// the extension script mechanism.
/// </remarks> /// </remarks>
public class AddressMap : IEnumerable<AddressMap.AddressMapEntry> { public class AddressMap : IEnumerable<AddressMap.AddressMapEntry> {
public const int NO_ENTRY_ADDR = -1; // address value indicating no entry public const int NO_ENTRY_ADDR = -1; // address value indicating no entry
@ -44,31 +44,19 @@ namespace CommonUtil {
/// entry in the list. It's convenient to maintain it explicitly however, as /// entry in the list. It's convenient to maintain it explicitly however, as
/// the list is read far more often than it is updated. /// the list is read far more often than it is updated.
/// ///
/// Entries are mutable, but must only be altered by AddressMap. Don't retain /// Instances are immutable.
/// instances of this across other activity.
/// </summary> /// </summary>
/// <remarks>
/// TODO: make this immutable. That should allow us to eliminate the copy constructor,
/// since we won't need to make copies of things.
/// </remarks>
[Serializable] [Serializable]
public class AddressMapEntry { public class AddressMapEntry {
public int Offset { get; set; } public int Offset { get; private set; }
public int Addr { get; set; } public int Addr { get; private set; }
public int Length { get; set; } public int Length { get; private set; }
public AddressMapEntry(int offset, int addr, int len) { public AddressMapEntry(int offset, int addr, int len) {
Offset = offset; Offset = offset;
Addr = addr; Addr = addr;
Length = len; Length = len;
} }
// Copy constructor.
public AddressMapEntry(AddressMapEntry src) {
Offset = src.Offset;
Addr = src.Addr;
Length = src.Length;
}
} }
/// <summary> /// <summary>
@ -99,7 +87,7 @@ namespace CommonUtil {
public AddressMap(List<AddressMapEntry> entries) { public AddressMap(List<AddressMapEntry> entries) {
mTotalLength = entries[entries.Count - 1].Offset + entries[entries.Count - 1].Length; mTotalLength = entries[entries.Count - 1].Offset + entries[entries.Count - 1].Length;
foreach (AddressMapEntry ent in entries) { foreach (AddressMapEntry ent in entries) {
mAddrList.Add(new AddressMapEntry(ent)); mAddrList.Add(ent);
} }
DebugValidate(); DebugValidate();
} }
@ -111,7 +99,7 @@ namespace CommonUtil {
public List<AddressMapEntry> GetEntryList() { public List<AddressMapEntry> GetEntryList() {
List<AddressMapEntry> newList = new List<AddressMapEntry>(mAddrList.Count); List<AddressMapEntry> newList = new List<AddressMapEntry>(mAddrList.Count);
foreach (AddressMapEntry ent in mAddrList) { foreach (AddressMapEntry ent in mAddrList) {
newList.Add(new AddressMapEntry(ent)); newList.Add(ent);
} }
return newList; return newList;
} }
@ -186,8 +174,7 @@ namespace CommonUtil {
AddressMapEntry ad = mAddrList[i]; AddressMapEntry ad = mAddrList[i];
if (ad.Offset == offset) { if (ad.Offset == offset) {
// update existing // update existing
ad.Addr = addr; mAddrList[i] = new AddressMapEntry(ad.Offset, addr, ad.Length);
mAddrList[i] = ad;
return; return;
} else if (ad.Offset > offset) { } else if (ad.Offset > offset) {
// The i'th entry is one past the interesting part. // The i'th entry is one past the interesting part.
@ -199,8 +186,7 @@ namespace CommonUtil {
AddressMapEntry prev = mAddrList[i - 1]; AddressMapEntry prev = mAddrList[i - 1];
int prevOldLen = prev.Length; int prevOldLen = prev.Length;
int prevNewLen = offset - prev.Offset; int prevNewLen = offset - prev.Offset;
prev.Length = prevNewLen; mAddrList[i - 1] = new AddressMapEntry(prev.Offset, prev.Addr, prevNewLen);
mAddrList[i - 1] = prev;
mAddrList.Insert(i, mAddrList.Insert(i,
new AddressMapEntry(offset, addr, prevOldLen - prevNewLen)); new AddressMapEntry(offset, addr, prevOldLen - prevNewLen));
@ -223,8 +209,8 @@ namespace CommonUtil {
if (mAddrList[i].Offset == offset) { if (mAddrList[i].Offset == offset) {
// Add the length to the previous entry. // Add the length to the previous entry.
AddressMapEntry prev = mAddrList[i - 1]; AddressMapEntry prev = mAddrList[i - 1];
prev.Length += mAddrList[i].Length; mAddrList[i - 1] = new AddressMapEntry(prev.Offset, prev.Addr,
mAddrList[i - 1] = prev; prev.Length + mAddrList[i].Length);
mAddrList.RemoveAt(i); mAddrList.RemoveAt(i);
DebugValidate(); DebugValidate();
@ -297,13 +283,14 @@ namespace CommonUtil {
} }
/// <summary> /// <summary>
/// Checks to see if the specified range of offsets is in a contiguous range of /// Checks to see if the specified range of offsets is in a single address range. Use
/// addresses. Use this to see if something crosses an address-change boundary. /// this to see if something crosses an address-change boundary. This does not
/// handle no-op address changes specially.
/// </summary> /// </summary>
/// <param name="offset">Start offset.</param> /// <param name="offset">Start offset.</param>
/// <param name="length">Length of region.</param> /// <param name="length">Length of region.</param>
/// <returns>True if the data area is unbroken.</returns> /// <returns>True if the data area is unbroken.</returns>
public bool IsContiguous(int offset, int length) { public bool IsSingleAddrRange(int offset, int length) {
Debug.Assert(offset >= 0 && offset < mTotalLength); Debug.Assert(offset >= 0 && offset < mTotalLength);
Debug.Assert(length > 0 && offset + length <= mTotalLength); Debug.Assert(length > 0 && offset + length <= mTotalLength);
return (IndexForOffset(offset) == IndexForOffset(offset + length - 1)); return (IndexForOffset(offset) == IndexForOffset(offset + length - 1));

View File

@ -1044,7 +1044,7 @@ namespace SourceGen {
" label='" + label + "'; file length is" + mFileData.Length); " label='" + label + "'; file length is" + mFileData.Length);
} }
if (!mAddrMap.IsContiguous(offset, length)) { if (!mAddrMap.IsSingleAddrRange(offset, length)) {
LogW(offset, "SIDF: format crosses address map boundary (len=" + length + ")"); LogW(offset, "SIDF: format crosses address map boundary (len=" + length + ")");
return false; return false;
} }

View File

@ -533,8 +533,8 @@ namespace SourceGen {
int startOffset = -1; int startOffset = -1;
for (int offset = 0; offset < mAnattribs.Length; ) { for (int offset = 0; offset < mAnattribs.Length; ) {
// We want to find a contiguous series of offsets which are not known // We want to find a contiguous series of offsets which are not known
// to hold code or data. We stop if we encounter a user-defined label // to hold code or data. We stop if we encounter a user-defined label,
// or format descriptor. // format descriptor, or address override.
Anattrib attr = mAnattribs[offset]; Anattrib attr = mAnattribs[offset];
if (attr.IsInstruction || attr.IsInlineData || attr.IsDataStart) { if (attr.IsInstruction || attr.IsInlineData || attr.IsDataStart) {
@ -572,19 +572,17 @@ namespace SourceGen {
} }
offset++; offset++;
// Check to see if the address has changed from the previous entry. // Check to see if we just crossed an address change.
// TODO(BUG): this test is insufficient -- they might have a .ORG that
// doesn't change the address. It's currently harmless because the
// .ORG is a no-op and gets swallowed up by the asm generator, but it
// looks wrong and could break things.
if (offset < mAnattribs.Length && if (offset < mAnattribs.Length &&
mAnattribs[offset-1].Address + 1 != mAnattribs[offset].Address) { !mProject.AddrMap.IsSingleAddrRange(offset - 1, 2)) {
// Must be an ORG here. Scan previous region. // Must be an ORG here. End region and scan.
AnalyzeRange(startOffset, offset - 1); AnalyzeRange(startOffset, offset - 1);
startOffset = -1; startOffset = -1;
} }
} }
} }
// Do the last bit.
if (startOffset >= 0) { if (startOffset >= 0) {
AnalyzeRange(startOffset, mAnattribs.Length - 1); AnalyzeRange(startOffset, mAnattribs.Length - 1);
} }

View File

@ -969,7 +969,7 @@ namespace SourceGen {
continue; continue;
} }
if (!AddrMap.IsContiguous(offset, dfd.Length)) { if (!AddrMap.IsSingleAddrRange(offset, dfd.Length)) {
string msg = "descriptor straddles address change; len=" + dfd.Length; string msg = "descriptor straddles address change; len=" + dfd.Length;
genLog.LogE("+" + offset.ToString("x6") + ": " + msg); genLog.LogE("+" + offset.ToString("x6") + ": " + msg);
Messages.Add(new MessageList.MessageEntry( Messages.Add(new MessageList.MessageEntry(

View File

@ -2479,7 +2479,7 @@ namespace SourceGen {
// This must match what GroupedOffsetSetFromSelected() does. // This must match what GroupedOffsetSetFromSelected() does.
if (!mProject.UserLabels.ContainsKey(nextOffset) && if (!mProject.UserLabels.ContainsKey(nextOffset) &&
!mProject.HasCommentNoteOrVis(nextOffset) && !mProject.HasCommentNoteOrVis(nextOffset) &&
thisAttr.Address == nextAttr.Address - 1) { mProject.AddrMap.IsSingleAddrRange(nextOffset - 1, 2)) {
// Good to go. // Good to go.
Debug.WriteLine("Grabbing second byte from +" + nextOffset.ToString("x6")); Debug.WriteLine("Grabbing second byte from +" + nextOffset.ToString("x6"));
trs.Add(nextOffset, rng.Type); trs.Add(nextOffset, rng.Type);
@ -3362,6 +3362,9 @@ namespace SourceGen {
/// or a string. It should not be possible to select part of a formatted section, /// or a string. It should not be possible to select part of a formatted section,
/// unless the user has been playing weird games with type hints to get overlapping /// unless the user has been playing weird games with type hints to get overlapping
/// format descriptors. /// format descriptors.
///
/// The type values used in the TypedRangeSet may not be contiguous. They're only
/// there to create group separation from otherwise contiguous address ranges.
/// </remarks> /// </remarks>
/// <returns>TypedRangeSet with all offsets.</returns> /// <returns>TypedRangeSet with all offsets.</returns>
private TypedRangeSet GroupedOffsetSetFromSelected() { private TypedRangeSet GroupedOffsetSetFromSelected() {
@ -3394,12 +3397,18 @@ namespace SourceGen {
if (attr.Address != expectedAddr) { if (attr.Address != expectedAddr) {
// For a contiguous selection, this should only happen if there's a .ORG // For a contiguous selection, this should only happen if there's a .ORG
// address change. For non-contiguous selection this is expected. In the // address change. For non-contiguous selection this is expected. In the
// latter case, incrementing the group number is unnecessary but harmless. // latter case, incrementing the group number is unnecessary but harmless
Debug.WriteLine("Address break: " + attr.Address + " vs. " + expectedAddr); // (the TypedRangeSet splits at the gap).
//Debug.Assert(mProject.AddrMap.Get(offset) >= 0); //Debug.WriteLine("Address break: $" + attr.Address.ToString("x4") + " vs. $"
// + expectedAddr.ToString("x4"));
expectedAddr = attr.Address; expectedAddr = attr.Address;
groupNum++; groupNum++;
} else if (offset > 0 && !mProject.AddrMap.IsSingleAddrRange(offset - 1, 2)) {
// Was the previous byte in a different address range? This is only
// strictly necessary if the previous byte was in the selection set (which
// it won't be if the selection starts at the beginning of an address
// range), but bumping the group number is harmless if it wasn't.
groupNum++;
} else if (mProject.UserLabels.ContainsKey(offset)) { } else if (mProject.UserLabels.ContainsKey(offset)) {
//if (mProject.GetAnattrib(offset).Symbol != null) { //if (mProject.GetAnattrib(offset).Symbol != null) {
// We consider auto labels when splitting regions for the data analysis, // We consider auto labels when splitting regions for the data analysis,

View File

@ -1,89 +1,248 @@
### 6502bench SourceGen dis65 v1.0 ### ### 6502bench SourceGen dis65 v1.0 ###
{ {
"_ContentVersion":3,"FileDataLength":1200,"FileDataCrc32":1114187983,"ProjectProps":{ "_ContentVersion":3,
"CpuName":"6502","IncludeUndocumentedInstr":false,"TwoByteBrk":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{ "FileDataLength":1200,
"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":true}, "FileDataCrc32":1114187983,
"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":["PROJ:2004-numeric-types.cs"],"ProjectSyms":{ "ProjectProps":{
"CpuName":"6502",
"IncludeUndocumentedInstr":false,
"TwoByteBrk":false,
"EntryFlags":32702671,
"AutoLabelStyle":"Simple",
"AnalysisParams":{
"AnalyzeUncategorizedData":true,
"DefaultTextScanMode":"LowHighAscii",
"MinCharsForString":4,
"SeekNearbyTargets":true,
"SmartPlpHandling":true},
"PlatformSymbolFileIdentifiers":[],
"ExtensionScriptFileIdentifiers":["PROJ:2004-numeric-types.cs"],
"ProjectSyms":{
}}, }},
"AddressMap":[{ "AddressMap":[{
"Offset":0,"Addr":4096}, "Offset":0,
"Addr":4096},
{ {
"Offset":1032,"Addr":5128}, "Offset":1032,
"Addr":5128},
{ {
"Offset":1048,"Addr":5160}],"TypeHints":[{ "Offset":1048,
"Low":0,"High":0,"Hint":"Code"}],"StatusFlagOverrides":{ "Addr":5160}],
"TypeHints":[{
"Low":0,
"High":0,
"Hint":"Code"}],
"StatusFlagOverrides":{
}, },
"Comments":{ "Comments":{
"588":"comment on bulk","882":"incorrect alignment","1128":"end-of-line comment"}, "588":"comment on bulk",
"882":"incorrect alignment",
"1032":"note no-op .ORG",
"1048":"meaningful .ORG",
"1128":"end-of-line comment"},
"LongComments":{ "LongComments":{
"-2147483647":{ "-2147483647":{
"Text":"Project file was edited to get all big-endian data types, and to have an incorrect .junk alignment directive.","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}, "Text":"Project file was edited to get all big-endian data types, and to have an incorrect .junk alignment directive.",
"BoxMode":false,
"MaxWidth":80,
"BackgroundColor":0},
"1112":{ "1112":{
"Text":"long comment\r\n","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}}, "Text":"long comment\r\n",
"BoxMode":false,
"MaxWidth":80,
"BackgroundColor":0}},
"Notes":{ "Notes":{
"1144":{ "1144":{
"Text":":ETON","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}}, "Text":":ETON",
"BoxMode":false,
"MaxWidth":80,
"BackgroundColor":0}},
"UserLabels":{ "UserLabels":{
"588":{ "588":{
"Label":"LABEL","Value":4684,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"}, "Label":"LABEL",
"Value":4684,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1064":{ "1064":{
"Label":"UserLabel","Value":5176,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"}}, "Label":"UserLabel",
"Value":5176,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"}},
"OperandFormats":{ "OperandFormats":{
"23":{ "23":{
"Length":1,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}, "Length":1,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"24":{ "24":{
"Length":2,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}, "Length":2,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"26":{ "26":{
"Length":3,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}, "Length":3,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"29":{ "29":{
"Length":4,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}, "Length":4,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"33":{ "33":{
"Length":1,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null}, "Length":1,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"34":{ "34":{
"Length":2,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null}, "Length":2,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"36":{ "36":{
"Length":3,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null}, "Length":3,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"39":{ "39":{
"Length":4,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null}, "Length":4,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"43":{ "43":{
"Length":2,"Format":"Fill","SubFormat":"None","SymbolRef":null}, "Length":2,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"46":{ "46":{
"Length":3,"Format":"Fill","SubFormat":"None","SymbolRef":null}, "Length":3,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"50":{ "50":{
"Length":4,"Format":"Fill","SubFormat":"None","SymbolRef":null}, "Length":4,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"55":{ "55":{
"Length":5,"Format":"Fill","SubFormat":"None","SymbolRef":null}, "Length":5,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"61":{ "61":{
"Length":256,"Format":"Fill","SubFormat":"None","SymbolRef":null}, "Length":256,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"318":{ "318":{
"Length":257,"Format":"Fill","SubFormat":"None","SymbolRef":null}, "Length":257,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"575":{ "575":{
"Length":1,"Format":"Dense","SubFormat":"None","SymbolRef":null}, "Length":1,
"Format":"Dense",
"SubFormat":"None",
"SymbolRef":null},
"577":{ "577":{
"Length":10,"Format":"Dense","SubFormat":"None","SymbolRef":null}, "Length":10,
"Format":"Dense",
"SubFormat":"None",
"SymbolRef":null},
"588":{ "588":{
"Length":64,"Format":"Dense","SubFormat":"None","SymbolRef":null}, "Length":64,
"Format":"Dense",
"SubFormat":"None",
"SymbolRef":null},
"653":{ "653":{
"Length":115,"Format":"Junk","SubFormat":"Align256","SymbolRef":null}, "Length":115,
"Format":"Junk",
"SubFormat":"Align256",
"SymbolRef":null},
"769":{ "769":{
"Length":63,"Format":"Junk","SubFormat":"Align64","SymbolRef":null}, "Length":63,
"Format":"Junk",
"SubFormat":"Align64",
"SymbolRef":null},
"833":{ "833":{
"Length":31,"Format":"Junk","SubFormat":"Align32","SymbolRef":null}, "Length":31,
"Format":"Junk",
"SubFormat":"Align32",
"SymbolRef":null},
"864":{ "864":{
"Length":8,"Format":"Junk","SubFormat":"None","SymbolRef":null}, "Length":8,
"Format":"Junk",
"SubFormat":"None",
"SymbolRef":null},
"873":{ "873":{
"Length":8,"Format":"Junk","SubFormat":"None","SymbolRef":null}, "Length":8,
"Format":"Junk",
"SubFormat":"None",
"SymbolRef":null},
"882":{ "882":{
"Length":2,"Format":"Junk","SubFormat":"Align128","SymbolRef":null}, "Length":2,
"Format":"Junk",
"SubFormat":"Align128",
"SymbolRef":null},
"884":{ "884":{
"Length":140,"Format":"Junk","SubFormat":"Align256","SymbolRef":null}, "Length":140,
"Format":"Junk",
"SubFormat":"Align256",
"SymbolRef":null},
"1192":{ "1192":{
"Length":1,"Format":"NumericLE","SubFormat":"Binary","SymbolRef":null}}, "Length":1,
"Format":"NumericLE",
"SubFormat":"Binary",
"SymbolRef":null}},
"LvTables":{ "LvTables":{
"1096":{ "1096":{
"Variables":[],"ClearPrevious":true}}, "Variables":[],
"ClearPrevious":true}},
"Visualizations":[{ "Visualizations":[{
"Tag":"vis000488","VisGenIdent":"dummy","VisGenParams":{ "Tag":"vis000488",
}}],"VisualizationAnimations":[],"VisualizationSets":{ "VisGenIdent":"dummy",
"VisGenParams":{
}}],
"VisualizationAnimations":[],
"VisualizationSets":{
"1160":{ "1160":{
"Tags":["vis000488"]}}} "Tags":["vis000488"]}}}

Binary file not shown.

View File

@ -0,0 +1,71 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":3,
"FileDataLength":50,
"FileDataCrc32":-1443914879,
"ProjectProps":{
"CpuName":"6502",
"IncludeUndocumentedInstr":false,
"TwoByteBrk":false,
"EntryFlags":32702671,
"AutoLabelStyle":"Simple",
"AnalysisParams":{
"AnalyzeUncategorizedData":true,
"DefaultTextScanMode":"LowHighAscii",
"MinCharsForString":4,
"SeekNearbyTargets":true,
"SmartPlpHandling":true},
"PlatformSymbolFileIdentifiers":["RT:Apple/F8-ROM.sym65",
"RT:Apple/Cxxx-IO.sym65",
"RT:Apple/DOS33.sym65"],
"ExtensionScriptFileIdentifiers":["RT:Apple/VisHiRes.cs"],
"ProjectSyms":{
}},
"AddressMap":[{
"Offset":0,
"Addr":8192},
{
"Offset":10,
"Addr":8202},
{
"Offset":16,
"Addr":8448}],
"TypeHints":[{
"Low":0,
"High":0,
"Hint":"Code"}],
"StatusFlagOverrides":{
},
"Comments":{
"3":"string should be split by no-op addr change",
"18":"edit this operand"},
"LongComments":{
},
"Notes":{
},
"UserLabels":{
"44":{
"Label":"addr1",
"Value":8476,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"}},
"OperandFormats":{
},
"LvTables":{
},
"Visualizations":[],
"VisualizationAnimations":[],
"VisualizationSets":{
}}

View File

@ -63,10 +63,13 @@ LABEL .byte $00,$11,$22,$33,$44,$55,$66,$77,$88,$99,$aa,$bb,$cc,$dd,$ee,$ff
.byte $81 .byte $81
.fill 2,$dd ;incorrect alignment .fill 2,$dd ;incorrect alignment
.align 256,$00 .align 256,$00
.fill 16,$82 .fill 8,$82
.logical $1408
.fill 8,$82 ;note no-op .ORG
.fill 8,$83 .fill 8,$83
.here
.logical $1428 .logical $1428
.fill 8,$83 .fill 8,$83 ;meaningful .ORG
.fill 8,$84 .fill 8,$84
UserLabel .fill 8,$84 UserLabel .fill 8,$84
.fill 8,$85 .fill 8,$85

View File

@ -58,10 +58,12 @@ LABEL hex 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
dfb $81 dfb $81
ds 2,$dd ;incorrect alignment ds 2,$dd ;incorrect alignment
ds \ ds \
ds 16,$82 ds 8,$82
org $1408
ds 8,$82 ;note no-op .ORG
ds 8,$83 ds 8,$83
org $1428 org $1428
ds 8,$83 ds 8,$83 ;meaningful .ORG
ds 8,$84 ds 8,$84
UserLabel ds 8,$84 UserLabel ds 8,$84
ds 8,$85 ds 8,$85

View File

@ -59,10 +59,13 @@ LABEL !hex 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
!byte $81 !byte $81
!fill 2,$dd ;incorrect alignment !fill 2,$dd ;incorrect alignment
!align 255,0,$00 !align 255,0,$00
!fill 16,$82 !fill 8,$82
!pseudopc $1408 {
!fill 8,$82 ;note no-op .ORG
!fill 8,$83 !fill 8,$83
} ;!pseudopc
!pseudopc $1428 { !pseudopc $1428 {
!fill 8,$83 !fill 8,$83 ;meaningful .ORG
!fill 8,$84 !fill 8,$84
UserLabel !fill 8,$84 UserLabel !fill 8,$84
!fill 8,$85 !fill 8,$85

View File

@ -62,11 +62,14 @@ LABEL: .byte $00,$11,$22,$33,$44,$55,$66,$77,$88,$99,$aa,$bb,$cc,$dd,$ee,$ff
.byte $81 .byte $81
.res 2,$dd ;incorrect alignment .res 2,$dd ;incorrect alignment
.res 140,$00 .res 140,$00
.res 16,$82 .res 8,$82
; .segment "SEG001"
.org $1408
.res 8,$82 ;note no-op .ORG
.res 8,$83 .res 8,$83
; .segment "SEG002" ; .segment "SEG002"
.org $1428 .org $1428
.res 8,$83 .res 8,$83 ;meaningful .ORG
.res 8,$84 .res 8,$84
UserLabel: .res 8,$84 UserLabel: .res 8,$84
.res 8,$85 .res 8,$85

View File

@ -0,0 +1,25 @@
.cpu "6502"
.enc sg_ascii
.cdef $20,$7e,$20
* = $2000
jmp L2100
.text "hello, " ;string should be split by no-op addr change
.logical $200a
.text "world"
.byte $80
.here
.logical $2100
L2100 lda #$00
sta addr1-1 ;edit this operand
sta addr1
sta addr1+1
jmp L2121
.text "testing stuff."
addr1 .text "!?---"
L2121 rts
.here

View File

@ -0,0 +1,20 @@
org $2000
jmp L2100
asc 'hello, ' ;string should be split by no-op addr change
org $200a
asc 'world'
dfb $80
org $2100
L2100 lda #$00
sta addr1-1 ;edit this operand
sta addr1
sta addr1+1
jmp L2121
asc 'testing stuff.'
addr1 asc '!?---'
L2121 rts

View File

@ -0,0 +1,23 @@
!cpu 6502
* = $2000
jmp L2100
!text "hello, " ;string should be split by no-op addr change
!pseudopc $200a {
!text "world"
!byte $80
} ;!pseudopc
!pseudopc $2100 {
L2100 lda #$00
sta addr1-1 ;edit this operand
sta addr1
sta addr1+1
jmp L2121
!text "testing stuff."
addr1 !text "!?---"
L2121 rts
} ;!pseudopc

View File

@ -0,0 +1,24 @@
.setcpu "6502"
; .segment "SEG000"
.org $2000
jmp L2100
.byte "hello, " ;string should be split by no-op addr change
; .segment "SEG001"
.org $200a
.byte "world"
.byte $80
; .segment "SEG002"
.org $2100
L2100: lda #$00
sta addr1-1 ;edit this operand
sta addr1
sta addr1+1
jmp L2121
.byte "testing stuff."
addr1: .byte "!?---"
L2121: rts

View File

@ -0,0 +1,15 @@
# 6502bench SourceGen generated linker script for 2024-ui-edge-cases
MEMORY {
MAIN: file=%O, start=%S, size=65536;
# MEM000: file=%O, start=$2000, size=10;
# MEM001: file=%O, start=$200a, size=6;
# MEM002: file=%O, start=$2100, size=34;
}
SEGMENTS {
CODE: load=MAIN, type=rw;
# SEG000: load=MEM000, type=rw;
# SEG001: load=MEM001, type=rw;
# SEG002: load=MEM002, type=rw;
}
FEATURES {}
SYMBOLS {}

View File

@ -0,0 +1,33 @@
; Copyright 2020 faddenSoft. All Rights Reserved.
; See the LICENSE.txt file for distribution terms (Apache 2.0).
;
; These tests are for exercising UI edge cases. They're not necessarily
; meaningful for the generate/assemble regression test.
;
; Assembler: Merlin 32
ORG $2000
jmp skip
asc 'hello, '
ORG $200a ;EDIT: add this no-op ORG statement
asc 'world' ;(string finder should split the string)
dfb $80
org $2100 ;EDIT: add this
skip
lda #$00
sta addr0 ;TEST: edit this operand ("addr1-1")
sta addr1
sta addr2
jmp done
L1 asc 'testing stuff'
addr0 asc '.'
addr1 asc '!' ;EDIT: place label here
addr2 asc '?'
asc '---'
done rts