mirror of
https://github.com/cc65/cc65.git
synced 2024-11-19 06:31:31 +00:00
Working on the backend
git-svn-id: svn://svn.cc65.org/cc65/trunk@729 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
1d3ea5cde0
commit
09eed789dd
@ -139,10 +139,13 @@ static int NumArg (const char* Arg, unsigned long* Num)
|
||||
|
||||
|
||||
|
||||
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)
|
||||
/* Create a new code entry, initialize and return it */
|
||||
{
|
||||
/* Allocate memory */
|
||||
/* Get the opcode description */
|
||||
const OPCDesc* D = GetOPCDesc (OPC);
|
||||
|
||||
/* Allocate memory */
|
||||
CodeEntry* E = xmalloc (sizeof (CodeEntry));
|
||||
|
||||
/* Initialize the fields */
|
||||
@ -246,30 +249,6 @@ void AttachCodeLabel (CodeEntry* E, CodeLabel* L)
|
||||
|
||||
|
||||
|
||||
int CodeEntryHasLabel (const CodeEntry* E)
|
||||
/* Check if the given code entry has labels attached */
|
||||
{
|
||||
return (CollCount (&E->Labels) > 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned GetCodeLabelCount (const CodeEntry* E)
|
||||
/* Get the number of labels attached to this entry */
|
||||
{
|
||||
return CollCount (&E->Labels);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index)
|
||||
/* Get a label from this code entry */
|
||||
{
|
||||
return CollAt (&E->Labels, Index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
|
||||
/* Move the code label L from it's former owner to the code entry E. */
|
||||
{
|
||||
@ -283,30 +262,6 @@ void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
|
||||
|
||||
|
||||
|
||||
int CodeEntryHasMark (const CodeEntry* E)
|
||||
/* Return true if the given code entry has the CEF_USERMARK flag set */
|
||||
{
|
||||
return (E->Flags & CEF_USERMARK) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CodeEntrySetMark (CodeEntry* E)
|
||||
/* Set the CEF_USERMARK flag for the given entry */
|
||||
{
|
||||
E->Flags |= CEF_USERMARK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CodeEntryResetMark (CodeEntry* E)
|
||||
/* Reset the CEF_USERMARK flag for the given entry */
|
||||
{
|
||||
E->Flags &= ~CEF_USERMARK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CodeEntrySetArg (CodeEntry* E, const char* Arg)
|
||||
/* Set a new argument for the given code entry. An old string is deleted. */
|
||||
{
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
/* common */
|
||||
#include "coll.h"
|
||||
#include "inline.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "codelab.h"
|
||||
@ -84,7 +85,7 @@ struct CodeEntry {
|
||||
|
||||
|
||||
|
||||
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);
|
||||
/* Create a new code entry, initialize and return it */
|
||||
|
||||
void FreeCodeEntry (CodeEntry* E);
|
||||
@ -101,26 +102,68 @@ int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2);
|
||||
void AttachCodeLabel (CodeEntry* E, CodeLabel* L);
|
||||
/* Attach the label to the entry */
|
||||
|
||||
int CodeEntryHasLabel (const CodeEntry* E);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int CodeEntryHasLabel (const CodeEntry* E)
|
||||
/* Check if the given code entry has labels attached */
|
||||
{
|
||||
return (CollCount (&E->Labels) > 0);
|
||||
}
|
||||
#else
|
||||
# define CodeEntryHasLabel(E) (CollCount (&(E)->Labels) > 0)
|
||||
#endif
|
||||
|
||||
unsigned GetCodeLabelCount (const CodeEntry* E);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned GetCodeLabelCount (const CodeEntry* E)
|
||||
/* Get the number of labels attached to this entry */
|
||||
{
|
||||
return CollCount (&E->Labels);
|
||||
}
|
||||
#else
|
||||
# define GetCodeLabelCount(E) CollCount (&(E)->Labels)
|
||||
#endif
|
||||
|
||||
CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index)
|
||||
/* Get a label from this code entry */
|
||||
{
|
||||
return CollAt (&E->Labels, Index);
|
||||
}
|
||||
#else
|
||||
# define GetCodeLabel(E, Index) CollAt (&(E)->Labels, (Index))
|
||||
#endif
|
||||
|
||||
void MoveCodeLabel (CodeLabel* L, CodeEntry* E);
|
||||
/* Move the code label L from it's former owner to the code entry E. */
|
||||
|
||||
int CodeEntryHasMark (const CodeEntry* E);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int CodeEntryHasMark (const CodeEntry* E)
|
||||
/* Return true if the given code entry has the CEF_USERMARK flag set */
|
||||
{
|
||||
return (E->Flags & CEF_USERMARK) != 0;
|
||||
}
|
||||
#else
|
||||
# define CodeEntryHasMark(E) (((E)->Flags & CEF_USERMARK) != 0)
|
||||
#endif
|
||||
|
||||
void CodeEntrySetMark (CodeEntry* E);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void CodeEntrySetMark (CodeEntry* E)
|
||||
/* Set the CEF_USERMARK flag for the given entry */
|
||||
{
|
||||
E->Flags |= CEF_USERMARK;
|
||||
}
|
||||
#else
|
||||
# define CodeEntrySetMark(E) ((E)->Flags |= CEF_USERMARK)
|
||||
#endif
|
||||
|
||||
void CodeEntryResetMark (CodeEntry* E);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void CodeEntryResetMark (CodeEntry* E)
|
||||
/* Reset the CEF_USERMARK flag for the given entry */
|
||||
{
|
||||
E->Flags &= ~CEF_USERMARK;
|
||||
}
|
||||
#else
|
||||
# define CodeEntryResetMark(E) ((E)->Flags &= ~CEF_USERMARK)
|
||||
#endif
|
||||
|
||||
void CodeEntrySetArg (CodeEntry* E, const char* Arg);
|
||||
/* Set a new argument for the given code entry. An old string is deleted. */
|
||||
|
@ -242,6 +242,322 @@ NextEntry:
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* nega optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegA1 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* ldx #$00
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
*
|
||||
* Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < GetCodeEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check for a ldx */
|
||||
if (E->OPC == OPC_LDX &&
|
||||
E->AM == AM_IMM &&
|
||||
(E->Flags & CEF_NUMARG) != 0 &&
|
||||
E->Num == 0 &&
|
||||
GetCodeEntries (S, L, I+1, 2) &&
|
||||
L[0]->OPC == OPC_LDA &&
|
||||
(L[0]->Use & REG_X) == 0 &&
|
||||
L[1]->OPC == OPC_JSR &&
|
||||
strcmp (L[1]->Arg, "bnega") == 0) {
|
||||
|
||||
/* Remove the ldx instruction */
|
||||
DelCodeEntry (S, I);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegA2 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
* jeq/jne ..
|
||||
*
|
||||
* Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < GetCodeEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OPC_LDA &&
|
||||
GetCodeEntries (S, L, I+1, 2) &&
|
||||
L[0]->OPC == OPC_JSR &&
|
||||
strcmp (L[0]->Arg, "bnega") == 0 &&
|
||||
!CodeEntryHasLabel (L[0]) &&
|
||||
(L[1]->Info & OF_ZBRA) != 0) {
|
||||
|
||||
/* Invert the branch */
|
||||
ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
|
||||
|
||||
/* Delete the subroutine call */
|
||||
DelCodeEntry (S, I+1);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* negax optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegAX1 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda (xx),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (xx),y
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda (xx),y
|
||||
* dey
|
||||
* ora (xx),y
|
||||
* jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < GetCodeEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[5];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OPC_LDA &&
|
||||
E->AM == AM_ZP_INDY &&
|
||||
GetCodeEntries (S, L, I+1, 5) &&
|
||||
L[0]->OPC == OPC_TAX &&
|
||||
L[1]->OPC == OPC_DEY &&
|
||||
L[2]->OPC == OPC_LDA &&
|
||||
L[2]->AM == AM_ZP_INDY &&
|
||||
strcmp (L[2]->Arg, E->Arg) == 0 &&
|
||||
!CodeEntryHasLabel (L[2]) &&
|
||||
L[3]->OPC == OPC_JSR &&
|
||||
strcmp (L[3]->Arg, "bnegax") == 0 &&
|
||||
!CodeEntryHasLabel (L[3]) &&
|
||||
(L[4]->Info & OF_ZBRA) != 0) {
|
||||
|
||||
/* lda --> ora */
|
||||
ReplaceOPC (L[2], OPC_ORA);
|
||||
|
||||
/* Invert the branch */
|
||||
ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
|
||||
|
||||
/* Delete the entries no longer needed. Beware: Deleting entries
|
||||
* will change the indices.
|
||||
*/
|
||||
DelCodeEntry (S, I+4); /* jsr bnegax */
|
||||
DelCodeEntry (S, I+1); /* tax */
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegAX2 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda xx
|
||||
* ldx yy
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda xx
|
||||
* ora xx+1
|
||||
* jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < GetCodeEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[3];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OPC_LDA &&
|
||||
GetCodeEntries (S, L, I+1, 3) &&
|
||||
L[0]->OPC == OPC_LDX &&
|
||||
!CodeEntryHasLabel (L[0]) &&
|
||||
L[1]->OPC == OPC_JSR &&
|
||||
strcmp (L[1]->Arg, "bnegax") == 0 &&
|
||||
!CodeEntryHasLabel (L[1]) &&
|
||||
(L[2]->Info & OF_ZBRA) != 0) {
|
||||
|
||||
/* ldx --> ora */
|
||||
ReplaceOPC (L[0], OPC_ORA);
|
||||
|
||||
/* Invert the branch */
|
||||
ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
|
||||
|
||||
/* Delete the subroutine call */
|
||||
DelCodeEntry (S, I+2);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegAX3 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr _xxx
|
||||
* jsr bnega(x)
|
||||
* jeq/jne ...
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* jsr _xxx
|
||||
* <boolean test>
|
||||
* jne/jeq ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < GetCodeEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OPC_JSR &&
|
||||
E->Arg[0] == '_' &&
|
||||
GetCodeEntries (S, L, I+1, 2) &&
|
||||
L[0]->OPC == OPC_JSR &&
|
||||
strncmp (L[0]->Arg,"bnega",5) == 0 &&
|
||||
!CodeEntryHasLabel (L[0]) &&
|
||||
(L[1]->Info & OF_ZBRA) != 0) {
|
||||
|
||||
/* Check if we're calling bnega or bnegax */
|
||||
int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
|
||||
|
||||
/* Delete the subroutine call */
|
||||
DelCodeEntry (S, I+1);
|
||||
|
||||
/* Insert apropriate test code */
|
||||
if (ByteSized) {
|
||||
/* Test bytes */
|
||||
InsertCodeEntry (S, NewCodeEntry (OPC_TAX, AM_IMP, 0, 0), I+1);
|
||||
} else {
|
||||
/* Test words */
|
||||
InsertCodeEntry (S, NewCodeEntry (OPC_STX, AM_ZP, "tmp1", 0), I+1);
|
||||
InsertCodeEntry (S, NewCodeEntry (OPC_ORA, AM_ZP, "tmp1", 0), I+2);
|
||||
}
|
||||
|
||||
/* Invert the branch */
|
||||
ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
@ -271,9 +587,21 @@ static OptFunc OptFuncs [] = {
|
||||
/* Optimize jump targets */
|
||||
{ OptJumpTarget, "OptJumpTarget", 0 },
|
||||
/* Optimize conditional branches */
|
||||
{ OptCondBranches, "OptCondBranches", 0 },
|
||||
{ OptCondBranches, "OptCondBranches", 0 },
|
||||
/* Replace jumps to RTS by RTS */
|
||||
{ OptRTSJumps, "OptRTSJumps", 0 },
|
||||
/* Remove calls to the bool transformer subroutines */
|
||||
{ OptBoolTransforms, "OptBoolTransforms", 0 },
|
||||
/* Optimize calls to nega */
|
||||
{ OptNegA1, "OptNegA1", 0 },
|
||||
/* Optimize calls to nega */
|
||||
{ OptNegA2, "OptNegA2", 0 },
|
||||
/* Optimize calls to negax */
|
||||
{ OptNegAX1, "OptNegAX1", 0 },
|
||||
/* Optimize calls to negax */
|
||||
{ OptNegAX2, "OptNegAX2", 0 },
|
||||
/* Optimize calls to negax */
|
||||
{ OptNegAX3, "OptNegAX3", 0 },
|
||||
/* Remove unused loads */
|
||||
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
||||
/* Optimize branch distance */
|
||||
|
@ -155,7 +155,7 @@ static const char* SkipSpace (const char* S)
|
||||
|
||||
|
||||
static const char* ReadToken (const char* L, const char* Term,
|
||||
char* Buf, unsigned BufSize)
|
||||
char* Buf, unsigned BufSize)
|
||||
/* Read the next token into Buf, return the updated line pointer. The
|
||||
* token is terminated by one of the characters given in term.
|
||||
*/
|
||||
@ -181,7 +181,7 @@ static const char* ReadToken (const char* L, const char* Term,
|
||||
/* Return the updated line pointer */
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
|
||||
@ -197,7 +197,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
|
||||
am_t AM = 0; /* Initialize to keep gcc silent */
|
||||
char Arg[64];
|
||||
char Reg;
|
||||
CodeEntry* E;
|
||||
CodeEntry* E;
|
||||
CodeLabel* Label;
|
||||
|
||||
/* Mnemonic */
|
||||
@ -353,7 +353,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
|
||||
/* We do now have the addressing mode in AM. Allocate a new CodeEntry
|
||||
* structure and initialize it.
|
||||
*/
|
||||
E = NewCodeEntry (OPC, AM, Arg, Label);
|
||||
E = NewCodeEntry (OPC->OPC, AM, Arg, Label);
|
||||
|
||||
/* Return the new code entry */
|
||||
return E;
|
||||
@ -393,7 +393,7 @@ CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
|
||||
S->ExitRegs = REG_NONE;
|
||||
}
|
||||
|
||||
/* Return the new struct */
|
||||
/* Return the new struct */
|
||||
return S;
|
||||
}
|
||||
|
||||
@ -527,14 +527,6 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
|
||||
|
||||
|
||||
|
||||
struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index)
|
||||
/* Get an entry from the given code segment */
|
||||
{
|
||||
return CollAt (&S->Entries, Index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index)
|
||||
/* Get the code entry following the one with the index Index. If there is no
|
||||
* following code entry, return NULL.
|
||||
@ -545,12 +537,34 @@ struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index)
|
||||
return 0;
|
||||
} else {
|
||||
/* Code entries left */
|
||||
return CollAt (&S->Entries, Index+1);
|
||||
return CollAtUnchecked (&S->Entries, Index+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int GetCodeEntries (CodeSeg* S, struct CodeEntry** List,
|
||||
unsigned Start, unsigned Count)
|
||||
/* Get Count code entries into List starting at index start. Return true if
|
||||
* we got the lines, return false if not enough lines were available.
|
||||
*/
|
||||
{
|
||||
/* Check if enough entries are available */
|
||||
if (Start + Count > CollCount (&S->Entries)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the entries */
|
||||
while (Count--) {
|
||||
*List++ = CollAtUnchecked (&S->Entries, Start++);
|
||||
}
|
||||
|
||||
/* We have the entries */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned GetCodeEntryIndex (CodeSeg* S, struct CodeEntry* E)
|
||||
/* Return the index of a code entry */
|
||||
{
|
||||
@ -917,11 +931,6 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
|
||||
|
||||
|
||||
|
||||
unsigned GetCodeEntryCount (const CodeSeg* S)
|
||||
/* Return the number of entries for the given code segment */
|
||||
{
|
||||
return CollCount (&S->Entries);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
/* common */
|
||||
#include "attrib.h"
|
||||
#include "coll.h"
|
||||
#include "inline.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "codelab.h"
|
||||
@ -106,14 +107,27 @@ void DelCodeEntry (CodeSeg* S, unsigned Index);
|
||||
* if the reference count drops to zero.
|
||||
*/
|
||||
|
||||
struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index)
|
||||
/* Get an entry from the given code segment */
|
||||
{
|
||||
return CollAt (&S->Entries, Index);
|
||||
}
|
||||
#else
|
||||
# define GetCodeEntry(S, Index) CollAt(&(S)->Entries, (Index))
|
||||
#endif
|
||||
|
||||
struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index);
|
||||
/* Get the code entry following the one with the index Index. If there is no
|
||||
* following code entry, return NULL.
|
||||
*/
|
||||
|
||||
int GetCodeEntries (CodeSeg* S, struct CodeEntry** List,
|
||||
unsigned Start, unsigned Count);
|
||||
/* Get Count code entries into List starting at index start. Return true if
|
||||
* we got the lines, return false if not enough lines were available.
|
||||
*/
|
||||
|
||||
unsigned GetCodeEntryIndex (CodeSeg* S, struct CodeEntry* E);
|
||||
/* Return the index of a code entry */
|
||||
|
||||
@ -162,8 +176,15 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last);
|
||||
void OutputCodeSeg (const CodeSeg* S, FILE* F);
|
||||
/* Output the code segment data to a file */
|
||||
|
||||
unsigned GetCodeEntryCount (const CodeSeg* S);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned GetCodeEntryCount (const CodeSeg* S)
|
||||
/* Return the number of entries for the given code segment */
|
||||
{
|
||||
return CollCount (&S->Entries);
|
||||
}
|
||||
#else
|
||||
# define GetCodeEntryCount(S) CollCount (&(S)->Entries)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
@ -44,6 +44,51 @@
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Replace jumps to RTS by RTS */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned OptRTSJumps (CodeSeg* S)
|
||||
/* Replace jumps to RTS by RTS */
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over all entries minus the last one */
|
||||
unsigned I = 0;
|
||||
while (I < GetCodeEntryCount (S)) {
|
||||
|
||||
/* Get the next entry */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check if it's an unconditional branch to a local target */
|
||||
if ((E->Info & OF_UBRA) != 0 &&
|
||||
E->JumpTo != 0 &&
|
||||
E->JumpTo->Owner->OPC == OPC_RTS) {
|
||||
|
||||
/* Delete the jump */
|
||||
DelCodeEntry (S, I);
|
||||
|
||||
/* Insert an RTS instruction instead */
|
||||
InsertCodeEntry (S, NewCodeEntry (OPC_RTS, AM_IMP, 0, 0), I);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Remove dead jumps */
|
||||
/*****************************************************************************/
|
||||
@ -118,9 +163,11 @@ unsigned OptDeadCode (CodeSeg* S)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Walk over all entries minus the last one */
|
||||
/* Walk over all entries */
|
||||
I = 0;
|
||||
while (I < Count-1) {
|
||||
while (I < Count) {
|
||||
|
||||
CodeEntry* N;
|
||||
|
||||
/* Get this entry */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
@ -128,7 +175,9 @@ unsigned OptDeadCode (CodeSeg* S)
|
||||
/* Check if it's an unconditional branch, and if the next entry has
|
||||
* no labels attached
|
||||
*/
|
||||
if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
|
||||
if ((E->Info & OF_DEAD) != 0 &&
|
||||
(N = GetNextCodeEntry (S, I)) != 0 &&
|
||||
!CodeEntryHasLabel (N)) {
|
||||
|
||||
/* Delete the next entry */
|
||||
DelCodeEntry (S, I+1);
|
||||
|
@ -48,7 +48,10 @@
|
||||
|
||||
|
||||
|
||||
unsigned OptDeadJumps (CodeSeg* S);
|
||||
unsigned OptRTSJumps (CodeSeg* S);
|
||||
/* Replace jumps to RTS by RTS */
|
||||
|
||||
unsigned OptDeadJumps (CodeSeg* S);
|
||||
/* Remove dead jumps (jumps to the next instruction) */
|
||||
|
||||
unsigned OptDeadCode (CodeSeg* S);
|
||||
|
@ -54,81 +54,81 @@
|
||||
|
||||
|
||||
|
||||
/* Mapper table, mnemonic --> opcode */
|
||||
static const OPCDesc OPCTable[OPC_COUNT] = {
|
||||
{ OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_AND, "and", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
|
||||
{ OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CMP, "cmp", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_CPX, "cpx", 0, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_CPY, "cpy", 0, REG_Y, REG_NONE, OF_NONE },
|
||||
{ OPC_DEA, "dea", 1, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_DEX, "dex", 1, REG_X, REG_X, OF_NONE },
|
||||
{ OPC_DEY, "dey", 1, REG_Y, REG_Y, OF_NONE },
|
||||
{ OPC_EOR, "eor", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_INA, "ina", 1, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
|
||||
{ OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
|
||||
{ OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | OF_LBRA },
|
||||
{ OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_LOAD },
|
||||
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_LOAD },
|
||||
{ OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_LOAD },
|
||||
{ OPC_LSR, "lsr", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_ORA, "ora", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_PHA, "pha", 1, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_PHX, "phx", 1, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_PHY, "phy", 1, REG_Y, REG_NONE, OF_NONE },
|
||||
{ OPC_PLA, "pla", 1, REG_NONE, REG_A, OF_NONE },
|
||||
{ OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_PLX, "plx", 1, REG_NONE, REG_X, OF_NONE },
|
||||
{ OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
|
||||
{ OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_ROR, "ror", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
|
||||
{ OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET },
|
||||
{ OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_STA, "sta", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_STX, "stx", 0, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_STY, "sty", 0, REG_Y, REG_NONE, OF_NONE },
|
||||
{ OPC_TAX, "tax", 1, REG_A, REG_X, OF_NONE },
|
||||
{ OPC_TAY, "tay", 1, REG_A, REG_Y, OF_NONE },
|
||||
{ OPC_TRB, "trb", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_TSB, "tsb", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_TSX, "tsx", 1, REG_NONE, REG_X, OF_NONE },
|
||||
{ OPC_TXA, "txa", 1, REG_X, REG_A, OF_NONE },
|
||||
{ OPC_TXS, "txs", 1, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_TYA, "tya", 1, REG_A, REG_A, OF_NONE },
|
||||
/* Opcode description table */
|
||||
const OPCDesc OPCTable[OPC_COUNT] = {
|
||||
{ OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_AND, "and", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA },
|
||||
{ OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA },
|
||||
{ OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
|
||||
{ OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CLV, "clv", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_CMP, "cmp", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_CPX, "cpx", 0, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_CPY, "cpy", 0, REG_Y, REG_NONE, OF_NONE },
|
||||
{ OPC_DEA, "dea", 1, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_DEX, "dex", 1, REG_X, REG_X, OF_NONE },
|
||||
{ OPC_DEY, "dey", 1, REG_Y, REG_Y, OF_NONE },
|
||||
{ OPC_EOR, "eor", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_INA, "ina", 1, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
|
||||
{ OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
|
||||
{ OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA },
|
||||
{ OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | OF_LBRA },
|
||||
{ OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA | OF_ZBRA },
|
||||
{ OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_LOAD },
|
||||
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_LOAD },
|
||||
{ OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_LOAD },
|
||||
{ OPC_LSR, "lsr", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_ORA, "ora", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_PHA, "pha", 1, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_PHP, "php", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_PHX, "phx", 1, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_PHY, "phy", 1, REG_Y, REG_NONE, OF_NONE },
|
||||
{ OPC_PLA, "pla", 1, REG_NONE, REG_A, OF_NONE },
|
||||
{ OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_PLX, "plx", 1, REG_NONE, REG_X, OF_NONE },
|
||||
{ OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
|
||||
{ OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_ROR, "ror", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
|
||||
{ OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET },
|
||||
{ OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
|
||||
{ OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_STA, "sta", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_STX, "stx", 0, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_STY, "sty", 0, REG_Y, REG_NONE, OF_NONE },
|
||||
{ OPC_TAX, "tax", 1, REG_A, REG_X, OF_NONE },
|
||||
{ OPC_TAY, "tay", 1, REG_A, REG_Y, OF_NONE },
|
||||
{ OPC_TRB, "trb", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_TSB, "tsb", 0, REG_A, REG_NONE, OF_NONE },
|
||||
{ OPC_TSX, "tsx", 1, REG_NONE, REG_X, OF_NONE },
|
||||
{ OPC_TXA, "txa", 1, REG_X, REG_A, OF_NONE },
|
||||
{ OPC_TXS, "txs", 1, REG_X, REG_NONE, OF_NONE },
|
||||
{ OPC_TYA, "tya", 1, REG_A, REG_A, OF_NONE },
|
||||
};
|
||||
|
||||
|
||||
@ -203,30 +203,6 @@ unsigned GetInsnSize (opc_t OPC, am_t AM)
|
||||
|
||||
|
||||
|
||||
const OPCDesc* GetOPCDesc (opc_t OPC)
|
||||
/* Get an opcode description */
|
||||
{
|
||||
/* Check the range */
|
||||
PRECONDITION (OPC >= (opc_t)0 && OPC < OPC_COUNT);
|
||||
|
||||
/* Return the description */
|
||||
return &OPCTable [OPC];
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char GetOPCInfo (opc_t OPC)
|
||||
/* Get opcode information */
|
||||
{
|
||||
/* Check the range */
|
||||
PRECONDITION (OPC >= (opc_t)0 && OPC < OPC_COUNT);
|
||||
|
||||
/* Return the info */
|
||||
return OPCTable[OPC].Info;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char GetAMUseInfo (am_t AM)
|
||||
/* Get usage info for the given addressing mode (addressing modes that use
|
||||
* index registers return REG_r info for these registers).
|
||||
|
@ -38,6 +38,11 @@
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "inline.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
@ -155,7 +160,8 @@ typedef enum {
|
||||
#define OF_NONE 0x0000U /* No additional information */
|
||||
#define OF_UBRA 0x0001U /* Unconditional branch */
|
||||
#define OF_CBRA 0x0002U /* Conditional branch */
|
||||
#define OF_LBRA 0x0004U /* Jump/branch is long */
|
||||
#define OF_ZBRA 0x0004U /* Branch on zero flag condition */
|
||||
#define OF_LBRA 0x0008U /* Jump/branch is long */
|
||||
#define OF_RET 0x0010U /* Return from function */
|
||||
#define OF_LOAD 0x0020U /* Register load */
|
||||
#define OF_BRA (OF_UBRA|OF_CBRA) /* Operation is a jump/branch */
|
||||
@ -171,6 +177,9 @@ typedef struct {
|
||||
unsigned char Info; /* Additional information */
|
||||
} OPCDesc;
|
||||
|
||||
/* Opcode description table */
|
||||
extern const OPCDesc OPCTable[OPC_COUNT];
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -187,11 +196,27 @@ const OPCDesc* FindOpcode (const char* OPC);
|
||||
unsigned GetInsnSize (opc_t OPC, am_t AM);
|
||||
/* Return the size of the given instruction */
|
||||
|
||||
const OPCDesc* GetOPCDesc (opc_t OPC);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE const OPCDesc* GetOPCDesc (opc_t OPC)
|
||||
/* Get an opcode description */
|
||||
{
|
||||
/* Return the description */
|
||||
return &OPCTable [OPC];
|
||||
}
|
||||
#else
|
||||
# define GetOPCDesc(OPC) (&OPCTable [(OPC)])
|
||||
#endif
|
||||
|
||||
unsigned char GetOPCInfo (opc_t OPC);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned char GetOPCInfo (opc_t OPC)
|
||||
/* Get opcode information */
|
||||
{
|
||||
/* Return the info */
|
||||
return OPCTable[OPC].Info;
|
||||
}
|
||||
#else
|
||||
# define GetOPCInfo(OPC) (OPCTable[(OPC)].Info)
|
||||
#endif
|
||||
|
||||
unsigned char GetAMUseInfo (am_t AM);
|
||||
/* Get usage info for the given addressing mode (addressing modes that use
|
||||
|
Loading…
Reference in New Issue
Block a user