+#include <stdlib.h>
+#include <string.h>
+
/* common */
+#include "chartype.h"
#include "check.h"
#include "xmalloc.h"
/* cc65 */
#include "codeinfo.h"
#include "error.h"
-#include "funcinfo.h"
#include "global.h"
#include "codelab.h"
#include "opcodes.h"
+/* Empty argument */
+static char EmptyArg[] = "";
+
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static void FreeArg (char* Arg)
+/* Free a code entry argument */
+{
+ if (Arg != EmptyArg) {
+ xfree (Arg);
+ }
+}
+
+
+
+static char* GetArgCopy (const char* Arg)
+/* Create an argument copy for assignment */
+{
+ if (Arg && Arg[0] != '\0') {
+ /* Create a copy */
+ return xstrdup (Arg);
+ } else {
+ /* Use the empty argument string */
+ return EmptyArg;
+ }
+}
+
+
+
+static int NumArg (const char* Arg, unsigned long* Num)
+/* If the given argument is numerical, convert it and return true. Otherwise
+ * set Num to zero and return false.
+ */
+{
+ char* End;
+ unsigned long Val;
+
+ /* Determine the base */
+ int Base = 10;
+ if (*Arg == '$') {
+ ++Arg;
+ Base = 16;
+ } else if (*Arg == '%') {
+ ++Arg;
+ Base = 2;
+ }
+
+ /* Convert the value. strtol is not exactly what we want here, but it's
+ * cheap and may be replaced by something fancier later.
+ */
+ Val = strtoul (Arg, &End, Base);
+
+ /* Check if the conversion was successful */
+ if (*End != '\0') {
+
+ /* Could not convert */
+ *Num = 0;
+ return 0;
+
+ } else {
+
+ /* Conversion ok */
+ *Num = Val;
+ return 1;
+
+ }
+}
+
+
+
+static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
+/* Set the Use and Chg in E */
+{
+ /* 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.
+ */
+ if ((E->Info & (OF_BRA | OF_CALL)) != 0 && E->JumpTo == 0) {
+ /* A subroutine call or jump to external symbol (function exit) */
+ GetFuncInfo (E->Arg, &E->Use, &E->Chg);
+ } else {
+ /* Some other instruction. Use the values from the opcode description
+ * plus addressing mode info
+ */
+ E->Use = D->Use | GetAMUseInfo (E->AM);
+ E->Chg = D->Chg;
+ }
+}
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
-CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel* JumpTo)
+CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg,
+ CodeLabel* JumpTo, LineInfo* LI)
/* Create a new code entry, initialize and return it */
{
+ /* Get the opcode description */
+ const OPCDesc* D = GetOPCDesc (OPC);
+
/* Allocate memory */
CodeEntry* E = xmalloc (sizeof (CodeEntry));
/* Initialize the fields */
- E->OPC = D->OPC;
- E->AM = AM;
- E->Size = GetInsnSize (E->OPC, E->AM);
- E->Hints = 0;
- E->Arg = (Arg && Arg[0] != '\0')? xstrdup (Arg) : 0;
- E->Num = 0;
- E->Flags = 0;
- E->Info = D->Info;
- if (E->OPC == OPC_JSR && E->Arg) {
- /* A subroutine call */
- E->Info |= GetFuncInfo (E->Arg);
- } else {
- /* Some other instruction */
- E->Info |= GetAMUseInfo (AM);
- }
- E->JumpTo = JumpTo;
+ E->OPC = D->OPC;
+ E->AM = AM;
+ E->Arg = GetArgCopy (Arg);
+ E->Flags = NumArg (E->Arg, &E->Num)? CEF_NUMARG : 0;
+ E->Info = D->Info;
+ E->Size = GetInsnSize (E->OPC, E->AM);
+ E->JumpTo = JumpTo;
+ E->LI = UseLineInfo (LI);
+ SetUseChgInfo (E, D);
InitCollection (&E->Labels);
/* If we have a label given, add this entry to the label */
if (JumpTo) {
- CollAppend (&JumpTo->JumpFrom, E);
+ CollAppend (&JumpTo->JumpFrom, E);
}
/* Return the initialized struct */
/* Free the given code entry */
{
/* Free the string argument if we have one */
- xfree (E->Arg);
+ FreeArg (E->Arg);
/* Cleanup the collection */
DoneCollection (&E->Labels);
+ /* Release the line info */
+ ReleaseLineInfo (E->LI);
+
/* Free the entry */
xfree (E);
}
-int CodeEntryHasLabel (const CodeEntry* E)
-/* Check if the given code entry has labels attached */
+void ReplaceOPC (CodeEntry* E, opc_t OPC)
+/* Replace the opcode of the instruction. This will also replace related info,
+ * Size, Use and Chg, but it will NOT update any arguments or labels.
+ */
{
- return (CollCount (&E->Labels) > 0);
+ /* Get the opcode descriptor */
+ const OPCDesc* D = GetOPCDesc (OPC);
+
+ /* Replace the opcode */
+ E->OPC = OPC;
+ E->Info = D->Info;
+ E->Size = GetInsnSize (E->OPC, E->AM);
+ SetUseChgInfo (E, D);
}
-void OutputCodeEntry (FILE* F, const CodeEntry* E)
+int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2)
+/* Check if both code entries are equal */
+{
+ return E1->OPC == E2->OPC && E1->AM == E2->AM && strcmp (E1->Arg, E2->Arg) == 0;
+}
+
+
+
+void AttachCodeLabel (CodeEntry* E, CodeLabel* L)
+/* Attach the label to the entry */
+{
+ /* Add it to the entries label list */
+ CollAppend (&E->Labels, L);
+
+ /* Tell the label about it's owner */
+ L->Owner = E;
+}
+
+
+
+void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
+/* Move the code label L from it's former owner to the code entry E. */
+{
+ /* Delete the label from the owner */
+ CollDeleteItem (&L->Owner->Labels, L);
+
+ /* Set the new owner */
+ CollAppend (&E->Labels, L);
+ L->Owner = E;
+}
+
+
+
+void CodeEntrySetArg (CodeEntry* E, const char* Arg)
+/* Set a new argument for the given code entry. An old string is deleted. */
+{
+ /* Free the old argument */
+ FreeArg (E->Arg);
+
+ /* Assign the new one */
+ E->Arg = GetArgCopy (Arg);
+}
+
+
+
+void OutputCodeEntry (const CodeEntry* E, FILE* F)
/* Output the code entry to a file */
{
const OPCDesc* D;
unsigned Chars;
+ const char* Target;
/* If we have a label, print that */
unsigned LabelCount = CollCount (&E->Labels);
unsigned I;
for (I = 0; I < LabelCount; ++I) {
- OutputCodeLabel (F, CollConstAt (&E->Labels, I));
+ OutputCodeLabel (CollConstAt (&E->Labels, I), F);
}
/* Get the opcode description */
/* Print the operand */
switch (E->AM) {
- case AM_IMP:
+ case AM65_IMP:
/* implicit */
break;
- case AM_ACC:
+ case AM65_ACC:
/* accumulator */
Chars += fprintf (F, "%*sa", 9-Chars, "");
break;
- case AM_IMM:
+ case AM65_IMM:
/* immidiate */
Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg);
break;
- case AM_ZP:
- case AM_ABS:
+ case AM65_ZP:
+ case AM65_ABS:
/* zeropage and absolute */
Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg);
break;
- case AM_ZPX:
- case AM_ABSX:
+ case AM65_ZPX:
+ case AM65_ABSX:
/* zeropage,X and absolute,X */
Chars += fprintf (F, "%*s%s,x", 9-Chars, "", E->Arg);
break;
- case AM_ABSY:
+ case AM65_ABSY:
/* absolute,Y */
Chars += fprintf (F, "%*s%s,y", 9-Chars, "", E->Arg);
break;
- case AM_ZPX_IND:
+ case AM65_ZPX_IND:
/* (zeropage,x) */
Chars += fprintf (F, "%*s(%s,x)", 9-Chars, "", E->Arg);
break;
- case AM_ZP_INDY:
+ case AM65_ZP_INDY:
/* (zeropage),y */
Chars += fprintf (F, "%*s(%s),y", 9-Chars, "", E->Arg);
break;
- case AM_ZP_IND:
+ case AM65_ZP_IND:
/* (zeropage) */
Chars += fprintf (F, "%*s(%s)", 9-Chars, "", E->Arg);
break;
- case AM_BRA:
+ case AM65_BRA:
/* branch */
- CHECK (E->JumpTo != 0);
- Chars += fprintf (F, "%*s%s", 9-Chars, "", E->JumpTo->Name);
+ Target = E->JumpTo? E->JumpTo->Name : E->Arg;
+ Chars += fprintf (F, "%*s%s", 9-Chars, "", Target);
break;
default:
}
/* Print usage info if requested by the debugging flag */
-// if (Debug) {
- Chars += fprintf (F,
- "%*s; USE: %c%c%c CHG: %c%c%c",
- 30-Chars, "",
- (E->Info & CI_USE_A)? 'A' : '_',
- (E->Info & CI_USE_X)? 'X' : '_',
- (E->Info & CI_USE_Y)? 'Y' : '_',
- (E->Info & CI_CHG_A)? 'A' : '_',
- (E->Info & CI_CHG_X)? 'X' : '_',
- (E->Info & CI_CHG_Y)? 'Y' : '_');
-// }
-
- /* Terminate the line */
- fprintf (F, "\n");
+ 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);
+ } else {
+ /* Terminate the line */
+ fprintf (F, "\n");
+ }
}
+