mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-29 10:50:28 +00:00
Remap labels that use opcode mnemonics
In a recent survey, three out of four cross assemblers surveyed recommended not using opcode mnemonics to their patients who use labels. We now remap labels like "AND" and "jmp", using the label map that's part of the label localizer. We skip the step for Merlin 32, which is perfectly happy to assemble "JMP JMP JMP". Also, fixed a bug in MaskLeadingUnderscores that could hang the source generator thread.
This commit is contained in:
parent
b74630dd5b
commit
824add17e8
@ -227,7 +227,7 @@ namespace Asm65 {
|
||||
/// Returns an entry from the OpDef array for the specified opcode, 0-255. (We could
|
||||
/// probably just make this the class indexer.)
|
||||
/// </summary>
|
||||
/// <param name="op">Instruction opcode</param>
|
||||
/// <param name="op">Instruction opcode number (0-255).</param>
|
||||
/// <returns>Instruction definition.</returns>
|
||||
public OpDef GetOpDef(int op) { return mOpDefs[op]; }
|
||||
|
||||
|
@ -222,6 +222,7 @@ namespace SourceGen.AsmGen {
|
||||
mLocalizer.LocalPrefix = "@";
|
||||
mLocalizer.Analyze();
|
||||
}
|
||||
mLocalizer.FixOpcodeLabels();
|
||||
|
||||
// Use UTF-8 encoding, without a byte-order mark.
|
||||
using (StreamWriter sw = new StreamWriter(pathName, false, new UTF8Encoding(false))) {
|
||||
|
@ -220,6 +220,7 @@ namespace SourceGen.AsmGen {
|
||||
mLocalizer.QuirkVariablesEndScope = true;
|
||||
mLocalizer.Analyze();
|
||||
}
|
||||
mLocalizer.FixOpcodeLabels();
|
||||
|
||||
// Use UTF-8 encoding, without a byte-order mark.
|
||||
using (StreamWriter sw = new StreamWriter(cfgName, false, new UTF8Encoding(false))) {
|
||||
|
@ -191,6 +191,7 @@ namespace SourceGen.AsmGen {
|
||||
mLocalizer.LocalPrefix = ":";
|
||||
mLocalizer.Analyze();
|
||||
}
|
||||
//mLocalizer.FixOpcodeLabels();
|
||||
|
||||
// Use UTF-8 encoding, without a byte-order mark.
|
||||
using (StreamWriter sw = new StreamWriter(pathName, false, new UTF8Encoding(false))) {
|
||||
|
@ -231,6 +231,7 @@ namespace SourceGen.AsmGen {
|
||||
mLocalizer.Analyze();
|
||||
}
|
||||
mLocalizer.MaskLeadingUnderscores();
|
||||
mLocalizer.FixOpcodeLabels();
|
||||
|
||||
// Use UTF-8 encoding, without a byte-order mark.
|
||||
using (StreamWriter sw = new StreamWriter(pathName, false, new UTF8Encoding(false))) {
|
||||
|
@ -332,11 +332,12 @@ namespace SourceGen.AsmGen {
|
||||
/// This is necessary for assemblers like 64tass that use a leading underscore to
|
||||
/// indicate that a label should be local.
|
||||
///
|
||||
/// This may be called even if label localization is disabled. In that case we just
|
||||
/// create an empty label map and populate as needed.
|
||||
///
|
||||
/// Only call this if underscores are used to indicate local labels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This may be called even if label localization is disabled. In that case we just
|
||||
/// create an empty label map and populate as needed.
|
||||
/// </remarks>
|
||||
public void MaskLeadingUnderscores() {
|
||||
bool allGlobal = false;
|
||||
if (LabelMap == null) {
|
||||
@ -383,8 +384,9 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
// Make sure it's unique.
|
||||
string uniqueLabel = newLabel;
|
||||
int uval = 1;
|
||||
int uval = 0;
|
||||
while (allLabels.ContainsKey(uniqueLabel)) {
|
||||
uval++;
|
||||
uniqueLabel = newLabel + uval.ToString();
|
||||
}
|
||||
allLabels.Add(uniqueLabel, uniqueLabel);
|
||||
@ -397,5 +399,91 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
Debug.WriteLine("UMAP: allcount=" + allLabels.Count + " mapcount=" + LabelMap.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remaps labels that match opcode names. Updated names will be added to LabelMap.
|
||||
/// This should be run after localization and underscore concealment have finished.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Most assemblers don't like it if you create a label with the same name as an
|
||||
/// opcode, e.g. "jmp LSR" doesn't work. We can use the label map to work around
|
||||
/// the issue.
|
||||
///
|
||||
/// Most assemblers regard mnemonics as case-insensitive, even if labels are
|
||||
/// case-sensitive, so we want to remap both "lsr" and "LSR".
|
||||
///
|
||||
/// This doesn't really have anything to do with label localization other than that
|
||||
/// we're updating the label remap table.
|
||||
/// </remarks>
|
||||
public void FixOpcodeLabels() {
|
||||
if (LabelMap == null) {
|
||||
LabelMap = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
// Create a searchable list of opcode names using the current CPU definition.
|
||||
// (All tested assemblers that failed on opcode names only did so for names
|
||||
// that were part of the current definition, e.g. "TSB" was accepted as a label
|
||||
// when the CPU was set to 6502.)
|
||||
Dictionary<string, Asm65.OpDef> opnames = new Dictionary<string, Asm65.OpDef>();
|
||||
Asm65.CpuDef cpuDef = mProject.CpuDef;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
Asm65.OpDef op = cpuDef.GetOpDef(i);
|
||||
// There may be multiple entries with the same name (e.g. "NOP"). That's fine.
|
||||
opnames[op.Mnemonic.ToUpperInvariant()] = op;
|
||||
}
|
||||
|
||||
// Create a list of all labels, for uniqueness testing. If a label has been
|
||||
// remapped, we add the remapped entry.
|
||||
// (All tested assemblers that failed on opcode names only did so for names
|
||||
// in their non-localized form. While "LSR" failed, "@LSR", "_LSR", ".LSR", etc.
|
||||
// were accepted. So if it was remapped by the localizer, we don't need to
|
||||
// worry about it.)
|
||||
SortedList<string, string> allLabels = new SortedList<string, string>();
|
||||
for (int i = 0; i < mProject.FileDataLength; i++) {
|
||||
Symbol sym = mProject.GetAnattrib(i).Symbol;
|
||||
if (sym == null) {
|
||||
continue;
|
||||
}
|
||||
LabelMap.TryGetValue(sym.Label, out string mapLabel);
|
||||
if (mapLabel != null) {
|
||||
allLabels.Add(mapLabel, mapLabel);
|
||||
} else {
|
||||
allLabels.Add(sym.Label, sym.Label);
|
||||
}
|
||||
}
|
||||
|
||||
// Now run through the list of labels, looking for any that match opcode
|
||||
// mnemonics.
|
||||
for (int i = 0; i < mProject.FileDataLength; i++) {
|
||||
Symbol sym = mProject.GetAnattrib(i).Symbol;
|
||||
if (sym == null) {
|
||||
// No label at this offset.
|
||||
continue;
|
||||
}
|
||||
string cmpLabel = sym.Label;
|
||||
if (LabelMap.TryGetValue(sym.Label, out string mapLabel)) {
|
||||
cmpLabel = mapLabel;
|
||||
}
|
||||
|
||||
if (opnames.ContainsKey(cmpLabel.ToUpperInvariant())) {
|
||||
//Debug.WriteLine("Remapping label (op mnemonic): " + sym.Label);
|
||||
|
||||
int uval = 0;
|
||||
string uniqueLabel;
|
||||
do {
|
||||
uval++;
|
||||
uniqueLabel = cmpLabel + "_" + uval.ToString();
|
||||
} while (allLabels.ContainsKey(uniqueLabel));
|
||||
|
||||
allLabels.Add(uniqueLabel, uniqueLabel);
|
||||
LabelMap.Add(sym.Label, uniqueLabel);
|
||||
}
|
||||
}
|
||||
|
||||
if (LabelMap.Count == 0) {
|
||||
// didn't do anything, lose the table
|
||||
LabelMap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@ -1,8 +1,8 @@
|
||||
### 6502bench SourceGen dis65 v1.0 ###
|
||||
{
|
||||
"_ContentVersion":1,"FileDataLength":87,"FileDataCrc32":255194945,"ProjectProps":{
|
||||
"CpuName":"65816","IncludeUndocumentedInstr":false,"EntryFlags":32702671,"AnalysisParams":{
|
||||
"AnalyzeUncategorizedData":true,"MinCharsForString":4,"SeekNearbyTargets":true},
|
||||
"_ContentVersion":2,"FileDataLength":103,"FileDataCrc32":1381810255,"ProjectProps":{
|
||||
"CpuName":"65C02","IncludeUndocumentedInstr":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{
|
||||
"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":true},
|
||||
"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":[],"ProjectSyms":{
|
||||
"__ENABLE_LABEL_LOCALIZATION":{
|
||||
"DataDescriptor":{
|
||||
@ -21,7 +21,7 @@
|
||||
"Low":0,"High":0,"Hint":"Code"}],"StatusFlagOverrides":{
|
||||
},
|
||||
"Comments":{
|
||||
},
|
||||
"92":"local","94":"global"},
|
||||
"LongComments":{
|
||||
},
|
||||
"Notes":{
|
||||
@ -64,7 +64,25 @@
|
||||
"14":{
|
||||
"Label":"__nopped","Value":4110,"Source":"User","Type":"LocalOrGlobalAddr"},
|
||||
"13":{
|
||||
"Label":"start","Value":4109,"Source":"User","Type":"LocalOrGlobalAddr"}},
|
||||
"Label":"start","Value":4109,"Source":"User","Type":"LocalOrGlobalAddr"},
|
||||
"86":{
|
||||
"Label":"_uname","Value":4182,"Source":"User","Type":"LocalOrGlobalAddr"},
|
||||
"87":{
|
||||
"Label":"X_uname11","Value":4183,"Source":"User","Type":"LocalOrGlobalAddr"},
|
||||
"88":{
|
||||
"Label":"X_uname1","Value":4184,"Source":"User","Type":"LocalOrGlobalAddr"},
|
||||
"92":{
|
||||
"Label":"AND","Value":4188,"Source":"User","Type":"LocalOrGlobalAddr"},
|
||||
"94":{
|
||||
"Label":"JMP","Value":4190,"Source":"User","Type":"GlobalAddr"},
|
||||
"96":{
|
||||
"Label":"jmp","Value":4192,"Source":"User","Type":"GlobalAddr"},
|
||||
"98":{
|
||||
"Label":"TSB","Value":4194,"Source":"User","Type":"GlobalAddr"},
|
||||
"89":{
|
||||
"Label":"X_uname","Value":4185,"Source":"User","Type":"LocalOrGlobalAddr"},
|
||||
"100":{
|
||||
"Label":"XCE","Value":4196,"Source":"User","Type":"GlobalAddr"}},
|
||||
"OperandFormats":{
|
||||
"23":{
|
||||
"Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
|
||||
@ -76,4 +94,6 @@
|
||||
"Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
|
||||
"Label":"_reach4","Part":"Low"}},
|
||||
"58":{
|
||||
"Length":3,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}}}
|
||||
"Length":3,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}},
|
||||
"LvTables":{
|
||||
}}
|
||||
|
@ -1,9 +1,7 @@
|
||||
.cpu "65816"
|
||||
.cpu "65c02"
|
||||
REALLYLONGLABELNAME = $8888 ;that's a long name
|
||||
|
||||
* = $1000
|
||||
.as
|
||||
.xs
|
||||
nop
|
||||
X_start lda _start
|
||||
lda X_start1
|
||||
@ -56,5 +54,19 @@ globlat jsr nglobal
|
||||
end nop
|
||||
EXCESSIVELY_LONG_LABEL
|
||||
lda REALLYLONGLABELNAME
|
||||
_X_uname
|
||||
nop
|
||||
_X_uname11
|
||||
nop
|
||||
_X_uname1
|
||||
nop
|
||||
_X_uname2
|
||||
nop
|
||||
lda #$00
|
||||
_AND bne _AND ;local
|
||||
JMP_1 bne JMP_1 ;global
|
||||
jmp_1 bne jmp_1
|
||||
TSB_1 bne TSB_1
|
||||
XCE bne XCE
|
||||
rts
|
||||
|
||||
|
@ -49,5 +49,17 @@ globlat jsr nglobal
|
||||
end nop
|
||||
EXCESSIVELY_LONG_LABEL
|
||||
lda REALLYLONGLABELNAME
|
||||
:_uname nop
|
||||
:X_uname11
|
||||
nop
|
||||
:X_uname1
|
||||
nop
|
||||
:X_uname nop
|
||||
lda #$00
|
||||
:AND bne :AND ;local
|
||||
JMP bne JMP ;global
|
||||
jmp bne jmp
|
||||
TSB bne TSB
|
||||
XCE bne XCE
|
||||
rts
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
!cpu 65816
|
||||
!cpu 65c02
|
||||
REALLYLONGLABELNAME = $8888 ;that's a long name
|
||||
|
||||
* = $1000
|
||||
!as
|
||||
!rs
|
||||
nop
|
||||
_start lda @start
|
||||
lda X_start
|
||||
@ -55,5 +53,18 @@ globlat jsr nglobal
|
||||
end nop
|
||||
EXCESSIVELY_LONG_LABEL
|
||||
lda REALLYLONGLABELNAME
|
||||
@_uname nop
|
||||
@X_uname11
|
||||
nop
|
||||
@X_uname1
|
||||
nop
|
||||
@X_uname
|
||||
nop
|
||||
lda #$00
|
||||
@AND bne @AND ;local
|
||||
JMP_1 bne JMP_1 ;global
|
||||
jmp_1 bne jmp_1
|
||||
TSB_1 bne TSB_1
|
||||
XCE bne XCE
|
||||
rts
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
.setcpu "65816"
|
||||
.setcpu "65C02"
|
||||
REALLYLONGLABELNAME = $8888 ;that's a long name
|
||||
|
||||
; .segment "SEG000"
|
||||
.org $1000
|
||||
.a8
|
||||
.i8
|
||||
nop
|
||||
_start: lda @start
|
||||
lda X_start
|
||||
@ -56,5 +54,18 @@ globlat: jsr nglobal
|
||||
end: nop
|
||||
EXCESSIVELY_LONG_LABEL:
|
||||
lda REALLYLONGLABELNAME
|
||||
@_uname: nop
|
||||
@X_uname11:
|
||||
nop
|
||||
@X_uname1:
|
||||
nop
|
||||
@X_uname:
|
||||
nop
|
||||
lda #$00
|
||||
@AND: bne @AND ;local
|
||||
JMP_1: bne JMP_1 ;global
|
||||
jmp_1: bne jmp_1
|
||||
TSB_1: bne TSB_1
|
||||
XCE: bne XCE
|
||||
rts
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# 6502bench SourceGen generated linker script for 2012-label-localizer
|
||||
MEMORY {
|
||||
MAIN: file=%O, start=%S, size=65536;
|
||||
# MEM000: file=%O, start=$1000, size=87;
|
||||
# MEM000: file=%O, start=$1000, size=103;
|
||||
}
|
||||
SEGMENTS {
|
||||
CODE: load=MAIN, type=rw;
|
||||
|
@ -3,6 +3,8 @@
|
||||
;
|
||||
; Assembler: Merlin 32
|
||||
|
||||
; NOTE: select CPU=65C02
|
||||
|
||||
EXTSYM equ $8888 ;EDIT: give this a long label
|
||||
|
||||
org $1000
|
||||
@ -62,4 +64,20 @@ globlat jsr nglobal ;EDIT: mark label as global
|
||||
bra cont
|
||||
cont nop ;EDIT: mark label as global
|
||||
lda EXTSYM
|
||||
|
||||
; test localizer uniquification
|
||||
; only relevant for 64tass, which uses a leading '_' to indicate local labels
|
||||
_uname nop
|
||||
X_uname11 nop
|
||||
X_uname1 nop
|
||||
X_uname nop
|
||||
|
||||
; test labels with opcode names (not really a localization thing)
|
||||
; EDIT: set these names, mark as global to prevent localization
|
||||
lda #$00
|
||||
ANDl bne ANDl ;leave label local
|
||||
JMPg bne JMPg ;make label global
|
||||
jmpg bne jmpg ;lower case name
|
||||
TSBg bne TSBg
|
||||
XCEg bne XCEg ;should be allowed
|
||||
rts
|
||||
|
Loading…
Reference in New Issue
Block a user