/* Clear the output struct */
A->AddrModeSet = 0;
- A->Bank = 0;
A->Expr = 0;
/* Handle an addressing size override */
/* First three fields get filled when calling GetEA */
unsigned long AddrModeSet; /* Possible addressing modes */
struct ExprNode* Expr; /* Expression if any (NULL otherwise) */
- struct ExprNode* Bank; /* Bank expression if any */
/* The following fields are used inside instr.c */
unsigned AddrMode; /* Actual addressing mode used */
-static void CheckAddrSize (const ExprNode* N, unsigned char* AddrSize)
-/* Internal routine that is recursively called to check for the address size
- * of the expression tree.
- */
-{
- unsigned char A;
- unsigned char Left, Right;
-
- if (N) {
- switch (N->Op & EXPR_TYPEMASK) {
-
- case EXPR_LEAFNODE:
- switch (N->Op) {
-
- case EXPR_SYMBOL:
- if (SymIsZP (N->V.Sym)) {
- if (*AddrSize < ADDR_SIZE_ZP) {
- *AddrSize = ADDR_SIZE_ZP;
- }
- } else if (SymHasExpr (N->V.Sym)) {
- /* Check if this expression is a byte expression */
- CheckAddrSize (GetSymExpr (N->V.Sym), AddrSize);
- } else {
- /* Undefined symbol, use absolute */
- if (*AddrSize < ADDR_SIZE_ABS) {
- *AddrSize = ADDR_SIZE_ABS;
- }
- }
- break;
-
- case EXPR_SECTION:
- A = GetSegAddrSize (N->V.SegNum);
- if (A > *AddrSize) {
- *AddrSize = A;
- }
- break;
-
- }
- break;
-
- case EXPR_UNARYNODE:
- switch (N->Op) {
-
- case EXPR_BYTE0:
- case EXPR_BYTE1:
- case EXPR_BYTE2:
- case EXPR_BYTE3:
- /* No need to look at the expression */
- *AddrSize = ADDR_SIZE_ZP;
- break;
-
- case EXPR_WORD0:
- case EXPR_WORD1:
- /* No need to look at the expression */
- *AddrSize = ADDR_SIZE_ABS;
- break;
-
- default:
- CheckAddrSize (N->Left, AddrSize);
- break;
- }
- break;
-
- case EXPR_BINARYNODE:
- Left = Right = ADDR_SIZE_DEFAULT;
- CheckAddrSize (N->Left, &Left);
- CheckAddrSize (N->Right, &Right);
- A = (Left > Right)? Left : Right;
- if (A > *AddrSize) {
- *AddrSize = A;
- }
- break;
-
- default:
- Internal ("Unknown expression op: %02X", N->Op);
- }
- }
-}
-
-
-
-int IsByteExpr (ExprNode* Root)
-/* Return true if this is a byte expression */
-{
- long Val;
-
- if (IsConstExpr (Root, &Val)) {
- return IsByteRange (Val);
- } else {
- unsigned char AddrSize = ADDR_SIZE_DEFAULT;
- CheckAddrSize (Root, &AddrSize);
- return (AddrSize == ADDR_SIZE_ZP);
- }
-}
-
-
-
ExprNode* CloneExpr (ExprNode* Expr)
/* Clone the given expression tree. The function will simply clone symbol
* nodes, it will not resolve them.
#include "nexttok.h"
#include "objcode.h"
#include "spool.h"
+#include "studyexpr.h"
#include "symtab.h"
*/
A->AddrModeSet &= Ins->AddrMode;
- /* If we have possible zero page addressing modes, and the expression
- * involved (if any) is not in byte range, remove the zero page addressing
- * modes.
+ /* If we have an expression, check it and remove any addressing modes that
+ * are too small for the expression size. Since we have to study the
+ * expression anyway, do also replace it by a simpler one if possible.
*/
- if (A->Expr && (A->AddrModeSet & AM_ZP) && !IsByteExpr (A->Expr)) {
- A->AddrModeSet &= ~AM_ZP;
+ if (A->Expr) {
+ ExprDesc ED;
+ ED_Init (&ED);
+
+ /* Study the expression */
+ StudyExpr (A->Expr, &ED);
+
+ /* Simplify it if possible */
+ A->Expr = SimplifyExpr (A->Expr, &ED);
+
+ /* Check the size */
+ switch (ED.AddrSize) {
+
+ case ADDR_SIZE_ABS:
+ printf ("abs\n");
+ A->AddrModeSet &= ~AM_SET_ZP;
+ break;
+
+ case ADDR_SIZE_FAR:
+ printf ("far\n");
+ A->AddrModeSet &= ~(AM_SET_ZP | AM_SET_ABS);
+ break;
+ }
+
+ /* Free any resource associated with the expression desc */
+ ED_Done (&ED);
}
/* Check if we have any adressing modes left */
/* Found, check the expression */
ExprNode* Left = A->Expr->Left;
if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
- Left->Op == EXPR_SYMBOL &&
- !SymIsZP (Left->V.Sym)) {
+ Left->Op == EXPR_SYMBOL &&
+ GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
/* Output a warning */
Warning (1, "Suspicious address expression");
break;
case 3:
- if (A->Bank) {
- /* Separate bank given */
- Emit3b (A->Opcode, A->Expr, A->Bank);
- } else {
- /* One far argument */
- Emit3 (A->Opcode, A->Expr);
- }
+ /* Far argument */
+ Emit3 (A->Opcode, A->Expr);
break;
default:
#define AM_ABS_X 0x00000040UL
#define AM_ABS_LONG_X 0x00000080UL
#define AM_DIR_Y 0x00000100UL
-#define AM_ABS_Y 0x00000200UL
-#define AM_DIR_IND 0x00000400UL
-#define AM_ABS_IND 0x00000800UL
-#define AM_DIR_IND_LONG 0x00001000UL
-#define AM_DIR_IND_Y 0x00002000UL
-#define AM_DIR_IND_LONG_Y 0x00004000UL
-#define AM_DIR_X_IND 0x00008000UL
-#define AM_ABS_X_IND 0x00010000UL
-#define AM_REL 0x00020000UL
+#define AM_ABS_Y 0x00000200UL
+#define AM_DIR_IND 0x00000400UL
+#define AM_ABS_IND 0x00000800UL
+#define AM_DIR_IND_LONG 0x00001000UL
+#define AM_DIR_IND_Y 0x00002000UL
+#define AM_DIR_IND_LONG_Y 0x00004000UL
+#define AM_DIR_X_IND 0x00008000UL
+#define AM_ABS_X_IND 0x00010000UL
+#define AM_REL 0x00020000UL
#define AM_REL_LONG 0x00040000UL
-#define AM_STACK_REL 0x00080000UL
-#define AM_STACK_REL_IND_Y 0x00100000UL
-#define AM_IMM_ACCU 0x00200000UL
-#define AM_IMM_INDEX 0x00400000UL
-#define AM_IMM_IMPLICIT 0x00800000UL
-#define AM_IMM (AM_IMM_ACCU | AM_IMM_INDEX | AM_IMM_IMPLICIT)
+#define AM_STACK_REL 0x00080000UL
+#define AM_STACK_REL_IND_Y 0x00100000UL
+#define AM_IMM_ACCU 0x00200000UL
+#define AM_IMM_INDEX 0x00400000UL
+#define AM_IMM_IMPLICIT 0x00800000UL
+#define AM_IMM (AM_IMM_ACCU | AM_IMM_INDEX | AM_IMM_IMPLICIT)
#define AM_BLOCKMOVE 0x01000000UL
/* Bitmask for all ZP operations that have correspondent ABS ops */
-#define AM_ZP (AM_DIR | AM_DIR_X | AM_DIR_Y | AM_DIR_IND | AM_DIR_X_IND)
+#define AM_SET_ZP (AM_DIR | AM_DIR_X | AM_DIR_Y | AM_DIR_IND | AM_DIR_X_IND)
+
+/* Bitmask for all ABS operations that have correspondent FAR ops */
+#define AM_SET_ABS (AM_ABS | AM_ABS_X)
/* Bit numbers and count */
-#define AMI_IMM_ACCU 21
-#define AMI_IMM_INDEX 22
-#define AMI_COUNT 25
+#define AMI_IMM_ACCU 21
+#define AMI_IMM_INDEX 22
+#define AMI_COUNT 25
-void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
-/* Emit an instruction with a three byte argument and separate bank */
-{
- Emit0 (OPC);
- EmitWord (Expr);
- EmitByte (Bank);
-}
-
-
-
void EmitSigned (ExprNode* Expr, unsigned Size)
/* Emit a signed expression with the given size */
{
/* */
/* */
/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
+/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
void Emit3 (unsigned char OPC, ExprNode* Expr);
/* Emit an instruction with a three byte argument */
-void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank);
-/* Emit an instruction with a three byte argument and separate bank */
-
void EmitSigned (ExprNode* Expr, unsigned Size);
/* Emit a signed expression with the given size */
GetSymName (Sym));
ED_Invalidate (D);
} else {
+
+ unsigned char AddrSize;
+
+ /* Mark the symbol and study its associated expression */
SymMarkUser (Sym);
StudyExprInternal (GetSymExpr (Sym), D);
SymUnmarkUser (Sym);
- ED_UpdateAddrSize (D, GetSymAddrSize (Sym));
+
+ /* If the symbol has an explicit address size, use it. This may
+ * lead to range errors later (maybe even in the linker stage), if
+ * the user lied about the address size, but for now we trust the
+ * user.
+ */
+ AddrSize = GetSymAddrSize (Sym);
+ if (AddrSize != ADDR_SIZE_DEFAULT) {
+ D->AddrSize = AddrSize;
+ }
}
} else {
/* The symbol is either undefined or an import. In both cases, track
* active, when the scope was opened. Set the size of the scope to the
* number of data bytes emitted into this segment.
*/
- if (CollCount (&CurrentScope->SegRanges) > 0) {
+ if (CollCount (&CurrentScope->SegRanges) > 0) {
const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
DefSizeOfScope (CurrentScope, GetSegRangeSize (R));
}
-int SymIsZP (SymEntry* S)
-/* Return true if the symbol is explicitly marked as zeropage symbol */
-{
- /* If the symbol is not a global symbol, was not defined before, check the
- * enclosing scope for a symbol with the same name, and return the ZP
- * attribute of this symbol if we find one.
- */
- if ((S->Flags & (SF_DEFINED | SF_IMPORT | SF_LOCAL)) == 0 &&
- S->SymTab->Parent != 0) {
-
- /* Try to find a symbol with the same name in the enclosing scope */
- SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name));
-
- /* If we found one, use the ZP flag */
- if (E && E->AddrSize == ADDR_SIZE_ZP) {
- S->AddrSize = ADDR_SIZE_ZP;
- }
- }
-
- /* Check the ZP flag */
- return (S->AddrSize == ADDR_SIZE_ZP);
-}
-
-
-
unsigned char GetCurrentSymTabType ()
/* Return the type of the current symbol table */
{
* scope.
*/
-int SymIsZP (SymEntry* Sym);
-/* Return true if the symbol is explicitly marked as zeropage symbol */
-
#if defined(HAVE_INLINE)
INLINE unsigned char GetSymTabType (const SymTable* S)
/* Return the type of the given symbol table */