mirror of
https://github.com/fadden/6502bench.git
synced 2025-01-05 23:30:20 +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:
parent
f56e4f2bec
commit
387b50d827
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -90,6 +90,7 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
}
|
||||
|
||||
// Reached end of start directives. Write the last one.
|
||||
if (arDirectPending) {
|
||||
gen.FlushArDirectives();
|
||||
arDirectPending = false;
|
||||
|
@ -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) {
|
||||
|
Binary file not shown.
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -18,7 +18,7 @@ _L11018 lda _L11018
|
||||
jmp _L11026
|
||||
|
||||
_L1101F .byte $80
|
||||
.logical *-$011020
|
||||
.logical $0000
|
||||
.byte $ea
|
||||
.byte $60
|
||||
.dword _L31004
|
||||
|
@ -1,5 +1,7 @@
|
||||
.setcpu "65816"
|
||||
.org $031000
|
||||
.org $011000
|
||||
.org *+$010000
|
||||
.org *+$010000
|
||||
.a8
|
||||
.i8
|
||||
L31000: lda L31000
|
||||
|
@ -1,4 +1,6 @@
|
||||
org $031000
|
||||
org $011000
|
||||
org *+$010000
|
||||
org *+$010000
|
||||
L31000 ldal L31000
|
||||
:L31004 ldal :L31004
|
||||
andl :L1101F
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user