mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-29 10:50:28 +00:00
Implement local variables for ACME
Unlike 64tass and Merlin, which allow you to redefine symbols, ACME uses "zones" that provide scope for local variables. This means that, at the point of a local variable table definition, we have to start a new zone and output the full set of active symbols, not just the newly-defined ones. (If you set the "clear previous" flag in the LvTable there's no difference.) We could do a bit better by only outputting the symbols that are actually used within the zone, similar to what we do for global project/platform symbols, but that's a bunch of work for questionable benefit.
This commit is contained in:
parent
c698048001
commit
d542a809f8
@ -188,6 +188,7 @@ namespace SourceGen.AsmGen {
|
||||
config.mForceDirectOperandPrefix = string.Empty;
|
||||
config.mForceAbsOperandPrefix = string.Empty;
|
||||
config.mForceLongOperandPrefix = string.Empty;
|
||||
config.mLocalVariableLablePrefix = ".";
|
||||
config.mEndOfLineCommentDelimiter = ";";
|
||||
config.mFullLineCommentDelimiterBase = ";";
|
||||
config.mBoxLineCommentDelimiter = ";";
|
||||
@ -472,8 +473,18 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
public void OutputVarDirective(string name, string valueStr, string comment) {
|
||||
OutputEquDirective(name, valueStr, comment);
|
||||
public void OutputLocalVariableTable(int offset, List<DefSymbol> newDefs,
|
||||
LocalVariableTable allDefs) {
|
||||
OutputLine(string.Empty, "!zone", "Z" + offset.ToString("x6"), string.Empty);
|
||||
for (int i = 0; i < allDefs.Count; i++) {
|
||||
DefSymbol defSym = allDefs[i];
|
||||
|
||||
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
|
||||
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
|
||||
PseudoOp.FormatNumericOpFlags.None);
|
||||
OutputEquDirective(SourceFormatter.FormatVariableLabel(defSym.Label),
|
||||
valueStr, defSym.Comment);
|
||||
}
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
|
@ -164,6 +164,8 @@ namespace SourceGen.AsmGen {
|
||||
// Special handling for forward references to zero-page labels is required.
|
||||
Quirks.SinglePassAssembler = true;
|
||||
|
||||
Quirks.NoRedefinableSymbols = true;
|
||||
|
||||
mWorkDirectory = workDirectory;
|
||||
mFileNameBase = fileNameBase;
|
||||
Settings = settings;
|
||||
@ -506,8 +508,16 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
public void OutputVarDirective(string name, string valueStr, string comment) {
|
||||
OutputEquDirective(name, valueStr, comment);
|
||||
public void OutputLocalVariableTable(int offset, List<DefSymbol> newDefs,
|
||||
LocalVariableTable allDefs) {
|
||||
foreach (DefSymbol defSym in newDefs) {
|
||||
// Use an operand length of 1 so values are shown as concisely as possible.
|
||||
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
|
||||
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
|
||||
PseudoOp.FormatNumericOpFlags.None);
|
||||
OutputEquDirective(SourceFormatter.FormatVariableLabel(defSym.Label),
|
||||
valueStr, defSym.Comment);
|
||||
}
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
|
@ -134,7 +134,6 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
Project = project;
|
||||
Quirks = new AssemblerQuirks();
|
||||
Quirks.HasRedefinableSymbols = true;
|
||||
Quirks.NoPcRelBankWrap = true;
|
||||
Quirks.TracksSepRepNotEmu = true;
|
||||
|
||||
@ -401,10 +400,16 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
public void OutputVarDirective(string name, string valueStr, string comment) {
|
||||
OutputLine(SourceFormatter.FormatVariableLabel(name),
|
||||
SourceFormatter.FormatPseudoOp(sDataOpNames.VarDirective),
|
||||
valueStr, SourceFormatter.FormatEolComment(comment));
|
||||
public void OutputLocalVariableTable(int offset, List<DefSymbol> newDefs,
|
||||
LocalVariableTable allDefs) {
|
||||
foreach (DefSymbol defSym in newDefs) {
|
||||
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
|
||||
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
|
||||
PseudoOp.FormatNumericOpFlags.None);
|
||||
OutputLine(SourceFormatter.FormatVariableLabel(defSym.Label),
|
||||
SourceFormatter.FormatPseudoOp(sDataOpNames.VarDirective),
|
||||
valueStr, SourceFormatter.FormatEolComment(defSym.Comment));
|
||||
}
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
|
@ -160,7 +160,6 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
Project = project;
|
||||
Quirks = new AssemblerQuirks();
|
||||
Quirks.HasRedefinableSymbols = true;
|
||||
Quirks.StackIntOperandIsImmediate = true;
|
||||
|
||||
mWorkDirectory = workDirectory;
|
||||
@ -538,9 +537,16 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
public void OutputVarDirective(string name, string valueStr, string comment) {
|
||||
OutputLine(name, SourceFormatter.FormatPseudoOp(sDataOpNames.VarDirective),
|
||||
valueStr, SourceFormatter.FormatEolComment(comment));
|
||||
public void OutputLocalVariableTable(int offset, List<DefSymbol> newDefs,
|
||||
LocalVariableTable allDefs) {
|
||||
foreach (DefSymbol defSym in newDefs) {
|
||||
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
|
||||
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
|
||||
PseudoOp.FormatNumericOpFlags.None);
|
||||
OutputLine(SourceFormatter.FormatVariableLabel(defSym.Label),
|
||||
SourceFormatter.FormatPseudoOp(sDataOpNames.VarDirective),
|
||||
valueStr, SourceFormatter.FormatEolComment(defSym.Comment));
|
||||
}
|
||||
}
|
||||
|
||||
// IGenerator
|
||||
|
@ -40,7 +40,7 @@ namespace SourceGen.AsmGen {
|
||||
bool doAddCycles = gen.Settings.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
|
||||
|
||||
LocalVariableLookup lvLookup = new LocalVariableLookup(proj.LvTables, proj,
|
||||
!gen.Quirks.HasRedefinableSymbols);
|
||||
gen.Quirks.NoRedefinableSymbols);
|
||||
|
||||
GenerateHeader(gen, sw);
|
||||
|
||||
@ -74,7 +74,9 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
List<DefSymbol> lvars = lvLookup.GetVariablesDefinedAtOffset(offset);
|
||||
if (lvars != null) {
|
||||
GenerateLocalVariables(gen, sw, lvars);
|
||||
// table defined here
|
||||
gen.OutputLocalVariableTable(offset, lvars,
|
||||
lvLookup.GetMergedTableAtOffset(offset));
|
||||
}
|
||||
|
||||
if (attr.IsInstructionStart) {
|
||||
@ -160,20 +162,6 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateLocalVariables(IGenerator gen, StreamWriter sw,
|
||||
List<DefSymbol> vars) {
|
||||
foreach (DefSymbol defSym in vars) {
|
||||
DisasmProject proj = gen.Project;
|
||||
Formatter formatter = gen.SourceFormatter;
|
||||
|
||||
// Use an operand length of 1 so values are shown as concisely as possible.
|
||||
string valueStr = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
|
||||
null, defSym.DataDescriptor, defSym.Value, 1,
|
||||
PseudoOp.FormatNumericOpFlags.None);
|
||||
gen.OutputVarDirective(defSym.Label, valueStr, defSym.Comment);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateInstruction(IGenerator gen, StreamWriter sw,
|
||||
LocalVariableLookup lvLookup, int offset, int instrBytes, bool doAddCycles) {
|
||||
DisasmProject proj = gen.Project;
|
||||
|
@ -137,12 +137,14 @@ namespace SourceGen.AsmGen {
|
||||
void OutputEquDirective(string name, string valueStr, string comment);
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a variable definition directive. The numeric value is already formatted.
|
||||
/// Outputs a series of local variable definitions.
|
||||
/// </summary>
|
||||
/// <param name="name">Symbol label.</param>
|
||||
/// <param name="valueStr">Formatted value.</param>
|
||||
/// <param name="comment">End-of-line comment.</param>
|
||||
void OutputVarDirective(string name, string valueStr, string comment);
|
||||
/// <param name="offset">Offset at which table is defined.</param>
|
||||
/// <param name="newDefs">New definitions, i.e. just the variables that were defined
|
||||
/// at this offset.</param>
|
||||
/// <param name="allDefs">All variable definitions that are active at this point.</param>
|
||||
void OutputLocalVariableTable(int offset, List<DefSymbol> newDefs,
|
||||
LocalVariableTable allDefs);
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a code origin directive.
|
||||
@ -200,7 +202,7 @@ namespace SourceGen.AsmGen {
|
||||
/// Does the assembler support a type of label whose value can be redefined to
|
||||
/// act as a local variable?
|
||||
/// </summary>
|
||||
public bool HasRedefinableSymbols { get; set; }
|
||||
public bool NoRedefinableSymbols { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is the assembler unable to generate relative branches that wrap around banks?
|
||||
|
@ -49,6 +49,20 @@ namespace SourceGen {
|
||||
///
|
||||
/// The BaseLabel does not change, but Label is updated by MakeUnique.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// LvLookup is run multiple times, and can be restarted in the middle of a run. It's
|
||||
/// essential that UniqueLabel behaves deterministically. For this to happen, the
|
||||
/// contents of SymbolTable can't change in a way that affects the outcome unless it
|
||||
/// also causes us to redo the uniquification. This mostly means that we have to be
|
||||
/// very careful about creating duplicate symbols, so that we don't get halfway through
|
||||
/// the analysis pass and invalidate our previous work. It's best to leave
|
||||
/// uniquification disabled until we're generating assembly source code.
|
||||
///
|
||||
/// The issues also make it hard to do the uniquification once, rather than every time we
|
||||
/// walk the code. Not all symbol changes cause a re-analysis (e.g. renaming a user
|
||||
/// label does not), and we don't want to fill the symbol table with the uniquified
|
||||
/// names because it could block user labels that would otherwise be valid.
|
||||
/// </remarks>
|
||||
private class UniqueLabel {
|
||||
public string BaseLabel { get; private set; }
|
||||
public string Label { get; private set; }
|
||||
@ -87,7 +101,7 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It's hard to do this as part of uniquification because the remapped base name ends
|
||||
/// up in the symbol table, and the uniqifier isn't able to tell that the entry in the
|
||||
/// up in the symbol table, and the uniquifier isn't able to tell that the entry in the
|
||||
/// symbol table is itself. The logic is simpler if we just rename the label before
|
||||
/// the uniquifier ever sees it.
|
||||
/// </remarks>
|
||||
|
@ -13,28 +13,42 @@ CONST_ZERO = $f0 ;project const
|
||||
ldx $04
|
||||
lda CONST_ZERO,S
|
||||
sta $f1,S
|
||||
VAR_ZERO = $00
|
||||
VAR_TWO = $02
|
||||
VAR_THREE = $03
|
||||
CONST_ZERO_VAR = $f0
|
||||
ldy VAR_ZERO
|
||||
lda (VAR_ZERO+1),y
|
||||
sta VAR_THREE
|
||||
!zone Z00000c
|
||||
.VAR_ZERO = $00
|
||||
.VAR_TWO = $02
|
||||
.VAR_THREE = $03
|
||||
.CONST_ZERO_VAR = $f0
|
||||
ldy .VAR_ZERO
|
||||
lda (.VAR_ZERO+1),y
|
||||
sta .VAR_THREE
|
||||
ldx $04
|
||||
lda CONST_ZERO_VAR,S
|
||||
lda .CONST_ZERO_VAR,S
|
||||
sta $f1,S
|
||||
eor 0
|
||||
ora 240,S
|
||||
PROJ_ZERO_DUP1 = $10 ;clash with project symbol
|
||||
DPCODE_DUP1 = $80 ;clash with user label
|
||||
lda VAR_ZERO
|
||||
lda VAR_ZERO+1
|
||||
lda VAR_TWO
|
||||
lda VAR_THREE
|
||||
!zone Z00001c
|
||||
.VAR_ZERO = $00
|
||||
.VAR_TWO = $02
|
||||
.VAR_THREE = $03
|
||||
.PROJ_ZERO_DUP1 = $10 ;clash with project symbol
|
||||
.DPCODE_DUP1 = $80 ;clash with user label
|
||||
.CONST_ZERO_VAR = $f0
|
||||
lda .VAR_ZERO
|
||||
lda .VAR_ZERO+1
|
||||
lda .VAR_TWO
|
||||
!zone Z000022
|
||||
.VAR_ZERO = $00
|
||||
.VAR_TWO = $02
|
||||
.VAR_THREE = $03
|
||||
.PROJ_ZERO_DUP1 = $10 ;clash with project symbol
|
||||
.DPCODE_DUP1 = $80 ;clash with user label
|
||||
.CONST_ZERO_VAR = $f0
|
||||
lda .VAR_THREE
|
||||
lda $04
|
||||
lda PROJ_ZERO_DUP1
|
||||
lda .PROJ_ZERO_DUP1
|
||||
lda $11
|
||||
lda+1 DPCODE
|
||||
!zone Z00002c
|
||||
ldx PROJ_ZERO
|
||||
ldx PROJ_ONE
|
||||
ldx $02
|
||||
@ -43,58 +57,131 @@ DPCODE_DUP1 = $80 ;clash with user label
|
||||
ldy PROJ_ONE
|
||||
ldy $02
|
||||
!byte $2c
|
||||
NH0 = $00 ;not hidden
|
||||
NH1 = $01 ;not hidden
|
||||
!zone Z00003c
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
L103C lda #$fe
|
||||
beq L103C
|
||||
ldy NH0
|
||||
ldy NH1
|
||||
ldy .NH0
|
||||
ldy .NH1
|
||||
ldy $02
|
||||
nop
|
||||
PTR0 = $10
|
||||
CONST0 = $10
|
||||
lda PTR0
|
||||
ldx PTR0+1
|
||||
!zone Z000047
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
lda .PTR0
|
||||
ldx .PTR0+1
|
||||
ldy $12
|
||||
lda (CONST0,S),y
|
||||
sta (CONST0+3,S),y
|
||||
lda (.CONST0,S),y
|
||||
sta (.CONST0+3,S),y
|
||||
;Test name redefinition. This is mostly of interest for assemblers without
|
||||
;redefinable variables, but also of interest to the cross-reference window.
|
||||
PTR = $20 ;#1
|
||||
ldx PTR
|
||||
PTR_3 = $22 ;#2
|
||||
ldx PTR_3
|
||||
PTR_4 = $24 ;#3
|
||||
ldx PTR_4
|
||||
!zone Z000051
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR = $20 ;#1
|
||||
ldx .PTR
|
||||
!zone Z000053
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR = $22 ;#2
|
||||
ldx .PTR
|
||||
!zone Z000055
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR = $24 ;#3
|
||||
ldx .PTR
|
||||
PTR_1 nop
|
||||
PTR_A = $20
|
||||
ldy PTR_A
|
||||
PTR_B = $1f
|
||||
ldy PTR_B+1
|
||||
PTR_C = $1d
|
||||
ldy PTR_C+3
|
||||
PTR_D = $21
|
||||
ldy PTR_C+3
|
||||
VAL0 = $30
|
||||
VAL1 = $31
|
||||
VAL2 = $32
|
||||
VAL3 = $33
|
||||
VAL4 = $34
|
||||
VAL5 = $35
|
||||
and VAL0
|
||||
and VAL1
|
||||
and VAL2
|
||||
and VAL3
|
||||
and VAL4
|
||||
and VAL5
|
||||
VAL14 = $31
|
||||
and VAL0
|
||||
and VAL14
|
||||
and VAL14+1
|
||||
and VAL14+2
|
||||
and VAL14+3
|
||||
and VAL5
|
||||
DPNOP = $80 ;same as org
|
||||
!zone Z000058
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR_A = $20
|
||||
.PTR = $24 ;#3
|
||||
ldy .PTR_A
|
||||
!zone Z00005a
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR_B = $1f
|
||||
.PTR = $24 ;#3
|
||||
ldy .PTR_B+1
|
||||
!zone Z00005c
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR_C = $1d
|
||||
.PTR = $24 ;#3
|
||||
ldy .PTR_C+3
|
||||
!zone Z00005e
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR_C = $1d
|
||||
.PTR_D = $21
|
||||
.PTR = $24 ;#3
|
||||
ldy .PTR_C+3
|
||||
!zone Z000060
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR_C = $1d
|
||||
.PTR_D = $21
|
||||
.PTR = $24 ;#3
|
||||
.VAL0 = $30
|
||||
.VAL1 = $31
|
||||
.VAL2 = $32
|
||||
.VAL3 = $33
|
||||
.VAL4 = $34
|
||||
.VAL5 = $35
|
||||
and .VAL0
|
||||
and .VAL1
|
||||
and .VAL2
|
||||
and .VAL3
|
||||
and .VAL4
|
||||
and .VAL5
|
||||
!zone Z00006c
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR_C = $1d
|
||||
.PTR_D = $21
|
||||
.PTR = $24 ;#3
|
||||
.VAL0 = $30
|
||||
.VAL14 = $31
|
||||
.VAL5 = $35
|
||||
and .VAL0
|
||||
and .VAL14
|
||||
and .VAL14+1
|
||||
and .VAL14+2
|
||||
and .VAL14+3
|
||||
and .VAL5
|
||||
!zone Z000078
|
||||
.NH0 = $00 ;not hidden
|
||||
.NH1 = $01 ;not hidden
|
||||
.PTR0 = $10
|
||||
.CONST0 = $10
|
||||
.PTR_C = $1d
|
||||
.PTR_D = $21
|
||||
.PTR = $24 ;#3
|
||||
.VAL0 = $30
|
||||
.VAL14 = $31
|
||||
.VAL5 = $35
|
||||
.DPNOP = $80 ;same as org
|
||||
lda+1 DPCODE
|
||||
jsr DPCODE
|
||||
rts
|
||||
|
Loading…
Reference in New Issue
Block a user