/* cc65 */
#include "error.h"
+#include "global.h"
/* b6502 */
#include "codeinfo.h"
E->AM = AM;
E->Size = GetInsnSize (E->OPC, E->AM);
E->Hints = 0;
- E->Arg.Num = 0;
+ E->Arg = 0;
+ E->Num = 0;
E->Flags = 0;
- E->Usage = D->Info & (CI_MASK_USE | CI_MASK_CHG);
+ E->Info = D->Info | GetAMUseInfo (AM);
E->JumpTo = JumpTo;
InitCollection (&E->Labels);
void FreeCodeEntry (CodeEntry* E)
/* Free the given code entry */
{
- /* ## Free the string argument if we have one */
+ /* Free the string argument if we have one */
+ xfree (E->Arg);
/* Cleanup the collection */
DoneCollection (&E->Labels);
+int CodeEntryHasLabel (const CodeEntry* E)
+/* Check if the given code entry has labels attached */
+{
+ return (CollCount (&E->Labels) > 0);
+}
+
+
+
void OutputCodeEntry (FILE* F, const CodeEntry* E)
/* Output the code entry to a file */
{
const OPCDesc* D;
+ unsigned Chars;
/* 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 (F, CollConstAt (&E->Labels, I));
}
/* Get the opcode description */
D = GetOPCDesc (E->OPC);
/* Print the mnemonic */
- fprintf (F, "\t%s", D->Mnemo);
+ Chars = fprintf (F, "\t%s", D->Mnemo);
/* Print the operand */
switch (E->AM) {
- case AM_IMP:
- /* implicit */
- break;
+ case AM_IMP:
+ /* implicit */
+ break;
- case AM_ACC:
- /* accumulator */
- fprintf (F, "\ta");
- break;
+ case AM_ACC:
+ /* accumulator */
+ Chars += fprintf (F, "%*sa", 9-Chars, "");
+ break;
- case AM_IMM:
- /* immidiate */
- fprintf (F, "\t#%s", E->Arg.Expr);
- break;
+ case AM_IMM:
+ /* immidiate */
+ Chars += fprintf (F, "%*s#%s", 9-Chars, "", E->Arg);
+ break;
- case AM_ZP:
- case AM_ABS:
+ case AM_ZP:
+ case AM_ABS:
/* zeropage and absolute */
- fprintf (F, "\t%s", E->Arg.Expr);
+ Chars += fprintf (F, "%*s%s", 9-Chars, "", E->Arg);
break;
case AM_ZPX:
case AM_ABSX:
/* zeropage,X and absolute,X */
- fprintf (F, "\t%s,x", E->Arg.Expr);
+ Chars += fprintf (F, "%*s%s,x", 9-Chars, "", E->Arg);
break;
case AM_ABSY:
/* absolute,Y */
- fprintf (F, "\t%s,y", E->Arg.Expr);
+ Chars += fprintf (F, "%*s%s,y", 9-Chars, "", E->Arg);
break;
case AM_ZPX_IND:
/* (zeropage,x) */
- fprintf (F, "\t(%s,x)", E->Arg.Expr);
+ Chars += fprintf (F, "%*s(%s,x)", 9-Chars, "", E->Arg);
break;
case AM_ZP_INDY:
/* (zeropage),y */
- fprintf (F, "\t(%s),y", E->Arg.Expr);
+ Chars += fprintf (F, "%*s(%s),y", 9-Chars, "", E->Arg);
break;
case AM_ZP_IND:
/* (zeropage) */
- fprintf (F, "\t(%s)", E->Arg.Expr);
+ Chars += fprintf (F, "%*s(%s)", 9-Chars, "", E->Arg);
break;
case AM_BRA:
/* branch */
CHECK (E->JumpTo != 0);
- fprintf (F, "\t%s", E->JumpTo->Name);
+ Chars += fprintf (F, "%*s%s", 9-Chars, "", E->JumpTo->Name);
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");
}
+/* Flags used */
+#define CEF_USERMARK 0x0001U /* Generic mark by user functions */
+#define CEF_NUMARG 0x0002U /* Insn has numerical argument */
+
/* Code entry structure */
typedef struct CodeEntry CodeEntry;
struct CodeEntry {
am_t AM; /* Adressing mode */
unsigned char Size; /* Estimated size */
unsigned char Hints; /* Hints for this entry */
- union {
- unsigned Num; /* Numeric argument */
- char* Expr; /* Textual argument */
- } Arg;
+ char* Arg; /* Argument as string */
+ unsigned Num; /* Numeric argument */
unsigned short Flags; /* Flags */
- unsigned short Usage; /* Register usage for this entry */
+ unsigned short Info; /* Register usage info for this entry */
CodeLabel* JumpTo; /* Jump label */
Collection Labels; /* Labels for this instruction */
};
void FreeCodeEntry (CodeEntry* E);
/* Free the given code entry */
+int CodeEntryHasLabel (const CodeEntry* E);
+/* Check if the given code entry has labels attached */
+
void OutputCodeEntry (FILE* F, const CodeEntry* E);
/* Output the code entry to a file */
/* common */
#include "xmalloc.h"
-/* cc65 */
+/* b6502 */
+#include "codeent.h"
#include "label.h"
+void AddLabelRef (CodeLabel* L, struct CodeEntry* E)
+/* Let the CodeEntry E reference the label L */
+{
+ /* The insn at E jumps to this label */
+ E->JumpTo = L;
+
+ /* Remember that in the label */
+ CollAppend (&L->JumpFrom, E);
+}
+
+
+
unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E)
/* Remove a reference to this label, return the number of remaining references */
{
void OutputCodeLabel (FILE* F, const CodeLabel* L)
/* Output the code label to a file */
{
- fprintf (F, "%s:\n", L->Name);
+ fprintf (F, "%s:", L->Name);
}
void FreeCodeLabel (CodeLabel* L);
/* Free the given code label */
+void AddLabelRef (CodeLabel* L, struct CodeEntry* E);
+/* Let the CodeEntry E reference the label L */
+
unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E);
/* Remove a reference to this label, return the number of remaining references */
+/* common */
+#include "print.h"
+
+/* cc65 */
+#include "global.h"
+
/* b6502 */
#include "codeent.h"
+#include "codeinfo.h"
#include "codeopt.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/*****************************************************************************/
-/* Remove dead jumps */
+/* Remove dead jumps */
/*****************************************************************************/
/* Check if it's a branch, if it has a local target, and if the target
* is the next instruction.
*/
- if (E->AM == AM_BRA) {
- printf ("BRA on entry %u:\n", I);
- if (E->JumpTo) {
- printf (" JumpTo ok\n");
- if (E->JumpTo->Owner == CollAt (&S->Entries, I+1)) {
- printf (" Branch to next insn\n");
- }
- }
- }
-
if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == CollAt (&S->Entries, I+1)) {
- /* Remember the label */
- CodeLabel* L = E->JumpTo;
+ /* Delete the dead jump */
+ DelCodeSegLine (S, I);
- /* Jump to next instruction, remove it */
- unsigned Remaining = RemoveLabelRef (L, E);
- CollDelete (&S->Entries, I);
- FreeCodeEntry (E);
+ /* Keep the number of entries updated */
--Count;
- /* If the label has no more references, remove it */
- if (Remaining == 0) {
- CollDeleteItem (&L->Owner->Labels, L);
- FreeCodeLabel (L);
- }
-
- /* Remember we had changes */
+ /* Remember, we had changes */
++OptChanges;
} else {
+/*****************************************************************************/
+/* Remove dead code */
+/*****************************************************************************/
+
+
+
+static void OptDeadCode (CodeSeg* S)
+/* Remove dead code (code that follows an unconditional jump or an rts/rti
+ * and has no label)
+ */
+{
+ unsigned I;
+
+ /* Get the number of entries, bail out if we have less than two entries */
+ unsigned Count = CollCount (&S->Entries);
+ if (Count < 2) {
+ return;
+ }
+
+ /* Walk over all entries minus the last one */
+ I = 0;
+ while (I < Count-1) {
+
+ /* Get this entry */
+ CodeEntry* E = CollAt (&S->Entries, I);
+
+ /* Check if it's an unconditional branch, and if the next entry has
+ * no labels attached
+ */
+ if ((E->OPC == OPC_JMP || E->OPC == OPC_BRA || E->OPC == OPC_RTS || E->OPC == OPC_RTI) &&
+ !CodeEntryHasLabel (CollAt (&S->Entries, I+1))) {
+
+ /* Delete the next entry */
+ DelCodeSegLine (S, I+1);
+
+ /* Keep the number of entries updated */
+ --Count;
+
+ /* Remember, we had changes */
+ ++OptChanges;
+
+ } else {
+
+ /* Next entry */
+ ++I;
+
+ }
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Optimize jump cascades */
+/*****************************************************************************/
+
+
+
+static void OptJumpCascades (CodeSeg* S)
+/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
+ * replaced by a jump to the final location. This will in some cases produce
+ * worse code, because some jump targets are no longer reachable by short
+ * branches, but this is quite rare, so there are more advantages than
+ * disadvantages.
+ */
+{
+ unsigned I;
+
+ /* Get the number of entries, bail out if we have no entries */
+ unsigned Count = CollCount (&S->Entries);
+ if (Count == 0) {
+ return;
+ }
+
+ /* Walk over all entries */
+ I = 0;
+ while (I < Count) {
+
+ CodeLabel* OldLabel;
+ CodeLabel* NewLabel;
+
+ /* Get this entry */
+ CodeEntry* E = CollAt (&S->Entries, I);
+
+ /* Check if it's a branch, if it has a label attached, and if the
+ * instruction at this label is also a branch.
+ */
+ if (E->AM == AM_BRA &&
+ (OldLabel = E->JumpTo) != 0 &&
+ OldLabel->Owner->AM == AM_BRA &&
+ (NewLabel = OldLabel->Owner->JumpTo) != 0) {
+
+ /* Get the instruction that has the new label attached */
+ CodeEntry* N = OldLabel->Owner;
+
+ /* Remove the reference to our label and delete it if this was
+ * the last reference.
+ */
+ if (RemoveLabelRef (OldLabel, E) == 0) {
+ /* Delete it */
+ DelCodeLabel (S, OldLabel);
+ }
+
+ /* Remove usage information from the entry and use the usage
+ * information from the new instruction instead.
+ */
+ E->Info &= ~(CI_MASK_USE | CI_MASK_CHG);
+ E->Info |= N->Info & ~(CI_MASK_USE | CI_MASK_CHG);
+
+ /* Use the new label */
+ AddLabelRef (NewLabel, E);
+
+ /* Remember ,we had changes */
+ ++OptChanges;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+}
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void RunOpt (CodeSeg* S)
/* Run the optimizer */
{
- printf ("Optimize\n");
+ typedef void (*OptFunc) (CodeSeg*);
+
+ /* Table with optimizer steps - are called in this order */
+ static const OptFunc OptFuncs [] = {
+ OptJumpCascades, /* Optimize jump cascades */
+ OptDeadJumps, /* Remove dead jumps */
+ OptDeadCode, /* Remove dead code */
+ };
/* Repeat all steps until there are no more changes */
do {
+ unsigned long Flags;
+ unsigned I;
+
/* Reset the number of changes */
OptChanges = 0;
- OptDeadJumps (S);
+ /* Run all optimization steps */
+ Flags = 1UL;
+ for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
+ if ((OptDisable & Flags) == 0) {
+ OptFuncs[I] (S);
+ } else if (Verbosity > 0 || Debug) {
+ printf ("Optimizer pass %u skipped\n", I);
+ }
+ Flags <<= 1;
+ }
} while (OptChanges > 0);
}
* white space, for example.
*/
{
- char Mnemo[16];
+ char Mnemo[16];
const OPCDesc* OPC;
am_t AM = 0; /* Initialize to keep gcc silent */
- char Expr[64];
+ char Arg[64];
char Reg;
CodeEntry* E;
CodeLabel* Label;
L = SkipSpace (L);
/* Get the addressing mode */
- Expr[0] = '\0';
+ Arg[0] = '\0';
switch (*L) {
case '\0':
case '#':
/* Immidiate */
- StrCopy (Expr, sizeof (Expr), L+1);
+ StrCopy (Arg, sizeof (Arg), L+1);
AM = AM_IMM;
break;
case '(':
/* Indirect */
- L = ReadToken (L+1, ",)", Expr, sizeof (Expr));
+ L = ReadToken (L+1, ",)", Arg, sizeof (Arg));
/* Check for errors */
if (*L == '\0') {
}
L = SkipSpace (L+1);
if (*L != '\0') {
- Error ("ASM code error: syntax error");
+ Error ("ASM code error: syntax error");
return 0;
}
AM = AM_ZP_INDY;
default:
/* Absolute, maybe indexed */
- L = ReadToken (L, ",", Expr, sizeof (Expr));
+ L = ReadToken (L, ",", Arg, sizeof (Arg));
if (*L == '\0') {
/* Assume absolute */
AM = AM_ABS;
AM = AM_ABSY;
} else {
Error ("ASM code error: syntax error");
- return 0;
+ return 0;
}
if (*L != '\0') {
Error ("ASM code error: syntax error");
* if it does not exist. Ignore anything but local labels here.
*/
Label = 0;
- if ((OPC->Info & CI_MASK_BRA) == CI_BRA && Expr[0] == 'L') {
+ if ((OPC->Info & CI_MASK_BRA) == CI_BRA && Arg[0] == 'L') {
unsigned Hash;
AM = AM_BRA;
/* Generate the hash over the label, then search for the label */
- Hash = HashStr (Expr) % CS_LABEL_HASH_SIZE;
- Label = FindCodeLabel (S, Expr, Hash);
+ Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
+ Label = FindCodeLabel (S, Arg, Hash);
/* If we don't have the label, it's a forward ref - create it */
if (Label == 0) {
/* Generate a new label */
- Label = NewCodeSegLabel (S, Expr, Hash);
+ Label = NewCodeSegLabel (S, Arg, Hash);
}
}
* structure and initialize it.
*/
E = NewCodeEntry (OPC, AM, Label);
- if (Expr[0] != '\0') {
+ if (Arg[0] != '\0') {
/* We have an additional expression */
- E->Arg.Expr = xstrdup (Expr);
+ E->Arg = xstrdup (Arg);
}
/* Return the new code entry */
void FreeCodeSeg (CodeSeg* S)
/* Free a code segment including all code entries */
{
- unsigned I, Count;
-
- /* Free the names */
- xfree (S->SegName);
- xfree (S->FuncName);
-
- /* Free the entries */
- Count = CollCount (&S->Entries);
- for (I = 0; I < Count; ++I) {
- FreeCodeEntry (CollAt (&S->Entries, I));
- }
-
- /* Free the collections */
- DoneCollection (&S->Entries);
- DoneCollection (&S->Labels);
-
- /* Free all labels */
- for (I = 0; I < sizeof(S->LabelHash) / sizeof(S->LabelHash[0]); ++I) {
- CodeLabel* L = S->LabelHash[I];
- while (L) {
- CodeLabel* Tmp = L;
- L = L->Next;
- FreeCodeLabel (Tmp);
- }
- }
-
- /* Free the struct */
- xfree (S);
+ FAIL ("Not implemented");
}
E = 0; /* Assume no insn created */
switch (*L) {
- case '\0':
+ case '\0':
/* Empty line, just ignore it */
break;
+void DelCodeSegLine (CodeSeg* S, unsigned Index)
+/* Delete an entry from the code segment. This includes deleting any associated
+ * labels, removing references to labels and even removing the referenced labels
+ * if the reference count drops to zero.
+ */
+{
+ /* Get the code entry for the given index */
+ CodeEntry* E = CollAt (&S->Entries, Index);
+
+ /* Remove any labels associated with this entry */
+ unsigned Count;
+ while ((Count = CollCount (&E->Labels)) > 0) {
+ DelCodeLabel (S, CollAt (&E->Labels, Count-1));
+ }
+
+ /* If this insn references a label, remove the reference. And, if the
+ * the reference count for this label drops to zero, remove this label.
+ */
+ if (E->JumpTo) {
+
+ /* Remove the reference */
+ if (RemoveLabelRef (E->JumpTo, E) == 0) {
+ /* No references remaining, remove the label */
+ DelCodeLabel (S, E->JumpTo);
+ }
+
+ /* Reset the label pointer to avoid problems later */
+ E->JumpTo = 0;
+ }
+
+ /* Delete the pointer to the insn */
+ CollDelete (&S->Entries, Index);
+
+ /* Delete the instruction itself */
+ FreeCodeEntry (E);
+}
+
+
+
void AddCodeLabel (CodeSeg* S, const char* Name)
/* Add a code label for the next instruction to follow */
{
/* Did we find it? */
if (L) {
- /* We found it - be sure it does not already have an owner */
- CHECK (L->Owner == 0);
+ /* We found it - be sure it does not already have an owner */
+ CHECK (L->Owner == 0);
} else {
- /* Not found - create a new one */
- L = NewCodeSegLabel (S, Name, Hash);
+ /* Not found - create a new one */
+ L = NewCodeSegLabel (S, Name, Hash);
}
/* We do now have a valid label. Remember it for later */
+void DelCodeLabel (CodeSeg* S, CodeLabel* L)
+/* Remove references from this label and delete it. */
+{
+ unsigned Count, I;
+
+ /* Get the first entry in the hash chain */
+ CodeLabel* List = S->LabelHash[L->Hash];
+
+ /* First, remove the label from the hash chain */
+ if (List == L) {
+ /* First entry in hash chain */
+ S->LabelHash[L->Hash] = L->Next;
+ } else {
+ /* Must search through the chain */
+ while (List->Next != L) {
+ /* If we've reached the end of the chain, something is *really* wrong */
+ CHECK (List->Next != 0);
+ /* Next entry */
+ List = List->Next;
+ }
+ /* The next entry is the one, we have been searching for */
+ List->Next = L->Next;
+ }
+
+ /* Remove references from insns jumping to this label */
+ Count = CollCount (&L->JumpFrom);
+ for (I = 0; I < Count; ++I) {
+ /* Get the insn referencing this label */
+ CodeEntry* E = CollAt (&L->JumpFrom, I);
+ /* Remove the reference */
+ E->JumpTo = 0;
+ }
+ CollDeleteAll (&L->JumpFrom);
+
+ /* Remove the reference to the owning instruction */
+ CollDeleteItem (&L->Owner->Labels, L);
+
+ /* All references removed, delete the label itself */
+ FreeCodeLabel (L);
+}
+
+
+
void AddCodeSegHint (CodeSeg* S, unsigned Hint)
/* Add a hint for the preceeding instruction */
{
/* Get the number of entries in this segment */
unsigned Count = CollCount (&S->Entries);
+ fprintf (F, "; Labels: ");
+ for (I = 0; I < CS_LABEL_HASH_SIZE; ++I) {
+ const CodeLabel* L = S->LabelHash[I];
+ while (L) {
+ fprintf (F, "%s ", L->Name);
+ L = L->Next;
+ }
+ }
+ fprintf (F, "\n");
+
/* Output the segment directive */
fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
unsigned RefCount = CollCount (&L->JumpFrom);
for (K = 0; K < RefCount; ++K) {
- /* Get the next instrcuction that references this label */
+ /* Get the next instruction that references this label */
CodeEntry* E = CollAt (&L->JumpFrom, K);
/* Change the reference */
CHECK (E->JumpTo == L);
- E->JumpTo = RefLab;
- CollAppend (&RefLab->JumpFrom, E);
+ AddLabelRef (RefLab, E);
}
+ /* There are no more instructions jumping to this label now */
+ CollDeleteAll (&L->JumpFrom);
+
/* Remove the label completely. */
- FreeCodeLabel (L);
- CollDelete (&E->Labels, J);
+ DelCodeLabel (S, L);
}
/* The reference label is the only remaining label. Check if there
*/
if (CollCount (&RefLab->JumpFrom) == 0) {
/* Delete the label */
- FreeCodeLabel (RefLab);
- /* Remove it from the list */
- CollDelete (&E->Labels, 0);
+ DelCodeLabel (S, RefLab);
}
}
}
void AddCodeSegLine (CodeSeg* S, const char* Format, ...) attribute ((format(printf,2,3)));
/* Add a line to the given code segment */
+void DelCodeSegLine (CodeSeg* S, unsigned Index);
+/* Delete an entry from the code segment. This includes deleting any associated
+ * labels, removing references to labels and even removing the referenced labels
+ * if the reference count drops to zero.
+ */
+
void AddCodeLabel (CodeSeg* S, const char* Name);
/* Add a code label for the next instruction to follow */
+void DelCodeLabel (CodeSeg* S, CodeLabel* L);
+/* Remove references from this label and delete it. */
+
void AddCodeSegHint (CodeSeg* S, unsigned Hint);
/* Add a hint for the preceeding instruction */
/* */
/* */
/* */
-/* (C) 1998-2000 Ullrich von Bassewitz */
+/* (C) 1998-2001 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
unsigned char WriteableStrings = 0; /* Literal strings are r/w */
unsigned char NoWarn = 0; /* Suppress warnings */
unsigned char Optimize = 0; /* Optimize flag */
+unsigned long OptDisable = 0; /* Optimizer passes to disable */
unsigned char FavourSize = 1; /* Favour size over speed */
unsigned CodeSizeFactor = 100; /* Size factor for generated code */
unsigned char InlineStdFuncs = 0; /* Inline some known functions */
/* */
/* */
/* */
-/* (C) 1998 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2001 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
extern unsigned char WriteableStrings; /* Literal strings are r/w */
extern unsigned char NoWarn; /* Suppress warnings */
extern unsigned char Optimize; /* Optimize flag */
+extern unsigned long OptDisable; /* Optimizer passes to disable */
extern unsigned char FavourSize; /* Favour size over speed */
extern unsigned CodeSizeFactor; /* Size factor for generated code */
extern unsigned char InlineStdFuncs; /* Inline some known functions */
P = Arg + 2;
while (*P) {
switch (*P++) {
-#if 0
case 'f':
sscanf (P, "%lx", (long*) &OptDisable);
break;
-#endif
case 'i':
FavourSize = 0;
CodeSizeFactor = 200;
+unsigned GetAMUseInfo (am_t AM)
+/* Get usage info for the given addressing mode (addressing modes that use
+ * index registers return CI_USE... info for these registers).
+ */
+{
+ /* Check the addressing mode. */
+ switch (AM) {
+ case AM_ACC: return CI_USE_A;
+ case AM_ZPX: return CI_USE_X;
+ case AM_ABSX: return CI_USE_X;
+ case AM_ABSY: return CI_USE_Y;
+ case AM_ZPX_IND: return CI_USE_X;
+ case AM_ZP_INDY: return CI_USE_Y;
+ default: return CI_USE_NONE;
+ }
+}
+
+
const OPCDesc* GetOPCDesc (opc_t OPC);
/* Get an opcode description */
+unsigned GetAMUseInfo (am_t AM);
+/* Get usage info for the given addressing mode (addressing modes that use
+ * index registers return CI_USE... info for these registers).
+ */
+
/* End of opcodes.h */