1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-11 02:29:53 +00:00

Implement IsRelative for cc65/merlin32

Added support for "relative" address regions to the Merlin 32 and cc65
code generators.  These generate "flat" address directives, and so
were a little more complicated.

Suppressed generation of relative operands for non-addressable regions.

Also, tweaked the 20250-nested-regions test to include a negative
relative region offset.
This commit is contained in:
Andy McFadden 2021-10-09 09:58:37 -07:00
parent f56e4f2bec
commit 387b50d827
17 changed files with 225 additions and 99 deletions

View File

@ -183,7 +183,7 @@ namespace CommonUtil {
public int ActualLength { get; private set; }
/// <summary>
/// Address associated with pre-label.
/// Address associated with pre-label and relative addressing.
/// </summary>
public int PreLabelAddress { get; private set; }
@ -207,6 +207,19 @@ namespace CommonUtil {
}
}
/// <summary>
/// Is this region validly marked "is relative"?
/// </summary>
/// <remarks>
/// The relative address is determined by subtracting the Address from the
/// PreLabelAddress, so neither may be NON_ADDR.
/// </remarks>
public bool HasValidIsRelative {
get {
return IsRelative && PreLabelAddress != NON_ADDR && Address != NON_ADDR;
}
}
/// <summary>
/// Full constructor.

View File

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

View File

@ -96,6 +96,18 @@ namespace SourceGen.AsmGen {
/// </summary>
private int mNextAddress = -1;
/// <summary>
/// True if we've seen an "is relative" flag in a block of address region start directives.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
bool mIsInRelative = false;
/// <summary>
/// Holds detected version of configured assembler.
/// </summary>
@ -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

View File

@ -91,6 +91,18 @@ namespace SourceGen.AsmGen {
/// </summary>
private int mNextAddress = -1;
/// <summary>
/// True if we've seen an "is relative" flag in a block of address region start directives.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
bool mIsInRelative = false;
/// <summary>
/// Holds detected version of configured assembler.
/// </summary>
@ -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

View File

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

View File

@ -90,6 +90,7 @@ namespace SourceGen.AsmGen {
}
}
// Reached end of start directives. Write the last one.
if (arDirectPending) {
gen.FlushArDirectives();
arDirectPending = false;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@ _L11018 lda _L11018
jmp _L11026
_L1101F .byte $80
.logical *-$011020
.logical $0000
.byte $ea
.byte $60
.dword _L31004

View File

@ -1,5 +1,7 @@
.setcpu "65816"
.org $031000
.org $011000
.org *+$010000
.org *+$010000
.a8
.i8
L31000: lda L31000

View File

@ -1,4 +1,6 @@
org $031000
org $011000
org *+$010000
org *+$010000
L31000 ldal L31000
:L31004 ldal :L31004
andl :L1101F

View File

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