1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-12-03 05:49:48 +00:00

Fix 64tass code gen corner case

On the 65816, if you say "JSR foo" from bank $12, but "foo" is an
address in bank 0, most assemblers will conclude that you're forming
a 16-bit argument with a 16-bit address and assemble happily.  64tass
halts with an error.  Up until v1.55 or so, you could fake it out
by supplying a large offset.

This no longer works.  The preferred way to say "no really I mean to
do this" is to append ",k" to the operand.  We now do that as needed.

I didn't want to define a new ExpressionMode for 64tass just to
support an operand modifier that should probably never actually get
generated (you can't call across banks with JSR!), so this is
implemented with a quirk and an op flag.

64tass v1.56.2625 is now the default.

(issue #104)
This commit is contained in:
Andy McFadden 2021-08-09 13:47:04 -07:00
parent 19ba34760b
commit 478afa542e
14 changed files with 150 additions and 22 deletions

View File

@ -127,6 +127,7 @@ namespace SourceGen.AsmGen {
// Version we're coded against.
private static CommonUtil.Version V1_53 = new CommonUtil.Version(1, 53, 1515);
private static CommonUtil.Version V1_56 = new CommonUtil.Version(1, 56, 2625);
// Pseudo-op string constants.
private static PseudoOp.PseudoOpNames sDataOpNames =
@ -178,13 +179,14 @@ namespace SourceGen.AsmGen {
if (asmVersion != null) {
mAsmVersion = asmVersion.Version; // Use the actual version.
} else {
mAsmVersion = V1_53; // No assembler installed, use default.
mAsmVersion = V1_56; // No assembler installed, use default.
}
Quirks.StackIntOperandIsImmediate = true;
Quirks.LeadingUnderscoreSpecial = true;
Quirks.Need24BitsForAbsPBR = true;
Quirks.BitNumberIsArg = true;
Quirks.BankZeroAbsPBRRestrict = true;
mWorkDirectory = workDirectory;
mFileNameBase = fileNameBase;

View File

@ -215,7 +215,8 @@ namespace SourceGen.AsmGen {
string formattedOperand = null;
int operandLen = instrLen - 1;
PseudoOp.FormatNumericOpFlags opFlags = PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix;
PseudoOp.FormatNumericOpFlags opFlags =
PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix;
bool isPcRelBankWrap = false;
// Tweak branch instructions. We want to show the absolute address rather
@ -243,6 +244,11 @@ namespace SourceGen.AsmGen {
if (op.IsAbsolutePBR) {
opFlags |= PseudoOp.FormatNumericOpFlags.IsAbsolutePBR;
}
if (gen.Quirks.BankZeroAbsPBRRestrict) {
// Hack to avoid having to define a new FormatConfig.ExpressionMode for 64tass.
// Get rid of this 64tass gets its own exp mode.
opFlags |= PseudoOp.FormatNumericOpFlags.Is64Tass;
}
// 16-bit operands outside bank 0 need to include the bank when computing
// symbol adjustment.

View File

@ -207,6 +207,13 @@ namespace SourceGen.AsmGen {
/// Enumeration of quirky or buggy behavior that GenCommon needs to handle.
/// </summary>
public class AssemblerQuirks {
/// <summary>
/// Does the assembler require a qualifier to be added to the operand when an instruction
/// formed with the Program Bank Register (JMP/JSR) attempts to access a bank zero
/// address from outside bank zero?
/// </summary>
public bool BankZeroAbsPBRRestrict { get; set; }
/// <summary>
/// Does the assembler expect the bit index for BBR/BBS/RMB/SMB to be expressed as
/// a separate argument?

View File

@ -562,6 +562,7 @@ namespace SourceGen {
IsAbsolutePBR = 1 << 1, // operand implicitly uses 'K' on 65816 (JMP/JSR)
HasHashPrefix = 1 << 2, // operand has a leading '#', reducing ambiguity
OmitLabelPrefixSuffix = 1 << 3, // don't show annotation char or non-unique prefix
Is64Tass = 1 << 4, // hack to allow 64tass to keep using "common" exp
}
/// <summary>
@ -798,6 +799,7 @@ namespace SourceGen {
symbolValue &= 0xffff;
}
bool needCommaK = false;
if ((flags & FormatNumericOpFlags.IsAbsolutePBR) != 0) {
if ((operandValue & 0x00ff0000) == (symbolValue & 0x00ff0000)) {
// JMP or JSR to something within the same bank. We don't need to
@ -805,10 +807,16 @@ namespace SourceGen {
symbolValue &= 0xffff;
} else {
// This is an absolute JMP/JSR to an out-of-bank location, which is
// bogus and should probably be prevented at a higher level. We handle
// it by altering the mask so an adjustment that covers the difference
// in bank values is generated.
mask = 0x00ffffff;
// bogus and should probably be prevented at a higher level. Most
// assemblers are perfectly happy with this because we're passing a
// 16-bit argument to a 16-bit operation, but 64tass doesn't like it
// when you do this. We used to just alter the mask to generate a
// (potentially very large) offset, but 64tass stopped accepting that.
// The correct approach is to add ",k" to the operand.
//mask = 0x00ffffff;
if ((flags & FormatNumericOpFlags.Is64Tass) != 0) {
needCommaK = true;
}
}
}
@ -863,6 +871,10 @@ namespace SourceGen {
if (sb[0] == '(' && (flags & FormatNumericOpFlags.HasHashPrefix) == 0) {
sb.Insert(0, "0+");
}
if (needCommaK) {
sb.Append(",k");
}
} else {
Debug.Assert(false, "bad numeric len");
sb.Append("?????");

View File

@ -166,7 +166,7 @@ code, but also needs to know how to handle the corner cases.</p>
<h3><a name="64tass">64tass</a></h3>
<p>Tested versions: v1.53.1515, v1.54.1900
<p>Tested versions: v1.53.1515, v1.54.1900, v1.56.2625
<a href="https://sourceforge.net/projects/tass64/">[web site]</a></p>
<p>Bugs:</p>
@ -202,7 +202,9 @@ code, but also needs to know how to handle the corner cases.</p>
65816 Program Bank Register (16-bit JMP/JSR) must be specified
as 24-bit values for code that lives outside bank 0. This is
true for both symbols and raw hex (e.g. <code>JSR $1234</code>
is invalid outside bank 0).</li>
is invalid outside bank 0). Attempting to JSR to a label in bank
0 from outside bank 0 causes an error, even though it is technically
a 16-bit operand.</li>
<li>The arguments to COP and BRK require immediate-mode syntax
(<code>COP #$03</code> rather than <code>COP $03</code>).
<li>For historical reasons, the default behavior of the assembler is to

View File

@ -1,8 +1,8 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":4,
"FileDataLength":238,
"FileDataCrc32":2077431201,
"FileDataLength":266,
"FileDataCrc32":-1640516088,
"ProjectProps":{
"CpuName":"65816",
"IncludeUndocumentedInstr":false,
@ -264,6 +264,54 @@
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"skip",
"Part":"Low"}},
"233":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"skip",
"Part":"Low"}},
"236":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"skip",
"Part":"Low"}},
"239":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"skip",
"Part":"Low"}},
"242":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"skip",
"Part":"Low"}},
"245":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"skip",
"Part":"Low"}},
"250":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"skip",
"Part":"Low"}}},
"LvTables":{

View File

@ -107,7 +107,7 @@ fwdchk nop
nop
rts
L543280 jsr skip+$540000
L543280 jsr skip,k
nop
rep #$30
.al
@ -132,8 +132,20 @@ L543280 jsr skip+$540000
lda #$eaea
rep #$30
nop
jsr $54edcb
nop
lda skip
lda skip+20
jsr skip,k
jsr skip+20,k
jsr (skip,k,x)
bne _L5432B7
jmp (skip,k,x)
_L5432B7 jsr $54edcb
lda $edcb
bne _L5432C2
jmp ($54edcb,x)
_L5432C2 nop
rtl
.here

View File

@ -8,5 +8,6 @@
!hex 1632201732201832207d32207e32207f32eaa200fc1932fc7a32206e32207132
!hex 206832206b3220743220773280187c19327c7a326c08106c0810dc0810dc0810
!hex 7d3254eaea60200e20eac23008a90000e230a90028a9eaeae23008a900c230a9
!hex 000028a9eaeac230ea20cbedea6b
!hex 000028a9eaeac230eaad0e20ad2220200e20202220fc0e20d0037c0e2020cbed
!hex adcbedd0037ccbedea6b
} ;!pseudopc

View File

@ -134,7 +134,19 @@ L543280: jsr skip
lda #$eaea
rep #$30
nop
jsr $edcb
nop
lda skip
lda skip+20
jsr skip
jsr skip+20
jsr (skip,x)
bne @L5432B7
jmp (skip,x)
@L5432B7: jsr $edcb
lda $edcb
bne @L5432C2
jmp ($edcb,x)
@L5432C2: nop
rtl

View File

@ -5,7 +5,7 @@ MEMORY {
# MEM001: file=%O, start=$440000, size=28;
# MEM002: file=%O, start=$44ffc0, size=15;
# MEM003: file=%O, start=$2000, size=32;
# MEM004: file=%O, start=$543210, size=152;
# MEM004: file=%O, start=$543210, size=180;
}
SEGMENTS {
CODE: load=MAIN, type=rw;

View File

@ -123,7 +123,19 @@ L543280 jsr skip
lda #$eaea
rep #$30
nop
jsr $edcb
nop
lda skip
lda skip+20
jsr skip
jsr skip+20
jsr (skip,x)
bne :L5432B7
jmp (skip,x)
:L5432B7 jsr $edcb
lda $edcb
bne :L5432C2
jmp ($edcb,x)
:L5432C2 nop
rtl

View File

@ -6,7 +6,7 @@ NOTE: some tests may fail if you use a version of the assembler that is
different from the one used to generate the expected output. The current
set was generated for:
* 64tass v1.53.1515
* 64tass v1.56.2625
* ACME v0.97
* cc65 v2.18
* Merlin 32 v1.0

View File

@ -2,7 +2,7 @@
; See the LICENSE.txt file for distribution terms (Apache 2.0).
;
; Assembler: cc65
; (cl65 --target none -C <cfg>.cfg <src>.S)
; cl65 --target none -C 20052-branches-and-banks.cfg 20052-branches-and-banks.S
;
; For the 65816 we want to exercise some additional things.
@ -169,8 +169,22 @@ nxt54b:
.i16
nop
; try a 16-bit JSR with no symbol
; try some 16-bit stuff with and without symbols
lda skip ;EDIT: set these to "skip" label
lda skip+20
jsr skip
jsr skip+20
jsr (skip,X)
bne past1
jmp (skip,X)
past1:
; try a few without symbols
jsr $edcb
lda $edcb
bne past2
jmp ($edcb,X)
past2:
nop
rtl