X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcodeent.c;h=2a7b45956d7665f783f118dd17a88451c3e6c088;hb=7c9bf720d8861c529f056532a308b1dbc94c25ab;hp=1594c80330e2df96779bc212b7436d509a3d78d8;hpb=0b08eb0e6869a736e3015b161d715c02f6d21bfc;p=cc65 diff --git a/src/cc65/codeent.c b/src/cc65/codeent.c index 1594c8033..2a7b45956 100644 --- a/src/cc65/codeent.c +++ b/src/cc65/codeent.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 2001-2002 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -40,6 +40,7 @@ #include "chartype.h" #include "check.h" #include "xmalloc.h" +#include "xsprintf.h" /* cc65 */ #include "codeinfo.h" @@ -136,6 +137,8 @@ static int NumArg (const char* Arg, unsigned long* Num) static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D) /* Set the Use and Chg in E */ { + const ZPInfo* Info; + /* If this is a subroutine call, or a jump to an external function, * lookup the information about this function and use it. The jump itself * does not change any registers, so we don't need to use the data from D. @@ -145,10 +148,62 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D) GetFuncInfo (E->Arg, &E->Use, &E->Chg); } else { /* Some other instruction. Use the values from the opcode description - * plus addressing mode info + * plus addressing mode info. */ E->Use = D->Use | GetAMUseInfo (E->AM); E->Chg = D->Chg; + + /* Check for special zero page registers used */ + switch (E->AM) { + + case AM65_ACC: + if (E->OPC == OP65_ASL || E->OPC == OP65_DEC || + E->OPC == OP65_INC || E->OPC == OP65_LSR || + E->OPC == OP65_ROL || E->OPC == OP65_ROR) { + /* A is changed by these insns */ + E->Chg |= REG_A; + } + break; + + case AM65_ZP: + case AM65_ABS: + /* Be conservative: */ + case AM65_ZPX: + case AM65_ABSX: + case AM65_ABSY: + Info = GetZPInfo (E->Arg); + if (Info && Info->ByteUse != REG_NONE) { + if (E->OPC == OP65_ASL || E->OPC == OP65_DEC || + E->OPC == OP65_INC || E->OPC == OP65_LSR || + E->OPC == OP65_ROL || E->OPC == OP65_ROR || + E->OPC == OP65_TRB || E->OPC == OP65_TSB) { + /* The zp loc is both, input and output */ + E->Chg |= Info->ByteUse; + E->Use |= Info->ByteUse; + } else if ((E->Info & OF_STORE) != 0) { + /* Just output */ + E->Chg |= Info->ByteUse; + } else { + /* Input only */ + E->Use |= Info->ByteUse; + } + } + break; + + case AM65_ZPX_IND: + case AM65_ZP_INDY: + case AM65_ZP_IND: + Info = GetZPInfo (E->Arg); + if (Info && Info->ByteUse != REG_NONE) { + /* These addressing modes will never change the zp loc */ + E->Use |= Info->WordUse; + } + break; + + default: + /* Keep gcc silent */ + break; + } } } @@ -160,6 +215,21 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D) +const char* MakeHexArg (unsigned Num) +/* Convert Num into a string in the form $XY, suitable for passing it as an + * argument to NewCodeEntry, and return a pointer to the string. + * BEWARE: The function returns a pointer to a static buffer, so the value is + * gone if you call it twice (and apart from that it's not thread and signal + * safe). + */ +{ + static char Buf[16]; + xsprintf (Buf, sizeof (Buf), "$%02X", (unsigned char) Num); + return Buf; +} + + + CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg, CodeLabel* JumpTo, LineInfo* LI) /* Create a new code entry, initialize and return it */ @@ -265,14 +335,35 @@ void CE_MoveLabel (CodeLabel* L, CodeEntry* E) -void CE_SetArg (CodeEntry* E, const char* Arg) -/* Set a new argument for the given code entry. An old string is deleted. */ +void CE_SetNumArg (CodeEntry* E, long Num) +/* Set a new numeric argument for the given code entry that must already + * have a numeric argument. + */ { + char Buf[16]; + + /* Check that the entry has a numerical argument */ + CHECK (E->Flags & CEF_NUMARG); + + /* Make the new argument string */ + if (E->Size == 2) { + Num &= 0xFF; + xsprintf (Buf, sizeof (Buf), "$%02X", (unsigned) Num); + } else if (E->Size == 3) { + Num &= 0xFFFF; + xsprintf (Buf, sizeof (Buf), "$%04X", (unsigned) Num); + } else { + Internal ("Invalid instruction size in CE_SetNumArg"); + } + /* Free the old argument */ FreeArg (E->Arg); /* Assign the new one */ - E->Arg = GetArgCopy (Arg); + E->Arg = GetArgCopy (Buf); + + /* Use the new numerical value */ + E->Num = Num; } @@ -285,6 +376,46 @@ int CE_KnownImm (const CodeEntry* E) +int CE_UseLoadFlags (const CodeEntry* E) +/* Return true if the instruction uses any flags that are set by a load of + * a register (N and Z). + */ +{ + /* A branch will use the flags */ + if (E->Info & OF_FBRA) { + return 1; + } + + /* Call of a boolean transformer routine will also use the flags */ + if (E->OPC == OP65_JSR) { + /* Get the condition that is evaluated and check it */ + switch (FindBoolCmpCond (E->Arg)) { + case CMP_EQ: + case CMP_NE: + case CMP_GT: + case CMP_GE: + case CMP_LT: + case CMP_LE: + case CMP_UGT: + case CMP_ULE: + case CMP_INV: + /* Will use the N or Z flags */ + return 1; + + + case CMP_UGE: /* Uses only carry */ + case CMP_ULT: /* Dito */ + default: /* No bool transformer subroutine */ + return 0; + } + } + + /* Anything else */ + return 0; +} + + + void CE_FreeRegInfo (CodeEntry* E) /* Free an existing register info struct */ { @@ -306,7 +437,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) RegContents* Out; /* Function register usage */ - unsigned char Use, Chg; + unsigned short Use, Chg; /* If we don't have a register info struct, allocate one. */ if (E->RI == 0) { @@ -338,6 +469,21 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) if (In->RegA >= 0) { if (CE_KnownImm (E)) { Out->RegA = In->RegA & (short) E->Num; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Use, In)) { + case REG_TMP1: + Out->RegA = In->RegA & In->Tmp1; + break; + case REG_SREG_LO: + Out->RegA = In->RegA & In->SRegLo; + break; + case REG_SREG_HI: + Out->RegA = In->RegA & In->SRegHi; + break; + default: + Out->RegA = -1; + break; + } } else { Out->RegA = -1; } @@ -347,6 +493,21 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) case OP65_ASL: if (E->AM == AM65_ACC && In->RegA >= 0) { Out->RegA = (In->RegA << 1) & 0xFF; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = (In->Tmp1 << 1) & 0xFF; + break; + case REG_SREG_LO: + Out->SRegLo = (In->SRegLo << 1) & 0xFF; + break; + case REG_SREG_HI: + Out->SRegHi = (In->SRegHi << 1) & 0xFF; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); } break; @@ -406,25 +567,40 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) case OP65_DEA: if (In->RegA >= 0) { - Out->RegA = In->RegA - 1; + Out->RegA = (In->RegA - 1) & 0xFF; } break; case OP65_DEC: if (E->AM == AM65_ACC && In->RegA >= 0) { - Out->RegA = In->RegA - 1; + Out->RegA = (In->RegA - 1) & 0xFF; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = (In->Tmp1 - 1) & 0xFF; + break; + case REG_SREG_LO: + Out->SRegLo = (In->SRegLo - 1) & 0xFF; + break; + case REG_SREG_HI: + Out->SRegHi = (In->SRegHi - 1) & 0xFF; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); } break; case OP65_DEX: if (In->RegX >= 0) { - Out->RegX = In->RegX - 1; + Out->RegX = (In->RegX - 1) & 0xFF; } break; case OP65_DEY: if (In->RegY >= 0) { - Out->RegY = In->RegY - 1; + Out->RegY = (In->RegY - 1) & 0xFF; } break; @@ -432,6 +608,21 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) if (In->RegA >= 0) { if (CE_KnownImm (E)) { Out->RegA = In->RegA ^ (short) E->Num; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Use, In)) { + case REG_TMP1: + Out->RegA = In->RegA ^ In->Tmp1; + break; + case REG_SREG_LO: + Out->RegA = In->RegA ^ In->SRegLo; + break; + case REG_SREG_HI: + Out->RegA = In->RegA ^ In->SRegHi; + break; + default: + Out->RegA = -1; + break; + } } else { Out->RegA = -1; } @@ -440,25 +631,40 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) case OP65_INA: if (In->RegA >= 0) { - Out->RegA = In->RegA + 1; + Out->RegA = (In->RegA + 1) & 0xFF; } break; case OP65_INC: if (E->AM == AM65_ACC && In->RegA >= 0) { - Out->RegA = In->RegA + 1; + Out->RegA = (In->RegA + 1) & 0xFF; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = (In->Tmp1 + 1) & 0xFF; + break; + case REG_SREG_LO: + Out->SRegLo = (In->SRegLo + 1) & 0xFF; + break; + case REG_SREG_HI: + Out->SRegHi = (In->SRegHi + 1) & 0xFF; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); } break; case OP65_INX: if (In->RegX >= 0) { - Out->RegX = In->RegX + 1; + Out->RegX = (In->RegX + 1) & 0xFF; } break; case OP65_INY: if (In->RegY >= 0) { - Out->RegY = In->RegY + 1; + Out->RegY = (In->RegY + 1) & 0xFF; } break; @@ -495,6 +701,33 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) if (Chg & REG_Y) { Out->RegY = -1; } + if (Chg & REG_TMP1) { + Out->Tmp1 = -1; + } + if (Chg & REG_SREG_LO) { + Out->SRegLo = -1; + } + if (Chg & REG_SREG_HI) { + Out->SRegHi = -1; + } + /* ## FIXME: Quick hack for some known functions: */ + if (strcmp (E->Arg, "tosandax") == 0) { + if (In->RegA == 0) { + Out->RegA = 0; + } + if (In->RegX == 0) { + Out->RegX = 0; + } + } else if (strcmp (E->Arg, "tosorax") == 0) { + if (In->RegA == 0xFF) { + Out->RegA = 0xFF; + } + if (In->RegX == 0xFF) { + Out->RegX = 0xFF; + } + } else if (FindBoolCmpCond (E->Arg) != CMP_INV) { + Out->RegX = 0; + } break; case OP65_JVC: @@ -505,25 +738,70 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) case OP65_LDA: if (CE_KnownImm (E)) { - Out->RegA = (unsigned char) E->Num; + Out->RegA = (unsigned char) E->Num; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Use, In)) { + case REG_TMP1: + Out->RegA = In->Tmp1; + break; + case REG_SREG_LO: + Out->RegA = In->SRegLo; + break; + case REG_SREG_HI: + Out->RegA = In->SRegHi; + break; + default: + Out->RegA = -1; + break; + } } else { - /* A is now unknown */ - Out->RegA = -1; + /* A is now unknown */ + Out->RegA = -1; } break; case OP65_LDX: if (CE_KnownImm (E)) { - Out->RegX = (unsigned char) E->Num; + Out->RegX = (unsigned char) E->Num; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Use, In)) { + case REG_TMP1: + Out->RegX = In->Tmp1; + break; + case REG_SREG_LO: + Out->RegX = In->SRegLo; + break; + case REG_SREG_HI: + Out->RegX = In->SRegHi; + break; + default: + Out->RegX = -1; + break; + } } else { - /* X is now unknown */ - Out->RegX = -1; + /* X is now unknown */ + Out->RegX = -1; } break; case OP65_LDY: if (CE_KnownImm (E)) { - Out->RegY = (unsigned char) E->Num; + Out->RegY = (unsigned char) E->Num; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Use, In)) { + case REG_TMP1: + Out->RegY = In->Tmp1; + break; + case REG_SREG_LO: + Out->RegY = In->SRegLo; + break; + case REG_SREG_HI: + Out->RegY = In->SRegHi; + break; + default: + Out->RegY = -1; + break; + } } else { /* Y is now unknown */ Out->RegY = -1; @@ -533,6 +811,21 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) case OP65_LSR: if (E->AM == AM65_ACC && In->RegA >= 0) { Out->RegA = (In->RegA >> 1) & 0xFF; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = (In->Tmp1 >> 1) & 0xFF; + break; + case REG_SREG_LO: + Out->SRegLo = (In->SRegLo >> 1) & 0xFF; + break; + case REG_SREG_HI: + Out->SRegHi = (In->SRegHi >> 1) & 0xFF; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); } break; @@ -543,6 +836,21 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) if (In->RegA >= 0) { if (CE_KnownImm (E)) { Out->RegA = In->RegA | (short) E->Num; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Use, In)) { + case REG_TMP1: + Out->RegA = In->RegA | In->Tmp1; + break; + case REG_SREG_LO: + Out->RegA = In->RegA | In->SRegLo; + break; + case REG_SREG_HI: + Out->RegA = In->RegA | In->SRegHi; + break; + default: + Out->RegA = -1; + break; + } } else { /* A is now unknown */ Out->RegA = -1; @@ -569,49 +877,152 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) case OP65_PLP: break; - case OP65_PLX: - Out->RegX = -1; - break; + case OP65_PLX: + Out->RegX = -1; + break; - case OP65_PLY: - Out->RegY = -1; - break; + case OP65_PLY: + Out->RegY = -1; + break; - case OP65_ROL: - Out->RegA = -1; - break; + case OP65_ROL: + /* We don't know the value of the carry bit */ + if (E->AM == AM65_ACC) { + Out->RegA = -1; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = -1; + break; + case REG_SREG_LO: + Out->SRegLo = -1; + break; + case REG_SREG_HI: + Out->SRegHi = -1; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } + break; - case OP65_ROR: - Out->RegA = -1; - break; + case OP65_ROR: + /* We don't know the value of the carry bit */ + if (E->AM == AM65_ACC) { + Out->RegA = -1; + } else if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = -1; + break; + case REG_SREG_LO: + Out->SRegLo = -1; + break; + case REG_SREG_HI: + Out->SRegHi = -1; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } + break; - case OP65_RTI: - break; + case OP65_RTI: + break; - case OP65_RTS: - break; + case OP65_RTS: + break; - case OP65_SBC: - /* We don't know the value of the carry bit */ - Out->RegA = -1; - break; + case OP65_SBC: + /* We don't know the value of the carry bit */ + Out->RegA = -1; + break; - case OP65_SEC: - break; + case OP65_SEC: + break; - case OP65_SED: - break; + case OP65_SED: + break; - case OP65_SEI: - break; + case OP65_SEI: + break; - case OP65_STA: + case OP65_STA: + if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, 0)) { + case REG_TMP1: + Out->Tmp1 = In->RegA; + break; + case REG_SREG_LO: + Out->SRegLo = In->RegA; + break; + case REG_SREG_HI: + Out->SRegHi = In->RegA; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } break; case OP65_STX: + if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, 0)) { + case REG_TMP1: + Out->Tmp1 = In->RegX; + break; + case REG_SREG_LO: + Out->SRegLo = In->RegX; + break; + case REG_SREG_HI: + Out->SRegHi = In->RegX; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } break; case OP65_STY: + if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, 0)) { + case REG_TMP1: + Out->Tmp1 = In->RegY; + break; + case REG_SREG_LO: + Out->SRegLo = In->RegY; + break; + case REG_SREG_HI: + Out->SRegHi = In->RegY; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } + break; + + case OP65_STZ: + if (E->AM == AM65_ZP) { + switch (GetKnownReg (E->Chg, 0)) { + case REG_TMP1: + Out->Tmp1 = 0; + break; + case REG_SREG_LO: + Out->SRegLo = 0; + break; + case REG_SREG_HI: + Out->SRegHi = 0; + break; + } + } else if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } break; case OP65_TAX: @@ -623,13 +1034,69 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) break; case OP65_TRB: - /* For now... */ - Out->RegA = -1; + if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } else if (E->AM == AM65_ZP) { + if (In->RegA >= 0) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 &= ~In->RegA; + break; + case REG_SREG_LO: + Out->SRegLo &= ~In->RegA; + break; + case REG_SREG_HI: + Out->SRegHi &= ~In->RegA; + break; + } + } else { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = -1; + break; + case REG_SREG_LO: + Out->SRegLo = -1; + break; + case REG_SREG_HI: + Out->SRegHi = -1; + break; + } + } + } break; case OP65_TSB: - /* For now... */ - Out->RegA = -1; + if (E->AM == AM65_ZPX) { + /* Invalidates all ZP registers */ + RC_InvalidateZP (Out); + } else if (E->AM == AM65_ZP) { + if (In->RegA >= 0) { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 |= In->RegA; + break; + case REG_SREG_LO: + Out->SRegLo |= In->RegA; + break; + case REG_SREG_HI: + Out->SRegHi |= In->RegA; + break; + } + } else { + switch (GetKnownReg (E->Chg, In)) { + case REG_TMP1: + Out->Tmp1 = -1; + break; + case REG_SREG_LO: + Out->SRegLo = -1; + break; + case REG_SREG_HI: + Out->SRegHi = -1; + break; + } + } + } break; case OP65_TSX: @@ -655,6 +1122,26 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs) +static char* RegInfoDesc (unsigned U, char* Buf) +/* Return a string containing register info */ +{ + Buf[0] = '\0'; + + strcat (Buf, U & REG_SREG_HI? "H" : "_"); + strcat (Buf, U & REG_SREG_LO? "L" : "_"); + strcat (Buf, U & REG_A? "A" : "_"); + strcat (Buf, U & REG_X? "X" : "_"); + strcat (Buf, U & REG_Y? "Y" : "_"); + strcat (Buf, U & REG_TMP1? "T1" : "__"); + strcat (Buf, U & REG_PTR1? "1" : "_"); + strcat (Buf, U & REG_PTR2? "2" : "_"); + strcat (Buf, U & REG_SAVE? "V" : "_"); + + return Buf; +} + + + void CE_Output (const CodeEntry* E, FILE* F) /* Output the code entry to a file */ { @@ -699,7 +1186,7 @@ void CE_Output (const CodeEntry* E, FILE* F) case AM65_ABS: /* zeropage and absolute */ Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg); - break; + break; case AM65_ZPX: case AM65_ABSX: @@ -740,16 +1227,14 @@ void CE_Output (const CodeEntry* E, FILE* F) /* Print usage info if requested by the debugging flag */ if (Debug) { - fprintf (F, - "%*s; USE: %c%c%c CHG: %c%c%c SIZE: %u\n", - 30-Chars, "", - (E->Use & REG_A)? 'A' : '_', - (E->Use & REG_X)? 'X' : '_', - (E->Use & REG_Y)? 'Y' : '_', - (E->Chg & REG_A)? 'A' : '_', - (E->Chg & REG_X)? 'X' : '_', - (E->Chg & REG_Y)? 'Y' : '_', - E->Size); + char Use [128]; + char Chg [128]; + fprintf (F, + "%*s; USE: %-20s CHG: %-20s SIZE: %u\n", + 30-Chars, "", + RegInfoDesc (E->Use, Use), + RegInfoDesc (E->Chg, Chg), + E->Size); } else { /* Terminate the line */ fprintf (F, "\n");