From ac2ecb0b2ca84c579eb4f6eba66ba46512e58700 Mon Sep 17 00:00:00 2001 From: bbbradsmith Date: Wed, 1 May 2019 02:12:03 -0400 Subject: [PATCH] 65816 now generate EXPR_NEARADDR instead of EXPR_WORD0 for default assumed address mode, which will be validated by the linker's range check rather than blindly truncated. Assuming the assembler correctly validated this, the linker is allowed to truncate. --- src/ca65/expr.c | 22 ++++++++++++++++++++++ src/ca65/expr.h | 3 +++ src/ca65/instr.c | 2 +- src/ca65/studyexpr.c | 24 ++++++++++++++++++++++++ src/common/exprdefs.c | 4 ++++ src/common/exprdefs.h | 5 +++-- src/ld65/expr.c | 4 ++++ 7 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/ca65/expr.c b/src/ca65/expr.c index 982bb05c6..8703b2a55 100644 --- a/src/ca65/expr.c +++ b/src/ca65/expr.c @@ -1865,6 +1865,28 @@ ExprNode* GenWordExpr (ExprNode* Expr) +ExprNode* GenNearAddrExpr (ExprNode* Expr) +/* A word sized expression that will error if given a far expression at assemble time. */ +{ + long Val; + /* Special handling for const expressions */ + if (IsEasyConst (Expr, &Val)) { + FreeExpr (Expr); + Expr = GenLiteralExpr (Val & 0xFFFF); + if (Val > 0xFFFF) + { + Error("Range error: constant too large for assumed near address."); + } + } else { + ExprNode* Operand = Expr; + Expr = NewExprNode (EXPR_NEARADDR); + Expr->Left = Operand; + } + return Expr; +} + + + ExprNode* GenFarAddrExpr (ExprNode* Expr) /* Force the given expression into a far address and return the result. */ { diff --git a/src/ca65/expr.h b/src/ca65/expr.h index 03c2c26d8..16dffd901 100644 --- a/src/ca65/expr.h +++ b/src/ca65/expr.h @@ -109,6 +109,9 @@ ExprNode* GenByteExpr (ExprNode* Expr); ExprNode* GenWordExpr (ExprNode* Expr); /* Force the given expression into a word and return the result. */ +ExprNode* GenNearAddrExpr (ExprNode* Expr); +/* A word sized expression that will error if given a far expression at assemble time. */ + ExprNode* GenFarAddrExpr (ExprNode* Expr); /* Force the given expression into a far address and return the result. */ diff --git a/src/ca65/instr.c b/src/ca65/instr.c index 532a8748e..58011eb8f 100644 --- a/src/ca65/instr.c +++ b/src/ca65/instr.c @@ -1217,7 +1217,7 @@ static void EmitCode (EffAddr* A) ** mode, force this address into 16 bit range to allow ** addressing inside a 64K segment. */ - Emit2 (A->Opcode, GenWordExpr (A->Expr)); + Emit2 (A->Opcode, GenNearAddrExpr (A->Expr)); } else { Emit2 (A->Opcode, A->Expr); } diff --git a/src/ca65/studyexpr.c b/src/ca65/studyexpr.c index 90d2d6e18..3aabd3f88 100644 --- a/src/ca65/studyexpr.c +++ b/src/ca65/studyexpr.c @@ -1277,6 +1277,26 @@ static void StudyDWord (ExprNode* Expr, ExprDesc* D) +static void StudyNearAddr (ExprNode* Expr, ExprDesc* D) +/* Study an EXPR_NearAddr expression node */ +{ + /* Study the expression */ + StudyExprInternal (Expr->Left, D); + + /* We can handle only const expressions */ + if (!ED_IsConst (D)) { + ED_Invalidate (D); + } + + /* Promote to absolute if smaller. */ + if (D->AddrSize < ADDR_SIZE_ABS) + { + D->AddrSize = ADDR_SIZE_ABS; + } +} + + + static void StudyExprInternal (ExprNode* Expr, ExprDesc* D) /* Study an expression tree and place the contents into D */ { @@ -1427,6 +1447,10 @@ static void StudyExprInternal (ExprNode* Expr, ExprDesc* D) StudyWord1 (Expr, D); break; + case EXPR_NEARADDR: + StudyNearAddr (Expr, D); + break; + case EXPR_FARADDR: StudyFarAddr (Expr, D); break; diff --git a/src/common/exprdefs.c b/src/common/exprdefs.c index d9a5adf6b..c9db831a2 100644 --- a/src/common/exprdefs.c +++ b/src/common/exprdefs.c @@ -210,6 +210,10 @@ static void InternalDumpExpr (const ExprNode* Expr, const ExprNode* (*ResolveSym printf (" WORD1"); break; + case EXPR_NEARADDR: + printf (" NEARADDR"); + break; + case EXPR_FARADDR: printf (" FARADDR"); break; diff --git a/src/common/exprdefs.h b/src/common/exprdefs.h index 5465c4f25..90da6dff4 100644 --- a/src/common/exprdefs.h +++ b/src/common/exprdefs.h @@ -97,8 +97,9 @@ #define EXPR_BYTE3 (EXPR_UNARYNODE | 0x0B) #define EXPR_WORD0 (EXPR_UNARYNODE | 0x0C) #define EXPR_WORD1 (EXPR_UNARYNODE | 0x0D) -#define EXPR_FARADDR (EXPR_UNARYNODE | 0x0E) -#define EXPR_DWORD (EXPR_UNARYNODE | 0x0F) +#define EXPR_NEARADDR (EXPR_UNARYNODE | 0x0E) +#define EXPR_FARADDR (EXPR_UNARYNODE | 0x0F) +#define EXPR_DWORD (EXPR_UNARYNODE | 0x10) diff --git a/src/ld65/expr.c b/src/ld65/expr.c index 2a08b5a98..482430a19 100644 --- a/src/ld65/expr.c +++ b/src/ld65/expr.c @@ -436,6 +436,10 @@ long GetExprVal (ExprNode* Expr) case EXPR_WORD1: return (GetExprVal (Expr->Left) >> 16) & 0xFFFF; + case EXPR_NEARADDR: + /* Assembler was expected to validate this truncation. */ + return GetExprVal (Expr->Left) & 0xFFFF; + case EXPR_FARADDR: return GetExprVal (Expr->Left) & 0xFFFFFF;