diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 892f4cd5f..e0cda84e9 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -349,23 +349,23 @@ static const FuncInfo FuncInfoTable[] = { /* Table with names of zero page locations used by the compiler */ static const ZPInfo ZPInfoTable[] = { - { 0, "ptr1", REG_PTR1_LO, REG_PTR1 }, - { 0, "ptr1+1", REG_PTR1_HI, REG_PTR1 }, - { 0, "ptr2", REG_PTR2_LO, REG_PTR2 }, - { 0, "ptr2+1", REG_PTR2_HI, REG_PTR2 }, - { 4, "ptr3", REG_NONE, REG_NONE }, - { 4, "ptr4", REG_NONE, REG_NONE }, - { 7, "regbank", REG_NONE, REG_NONE }, - { 0, "regsave", REG_SAVE_LO, REG_SAVE }, - { 0, "regsave+1", REG_SAVE_HI, REG_SAVE }, - { 0, "sp", REG_SP_LO, REG_SP }, - { 0, "sp+1", REG_SP_HI, REG_SP }, - { 0, "sreg", REG_SREG_LO, REG_SREG }, - { 0, "sreg+1", REG_SREG_HI, REG_SREG }, - { 0, "tmp1", REG_TMP1, REG_TMP1 }, - { 0, "tmp2", REG_NONE, REG_NONE }, - { 0, "tmp3", REG_NONE, REG_NONE }, - { 0, "tmp4", REG_NONE, REG_NONE }, + { 0, "ptr1", 2, REG_PTR1_LO, REG_PTR1 }, + { 0, "ptr1+1", 1, REG_PTR1_HI, REG_PTR1 }, + { 0, "ptr2", 2, REG_PTR2_LO, REG_PTR2 }, + { 0, "ptr2+1", 1, REG_PTR2_HI, REG_PTR2 }, + { 4, "ptr3", 2, REG_NONE, REG_NONE }, + { 4, "ptr4", 2, REG_NONE, REG_NONE }, + { 7, "regbank", 6, REG_NONE, REG_NONE }, + { 0, "regsave", 4, REG_SAVE_LO, REG_SAVE }, + { 0, "regsave+1", 3, REG_SAVE_HI, REG_SAVE }, + { 0, "sp", 2, REG_SP_LO, REG_SP }, + { 0, "sp+1", 1, REG_SP_HI, REG_SP }, + { 0, "sreg", 2, REG_SREG_LO, REG_SREG }, + { 0, "sreg+1", 1, REG_SREG_HI, REG_SREG }, + { 0, "tmp1", 1, REG_TMP1, REG_TMP1 }, + { 0, "tmp2", 1, REG_NONE, REG_NONE }, + { 0, "tmp3", 1, REG_NONE, REG_NONE }, + { 0, "tmp4", 1, REG_NONE, REG_NONE }, }; #define ZPInfoCount (sizeof(ZPInfoTable) / sizeof(ZPInfoTable[0])) @@ -377,6 +377,83 @@ static const ZPInfo ZPInfoTable[] = { +static int IsAddrOnZP (long Address) +/* Return true if the Address is within the ZP range. +** FIXME: ZP range may vary depending on the CPU settings. +*/ +{ + /* ZP in range [0x00, 0xFF] */ + return Address >= 0 && Address < 0x100; +} + + + +int IsZPArg (const char* Name) +/* Exam if the main part of the arg string indicates a ZP loc */ +{ + unsigned short ArgInfo = 0; + long Offset = 0; + StrBuf NameBuf = AUTO_STRBUF_INITIALIZER; + SymEntry* E = 0; + const ZPInfo* Info = 0; + + if (!ParseOpcArgStr (Name, &ArgInfo, &NameBuf, &Offset)) { + /* Parsing failed */ + SB_Done (&NameBuf); + return 0; + } + + if ((ArgInfo & AIF_HAS_NAME) == 0) { + /* Numeric locs have no names */ + SB_Done (&NameBuf); + + /* We can check it against the ZP boundary if it is known */ + return IsAddrOnZP (Offset); + } + + if ((ArgInfo & AIF_BUILTIN) != 0) { + /* Search for the name in the list of builtin ZPs */ + Info = GetZPInfo (SB_GetConstBuf (&NameBuf)); + + SB_Done (&NameBuf); + + /* Do we know the ZP? */ + if (Info != 0) { + /* Use the information we have */ + return Offset >= 0 && Offset < (int)Info->Size; + } + + /* Assume it be non-ZP */ + return 0; + } + + if ((ArgInfo & AIF_EXTERNAL) == 0) { + /* We don't support local variables on ZP */ + SB_Done (&NameBuf); + return 0; + } + + /* Search for the symbol in the global symbol table skipping the underline + ** in its name. + */ + E = FindGlobalSym (SB_GetConstBuf (&NameBuf) + 1); + + SB_Done (&NameBuf); + + /* We are checking the offset against the symbol size rather than the actual + ** zeropage boundary, since we can't magically ensure that until linking and + ** can only trust the user in writing the correct code for now. + */ + if (E != 0 && (E->Flags & SC_ZEROPAGE) != 0) { + return Offset >= 0 && (unsigned)Offset < CheckedSizeOf (E->Type); + } + + /* Not found on ZP */ + return 0; +} + + + static int CompareFuncInfo (const void* Key, const void* Info) /* Compare function for bsearch */ { diff --git a/src/cc65/codeinfo.h b/src/cc65/codeinfo.h index 32bc5dd9c..88e26cdf4 100644 --- a/src/cc65/codeinfo.h +++ b/src/cc65/codeinfo.h @@ -119,7 +119,8 @@ struct RegContents; typedef struct ZPInfo ZPInfo; struct ZPInfo { unsigned char Len; /* Length of the following string */ - char Name[11]; /* Name of zero page symbol */ + char Name[10]; /* Name of zero page symbol */ + unsigned char Size; /* Maximum buffer size of this register */ unsigned short ByteUse; /* Register info for this symbol */ unsigned short WordUse; /* Register info for 16 bit access */ }; @@ -162,6 +163,9 @@ typedef enum { +int IsZPArg (const char* Arg); +/* Exam if the main part of the arg string indicates a ZP loc */ + fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg); /* For the given function, lookup register information and store it into ** the given variables. If the function is unknown, assume it will use and diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index 8177d4fd4..0626f3d18 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -403,7 +403,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L) if ((OPC->Info & OF_BRA) != 0) { /* Branch */ AM = AM65_BRA; - } else if (GetZPInfo(Arg) != 0) { + } else if (IsZPArg (Arg)) { AM = AM65_ZP; } else { /* Check for subroutine call to local label */ @@ -424,12 +424,15 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L) Reg = toupper (*L); L = SkipSpace (L+1); if (Reg == 'X') { - if (GetZPInfo(Arg) != 0) { + if (IsZPArg (Arg)) { AM = AM65_ZPX; } else { AM = AM65_ABSX; } } else if (Reg == 'Y') { + /* On 6502 only LDX and STX support AM65_ZPY. + ** We just play it simple and safe for now. + */ AM = AM65_ABSY; } else { Error ("ASM code error: syntax error"); diff --git a/src/cc65/opcodes.c b/src/cc65/opcodes.c index 3c02c84c4..86b904df9 100644 --- a/src/cc65/opcodes.c +++ b/src/cc65/opcodes.c @@ -649,6 +649,7 @@ unsigned GetInsnSize (opc_t OPC, am_t AM) case AM65_IMM: return 2; case AM65_ZP: return 2; case AM65_ZPX: return 2; + case AM65_ZPY: return 2; case AM65_ABS: return 3; case AM65_ABSX: return 3; case AM65_ABSY: return 3;