Working on the backend
git-svn-id: svn://svn.cc65.org/cc65/trunk@729 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -139,9 +139,12 @@ 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 */
|
/* Create a new code entry, initialize and return it */
|
||||||
{
|
{
|
||||||
|
/* Get the opcode description */
|
||||||
|
const OPCDesc* D = GetOPCDesc (OPC);
|
||||||
|
|
||||||
/* Allocate memory */
|
/* Allocate memory */
|
||||||
CodeEntry* E = xmalloc (sizeof (CodeEntry));
|
CodeEntry* E = xmalloc (sizeof (CodeEntry));
|
||||||
|
|
||||||
@@ -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)
|
void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
|
||||||
/* Move the code label L from it's former owner to the code entry 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)
|
void CodeEntrySetArg (CodeEntry* E, const char* Arg)
|
||||||
/* Set a new argument for the given code entry. An old string is deleted. */
|
/* Set a new argument for the given code entry. An old string is deleted. */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
/* common */
|
/* common */
|
||||||
#include "coll.h"
|
#include "coll.h"
|
||||||
|
#include "inline.h"
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "codelab.h"
|
#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 */
|
/* Create a new code entry, initialize and return it */
|
||||||
|
|
||||||
void FreeCodeEntry (CodeEntry* E);
|
void FreeCodeEntry (CodeEntry* E);
|
||||||
@@ -101,26 +102,68 @@ int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2);
|
|||||||
void AttachCodeLabel (CodeEntry* E, CodeLabel* L);
|
void AttachCodeLabel (CodeEntry* E, CodeLabel* L);
|
||||||
/* Attach the label to the entry */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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);
|
void MoveCodeLabel (CodeLabel* L, CodeEntry* E);
|
||||||
/* Move the code label L from it's former owner to the code entry 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 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 */
|
/* 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 */
|
/* 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);
|
void CodeEntrySetArg (CodeEntry* E, const char* Arg);
|
||||||
/* Set a new argument for the given code entry. An old string is deleted. */
|
/* 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 */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -271,9 +587,21 @@ static OptFunc OptFuncs [] = {
|
|||||||
/* Optimize jump targets */
|
/* Optimize jump targets */
|
||||||
{ OptJumpTarget, "OptJumpTarget", 0 },
|
{ OptJumpTarget, "OptJumpTarget", 0 },
|
||||||
/* Optimize conditional branches */
|
/* 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 */
|
/* Remove calls to the bool transformer subroutines */
|
||||||
{ OptBoolTransforms, "OptBoolTransforms", 0 },
|
{ 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 */
|
/* Remove unused loads */
|
||||||
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
||||||
/* Optimize branch distance */
|
/* Optimize branch distance */
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ static const char* SkipSpace (const char* S)
|
|||||||
|
|
||||||
|
|
||||||
static const char* ReadToken (const char* L, const char* Term,
|
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
|
/* Read the next token into Buf, return the updated line pointer. The
|
||||||
* token is terminated by one of the characters given in term.
|
* token is terminated by one of the characters given in term.
|
||||||
*/
|
*/
|
||||||
@@ -197,7 +197,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
|
|||||||
am_t AM = 0; /* Initialize to keep gcc silent */
|
am_t AM = 0; /* Initialize to keep gcc silent */
|
||||||
char Arg[64];
|
char Arg[64];
|
||||||
char Reg;
|
char Reg;
|
||||||
CodeEntry* E;
|
CodeEntry* E;
|
||||||
CodeLabel* Label;
|
CodeLabel* Label;
|
||||||
|
|
||||||
/* Mnemonic */
|
/* 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
|
/* We do now have the addressing mode in AM. Allocate a new CodeEntry
|
||||||
* structure and initialize it.
|
* structure and initialize it.
|
||||||
*/
|
*/
|
||||||
E = NewCodeEntry (OPC, AM, Arg, Label);
|
E = NewCodeEntry (OPC->OPC, AM, Arg, Label);
|
||||||
|
|
||||||
/* Return the new code entry */
|
/* Return the new code entry */
|
||||||
return E;
|
return E;
|
||||||
@@ -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)
|
struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index)
|
||||||
/* Get the code entry following the one with the index Index. If there is no
|
/* Get the code entry following the one with the index Index. If there is no
|
||||||
* following code entry, return NULL.
|
* following code entry, return NULL.
|
||||||
@@ -545,12 +537,34 @@ struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index)
|
|||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
/* Code entries left */
|
/* 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)
|
unsigned GetCodeEntryIndex (CodeSeg* S, struct CodeEntry* E)
|
||||||
/* Return the index of a code entry */
|
/* 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 */
|
/* common */
|
||||||
#include "attrib.h"
|
#include "attrib.h"
|
||||||
#include "coll.h"
|
#include "coll.h"
|
||||||
|
#include "inline.h"
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "codelab.h"
|
#include "codelab.h"
|
||||||
@@ -106,14 +107,27 @@ void DelCodeEntry (CodeSeg* S, unsigned Index);
|
|||||||
* if the reference count drops to zero.
|
* 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 */
|
/* 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);
|
struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index);
|
||||||
/* Get the code entry following the one with the index Index. If there is no
|
/* Get the code entry following the one with the index Index. If there is no
|
||||||
* following code entry, return NULL.
|
* 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);
|
unsigned GetCodeEntryIndex (CodeSeg* S, struct CodeEntry* E);
|
||||||
/* Return the index of a code entry */
|
/* Return the index of a code entry */
|
||||||
|
|
||||||
@@ -162,8 +176,15 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last);
|
|||||||
void OutputCodeSeg (const CodeSeg* S, FILE* F);
|
void OutputCodeSeg (const CodeSeg* S, FILE* F);
|
||||||
/* Output the code segment data to a file */
|
/* 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 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 */
|
/* Remove dead jumps */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -118,9 +163,11 @@ unsigned OptDeadCode (CodeSeg* S)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Walk over all entries minus the last one */
|
/* Walk over all entries */
|
||||||
I = 0;
|
I = 0;
|
||||||
while (I < Count-1) {
|
while (I < Count) {
|
||||||
|
|
||||||
|
CodeEntry* N;
|
||||||
|
|
||||||
/* Get this entry */
|
/* Get this entry */
|
||||||
CodeEntry* E = GetCodeEntry (S, I);
|
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
|
/* Check if it's an unconditional branch, and if the next entry has
|
||||||
* no labels attached
|
* 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 */
|
/* Delete the next entry */
|
||||||
DelCodeEntry (S, I+1);
|
DelCodeEntry (S, I+1);
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptRTSJumps (CodeSeg* S);
|
||||||
|
/* Replace jumps to RTS by RTS */
|
||||||
|
|
||||||
unsigned OptDeadJumps (CodeSeg* S);
|
unsigned OptDeadJumps (CodeSeg* S);
|
||||||
/* Remove dead jumps (jumps to the next instruction) */
|
/* Remove dead jumps (jumps to the next instruction) */
|
||||||
|
|
||||||
|
|||||||
@@ -54,81 +54,81 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Mapper table, mnemonic --> opcode */
|
/* Opcode description table */
|
||||||
static const OPCDesc OPCTable[OPC_COUNT] = {
|
const OPCDesc OPCTable[OPC_COUNT] = {
|
||||||
{ OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_AND, "and", 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_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
{ OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BCS, "bcs", 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_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA | OF_ZBRA },
|
||||||
{ OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
|
{ OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
|
||||||
{ OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA },
|
{ OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BNE, "bne", 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_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
|
{ OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
|
||||||
{ OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
{ OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BVS, "bvs", 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_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_CLD, "cld", 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_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_CLV, "clv", 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_CMP, "cmp", 0, REG_A, REG_NONE, OF_NONE },
|
||||||
{ OPC_CPX, "cpx", 0, REG_X, 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_CPY, "cpy", 0, REG_Y, REG_NONE, OF_NONE },
|
||||||
{ OPC_DEA, "dea", 1, REG_A, REG_A, OF_NONE },
|
{ OPC_DEA, "dea", 1, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_DEC, "dec", 0, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_DEX, "dex", 1, REG_X, REG_X, OF_NONE },
|
{ OPC_DEX, "dex", 1, REG_X, REG_X, OF_NONE },
|
||||||
{ OPC_DEY, "dey", 1, REG_Y, REG_Y, OF_NONE },
|
{ OPC_DEY, "dey", 1, REG_Y, REG_Y, OF_NONE },
|
||||||
{ OPC_EOR, "eor", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_EOR, "eor", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_INA, "ina", 1, 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_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
|
{ OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
|
||||||
{ OPC_INY, "iny", 1, REG_Y, REG_Y, 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_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||||
{ OPC_JCS, "jcs", 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_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_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||||
{ OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA | 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_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_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||||
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
{ 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_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA | OF_LBRA },
|
||||||
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_LOAD },
|
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_LOAD },
|
||||||
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_LOAD },
|
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_LOAD },
|
||||||
{ OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_LOAD },
|
{ OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_LOAD },
|
||||||
{ OPC_LSR, "lsr", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_LSR, "lsr", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_NOP, "nop", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_ORA, "ora", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_ORA, "ora", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_PHA, "pha", 1, REG_A, REG_NONE, OF_NONE },
|
{ OPC_PHA, "pha", 1, REG_A, REG_NONE, OF_NONE },
|
||||||
{ OPC_PHP, "php", 1, REG_NONE, 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_PHX, "phx", 1, REG_X, REG_NONE, OF_NONE },
|
||||||
{ OPC_PHY, "phy", 1, REG_Y, 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_PLA, "pla", 1, REG_NONE, REG_A, OF_NONE },
|
||||||
{ OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_PLP, "plp", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_PLX, "plx", 1, REG_NONE, REG_X, OF_NONE },
|
{ OPC_PLX, "plx", 1, REG_NONE, REG_X, OF_NONE },
|
||||||
{ OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
|
{ OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
|
||||||
{ OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_ROR, "ror", 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_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
|
||||||
{ OPC_RTS, "rts", 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_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_SED, "sed", 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_SEI, "sei", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_STA, "sta", 0, REG_A, 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_STX, "stx", 0, REG_X, REG_NONE, OF_NONE },
|
||||||
{ OPC_STY, "sty", 0, REG_Y, 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_TAX, "tax", 1, REG_A, REG_X, OF_NONE },
|
||||||
{ OPC_TAY, "tay", 1, REG_A, REG_Y, OF_NONE },
|
{ OPC_TAY, "tay", 1, REG_A, REG_Y, OF_NONE },
|
||||||
{ OPC_TRB, "trb", 0, REG_A, REG_NONE, OF_NONE },
|
{ OPC_TRB, "trb", 0, REG_A, REG_NONE, OF_NONE },
|
||||||
{ OPC_TSB, "tsb", 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_TSX, "tsx", 1, REG_NONE, REG_X, OF_NONE },
|
||||||
{ OPC_TXA, "txa", 1, REG_X, REG_A, OF_NONE },
|
{ OPC_TXA, "txa", 1, REG_X, REG_A, OF_NONE },
|
||||||
{ OPC_TXS, "txs", 1, REG_X, REG_NONE, OF_NONE },
|
{ OPC_TXS, "txs", 1, REG_X, REG_NONE, OF_NONE },
|
||||||
{ OPC_TYA, "tya", 1, REG_A, REG_A, 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)
|
unsigned char GetAMUseInfo (am_t AM)
|
||||||
/* Get usage info for the given addressing mode (addressing modes that use
|
/* Get usage info for the given addressing mode (addressing modes that use
|
||||||
* index registers return REG_r info for these registers).
|
* index registers return REG_r info for these registers).
|
||||||
|
|||||||
@@ -38,6 +38,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "inline.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Data */
|
/* Data */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -155,7 +160,8 @@ typedef enum {
|
|||||||
#define OF_NONE 0x0000U /* No additional information */
|
#define OF_NONE 0x0000U /* No additional information */
|
||||||
#define OF_UBRA 0x0001U /* Unconditional branch */
|
#define OF_UBRA 0x0001U /* Unconditional branch */
|
||||||
#define OF_CBRA 0x0002U /* Conditional 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_RET 0x0010U /* Return from function */
|
||||||
#define OF_LOAD 0x0020U /* Register load */
|
#define OF_LOAD 0x0020U /* Register load */
|
||||||
#define OF_BRA (OF_UBRA|OF_CBRA) /* Operation is a jump/branch */
|
#define OF_BRA (OF_UBRA|OF_CBRA) /* Operation is a jump/branch */
|
||||||
@@ -171,6 +177,9 @@ typedef struct {
|
|||||||
unsigned char Info; /* Additional information */
|
unsigned char Info; /* Additional information */
|
||||||
} OPCDesc;
|
} 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);
|
unsigned GetInsnSize (opc_t OPC, am_t AM);
|
||||||
/* Return the size of the given instruction */
|
/* 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 */
|
/* 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 */
|
/* Get opcode information */
|
||||||
|
{
|
||||||
|
/* Return the info */
|
||||||
|
return OPCTable[OPC].Info;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define GetOPCInfo(OPC) (OPCTable[(OPC)].Info)
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned char GetAMUseInfo (am_t AM);
|
unsigned char GetAMUseInfo (am_t AM);
|
||||||
/* Get usage info for the given addressing mode (addressing modes that use
|
/* Get usage info for the given addressing mode (addressing modes that use
|
||||||
|
|||||||
Reference in New Issue
Block a user