1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-25 05:29:31 +00:00

Allow explicit widths in project/platform symbols, part 4 (of 4)

Handle situation where a symbol wraps around a bank.  Updated
2021-external-symbols for that, and to test the behavior when file
data and an external symbol overlap.

The bank-wrap test turned up a bug in Merlin 32.  A workaround has
been added.

Updated documentation to explain widths.
This commit is contained in:
Andy McFadden 2019-10-03 10:32:54 -07:00
parent 0d9814d993
commit 37855c8f8e
15 changed files with 173 additions and 86 deletions

View File

@ -934,7 +934,9 @@ namespace SourceGen {
keepLen = Math.Max(keepLen, operandLen);
adjustment = adjOperand - sym.Value;
if (keepLen == 1) {
int origAdjust = adjustment;
adjustment %= 256;
// Adjust for aesthetics. The assembler implicitly applies a modulo operation,
// so we can use the value closest to zero.
@ -943,6 +945,21 @@ namespace SourceGen {
} else if (adjustment < -128) {
adjustment = (256 + adjustment) /*% 256*/;
}
// We have a problem with ambiguous direct-page arguments if the adjusted
// value crosses a bank boundary. For example, "LDA $fff0+24" is computed
// as $010008, which is too big for a DP arg, so Merlin treats it as absolute
// (LDA $0008) instead of DP. If Merlin had done the implicit "& $ffff" before
// testing the value for DP range, this would behave correctly. Unfortunately
// there is no "force DP" modifier, so we either need to add an explicit mask
// or just punt and use the original adjustment.
// TODO(someday): we only need to do this for ambiguous DP. If the instruction
// is imm or doesn't have an abs equivalent, or it's a fixed-width data item
// like .DD1, we can still use the nicer-looking adjustment. We don't currently
// pass the OpDef in here.
if ((sym.Value & 0xff0000) != ((sym.Value + adjustment) & 0xff0000)) {
adjustment = origAdjust;
}
} else if (keepLen == 2) {
adjustment %= 65536;
if (adjustment > 32767) {

View File

@ -80,9 +80,11 @@ method in <code>DisasmProject.cs</code>):</p>
</ul>
<p>Once analysis is complete, a line-by-line display list is generated
by walking through the annotated file data. Most of the actual strings
aren't rendered until they're needed. For complicated multi-line items
like string operands, the formatted text is cached.</p>
by walking through the annotated file data. Most of the actual text
isn't rendered until they're needed. For complicated multi-line items
like string operands, the formatted text must be generated to know how
many lines it will occupy, so it's done immediately and cached for re-use
on subsequent runs.</p>
<h3><a name="auto-format">Automatic Formatting</a></h3>

View File

@ -302,11 +302,19 @@ with platform symbols and user labels.</p>
<p>The value may be entered in decimal, hexadecimal, or binary. The numeric
base you choose will be remembered, so that the value will be displayed
the same way when used in a .EQ directive.</p>
<p>You can optionally provide a width. For example, if the address is
of a two-byte pointer or a 64-byte buffer, you would set the width field
to cause all references to any location in that range to be set to the
symbol. Widths may be entered in hex or decimal. If the field
is left blank, a width of 1 is assumed. Overlapping symbols are allowed.
The width is ignored for constants.</p>
<p>If you enter a comment, it will be placed at the end of the line of
the .EQ directive.</p>
<p>Symbols marked as "address" will be applied automatically when an
operand references an address outside the scope of the data file. Symbols
marked as "constant" will not, though you can still specify them manually.</p>
operand references an address outside the scope of the data file. They
will not be applied to addresses inside the data file. Symbols
marked as "constant" are not applied automatically, and must be
explicitly specified as an operand.</p>
<h2><a name="lvtable">Create/Edit Local Variable Table</a></h2>

View File

@ -395,7 +395,7 @@ by splitting formatted data into sub-regions at label boundaries.</p>
<h2><a name="about-symbols">All About Symbols</a></h2>
<p>A symbol has two parts, a label and a value. The label is a short
<p>A symbol has two basic parts, a label and a value. The label is a short
ASCII string; the value may be an 8-to-24-bit address or a numeric
constant. Symbols can be defined in different ways, and applied in
different ways.</p>
@ -441,9 +441,23 @@ it finds one, it automatically uses that symbol. Symbolic constants
can be used the same way, but are not matched automatically. This makes
them useful for things like operating system function numbers.</p>
<p>If two platform symbols have the same value, the one whose label comes
first alphabetically is used. If two platform symbols have the same label,
the most recently read one is kept.</p>
<p>If two platform symbols have the same label, only the most recently read
one is kept. If two platform symbols have different labels but the
same value, both symbols will be kept, but the one in the file loaded
last will take priority when doing a lookup by address. If symbols with
the same value are defined in the same file, the one whose symbol appears
first alphabetically takes priority.</p>
<p>Platform address symbols have an optional width. This can be used
to define multi-byte items, such as two-byte pointers or 256-byte stacks.
If no width is specified, a default value of 1 is used. Widths are ignored
for constants.
Overlapping symbols are resolved as described earlier, with symbols loaded
later taking priority over previously-loaded symbols. In addition,
symbols defined closer to the target address take priority, so if you put
a 4-byte symbol in the middle of a 256-byte symbol, the 4-byte symbol will
be visible because the start point is closer to the addresses it covers
than the start of the 256-byte range.</p>
<p><b>Project symbols</b> behave like platform symbols, but they are
defined in the project file itself. The editor will prevent you from

View File

@ -238,7 +238,8 @@ nearby labels for data loads and stores, adjusting them to fit
(e.g. <code>LDA LABEL+1</code>). If not enabled, labels are not applied
unless they match exactly. Note that references into the middle of an
instruction or formatted data area are always adjusted, regardless of
how this is set. This setting has no effect on local variables.</p>
how this is set. This setting has no effect on local variables, and
only enables a 1-byte backward search on project/platform symbols.</p>
<p>If "smart PLP handling" is checked, the analyzer will try to use
the processor status flags from a nearby <code>PHP</code> when a
<code>PLP</code> is encountered. If not enabled, all flags are set to

View File

@ -4,7 +4,7 @@
*SYNOPSIS Symbol set 1 for test 2021-external-symbols
; Platform symbols aren't applied to file data.
PlatStart @ $1000
CodeWrap @ $0f00 $1000 ;encases program
; SameName2 and SameName3 are replaced by later file
SameName1 @ $2000
@ -14,6 +14,9 @@ SameName3 @ $2020
; Symbols with the same values but different names are defined
; in later files. Names are chosen to not provide a strict
; alphabetical progression.
;
; These do not have widths, so we can check N+1 to confirm that it does
; not resolve to a symbol.
SameValA_C @ $2100
SameValB_B @ $2110
SameValC_A @ $2120
@ -45,5 +48,8 @@ SepOver2 @ $3102 4 ;$3102-3105, inclusive
; Test overlap with local variable. Declare at $41(2b).
OverVar @ $40 4
; Test bank wrap.
BankWrap @ $fff0 $20
; Width specifiers on constants should be ignored.
FatConst = $4000 8

View File

@ -1,17 +1,17 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":2,"FileDataLength":205,"FileDataCrc32":178586750,"ProjectProps":{
"_ContentVersion":2,"FileDataLength":222,"FileDataCrc32":-233099313,"ProjectProps":{
"CpuName":"6502","IncludeUndocumentedInstr":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{
"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":true},
"PlatformSymbolFileIdentifiers":["PROJ:2021-external-symbols-1.sym65","PROJ:2021-external-symbols-2.sym65","PROJ:2021-external-symbols-3.sym65"],"ExtensionScriptFileIdentifiers":[],"ProjectSyms":{
"ProjSim1":{
"ProjSym1":{
"DataDescriptor":{
"Length":4,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Comment":"","HasWidth":true,"Label":"ProjSim1","Value":8706,"Source":"Project","Type":"ExternalAddr"},
"ProjSim2":{
"Comment":"","HasWidth":true,"Label":"ProjSym1","Value":8706,"Source":"Project","Type":"ExternalAddr"},
"ProjSym2":{
"DataDescriptor":{
"Length":1,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Comment":"","HasWidth":true,"Label":"ProjSim2","Value":8714,"Source":"Project","Type":"ExternalAddr"}}},
"Comment":"","HasWidth":true,"Label":"ProjSym2","Value":8714,"Source":"Project","Type":"ExternalAddr"}}},
"AddressMap":[{
"Offset":0,"Addr":4096}],"TypeHints":[{
"Low":0,"High":0,"Hint":"Code"}],"StatusFlagOverrides":{
@ -25,11 +25,11 @@
"UserLabels":{
},
"OperandFormats":{
"195":{
"207":{
"Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
"Label":"FatConst","Part":"Low"}}},
"LvTables":{
"180":{
"192":{
"Variables":[{
"DataDescriptor":{
"Length":2,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},

View File

@ -1,6 +1,6 @@
.cpu "6502"
OverVar = $40
PlatStart = $1000
CodeWrap = $0f00 ;encases program
SameName1 = $2000
SameName2 = $2011
SameName3 = $2022
@ -8,9 +8,9 @@ SameValA_A = $2100
SameValB_A = $2110
SameValC_C = $2120
ChkProj1 = $2200
ProjSim1 = $2202
ProjSym1 = $2202
ChkProj2 = $2204
ProjSim2 = $220a
ProjSym2 = $220a
Over1 = $3000 ;$3000-300f, inclusive
Over2 = $3002 ;$3002-3009
Over2a = $3006 ;$3006
@ -18,11 +18,15 @@ Over3 = $3006 ;$3006-300c
SepOver1 = $3100 ;$3100-3103, inclusive
SepOver2 = $3102 ;$3102-3105, inclusive
FatConst = $4000
BankWrap = $fff0
* = $1000
L1000 lda PlatStart-1
L1000 lda CodeWrap+255
ldx L1000
ldy L1000+1
lda L10DD
lda CodeWrap+478
lda CodeWrap+485
nop
lda $1ffe
lda SameName1-1
@ -30,6 +34,7 @@ L1000 lda PlatStart-1
lda $200f
lda SameName2-1
lda SameName2
lda $2012
lda $201f
lda $2020
lda SameName3-1
@ -43,15 +48,15 @@ L1000 lda PlatStart-1
lda ChkProj1-1
lda ChkProj1
lda ChkProj1+1
lda ProjSim1
lda ProjSim1+1
lda ProjSim1+2
lda ProjSim1+3
lda ProjSym1
lda ProjSym1+1
lda ProjSym1+2
lda ProjSym1+3
lda ChkProj2+2
lda ChkProj2+3
lda $2208
lda ProjSim2-1
lda ProjSim2
lda ProjSym2-1
lda ProjSym2
lda $220b
nop
lda $2ffe
@ -96,5 +101,7 @@ LocalVar .var $41
lda FatConst-1
lda $4000
lda $4001
rts
lda BankWrap+8
lda <BankWrap-232
L10DD rts

View File

@ -1,5 +1,5 @@
OverVar equ $40
PlatStart equ $1000
CodeWrap equ $0f00 ;encases program
SameName1 equ $2000
SameName2 equ $2011
SameName3 equ $2022
@ -7,9 +7,9 @@ SameValA_A equ $2100
SameValB_A equ $2110
SameValC_C equ $2120
ChkProj1 equ $2200
ProjSim1 equ $2202
ProjSym1 equ $2202
ChkProj2 equ $2204
ProjSim2 equ $220a
ProjSym2 equ $220a
Over1 equ $3000 ;$3000-300f, inclusive
Over2 equ $3002 ;$3002-3009
Over2a equ $3006 ;$3006
@ -17,11 +17,15 @@ Over3 equ $3006 ;$3006-300c
SepOver1 equ $3100 ;$3100-3103, inclusive
SepOver2 equ $3102 ;$3102-3105, inclusive
FatConst equ $4000
BankWrap equ $fff0
org $1000
L1000 lda PlatStart-1
L1000 lda CodeWrap+255
ldx L1000
ldy L1000+1
lda L10DD
lda CodeWrap+478
lda CodeWrap+485
nop
lda $1ffe
lda SameName1-1
@ -29,6 +33,7 @@ L1000 lda PlatStart-1
lda $200f
lda SameName2-1
lda SameName2
lda $2012
lda $201f
lda $2020
lda SameName3-1
@ -42,15 +47,15 @@ L1000 lda PlatStart-1
lda ChkProj1-1
lda ChkProj1
lda ChkProj1+1
lda ProjSim1
lda ProjSim1+1
lda ProjSim1+2
lda ProjSim1+3
lda ProjSym1
lda ProjSym1+1
lda ProjSym1+2
lda ProjSym1+3
lda ChkProj2+2
lda ChkProj2+3
lda $2208
lda ProjSim2-1
lda ProjSim2
lda ProjSym2-1
lda ProjSym2
lda $220b
nop
lda $2ffe
@ -95,5 +100,7 @@ L1000 lda PlatStart-1
lda FatConst-1
lda $4000
lda $4001
rts
lda BankWrap+8
lda <BankWrap-65512
L10DD rts

View File

@ -1,6 +1,6 @@
!cpu 6502
OverVar = $40
PlatStart = $1000
CodeWrap = $0f00 ;encases program
SameName1 = $2000
SameName2 = $2011
SameName3 = $2022
@ -8,9 +8,9 @@ SameValA_A = $2100
SameValB_A = $2110
SameValC_C = $2120
ChkProj1 = $2200
ProjSim1 = $2202
ProjSym1 = $2202
ChkProj2 = $2204
ProjSim2 = $220a
ProjSym2 = $220a
Over1 = $3000 ;$3000-300f, inclusive
Over2 = $3002 ;$3002-3009
Over2a = $3006 ;$3006
@ -18,11 +18,15 @@ Over3 = $3006 ;$3006-300c
SepOver1 = $3100 ;$3100-3103, inclusive
SepOver2 = $3102 ;$3102-3105, inclusive
FatConst = $4000
BankWrap = $fff0
* = $1000
L1000 lda PlatStart-1
L1000 lda CodeWrap+255
ldx L1000
ldy L1000+1
lda L10DD
lda CodeWrap+478
lda CodeWrap+485
nop
lda $1ffe
lda SameName1-1
@ -30,6 +34,7 @@ L1000 lda PlatStart-1
lda $200f
lda SameName2-1
lda SameName2
lda $2012
lda $201f
lda $2020
lda SameName3-1
@ -43,15 +48,15 @@ L1000 lda PlatStart-1
lda ChkProj1-1
lda ChkProj1
lda ChkProj1+1
lda ProjSim1
lda ProjSim1+1
lda ProjSim1+2
lda ProjSim1+3
lda ProjSym1
lda ProjSym1+1
lda ProjSym1+2
lda ProjSym1+3
lda ChkProj2+2
lda ChkProj2+3
lda $2208
lda ProjSim2-1
lda ProjSim2
lda ProjSym2-1
lda ProjSym2
lda $220b
nop
lda $2ffe
@ -84,7 +89,7 @@ L1000 lda PlatStart-1
lda SepOver2+3
lda $3106
nop
!zone Z0000b4
!zone Z0000c0
.LocalVar = $41
ldx $3e
ldx OverVar-1
@ -97,5 +102,7 @@ L1000 lda PlatStart-1
lda FatConst-1
lda $4000
lda $4001
rts
lda BankWrap+8
lda <BankWrap-232
L10DD rts

View File

@ -1,6 +1,6 @@
.setcpu "6502"
OverVar = $40
PlatStart = $1000
CodeWrap = $0f00 ;encases program
SameName1 = $2000
SameName2 = $2011
SameName3 = $2022
@ -8,9 +8,9 @@ SameValA_A = $2100
SameValB_A = $2110
SameValC_C = $2120
ChkProj1 = $2200
ProjSim1 = $2202
ProjSym1 = $2202
ChkProj2 = $2204
ProjSim2 = $220a
ProjSym2 = $220a
Over1 = $3000 ;$3000-300f, inclusive
Over2 = $3002 ;$3002-3009
Over2a = $3006 ;$3006
@ -18,12 +18,16 @@ Over3 = $3006 ;$3006-300c
SepOver1 = $3100 ;$3100-3103, inclusive
SepOver2 = $3102 ;$3102-3105, inclusive
FatConst = $4000
BankWrap = $fff0
; .segment "SEG000"
.org $1000
L1000: lda PlatStart-1
L1000: lda CodeWrap+255
ldx L1000
ldy L1000+1
lda L10DD
lda CodeWrap+478
lda CodeWrap+485
nop
lda $1ffe
lda SameName1-1
@ -31,6 +35,7 @@ L1000: lda PlatStart-1
lda $200f
lda SameName2-1
lda SameName2
lda $2012
lda $201f
lda $2020
lda SameName3-1
@ -44,15 +49,15 @@ L1000: lda PlatStart-1
lda ChkProj1-1
lda ChkProj1
lda ChkProj1+1
lda ProjSim1
lda ProjSim1+1
lda ProjSim1+2
lda ProjSim1+3
lda ProjSym1
lda ProjSym1+1
lda ProjSym1+2
lda ProjSym1+3
lda ChkProj2+2
lda ChkProj2+3
lda $2208
lda ProjSim2-1
lda ProjSim2
lda ProjSym2-1
lda ProjSym2
lda $220b
nop
lda $2ffe
@ -97,5 +102,7 @@ LocalVar .set $41
lda FatConst-1
lda $4000
lda $4001
rts
lda BankWrap+8
lda <BankWrap-232
L10DD: rts

View File

@ -1,7 +1,7 @@
# 6502bench SourceGen generated linker script for 2021-external-symbols
MEMORY {
MAIN: file=%O, start=%S, size=65536;
# MEM000: file=%O, start=$1000, size=205;
# MEM000: file=%O, start=$1000, size=222;
}
SEGMENTS {
CODE: load=MAIN, type=rw;

View File

@ -9,23 +9,27 @@
; make sure platform symbols don't get set for file data
; DO NOT set a user label here
Start lda Start-1 ;PlatStart-1
ldx Start ;auto
ldy Start+1 ;auto+1
Start lda Start-1 ;CodeWrap+255
ldx Start ;(auto)
ldy Start+1 ;(auto+1)
lda END ;(auto)
lda END+1 ;CodeWrap+X
lda END+8 ;CodeWrap+Y
nop
; test overlapping labels (multiple sym files)
lda $1ffe ;should have no symbol
lda $1ffe ;(no sym)
lda $1fff ;should be SameName1-1
lda $2000 ;should be SameName1
lda $200f ;should have no symbol
lda $200f ;(no sym)
lda $2010 ;should be SameName2-1
lda $2011 ;should be SameName2
lda $2012 ;(no sym)
lda $201f ;should have no symbol
lda $2020 ;should have no symbol
lda $201f ;(no sym)
lda $2020 ;(no sym)
lda $2021 ;should be sym-1
lda $2022 ;should be SameName3
@ -40,7 +44,7 @@ Start lda Start-1 ;PlatStart-1
; test overlap with project symbol
; EDIT: define project symbols ProjSym1 at $2202(4b) and ProjSim2 at $220a(1b)
lda $21fe ;should have no symbol
lda $21fe ;(no sym)
lda $21ff ;SYM-1
lda $2200 ;ChkProj1
lda $2201 ;ChkProj1+1
@ -50,15 +54,15 @@ Start lda Start-1 ;PlatStart-1
lda $2205 ;ProjSym1+3
lda $2206 ;ChkProj2+2
lda $2207 ;ChkProj2+3
lda $2208 ;should have no symbol
lda $2208 ;(no sym)
lda $2209 ;ProjSym2-1
lda $220a ;ProjSym2
lda $220b ;should have no symbol
lda $220b ;(no sym)
nop
; test overlapping regions, single file
lda $2ffe ;should have no symbol
lda $2ffe ;(no sym)
lda $2fff ;Over1-1
lda $3000 ;Over1
lda $3001 ;Over1+1
@ -76,12 +80,12 @@ Start lda Start-1 ;PlatStart-1
lda $300d ;Over1+13
lda $300e ;Over1+14
lda $300f ;Over1+15
lda $3010 ;should have no symbol
lda $3010 ;(no sym)
nop
; test overlapping regions, multiple platform files
lda $30fe ;should have no symbol
lda $30fe ;(no sym)
lda $30ff ;SepOver1-1
lda $3100 ;SepOver1
lda $3101 ;SepOver1+1
@ -89,24 +93,28 @@ Start lda Start-1 ;PlatStart-1
lda $3103 ;SepOver1+3
lda $3104 ;SepOver2+2
lda $3105 ;SepOver2+3
lda $3106 ;should have no symbol
lda $3106 ;(no sym)
nop
; test overlap with local variable
; EDIT: create variable LocalVar at $41(2b)
ldx $3e ;should have no symbol
ldx $3e ;(no sym)
ldx $3f ;should be OverVar-1
ldx $40 ;should be OverVar
ldx $41 ;should be LocalVar
ldx $42 ;should be LocalVar+1
ldx $43 ;should be OverVar+3
ldx $44 ;should have no symbol
ldx $44 ;(no sym)
nop
lda $3fff ;EDIT: change to "FatConst"
lda $4000 ;should have no symbol
lda $4001 ;should have no symbol
lda $4000 ;(no sym)
lda $4001 ;(no sym)
rts
; test bank wrap
lda $fff8 ;should be BankWrap+8
lda $08 ;should be BankWrap+24 or <BankWrap-232
END rts

View File

@ -173,9 +173,11 @@ namespace SourceGen {
// we'd have to make sure that they didn't win for addresses outside the file
for (int i = 0; i < width; i++) {
// see if there's already something here
mSymbolsByAddress.TryGetValue(sym.Value + i, out Symbol curSym);
mSymbolsByAddress[sym.Value + i] = (curSym == null) ? sym :
// See if there's already something here. If we reach the end of the
// bank, wrap around.
int addr = (sym.Value & 0xff0000) + ((sym.Value + i) & 0xffff);
mSymbolsByAddress.TryGetValue(addr, out Symbol curSym);
mSymbolsByAddress[addr] = (curSym == null) ? sym :
HighestPriority(sym, curSym);
}
}
@ -205,6 +207,7 @@ namespace SourceGen {
// Same source, so this is e.g. two project symbol definitions that overlap. We
// handle this by selecting whichever one was defined closer to the target address,
// i.e. whichever one has the higher value.
// TODO(someday): this mishandles bank wrap... do we care?
if (sym1.Value > sym2.Value) {
return sym1;
} else if (sym1.Value < sym2.Value) {