diff --git a/CommonUtil/AddressMap.cs b/CommonUtil/AddressMap.cs
index bccf941..b083584 100644
--- a/CommonUtil/AddressMap.cs
+++ b/CommonUtil/AddressMap.cs
@@ -183,7 +183,7 @@ namespace CommonUtil {
public int ActualLength { get; private set; }
///
- /// Address associated with pre-label.
+ /// Address associated with pre-label and relative addressing.
///
public int PreLabelAddress { get; private set; }
@@ -207,6 +207,19 @@ namespace CommonUtil {
}
}
+ ///
+ /// Is this region validly marked "is relative"?
+ ///
+ ///
+ /// The relative address is determined by subtracting the Address from the
+ /// PreLabelAddress, so neither may be NON_ADDR.
+ ///
+ public bool HasValidIsRelative {
+ get {
+ return IsRelative && PreLabelAddress != NON_ADDR && Address != NON_ADDR;
+ }
+ }
+
///
/// Full constructor.
diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs
index ad3d97f..3c7c72c 100644
--- a/SourceGen/AsmGen/AsmAcme.cs
+++ b/SourceGen/AsmGen/AsmAcme.cs
@@ -600,7 +600,7 @@ namespace SourceGen.AsmGen {
}
AddressMap.AddressRegion region = change.Region;
string addrStr;
- if (region.IsRelative && region.PreLabelAddress != Address.NON_ADDR) {
+ if (region.HasValidIsRelative) {
int diff = nextAddress - region.PreLabelAddress;
string pfxStr;
if (diff >= 0) {
diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs
index e2c4121..0ad57ba 100644
--- a/SourceGen/AsmGen/AsmCc65.cs
+++ b/SourceGen/AsmGen/AsmCc65.cs
@@ -96,6 +96,18 @@ namespace SourceGen.AsmGen {
///
private int mNextAddress = -1;
+ ///
+ /// True if we've seen an "is relative" flag in a block of address region start directives.
+ ///
+ ///
+ /// The trick with IsRelative is that, if there are multiple arstarts at the same
+ /// offset, we need to output some or all of them, starting from the one just before
+ /// the first IsRelative start. We probably want to disable the use of Flush and
+ /// just generate them as they appear, using the next Flush as the signal to return
+ /// to standard behavior.
+ ///
+ bool mIsInRelative = false;
+
///
/// Holds detected version of configured assembler.
///
@@ -540,34 +552,73 @@ namespace SourceGen.AsmGen {
// IGenerator
public void OutputArDirective(CommonUtil.AddressMap.AddressChange change) {
- if (change.IsStart && change.Region.HasValidPreLabel) {
- // Need to output the previous ORG, if any, then a label on a line by itself.
- if (mNextAddress >= 0) {
- OutputLine(string.Empty,
- SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
- SourceFormatter.FormatHexValue(mNextAddress, 4),
- string.Empty);
- }
- string labelStr = mLocalizer.ConvLabel(change.Region.PreLabel);
- OutputLine(labelStr, string.Empty, string.Empty, string.Empty);
- }
-
int nextAddress = change.Address;
if (nextAddress == Address.NON_ADDR) {
// Start non-addressable regions at zero to ensure they don't overflow bank.
nextAddress = 0;
}
+
+ if (change.IsStart) {
+ AddressMap.AddressRegion region = change.Region;
+ if (region.HasValidPreLabel || region.HasValidIsRelative) {
+ // Need to output the previous ORG, if one is pending.
+ if (mNextAddress >= 0) {
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ SourceFormatter.FormatHexValue(mNextAddress, 4),
+ string.Empty);
+ }
+ }
+ if (region.HasValidPreLabel) {
+ string labelStr = mLocalizer.ConvLabel(change.Region.PreLabel);
+ OutputLine(labelStr, string.Empty, string.Empty, string.Empty);
+ }
+ if (region.HasValidIsRelative) {
+ // Found a valid IsRelative. Switch to "relative mode" if not there already.
+ mIsInRelative = true;
+ }
+ if (mIsInRelative) {
+ // Once we see a region with IsRelative set, we output regions as we
+ // find them until the next Flush.
+ string addrStr;
+ if (region.HasValidIsRelative) {
+ int diff = nextAddress - region.PreLabelAddress;
+ string pfxStr;
+ if (diff >= 0) {
+ pfxStr = "*+";
+ } else {
+ pfxStr = "*-";
+ diff = -diff;
+ }
+ addrStr = pfxStr + SourceFormatter.FormatHexValue(diff, 4);
+ } else {
+ addrStr = SourceFormatter.FormatHexValue(nextAddress, 4);
+ }
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ addrStr, string.Empty);
+
+ mNextAddress = -1;
+ return;
+ }
+ }
+
mNextAddress = nextAddress;
}
// IGenerator
public void FlushArDirectives() {
- // TODO(someday): handle IsRelative
- OutputLine(string.Empty,
- SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
- SourceFormatter.FormatHexValue(mNextAddress, 4),
- string.Empty);
+ // Output pending directives. There will always be something to do here unless
+ // we were in "relative" mode.
+ Debug.Assert(mNextAddress >= 0 || mIsInRelative);
+ if (mNextAddress >= 0) {
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ SourceFormatter.FormatHexValue(mNextAddress, 4),
+ string.Empty);
+ }
mNextAddress = -1;
+ mIsInRelative = false;
}
// IGenerator
diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs
index 7662a29..3a69e67 100644
--- a/SourceGen/AsmGen/AsmMerlin32.cs
+++ b/SourceGen/AsmGen/AsmMerlin32.cs
@@ -91,6 +91,18 @@ namespace SourceGen.AsmGen {
///
private int mNextAddress = -1;
+ ///
+ /// True if we've seen an "is relative" flag in a block of address region start directives.
+ ///
+ ///
+ /// The trick with IsRelative is that, if there are multiple arstarts at the same
+ /// offset, we need to output some or all of them, starting from the one just before
+ /// the first IsRelative start. We probably want to disable the use of Flush and
+ /// just generate them as they appear, using the next Flush as the signal to return
+ /// to standard behavior.
+ ///
+ bool mIsInRelative = false;
+
///
/// Holds detected version of configured assembler.
///
@@ -491,35 +503,75 @@ namespace SourceGen.AsmGen {
// IGenerator
public void OutputArDirective(CommonUtil.AddressMap.AddressChange change) {
- if (change.IsStart && change.Region.HasValidPreLabel) {
- // Need to output the previous ORG, if any, then a label on a line by itself.
- if (mNextAddress >= 0) {
- OutputLine(string.Empty,
- SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
- SourceFormatter.FormatHexValue(mNextAddress, 4),
- string.Empty);
- }
- string labelStr = mLocalizer.ConvLabel(change.Region.PreLabel);
- OutputLine(labelStr, string.Empty, string.Empty, string.Empty);
- }
-
int nextAddress = change.Address;
if (nextAddress == Address.NON_ADDR) {
// Start non-addressable regions at zero to ensure they don't overflow bank.
nextAddress = 0;
}
+
+ if (change.IsStart) {
+ AddressMap.AddressRegion region = change.Region;
+ if (region.HasValidPreLabel || region.HasValidIsRelative) {
+ // Need to output the previous ORG, if one is pending.
+ if (mNextAddress >= 0) {
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ SourceFormatter.FormatHexValue(mNextAddress, 4),
+ string.Empty);
+ }
+ }
+ if (region.HasValidPreLabel) {
+ string labelStr = mLocalizer.ConvLabel(change.Region.PreLabel);
+ OutputLine(labelStr, string.Empty, string.Empty, string.Empty);
+ }
+ if (region.HasValidIsRelative) {
+ // Found a valid IsRelative. Switch to "relative mode" if not there already.
+ mIsInRelative = true;
+ }
+ if (mIsInRelative) {
+ // Once we see a region with IsRelative set, we output regions as we
+ // find them until the next Flush.
+ string addrStr;
+ if (region.HasValidIsRelative) {
+ Debug.Assert(nextAddress != Address.NON_ADDR &&
+ region.PreLabelAddress != Address.NON_ADDR);
+ int diff = nextAddress - region.PreLabelAddress;
+ string pfxStr;
+ if (diff >= 0) {
+ pfxStr = "*+";
+ } else {
+ pfxStr = "*-";
+ diff = -diff;
+ }
+ addrStr = pfxStr + SourceFormatter.FormatHexValue(diff, 4);
+ } else {
+ addrStr = SourceFormatter.FormatHexValue(nextAddress, 4);
+ }
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ addrStr, string.Empty);
+
+ mNextAddress = -1;
+ return;
+ }
+ }
+
mNextAddress = nextAddress;
}
// IGenerator
public void FlushArDirectives() {
- // TODO(someday): handle IsRelative
- Debug.Assert(mNextAddress >= 0);
- OutputLine(string.Empty,
- SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
- SourceFormatter.FormatHexValue(mNextAddress, 4),
- string.Empty);
+ // Output pending directives. There will always be something to do here unless
+ // we were in "relative" mode.
+ Debug.Assert(mNextAddress >= 0 || mIsInRelative);
+ if (mNextAddress >= 0) {
+ OutputLine(string.Empty,
+ SourceFormatter.FormatPseudoOp(sDataOpNames.ArStartDirective),
+ SourceFormatter.FormatHexValue(mNextAddress, 4),
+ string.Empty);
+ }
mNextAddress = -1;
+ mIsInRelative = false;
}
// IGenerator
diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs
index 3c406d0..01c71f1 100644
--- a/SourceGen/AsmGen/AsmTass64.cs
+++ b/SourceGen/AsmGen/AsmTass64.cs
@@ -709,7 +709,7 @@ namespace SourceGen.AsmGen {
AddressMap.AddressRegion region = change.Region;
string addrStr;
- if (region.IsRelative && region.PreLabelAddress != Address.NON_ADDR) {
+ if (region.HasValidIsRelative) {
int diff = nextAddress - region.PreLabelAddress;
string pfxStr;
if (diff >= 0) {
diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs
index 2a41b25..04225c0 100644
--- a/SourceGen/AsmGen/GenCommon.cs
+++ b/SourceGen/AsmGen/GenCommon.cs
@@ -90,6 +90,7 @@ namespace SourceGen.AsmGen {
}
}
+ // Reached end of start directives. Write the last one.
if (arDirectPending) {
gen.FlushArDirectives();
arDirectPending = false;
diff --git a/SourceGen/LineListGen.cs b/SourceGen/LineListGen.cs
index eeef4b4..eaf6e7c 100644
--- a/SourceGen/LineListGen.cs
+++ b/SourceGen/LineListGen.cs
@@ -1095,8 +1095,7 @@ namespace SourceGen {
string addrStr;
if (region.Address == Address.NON_ADDR) {
addrStr = Address.NON_ADDR_STR;
- } else if (change.Region.IsRelative &&
- change.Region.PreLabelAddress != Address.NON_ADDR) {
+ } else if (change.Region.HasValidIsRelative) {
int diff = region.Address - change.Region.PreLabelAddress;
string pfxStr;
if (diff >= 0) {
diff --git a/SourceGen/SGTestData/20250-nested-regions b/SourceGen/SGTestData/20250-nested-regions
index 9fd3fb4..e7ca6b8 100644
Binary files a/SourceGen/SGTestData/20250-nested-regions and b/SourceGen/SGTestData/20250-nested-regions differ
diff --git a/SourceGen/SGTestData/20250-nested-regions.dis65 b/SourceGen/SGTestData/20250-nested-regions.dis65
index 9e9e35e..d460e2d 100644
--- a/SourceGen/SGTestData/20250-nested-regions.dis65
+++ b/SourceGen/SGTestData/20250-nested-regions.dis65
@@ -2,7 +2,7 @@
{
"_ContentVersion":5,
"FileDataLength":156,
-"FileDataCrc32":1681364707,
+"FileDataCrc32":367497130,
"ProjectProps":{
"CpuName":"6502",
"IncludeUndocumentedInstr":false,
@@ -74,17 +74,17 @@
{
"Offset":132,
-"Addr":53248,
+"Addr":57344,
"Length":24,
"PreLabel":"",
"IsRelative":true},
{
"Offset":139,
-"Addr":57344,
+"Addr":53248,
"Length":17,
"PreLabel":"",
-"IsRelative":false},
+"IsRelative":true},
{
"Offset":145,
diff --git a/SourceGen/SGTestData/Expected/20250-nested-regions_64tass.S b/SourceGen/SGTestData/Expected/20250-nested-regions_64tass.S
index 7aeb89a..3f438b0 100644
--- a/SourceGen/SGTestData/Expected/20250-nested-regions_64tass.S
+++ b/SourceGen/SGTestData/Expected/20250-nested-regions_64tass.S
@@ -7,7 +7,7 @@
.logical *+$1000
L3000 bit L3000
_L3003 lda _L3003
- and _LD003
+ and _LE003
jmp _L200C
.here
@@ -22,7 +22,7 @@ _L1012 bit _L1012
.null "Null-term PETSCII string"
.byte $80
.word _L3003
- .word _LD003
+ .word _LE003
.byte $80
.here
@@ -72,22 +72,22 @@ _L5017 rts
_L4040 bit _L4040
bit _L5017
nop
- jmp _LD000
-
- .here
- .logical *+$bf7e
-_LD000 bit _L200C
-_LD003 nop
jmp _LE000
- .logical $e000
-_LE000 bit _LE000
+ .here
+ .logical *+$cf7e
+_LE000 bit _L200C
+_LE003 nop
+ jmp _LD000
+
+ .logical *-$1007
+_LD000 bit _LD000
jmp _LF000
.logical $f000
_LF000 bit _LF000
lda _L3003
- and _LD003
+ and _LE003
nop
rts
diff --git a/SourceGen/SGTestData/Expected/20250-nested-regions_acme.S b/SourceGen/SGTestData/Expected/20250-nested-regions_acme.S
index c8bb315..fd03138 100644
--- a/SourceGen/SGTestData/Expected/20250-nested-regions_acme.S
+++ b/SourceGen/SGTestData/Expected/20250-nested-regions_acme.S
@@ -7,7 +7,7 @@
!pseudopc *+$1000 {
L3000 bit L3000
@L3003 lda @L3003
- and @LD003
+ and @LE003
jmp @L200C
}
@@ -22,7 +22,7 @@ L3000 bit L3000
!pet "Null-term PETSCII string",$00
!byte $80
!word @L3003
- !word @LD003
+ !word @LE003
!byte $80
}
@@ -72,22 +72,22 @@ L3000 bit L3000
@L4040 bit @L4040
bit @L5017
nop
- jmp @LD000
-
- }
- !pseudopc *+$bf7e {
-@LD000 bit @L200C
-@LD003 nop
jmp @LE000
- !pseudopc $e000 {
-@LE000 bit @LE000
+ }
+ !pseudopc *+$cf7e {
+@LE000 bit @L200C
+@LE003 nop
+ jmp @LD000
+
+ !pseudopc *-$1007 {
+@LD000 bit @LD000
jmp @LF000
!pseudopc $f000 {
@LF000 bit @LF000
lda @L3003
- and @LD003
+ and @LE003
nop
rts
diff --git a/SourceGen/SGTestData/Expected/20250-nested-regions_cc65.S b/SourceGen/SGTestData/Expected/20250-nested-regions_cc65.S
index 3f14590..dbc2d5a 100644
--- a/SourceGen/SGTestData/Expected/20250-nested-regions_cc65.S
+++ b/SourceGen/SGTestData/Expected/20250-nested-regions_cc65.S
@@ -2,10 +2,12 @@
.org $0000
.word $3000 ;load address
- .org $3000
+ .org $1000
+ .org *+$1000
+ .org *+$1000
L3000: bit L3000
@L3003: lda @L3003
- and @LD003
+ and @LE003
jmp @L200C
.org $200c
@@ -21,7 +23,7 @@ L3000: bit L3000
.byte $c9,$20,$53,$54,$52,$49,$4e,$47,$00
.byte $80
.word @L3003
- .word @LD003
+ .word @LE003
.byte $80
.org $4000
@@ -70,21 +72,22 @@ L3000: bit L3000
@L4040: bit @L4040
bit @L5017
nop
- jmp @LD000
-
- .org $d000
-@LD000: bit @L200C
-@LD003: nop
jmp @LE000
- .org $e000
-@LE000: bit @LE000
+ .org $1082
+ .org *+$cf7e
+@LE000: bit @L200C
+@LE003: nop
+ jmp @LD000
+
+ .org *-$1007
+@LD000: bit @LD000
jmp @LF000
.org $f000
@LF000: bit @LF000
lda @L3003
- and @LD003
+ and @LE003
nop
rts
diff --git a/SourceGen/SGTestData/Expected/20250-nested-regions_merlin32.S b/SourceGen/SGTestData/Expected/20250-nested-regions_merlin32.S
index 5986f41..4faca70 100644
--- a/SourceGen/SGTestData/Expected/20250-nested-regions_merlin32.S
+++ b/SourceGen/SGTestData/Expected/20250-nested-regions_merlin32.S
@@ -1,10 +1,12 @@
org $0000
dw $3000 ;load address
- org $3000
+ org $1000
+ org *+$1000
+ org *+$1000
L3000 bit L3000
:L3003 lda :L3003
- and :LD003
+ and :LE003
jmp :L200C
org $200c
@@ -19,7 +21,7 @@ L3000 bit L3000
hex ce554c4c2d5445524d20d0c5d4d3c3c9c920535452494e4700
dfb $80
dw :L3003
- dw :LD003
+ dw :LE003
dfb $80
org $4000
@@ -68,21 +70,22 @@ L3000 bit L3000
:L4040 bit :L4040
bit :L5017
nop
- jmp :LD000
-
- org $d000
-:LD000 bit :L200C
-:LD003 nop
jmp :LE000
- org $e000
-:LE000 bit :LE000
+ org $1082
+ org *+$cf7e
+:LE000 bit :L200C
+:LE003 nop
+ jmp :LD000
+
+ org *-$1007
+:LD000 bit :LD000
jmp :LF000
org $f000
:LF000 bit :LF000
lda :L3003
- and :LD003
+ and :LE003
nop
rts
diff --git a/SourceGen/SGTestData/Expected/20252-nested-regions_64tass.S b/SourceGen/SGTestData/Expected/20252-nested-regions_64tass.S
index f8d7751..761d57c 100644
--- a/SourceGen/SGTestData/Expected/20252-nested-regions_64tass.S
+++ b/SourceGen/SGTestData/Expected/20252-nested-regions_64tass.S
@@ -18,7 +18,7 @@ _L11018 lda _L11018
jmp _L11026
_L1101F .byte $80
- .logical *-$011020
+ .logical $0000
.byte $ea
.byte $60
.dword _L31004
diff --git a/SourceGen/SGTestData/Expected/20252-nested-regions_cc65.S b/SourceGen/SGTestData/Expected/20252-nested-regions_cc65.S
index 58eb4c2..1a5e645 100644
--- a/SourceGen/SGTestData/Expected/20252-nested-regions_cc65.S
+++ b/SourceGen/SGTestData/Expected/20252-nested-regions_cc65.S
@@ -1,5 +1,7 @@
.setcpu "65816"
- .org $031000
+ .org $011000
+ .org *+$010000
+ .org *+$010000
.a8
.i8
L31000: lda L31000
diff --git a/SourceGen/SGTestData/Expected/20252-nested-regions_merlin32.S b/SourceGen/SGTestData/Expected/20252-nested-regions_merlin32.S
index a03da82..7a79e8b 100644
--- a/SourceGen/SGTestData/Expected/20252-nested-regions_merlin32.S
+++ b/SourceGen/SGTestData/Expected/20252-nested-regions_merlin32.S
@@ -1,4 +1,6 @@
- org $031000
+ org $011000
+ org *+$010000
+ org *+$010000
L31000 ldal L31000
:L31004 ldal :L31004
andl :L1101F
diff --git a/SourceGen/SGTestData/Source/20250-nested-regions.S b/SourceGen/SGTestData/Source/20250-nested-regions.S
index 57a1567..fb64237 100644
--- a/SourceGen/SGTestData/Source/20250-nested-regions.S
+++ b/SourceGen/SGTestData/Source/20250-nested-regions.S
@@ -107,17 +107,17 @@ a4040 bit a4040
.here ;$4000
+; EDIT: create region starting at $e000, ending at REGION2_END; relative
+ .logical $e000
+tailend
+partek bit part2k
+late nop
+ jmp partdk
+
; EDIT: create region starting at $d000, ending at REGION2_END; relative
.logical $d000
-tailend
-partdk bit part2k
-late nop
- jmp partek
-; EDIT: create
- .logical $e000
-
-partek bit partek
+partdk bit partdk
jmp partfk
; EDIT: create, make it floating