1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-11-26 06:49:19 +00:00

Get 64tass expressions working

We now insert parenthesis as needed.  This can cause problems in
some situations, so we always prefix parenthetical expressions with
"0+", which looks goofy and is unnecessary for immediate operands.
But it does generate working source code.

Renamed the "simple" expression mode to "common", as it's not
particularly simple but is what you'd expect most assemblers to do.
(OTOH, life has been full of surprises.)

(issue #16)
This commit is contained in:
Andy McFadden 2018-10-24 14:57:09 -07:00
parent 61914c8f79
commit da91f86043
5 changed files with 268 additions and 30 deletions

View File

@ -81,12 +81,12 @@ namespace Asm65 {
public CharConvMode mHexDumpCharConvMode; // character conversion mode for dumps
// Hopefully we don't need a separate mode for every assembler in existence.
public enum ExpressionMode { Unknown = 0, Simple, Cc65, Merlin };
public enum ExpressionMode { Unknown = 0, Common, Cc65, Merlin };
public ExpressionMode mExpressionMode; // symbol rendering mode
// Deserialization helper.
public static ExpressionMode ParseExpressionMode(string str) {
ExpressionMode em = ExpressionMode.Simple;
ExpressionMode em = ExpressionMode.Common;
if (!string.IsNullOrEmpty(str)) {
if (Enum.TryParse<ExpressionMode>(str, out ExpressionMode pem)) {
em = pem;

View File

@ -185,7 +185,7 @@ namespace SourceGen.AsmGen {
config.mFullLineCommentDelimiterBase = ";";
config.mBoxLineCommentDelimiter = ";";
config.mAllowHighAsciiCharConst = false;
config.mExpressionMode = Formatter.FormatConfig.ExpressionMode.Simple;
config.mExpressionMode = Formatter.FormatConfig.ExpressionMode.Common;
}
// IGenerator

View File

@ -537,8 +537,8 @@ namespace SourceGen {
StringBuilder sb = new StringBuilder();
switch (formatter.ExpressionMode) {
case Formatter.FormatConfig.ExpressionMode.Simple:
FormatNumericSymbolSimple(formatter, sym, labelMap,
case Formatter.FormatConfig.ExpressionMode.Common:
FormatNumericSymbolCommon(formatter, sym, labelMap,
dfd, operandValue, operandLen, isPcRel, sb);
break;
case Formatter.FormatConfig.ExpressionMode.Cc65:
@ -568,7 +568,7 @@ namespace SourceGen {
/// <summary>
/// Format the symbol and adjustment using common expression syntax.
/// </summary>
private static void FormatNumericSymbolSimple(Formatter formatter, Symbol sym,
private static void FormatNumericSymbolCommon(Formatter formatter, Symbol sym,
Dictionary<string, string> labelMap, FormatDescriptor dfd,
int operandValue, int operandLen, bool isPcRel, StringBuilder sb) {
// We could have some simple code that generated correct output, shifting and
@ -584,7 +584,8 @@ namespace SourceGen {
}
if (operandLen == 1) {
// Use the byte-selection operator to get the right piece.
// Use the byte-selection operator to get the right piece. In 64tass the
// selection operator has a very low precedence, similar to Merlin 32.
string selOp;
if (dfd.SymbolRef.ValuePart == WeakSymbolRef.Part.Bank) {
symbolValue = (sym.Value >> 16) & 0xff;
@ -604,25 +605,36 @@ namespace SourceGen {
selOp = "<";
}
}
sb.Append(selOp);
sb.Append(symLabel);
operandValue &= 0xff;
if (operandValue != symbolValue &&
dfd.SymbolRef.ValuePart != WeakSymbolRef.Part.Low) {
// Adjustment is required to an upper-byte part.
sb.Append('(');
sb.Append(selOp);
sb.Append(symLabel);
sb.Append(')');
} else {
// no adjustment required
sb.Append(selOp);
sb.Append(symLabel);
}
} else if (operandLen <= 4) {
// Operands and values should be 8/16/24 bit unsigned quantities. 32-bit
// support is really there so you can have a 24-bit pointer in a 32-bit hole.
// Might need to adjust this if 32-bit signed quantities become interesting.
uint mask = 0xffffffff >> ((4 - operandLen) * 8);
string shOp;
int rightShift;
if (dfd.SymbolRef.ValuePart == WeakSymbolRef.Part.Bank) {
symbolValue = (sym.Value >> 16);
shOp = " >> 16";
rightShift = 16;
} else if (dfd.SymbolRef.ValuePart == WeakSymbolRef.Part.High) {
symbolValue = (sym.Value >> 8);
shOp = " >> 8";
rightShift = 8;
} else {
symbolValue = sym.Value;
shOp = "";
rightShift = 0;
}
if (isPcRel) {
@ -634,20 +646,41 @@ namespace SourceGen {
symbolValue &= 0xffff;
}
sb.Append(symLabel);
sb.Append(shOp);
bool needMask = false;
if (symbolValue > mask) {
// Post-shift value won't fit in an operand-size box.
symbolValue = (int) (symbolValue & mask);
sb.Append(" & ");
sb.Append(formatter.FormatHexValue((int)mask, 2));
}
if (sb.Length != symLabel.Length) {
sb.Append(' ');
needMask = true;
}
operandValue = (int)(operandValue & mask);
// Generate one of:
// label [+ adj]
// (label >> rightShift) [+ adj]
// (label & mask) [+ adj]
// ((label >> rightShift) & mask) [+ adj]
if (rightShift != 0 || needMask) {
if (rightShift != 0 && needMask) {
sb.Append("0+((");
} else {
sb.Append("0+(");
}
}
sb.Append(symLabel);
if (rightShift != 0) {
sb.Append(" >> ");
sb.Append(rightShift.ToString());
sb.Append(')');
}
if (needMask) {
sb.Append(" & ");
sb.Append(formatter.FormatHexValue((int)mask, 2));
sb.Append(')');
}
} else {
Debug.Assert(false, "bad numeric len");
sb.Append("?????");
@ -704,9 +737,6 @@ namespace SourceGen {
operandValue &= 0xff;
} else if (operandLen <= 4) {
// Operands and values should be 8/16/24 bit unsigned quantities. 32-bit
// support is really there so you can have a 24-bit pointer in a 32-bit hole.
// Might need to adjust this if 32-bit signed quantities become interesting.
uint mask = 0xffffffff >> ((4 - operandLen) * 8);
string shOp;
if (dfd.SymbolRef.ValuePart == WeakSymbolRef.Part.Bank) {
@ -737,12 +767,11 @@ namespace SourceGen {
sb.Append(" & ");
sb.Append(formatter.FormatHexValue((int)mask, 2));
}
operandValue = (int)(operandValue & mask);
if (sb.Length != symLabel.Length) {
sb.Append(' ');
}
operandValue = (int)(operandValue & mask);
} else {
Debug.Assert(false, "bad numeric len");
sb.Append("?????");

View File

@ -0,0 +1,209 @@
;Project was edited to add a label in the middle of a dense hex region, and add
;a duplicate label.
.cpu "65816"
zip = $cd
absl = $1029
plataddr = $3000 ;address only in platform file
projalsa = $3200 ;same val as projalso
absh = $feed
biggie = $123456
thirty2 = $12345678 ;32-bit constant test
* = $012345
.as
.xs
start clc
xce
sep #$30
lda #zip
lda #zip+16
lda #zip-192
lda #<absh
lda #>absh
lda #<absh-192
lda #(>absh)+1
lda #<absl
lda #>absl
lda #<absl+192
lda #(>absl)-1
lda #<start
lda #>start
lda #`start
pea $feed
pea 0+(start & $ffff)
pea $0001
pea $3456
pea $0012
pea absh
pea 0+(start & $ffff)
pea 0+(start >> 16)
pea 0+(biggie & $ffff)
pea 0+(biggie >> 16)
lda zip+1
lda @wzip+1
lda @lzip+1
lda absh-1
lda @labsh-1
lda absh+1
lda @labsh+1
lda 0+(start & $ffff)+1
lda start+1
lda 0+(start & $ffff)-1
lda start-1
lda 0+(biggie & $ffff)+1
lda biggie+1
lda 0+(biggie & $ffff)-1
lda biggie-1
rep #$30
.al
.xl
lda #zip
lda #zip+16
lda #zip+64
lda #absl
lda #0+(absl >> 8)
lda #absl-4096
lda #0+(absl >> 8)-16
lda #0+(absl >> 16)
lda #absh
lda #0+(absh >> 8)
lda #absh-61440
lda #0+(absh >> 8)+16
lda #0+(absh >> 16)+1
lda #0+(start & $ffff)
lda #0+(start >> 8)
lda #0+(start >> 16)
lda #0+(biggie & $ffff)
lda #0+(biggie >> 8)
lda #0+(biggie >> 16)
bra skipdata
.byte zip
.byte <absh
.byte >absh
.byte <start
.byte >start
.byte `start
.word zip
.word absl
.word 0+(absl >> 8)
.word absl-4096
.word 0+(absl >> 8)-16
.word absh
.word 0+(absh >> 8)
.word absh-61440
.word 0+(absh >> 8)+16
.word 0+(start & $ffff)
.word 0+(start >> 8)
.word 0+(start >> 16)
.word 0+(start & $ffff)+1
.word 0+(start >> 8)
.word 0+(start >> 16)
.byte $fe,$ed
.long zip
.long absh
.long 0+(absh >> 8)
.long start
.long 0+(start >> 8)
.long 0+(start >> 16)
.dword zip
.dword absh
.dword 0+(absh >> 8)
.dword start-1
.dword 0+(start >> 8)
.dword 0+(start >> 16)
skipdata lda #0+(biggie >> 16)-1
mvn `biggie,(`biggie)-17
mvp `start,(`start)+17
mvn 18,1
mvp %00000001,%00010010
per skipdata
brl nextchunk
nextchunk jml L1000_1
.logical $1000
L1000_1 nop
L1000 nop
L1000_0 nop
l1000 sep #$30
.as
.xs
lda plataddr
lda $3100
lda projalsa
lda $3300
bra calls
nop
targ nop
nop
L1016 per targ-1
per targ
per targ+1
jsr targ-1
jsr targ
jsr targ+1
L1028 bra targ-1
L102A bra targ
L102C bra targ+1
L102E brl targ-1
L1031 brl targ
L1034 brl targ+1
L1037 jmp targ-1
L103A jmp targ
L103D jmp targ+1
L1040 jml targ-1
jml targ
jml targ+1
calls jsr L1016
jsr L1028
jsr L102A
jsr L102C
jsr L102E
jsr L1031
jsr L1034
jsr L1037
jsr L103A
jsr L103D
jsr L1040
jsr $1044
jsr $1048
brl L118E
bulk .byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f ;bulky
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
string .text "This is a long string. Put a label and comment on it to confir" ;stringy
.text "m that the label and comment only appear on the first line. T"
.text "he quick brown fox jumps over the lazy dogs."
L118E lda #<thirty2+2
lda #(>thirty2)+3
lda #`thirty2
rep #$30
.al
.xl
lda #0+(thirty2 & $ffff)+3
lda #0+((thirty2 >> 8) & $ffff)+4
lda #0+(thirty2 >> 16)
rts
.here

View File

@ -40,14 +40,14 @@ LFFC3 brl L0003
.logical $440000
L440000 cmp L440000
L440004 lda L440000
lda @wL440000 & $ffff
lda @w0+(L440000 & $ffff)
lda L0000
bmi L440004
per high44
bne high44
brl L44FFC0
dat44 .word dat44 & $ffff
dat44 .word 0+(dat44 & $ffff)
.long dat44
.here
@ -62,8 +62,8 @@ L44FFCB jml L2000
.here
.logical $2000
L2000 bit L2000
pea dat44 & $ffff
pea dat44 >> 16
pea 0+(dat44 & $ffff)
pea 0+(dat44 >> 16)
bne L200E
jml [lodat]