1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-12-26 19:29: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.
///
/// 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
/// it's useful to know the offset of the referring code when evaluating a
/// reference, so that a "local" match can take priority.
/// which means a given address can map to multiple offsets (overlays, bank-switched
/// RAM, etc). For this reason it's useful to know the offset of the referring code
/// when evaluating a reference, so that "local" matches take priority.
/// </summary>
/// <remarks>
/// This was part of the main SourceGen application, but I want to share it with
/// script extensions.
/// the extension script mechanism.
/// </remarks>
public class AddressMap : IEnumerable<AddressMap.AddressMapEntry> {
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
/// 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 of this across other activity.
/// Instances are immutable.
/// </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]
public class AddressMapEntry {
public int Offset { get; set; }
public int Addr { get; set; }
public int Length { get; set; }
public int Offset { get; private set; }
public int Addr { get; private set; }
public int Length { get; private set; }
public AddressMapEntry(int offset, int addr, int len) {
Offset = offset;
Addr = addr;
Length = len;
}
// Copy constructor.
public AddressMapEntry(AddressMapEntry src) {
Offset = src.Offset;
Addr = src.Addr;
Length = src.Length;
}
}
/// <summary>
@ -99,7 +87,7 @@ namespace CommonUtil {
public AddressMap(List<AddressMapEntry> entries) {
mTotalLength = entries[entries.Count - 1].Offset + entries[entries.Count - 1].Length;
foreach (AddressMapEntry ent in entries) {
mAddrList.Add(new AddressMapEntry(ent));
mAddrList.Add(ent);
}
DebugValidate();
}
@ -111,7 +99,7 @@ namespace CommonUtil {
public List<AddressMapEntry> GetEntryList() {
List<AddressMapEntry> newList = new List<AddressMapEntry>(mAddrList.Count);
foreach (AddressMapEntry ent in mAddrList) {
newList.Add(new AddressMapEntry(ent));
newList.Add(ent);
}
return newList;
}
@ -186,8 +174,7 @@ namespace CommonUtil {
AddressMapEntry ad = mAddrList[i];
if (ad.Offset == offset) {
// update existing
ad.Addr = addr;
mAddrList[i] = ad;
mAddrList[i] = new AddressMapEntry(ad.Offset, addr, ad.Length);
return;
} else if (ad.Offset > offset) {
// The i'th entry is one past the interesting part.
@ -199,8 +186,7 @@ namespace CommonUtil {
AddressMapEntry prev = mAddrList[i - 1];
int prevOldLen = prev.Length;
int prevNewLen = offset - prev.Offset;
prev.Length = prevNewLen;
mAddrList[i - 1] = prev;
mAddrList[i - 1] = new AddressMapEntry(prev.Offset, prev.Addr, prevNewLen);
mAddrList.Insert(i,
new AddressMapEntry(offset, addr, prevOldLen - prevNewLen));
@ -223,8 +209,8 @@ namespace CommonUtil {
if (mAddrList[i].Offset == offset) {
// Add the length to the previous entry.
AddressMapEntry prev = mAddrList[i - 1];
prev.Length += mAddrList[i].Length;
mAddrList[i - 1] = prev;
mAddrList[i - 1] = new AddressMapEntry(prev.Offset, prev.Addr,
prev.Length + mAddrList[i].Length);
mAddrList.RemoveAt(i);
DebugValidate();
@ -297,13 +283,14 @@ namespace CommonUtil {
}
/// <summary>
/// Checks to see if the specified range of offsets is in a contiguous range of
/// addresses. Use this to see if something crosses an address-change boundary.
/// Checks to see if the specified range of offsets is in a single address range. Use
/// this to see if something crosses an address-change boundary. This does not
/// handle no-op address changes specially.
/// </summary>
/// <param name="offset">Start offset.</param>
/// <param name="length">Length of region.</param>
/// <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(length > 0 && offset + length <= mTotalLength);
return (IndexForOffset(offset) == IndexForOffset(offset + length - 1));

View File

@ -1044,7 +1044,7 @@ namespace SourceGen {
" 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 + ")");
return false;
}

View File

@ -533,8 +533,8 @@ namespace SourceGen {
int startOffset = -1;
for (int offset = 0; offset < mAnattribs.Length; ) {
// 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
// or format descriptor.
// to hold code or data. We stop if we encounter a user-defined label,
// format descriptor, or address override.
Anattrib attr = mAnattribs[offset];
if (attr.IsInstruction || attr.IsInlineData || attr.IsDataStart) {
@ -572,19 +572,17 @@ namespace SourceGen {
}
offset++;
// Check to see if the address has changed from the previous entry.
// 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.
// Check to see if we just crossed an address change.
if (offset < mAnattribs.Length &&
mAnattribs[offset-1].Address + 1 != mAnattribs[offset].Address) {
// Must be an ORG here. Scan previous region.
!mProject.AddrMap.IsSingleAddrRange(offset - 1, 2)) {
// Must be an ORG here. End region and scan.
AnalyzeRange(startOffset, offset - 1);
startOffset = -1;
}
}
}
// Do the last bit.
if (startOffset >= 0) {
AnalyzeRange(startOffset, mAnattribs.Length - 1);
}

View File

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

View File

@ -2479,7 +2479,7 @@ namespace SourceGen {
// This must match what GroupedOffsetSetFromSelected() does.
if (!mProject.UserLabels.ContainsKey(nextOffset) &&
!mProject.HasCommentNoteOrVis(nextOffset) &&
thisAttr.Address == nextAttr.Address - 1) {
mProject.AddrMap.IsSingleAddrRange(nextOffset - 1, 2)) {
// Good to go.
Debug.WriteLine("Grabbing second byte from +" + nextOffset.ToString("x6"));
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,
/// unless the user has been playing weird games with type hints to get overlapping
/// 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>
/// <returns>TypedRangeSet with all offsets.</returns>
private TypedRangeSet GroupedOffsetSetFromSelected() {
@ -3394,12 +3397,18 @@ namespace SourceGen {
if (attr.Address != expectedAddr) {
// For a contiguous selection, this should only happen if there's a .ORG
// address change. For non-contiguous selection this is expected. In the
// latter case, incrementing the group number is unnecessary but harmless.
Debug.WriteLine("Address break: " + attr.Address + " vs. " + expectedAddr);
//Debug.Assert(mProject.AddrMap.Get(offset) >= 0);
// latter case, incrementing the group number is unnecessary but harmless
// (the TypedRangeSet splits at the gap).
//Debug.WriteLine("Address break: $" + attr.Address.ToString("x4") + " vs. $"
// + expectedAddr.ToString("x4"));
expectedAddr = attr.Address;
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)) {
//if (mProject.GetAnattrib(offset).Symbol != null) {
// We consider auto labels when splitting regions for the data analysis,

View File

@ -1,89 +1,248 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":3,"FileDataLength":1200,"FileDataCrc32":1114187983,"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":{
"_ContentVersion":3,
"FileDataLength":1200,
"FileDataCrc32":1114187983,
"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":[{
"Offset":0,"Addr":4096},
"Offset":0,
"Addr":4096},
{
"Offset":1032,"Addr":5128},
"Offset":1032,
"Addr":5128},
{
"Offset":1048,"Addr":5160}],"TypeHints":[{
"Low":0,"High":0,"Hint":"Code"}],"StatusFlagOverrides":{
"Offset":1048,
"Addr":5160}],
"TypeHints":[{
"Low":0,
"High":0,
"Hint":"Code"}],
"StatusFlagOverrides":{
},
"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":{
"-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":{
"Text":"long comment\r\n","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}},
"Text":"long comment\r\n",
"BoxMode":false,
"MaxWidth":80,
"BackgroundColor":0}},
"Notes":{
"1144":{
"Text":":ETON","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}},
"Text":":ETON",
"BoxMode":false,
"MaxWidth":80,
"BackgroundColor":0}},
"UserLabels":{
"588":{
"Label":"LABEL","Value":4684,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"},
"Label":"LABEL",
"Value":4684,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"1064":{
"Label":"UserLabel","Value":5176,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"}},
"Label":"UserLabel",
"Value":5176,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"}},
"OperandFormats":{
"23":{
"Length":1,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Length":1,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"24":{
"Length":2,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Length":2,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"26":{
"Length":3,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Length":3,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"29":{
"Length":4,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Length":4,
"Format":"NumericLE",
"SubFormat":"Hex",
"SymbolRef":null},
"33":{
"Length":1,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null},
"Length":1,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"34":{
"Length":2,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null},
"Length":2,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"36":{
"Length":3,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null},
"Length":3,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"39":{
"Length":4,"Format":"NumericBE","SubFormat":"Hex","SymbolRef":null},
"Length":4,
"Format":"NumericBE",
"SubFormat":"Hex",
"SymbolRef":null},
"43":{
"Length":2,"Format":"Fill","SubFormat":"None","SymbolRef":null},
"Length":2,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"46":{
"Length":3,"Format":"Fill","SubFormat":"None","SymbolRef":null},
"Length":3,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"50":{
"Length":4,"Format":"Fill","SubFormat":"None","SymbolRef":null},
"Length":4,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"55":{
"Length":5,"Format":"Fill","SubFormat":"None","SymbolRef":null},
"Length":5,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"61":{
"Length":256,"Format":"Fill","SubFormat":"None","SymbolRef":null},
"Length":256,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"318":{
"Length":257,"Format":"Fill","SubFormat":"None","SymbolRef":null},
"Length":257,
"Format":"Fill",
"SubFormat":"None",
"SymbolRef":null},
"575":{
"Length":1,"Format":"Dense","SubFormat":"None","SymbolRef":null},
"Length":1,
"Format":"Dense",
"SubFormat":"None",
"SymbolRef":null},
"577":{
"Length":10,"Format":"Dense","SubFormat":"None","SymbolRef":null},
"Length":10,
"Format":"Dense",
"SubFormat":"None",
"SymbolRef":null},
"588":{
"Length":64,"Format":"Dense","SubFormat":"None","SymbolRef":null},
"Length":64,
"Format":"Dense",
"SubFormat":"None",
"SymbolRef":null},
"653":{
"Length":115,"Format":"Junk","SubFormat":"Align256","SymbolRef":null},
"Length":115,
"Format":"Junk",
"SubFormat":"Align256",
"SymbolRef":null},
"769":{
"Length":63,"Format":"Junk","SubFormat":"Align64","SymbolRef":null},
"Length":63,
"Format":"Junk",
"SubFormat":"Align64",
"SymbolRef":null},
"833":{
"Length":31,"Format":"Junk","SubFormat":"Align32","SymbolRef":null},
"Length":31,
"Format":"Junk",
"SubFormat":"Align32",
"SymbolRef":null},
"864":{
"Length":8,"Format":"Junk","SubFormat":"None","SymbolRef":null},
"Length":8,
"Format":"Junk",
"SubFormat":"None",
"SymbolRef":null},
"873":{
"Length":8,"Format":"Junk","SubFormat":"None","SymbolRef":null},
"Length":8,
"Format":"Junk",
"SubFormat":"None",
"SymbolRef":null},
"882":{
"Length":2,"Format":"Junk","SubFormat":"Align128","SymbolRef":null},
"Length":2,
"Format":"Junk",
"SubFormat":"Align128",
"SymbolRef":null},
"884":{
"Length":140,"Format":"Junk","SubFormat":"Align256","SymbolRef":null},
"Length":140,
"Format":"Junk",
"SubFormat":"Align256",
"SymbolRef":null},
"1192":{
"Length":1,"Format":"NumericLE","SubFormat":"Binary","SymbolRef":null}},
"Length":1,
"Format":"NumericLE",
"SubFormat":"Binary",
"SymbolRef":null}},
"LvTables":{
"1096":{
"Variables":[],"ClearPrevious":true}},
"Variables":[],
"ClearPrevious":true}},
"Visualizations":[{
"Tag":"vis000488","VisGenIdent":"dummy","VisGenParams":{
}}],"VisualizationAnimations":[],"VisualizationSets":{
"Tag":"vis000488",
"VisGenIdent":"dummy",
"VisGenParams":{
}}],
"VisualizationAnimations":[],
"VisualizationSets":{
"1160":{
"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
.fill 2,$dd ;incorrect alignment
.align 256,$00
.fill 16,$82
.fill 8,$82
.logical $1408
.fill 8,$82 ;note no-op .ORG
.fill 8,$83
.here
.logical $1428
.fill 8,$83
.fill 8,$83 ;meaningful .ORG
.fill 8,$84
UserLabel .fill 8,$84
.fill 8,$85

View File

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

View File

@ -59,10 +59,13 @@ LABEL !hex 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
!byte $81
!fill 2,$dd ;incorrect alignment
!align 255,0,$00
!fill 16,$82
!fill 8,$82
!pseudopc $1408 {
!fill 8,$82 ;note no-op .ORG
!fill 8,$83
} ;!pseudopc
!pseudopc $1428 {
!fill 8,$83
!fill 8,$83 ;meaningful .ORG
!fill 8,$84
UserLabel !fill 8,$84
!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
.res 2,$dd ;incorrect alignment
.res 140,$00
.res 16,$82
.res 8,$82
; .segment "SEG001"
.org $1408
.res 8,$82 ;note no-op .ORG
.res 8,$83
; .segment "SEG002"
.org $1428
.res 8,$83
.res 8,$83 ;meaningful .ORG
.res 8,$84
UserLabel: .res 8,$84
.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