GAS now takes > modifier to force long addressing.
This commit is contained in:
parent
b6a6a5cdcc
commit
c9129f2a81
2 changed files with 40 additions and 12 deletions
|
|
@ -29,13 +29,14 @@ __start:
|
||||||
; NUL-terminated C string of the invocation command line.
|
; NUL-terminated C string of the invocation command line.
|
||||||
; Stash the cmdline pointer (Y:X) to bank-0 scratch $00:00B0..B3
|
; Stash the cmdline pointer (Y:X) to bank-0 scratch $00:00B0..B3
|
||||||
; and the user ID (A) to $00:00B6, BEFORE we switch to DP=0.
|
; and the user ID (A) to $00:00B6, BEFORE we switch to DP=0.
|
||||||
; Bank-explicit `sta long` so we don't depend on DP/DBR here.
|
; Bank-explicit `sta long` (force-long `>` prefix) so we don't depend
|
||||||
|
; on DP/DBR here.
|
||||||
rep #0x30
|
rep #0x30
|
||||||
.byte 0x8f, 0xb6, 0x00, 0x00 ; sta long $00:00B6 (user ID)
|
sta >$0000B6 ; sta long $00:00B6 (user ID)
|
||||||
tya
|
tya
|
||||||
.byte 0x8f, 0xb0, 0x00, 0x00 ; sta long $00:00B0 (cmdline low word = Y)
|
sta >$0000B0 ; sta long $00:00B0 (cmdline low word = Y)
|
||||||
txa
|
txa
|
||||||
.byte 0x8f, 0xb2, 0x00, 0x00 ; sta long $00:00B2 (cmdline high word = X)
|
sta >$0000B2 ; sta long $00:00B2 (cmdline high word = X)
|
||||||
|
|
||||||
; Set DBR := PBR (our entry-segment bank) — same Loader-contract
|
; Set DBR := PBR (our entry-segment bank) — same Loader-contract
|
||||||
; mitigation as crt0Gsos.s.
|
; mitigation as crt0Gsos.s.
|
||||||
|
|
@ -49,7 +50,7 @@ __start:
|
||||||
; GS/OS calls (see __gnoSaveDP / gsosWrite-under-GNO path).
|
; GS/OS calls (see __gnoSaveDP / gsosWrite-under-GNO path).
|
||||||
rep #0x30
|
rep #0x30
|
||||||
tdc ; A = current (GNO) DP
|
tdc ; A = current (GNO) DP
|
||||||
.byte 0x8f, 0xb4, 0x00, 0x00 ; sta long $00:00B4 (stash GNO DP word)
|
sta >$0000B4 ; sta long $00:00B4 (stash GNO DP word)
|
||||||
|
|
||||||
; Set DP=0 — backend assumes DP=0 for `sta dp` / `[dp],y` etc.
|
; Set DP=0 — backend assumes DP=0 for `sta dp` / `[dp],y` etc.
|
||||||
lda #0
|
lda #0
|
||||||
|
|
|
||||||
|
|
@ -93,14 +93,22 @@ class W65816Operand : public MCParsedAsmOperand {
|
||||||
|
|
||||||
SMLoc Start, End;
|
SMLoc Start, End;
|
||||||
|
|
||||||
|
// Set only for k_Addr operands carrying an explicit force-long prefix
|
||||||
|
// (`>expr`). When true the operand matches ONLY the 24-bit absolute-long
|
||||||
|
// addressing class (AddrLong), regardless of how small the value is, so a
|
||||||
|
// bank-explicit `sta >$000071` reaches STA_Long (0x8F) instead of being
|
||||||
|
// narrowed to STA_DP/STA_Abs by value fit.
|
||||||
|
bool ForceLong = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
W65816Operand(StringRef T, SMLoc S)
|
W65816Operand(StringRef T, SMLoc S)
|
||||||
: Kind(k_Tok), Tok({T.data(), (unsigned)T.size()}), Start(S),
|
: Kind(k_Tok), Tok({T.data(), (unsigned)T.size()}), Start(S),
|
||||||
End(SMLoc::getFromPointer(T.data() + T.size())) {}
|
End(SMLoc::getFromPointer(T.data() + T.size())) {}
|
||||||
W65816Operand(unsigned R, SMLoc S, SMLoc E)
|
W65816Operand(unsigned R, SMLoc S, SMLoc E)
|
||||||
: Kind(k_Reg), RegNum(R), Start(S), End(E) {}
|
: Kind(k_Reg), RegNum(R), Start(S), End(E) {}
|
||||||
W65816Operand(KindTy K, const MCExpr *E, SMLoc S, SMLoc E2)
|
W65816Operand(KindTy K, const MCExpr *E, SMLoc S, SMLoc E2,
|
||||||
: Kind(K), Start(S), End(E2) {
|
bool ForceLong = false)
|
||||||
|
: Kind(K), Start(S), End(E2), ForceLong(ForceLong) {
|
||||||
if (K == k_Imm)
|
if (K == k_Imm)
|
||||||
Imm = E;
|
Imm = E;
|
||||||
else
|
else
|
||||||
|
|
@ -124,8 +132,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<W65816Operand> createAddr(const MCExpr *Val, SMLoc S,
|
static std::unique_ptr<W65816Operand> createAddr(const MCExpr *Val, SMLoc S,
|
||||||
SMLoc E) {
|
SMLoc E,
|
||||||
return std::make_unique<W65816Operand>(k_Addr, Val, S, E);
|
bool ForceLong = false) {
|
||||||
|
return std::make_unique<W65816Operand>(k_Addr, Val, S, E, ForceLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MCParsedAsmOperand hooks ------------------------------------------
|
// --- MCParsedAsmOperand hooks ------------------------------------------
|
||||||
|
|
@ -189,15 +198,21 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAddrDP() const {
|
bool isAddrDP() const {
|
||||||
return Kind == k_Addr && isConstant(Addr) && constFitsUnsigned(Addr, 8);
|
return Kind == k_Addr && !ForceLong &&
|
||||||
|
isConstant(Addr) && constFitsUnsigned(Addr, 8);
|
||||||
}
|
}
|
||||||
bool isAddrAbs() const {
|
bool isAddrAbs() const {
|
||||||
return Kind == k_Addr &&
|
return Kind == k_Addr && !ForceLong &&
|
||||||
(!isConstant(Addr) || constFitsUnsigned(Addr, 16));
|
(!isConstant(Addr) || constFitsUnsigned(Addr, 16));
|
||||||
}
|
}
|
||||||
bool isAddrLong() const {
|
bool isAddrLong() const {
|
||||||
if (Kind != k_Addr)
|
if (Kind != k_Addr)
|
||||||
return false;
|
return false;
|
||||||
|
// Explicit `>expr` prefix forces the long form for any value that fits
|
||||||
|
// in 24 bits (or any symbol), and the narrower AddrDP/AddrAbs predicates
|
||||||
|
// above bail, so the matcher has only the long variant to pick.
|
||||||
|
if (ForceLong)
|
||||||
|
return !isConstant(Addr) || constFitsUnsigned(Addr, 24);
|
||||||
if (!isConstant(Addr))
|
if (!isConstant(Addr))
|
||||||
// Symbolic — accept; if a same-mnemonic narrower form exists (Abs)
|
// Symbolic — accept; if a same-mnemonic narrower form exists (Abs)
|
||||||
// the matcher will prefer it.
|
// the matcher will prefer it.
|
||||||
|
|
@ -590,6 +605,18 @@ bool W65816AsmParser::parseOperand(OperandVector &Operands) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force-long prefix: `>expr` selects the 24-bit absolute-long addressing
|
||||||
|
// form even when the value would otherwise fit in DP/abs. This is the only
|
||||||
|
// way to spell, e.g., a bank-explicit `sta >$000071` (opcode 0x8F) — the
|
||||||
|
// 65816 encodes width in the opcode, so without the prefix the matcher
|
||||||
|
// always narrows by value fit. ('>' lexes as AsmToken::Greater; it cannot
|
||||||
|
// begin an address expression, so consuming it here is unambiguous.)
|
||||||
|
bool ForceLong = false;
|
||||||
|
if (getLexer().is(AsmToken::Greater)) {
|
||||||
|
Parser.Lex(); // eat '>'
|
||||||
|
ForceLong = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Anything else is an address / branch-target / block-move byte. We
|
// Anything else is an address / branch-target / block-move byte. We
|
||||||
// rely on the standard LLVM asm expression parser, which accepts
|
// rely on the standard LLVM asm expression parser, which accepts
|
||||||
// identifiers (labels), decimal integers, hex ($... via MCAsmInfo
|
// identifiers (labels), decimal integers, hex ($... via MCAsmInfo
|
||||||
|
|
@ -599,7 +626,7 @@ bool W65816AsmParser::parseOperand(OperandVector &Operands) {
|
||||||
if (Parser.parseExpression(Val))
|
if (Parser.parseExpression(Val))
|
||||||
return Error(S, "expected expression");
|
return Error(S, "expected expression");
|
||||||
SMLoc E = getLexer().getLoc();
|
SMLoc E = getLexer().getLoc();
|
||||||
Operands.push_back(W65816Operand::createAddr(Val, S, E));
|
Operands.push_back(W65816Operand::createAddr(Val, S, E, ForceLong));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue