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;