mirror of
https://github.com/cc65/cc65.git
synced 2025-03-04 00:30:35 +00:00
Working on the backend
git-svn-id: svn://svn.cc65.org/cc65/trunk@718 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
cc9826721b
commit
e6a5e57b47
@ -73,6 +73,7 @@ CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel*
|
||||
E->Arg = (Arg && Arg[0] != '\0')? xstrdup (Arg) : 0;
|
||||
E->Num = 0;
|
||||
E->Flags = 0;
|
||||
E->Info = D->Info;
|
||||
E->Use = D->Use;
|
||||
E->Chg = D->Chg;
|
||||
if (E->OPC == OPC_JSR && E->Arg) {
|
||||
@ -119,6 +120,51 @@ int CodeEntryHasLabel (const 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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. */
|
||||
{
|
||||
/* Delete the label from the owner */
|
||||
CollDeleteItem (&L->Owner->Labels, L);
|
||||
|
||||
/* Set the new owner */
|
||||
CollAppend (&E->Labels, L);
|
||||
L->Owner = E;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OutputCodeEntry (const CodeEntry* E, FILE* F)
|
||||
/* Output the code entry to a file */
|
||||
{
|
||||
|
@ -69,6 +69,7 @@ struct CodeEntry {
|
||||
char* Arg; /* Argument as string */
|
||||
unsigned Num; /* Numeric argument */
|
||||
unsigned short Flags; /* Flags */
|
||||
unsigned char Info; /* Additional code info */
|
||||
unsigned char Use; /* Registers used */
|
||||
unsigned char Chg; /* Registers changed/destroyed */
|
||||
CodeLabel* JumpTo; /* Jump label */
|
||||
@ -92,6 +93,21 @@ void FreeCodeEntry (CodeEntry* E);
|
||||
int CodeEntryHasLabel (const CodeEntry* E);
|
||||
/* Check if the given code entry has labels attached */
|
||||
|
||||
int CodeEntryHasMark (const CodeEntry* E);
|
||||
/* Return true if the given code entry has the CEF_USERMARK flag set */
|
||||
|
||||
void CodeEntrySetMark (CodeEntry* E);
|
||||
/* Set the CEF_USERMARK flag for the given entry */
|
||||
|
||||
void CodeEntryResetMark (CodeEntry* E);
|
||||
/* Reset the CEF_USERMARK flag for the given entry */
|
||||
|
||||
CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index);
|
||||
/* Get a label from this code entry */
|
||||
|
||||
void MoveCodeLabel (CodeLabel* L, CodeEntry* E);
|
||||
/* Move the code label L from it's former owner to the code entry E. */
|
||||
|
||||
void OutputCodeEntry (const CodeEntry* E, FILE* F);
|
||||
/* Output the code entry to a file */
|
||||
|
||||
|
@ -396,77 +396,41 @@ void g_enter (unsigned flags, unsigned argsize)
|
||||
|
||||
|
||||
|
||||
void g_leave (int flags, int val)
|
||||
void g_leave (void)
|
||||
/* Function epilogue */
|
||||
{
|
||||
int k;
|
||||
char buf [40];
|
||||
|
||||
/* CF_REG is set if we're returning a value from the function */
|
||||
if ((flags & CF_REG) == 0) {
|
||||
AddCodeHint ("x:-");
|
||||
AddCodeHint ("a:-");
|
||||
}
|
||||
|
||||
/* How many bytes of locals do we have to drop? */
|
||||
k = -oursp;
|
||||
int k = -oursp;
|
||||
|
||||
/* If we didn't have a variable argument list, don't call leave */
|
||||
if (funcargs >= 0) {
|
||||
|
||||
/* Load a function return code if needed */
|
||||
if ((flags & CF_CONST) != 0) {
|
||||
g_getimmed (flags, val, 0);
|
||||
}
|
||||
|
||||
/* Drop stackframe or leave with rts */
|
||||
/* Drop stackframe if needed */
|
||||
k += funcargs;
|
||||
if (k == 0) {
|
||||
AddCodeHint ("y:-"); /* Y register no longer used */
|
||||
AddCodeLine ("rts");
|
||||
} else if (k <= 8) {
|
||||
AddCodeHint ("y:-"); /* Y register no longer used */
|
||||
AddCodeLine ("jmp incsp%d", k);
|
||||
} else {
|
||||
CheckLocalOffs (k);
|
||||
ldyconst (k);
|
||||
AddCodeLine ("jmp addysp");
|
||||
if (k > 0) {
|
||||
if (k <= 8) {
|
||||
AddCodeLine ("jsr incsp%d", k);
|
||||
} else {
|
||||
CheckLocalOffs (k);
|
||||
ldyconst (k);
|
||||
AddCodeLine ("jsr addysp");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
strcpy (buf, "\tjmp\tleave");
|
||||
if (k) {
|
||||
if (k == 0) {
|
||||
/* Nothing to drop */
|
||||
AddCodeLine ("jsr leave");
|
||||
} else {
|
||||
/* We've a stack frame to drop */
|
||||
ldyconst (k);
|
||||
strcat (buf, "y");
|
||||
} else {
|
||||
/* Y register no longer used */
|
||||
AddCodeHint ("y:-");
|
||||
AddCodeLine ("jsr leavey");
|
||||
}
|
||||
if (flags & CF_CONST) {
|
||||
if ((flags & CF_TYPE) != CF_LONG) {
|
||||
/* Constant int sized value given for return code */
|
||||
if (val == 0) {
|
||||
/* Special case: return 0 */
|
||||
strcat (buf, "00");
|
||||
} else if (((val >> 8) & 0xFF) == 0) {
|
||||
/* Special case: constant with high byte zero */
|
||||
ldaconst (val); /* Load low byte */
|
||||
strcat (buf, "0");
|
||||
} else {
|
||||
/* Others: arbitrary constant value */
|
||||
g_getimmed (flags, val, 0); /* Load value */
|
||||
}
|
||||
} else {
|
||||
/* Constant long value: No shortcut possible */
|
||||
g_getimmed (flags, val, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Output the jump */
|
||||
AddCodeLine (buf);
|
||||
}
|
||||
|
||||
/* Add the final rts */
|
||||
AddCodeLine ("rts");
|
||||
}
|
||||
|
||||
|
||||
|
@ -206,7 +206,7 @@ void g_scale (unsigned flags, long val);
|
||||
void g_enter (unsigned flags, unsigned argsize);
|
||||
/* Function prologue */
|
||||
|
||||
void g_leave (int flags, int val);
|
||||
void g_leave (void);
|
||||
/* Function epilogue */
|
||||
|
||||
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* common */
|
||||
#include "coll.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "codeinfo.h"
|
||||
|
||||
@ -95,6 +98,12 @@ static const FuncInfo FuncInfoTable[] = {
|
||||
};
|
||||
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
|
||||
|
||||
/* Structure used to pass information to the RegValUsedInt1 and 2 functions */
|
||||
typedef struct RVUInfo RVUInfo;
|
||||
struct RVUInfo {
|
||||
Collection VisitedLines; /* Lines already visited */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -133,6 +142,201 @@ void GetFuncInfo (const char* Name, unsigned char* Use, unsigned char* Chg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
static unsigned RVUInt2 (Line* L,
|
||||
LineColl* LC, /* To remember visited lines */
|
||||
unsigned Used, /* Definitely used registers */
|
||||
unsigned Unused) /* Definitely unused registers */
|
||||
/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
|
||||
{
|
||||
int I;
|
||||
|
||||
/* Check the following instructions. We classifiy them into primary
|
||||
* loads (register value not used), neutral (check next instruction),
|
||||
* and unknown (assume register was used).
|
||||
*/
|
||||
while (1) {
|
||||
|
||||
unsigned R;
|
||||
|
||||
/* Get the next line and follow jumps */
|
||||
do {
|
||||
|
||||
/* Handle jumps to local labels (continue there) */
|
||||
if (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL")) {
|
||||
/* Get the target of the jump */
|
||||
L = GetTargetLine (L->Line+5);
|
||||
}
|
||||
|
||||
/* Get the next line, skip local labels */
|
||||
do {
|
||||
L = NextCodeSegLine (L);
|
||||
} while (L && (IsLocalLabel (L) || L->Line[0] == '\0'));
|
||||
|
||||
/* Bail out if we're done */
|
||||
if (L == 0 || IsExtLabel (L)) {
|
||||
/* End of function reached */
|
||||
goto ExitPoint;
|
||||
}
|
||||
|
||||
/* Check if we had this line already. If so, bail out, if not,
|
||||
* add it to the list of known lines.
|
||||
*/
|
||||
if (LCHasLine (LC, L) || !LCAddLine (LC, L)) {
|
||||
goto ExitPoint;
|
||||
}
|
||||
|
||||
} while (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL"));
|
||||
|
||||
/* Special handling of code hints */
|
||||
if (IsHintLine (L)) {
|
||||
|
||||
if (IsHint (L, "a:-") && (Used & REG_A) == 0) {
|
||||
Unused |= REG_A;
|
||||
} else if (IsHint (L, "x:-") && (Used & REG_X) == 0) {
|
||||
Unused |= REG_X;
|
||||
} else if (IsHint (L, "y:-") && (Used & REG_Y) == 0) {
|
||||
Unused |= REG_Y;
|
||||
}
|
||||
|
||||
/* Special handling for branches */
|
||||
} else if (LineMatchX (L, ShortBranches) >= 0 ||
|
||||
LineMatchX (L, LongBranches) >= 0) {
|
||||
const char* Target = L->Line+5;
|
||||
if (Target[0] == 'L') {
|
||||
/* Jump to local label. Check the register usage starting at
|
||||
* the branch target and at the code following the branch.
|
||||
* All registers that are unused in both execution flows are
|
||||
* returned as unused.
|
||||
*/
|
||||
unsigned U1, U2;
|
||||
U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
|
||||
U1 = RVUInt1 (L, LC, Used, Unused);
|
||||
return U1 | U2; /* Used in any of the branches */
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Search for the instruction in this line */
|
||||
I = FindCmd (L);
|
||||
|
||||
/* If we don't find it, assume all other registers are used */
|
||||
if (I < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Evaluate the use flags, check for addressing modes */
|
||||
R = CmdDesc[I].Use;
|
||||
if (IsXAddrMode (L)) {
|
||||
R |= REG_X;
|
||||
} else if (IsYAddrMode (L)) {
|
||||
R |= REG_Y;
|
||||
}
|
||||
if (R) {
|
||||
/* Remove registers that were already new loaded */
|
||||
R &= ~Unused;
|
||||
|
||||
/* Remember the remaining registers */
|
||||
Used |= R;
|
||||
}
|
||||
|
||||
/* Evaluate the load flags */
|
||||
R = CmdDesc[I].Load;
|
||||
if (R) {
|
||||
/* Remove registers that were already used */
|
||||
R &= ~Used;
|
||||
|
||||
/* Remember the remaining registers */
|
||||
Unused |= R;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If we know about all registers, bail out */
|
||||
if ((Used | Unused) == REG_ALL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ExitPoint:
|
||||
/* Return to the caller the complement of all unused registers */
|
||||
return ~Unused & REG_ALL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned RVUInt1 (Line* L,
|
||||
LineColl* LC, /* To remember visited lines */
|
||||
unsigned Used, /* Definitely used registers */
|
||||
unsigned Unused) /* Definitely unused registers */
|
||||
/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
|
||||
{
|
||||
/* Remember the current count of the line collection */
|
||||
unsigned Count = LC->Count;
|
||||
|
||||
/* Call the worker routine */
|
||||
unsigned R = RVUInt2 (L, LC, Used, Unused);
|
||||
|
||||
/* Restore the old count */
|
||||
LC->Count = Count;
|
||||
|
||||
/* Return the result */
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned RegValUsed (Line* Start)
|
||||
/* Check the next instructions after the one in L for register usage. If
|
||||
* a register is used as an index, or in a store or other instruction, it
|
||||
* is assumed to be used. If a register is loaded with a value, before it
|
||||
* was used by one of the actions described above, it is assumed unused.
|
||||
* If the end of the lookahead is reached, all registers that are uncertain
|
||||
* are marked as used.
|
||||
* The result of the search is returned.
|
||||
*/
|
||||
{
|
||||
unsigned R;
|
||||
|
||||
/* Create a new line collection and enter the start line */
|
||||
LineColl* LC = NewLineColl (256);
|
||||
LCAddLine (LC, Start);
|
||||
|
||||
/* Call the recursive subfunction */
|
||||
R = RVUInt1 (Start, LC, REG_NONE, REG_NONE);
|
||||
|
||||
/* Delete the line collection */
|
||||
FreeLineColl (LC);
|
||||
|
||||
/* Return the registers used */
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int RegAUsed (Line* Start)
|
||||
/* Check if the value in A is used. */
|
||||
{
|
||||
return (RegValUsed (Start) & REG_A) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int RegXUsed (Line* Start)
|
||||
/* Check if the value in X is used. */
|
||||
{
|
||||
return (RegValUsed (Start) & REG_X) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int RegYUsed (Line* Start)
|
||||
/* Check if the value in Y is used. */
|
||||
{
|
||||
return (RegValUsed (Start) & REG_Y) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
|
||||
/* common */
|
||||
#include "check.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* cc65 */
|
||||
@ -107,6 +108,30 @@ unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E)
|
||||
|
||||
|
||||
|
||||
void MoveLabelRefs (CodeLabel* OldLabel, CodeLabel* NewLabel)
|
||||
/* Move all references to OldLabel to point to NewLabel. OldLabel will have no
|
||||
* more references on return.
|
||||
*/
|
||||
{
|
||||
/* Walk through all instructions referencing the old label */
|
||||
unsigned Count = CollCount (&OldLabel->JumpFrom);
|
||||
while (Count--) {
|
||||
|
||||
/* Get the instruction that references the old label */
|
||||
CodeEntry* E = CollAt (&OldLabel->JumpFrom, Count);
|
||||
|
||||
/* Change the reference to the new label */
|
||||
CHECK (E->JumpTo == OldLabel);
|
||||
AddLabelRef (NewLabel, E);
|
||||
|
||||
}
|
||||
|
||||
/* There are no more references to the old label */
|
||||
CollDeleteAll (&OldLabel->JumpFrom);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OutputCodeLabel (const CodeLabel* L, FILE* F)
|
||||
/* Output the code label to a file */
|
||||
{
|
||||
|
@ -95,6 +95,11 @@ void AddLabelRef (CodeLabel* L, struct CodeEntry* E);
|
||||
unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E);
|
||||
/* Remove a reference to this label, return the number of remaining references */
|
||||
|
||||
void MoveLabelRefs (CodeLabel* OldLabel, CodeLabel* NewLabel);
|
||||
/* Move all references to OldLabel to point to NewLabel. OldLabel will have no
|
||||
* more references on return.
|
||||
*/
|
||||
|
||||
void OutputCodeLabel (const CodeLabel* L, FILE* F);
|
||||
/* Output the code label to a file */
|
||||
|
||||
|
@ -80,12 +80,12 @@ static void OptDeadJumps (CodeSeg* S)
|
||||
while (I < Count-1) {
|
||||
|
||||
/* Get the next entry */
|
||||
E = CollAt (&S->Entries, I);
|
||||
E = GetCodeEntry (S, I);
|
||||
|
||||
/* 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 && E->JumpTo && E->JumpTo->Owner == CollAt (&S->Entries, I+1)) {
|
||||
if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
|
||||
|
||||
/* Delete the dead jump */
|
||||
DelCodeEntry (S, I);
|
||||
@ -131,13 +131,12 @@ static void OptDeadCode (CodeSeg* S)
|
||||
while (I < Count-1) {
|
||||
|
||||
/* Get this entry */
|
||||
CodeEntry* E = CollAt (&S->Entries, I);
|
||||
CodeEntry* E = GetCodeEntry (S, 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))) {
|
||||
if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
|
||||
|
||||
/* Delete the next entry */
|
||||
DelCodeEntry (S, I+1);
|
||||
@ -189,15 +188,17 @@ static void OptJumpCascades (CodeSeg* S)
|
||||
CodeLabel* NewLabel;
|
||||
|
||||
/* Get this entry */
|
||||
CodeEntry* E = CollAt (&S->Entries, I);
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check if it's a branch, if it has a label attached, and if the
|
||||
* instruction at this label is also a branch.
|
||||
* instruction at this label is also a branch, and (important) if
|
||||
* both instructions are not identical.
|
||||
*/
|
||||
if (E->AM == AM_BRA &&
|
||||
(OldLabel = E->JumpTo) != 0 &&
|
||||
OldLabel->Owner->AM == AM_BRA &&
|
||||
(NewLabel = OldLabel->Owner->JumpTo) != 0) {
|
||||
if (E->AM == AM_BRA && /* It's a branch */
|
||||
(OldLabel = E->JumpTo) != 0 && /* Label attached */
|
||||
OldLabel->Owner->AM == AM_BRA && /* Jumps to a branch.. */
|
||||
(NewLabel = OldLabel->Owner->JumpTo) != 0 && /* ..which has a label */
|
||||
OldLabel->Owner != E) { /* And both are distinct */
|
||||
|
||||
/* Get the instruction that has the new label attached */
|
||||
CodeEntry* N = OldLabel->Owner;
|
||||
@ -230,6 +231,99 @@ static void OptJumpCascades (CodeSeg* S)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Optimize jsr/rts */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void OptRTS (CodeSeg* S)
|
||||
/* Optimize subroutine calls followed by an RTS. The subroutine call will get
|
||||
* replaced by a jump. Don't bother to delete the RTS if it does not have a
|
||||
* label, the dead code elimination should take care of it.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Get the number of entries, bail out if we have less than 2 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 = GetCodeEntry (S, I);
|
||||
|
||||
/* Check if it's a subroutine call and if the following insn is RTS */
|
||||
if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
|
||||
|
||||
/* Change the jsr to a jmp */
|
||||
E->OPC = OPC_JMP;
|
||||
|
||||
/* Change the opcode info to that of the jump */
|
||||
E->Info = GetOPCInfo (OPC_JMP);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++OptChanges;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Optimize jump targets */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void OptJumpTarget (CodeSeg* S)
|
||||
/* If the instruction preceeding an unconditional branch is the same as the
|
||||
* instruction preceeding the jump target, the jump target may be moved
|
||||
* one entry back. This is a size optimization, since the instruction before
|
||||
* the branch gets removed.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Get the number of entries, bail out if we have not enough */
|
||||
unsigned Count = CollCount (&S->Entries);
|
||||
if (Count < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Walk over all entries minus the first one */
|
||||
I = 1;
|
||||
while (I < Count) {
|
||||
|
||||
/* Get this entry and the entry before this one */
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* Check if we have a jump or branch, and a matching label */
|
||||
if ((E->Info & OF_UBRA) != 0 && E->JumpTo) {
|
||||
|
||||
/* Remember, we had changes */
|
||||
++OptChanges;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
@ -243,9 +337,10 @@ void RunOpt (CodeSeg* S)
|
||||
|
||||
/* 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 */
|
||||
OptJumpCascades, /* Optimize jump cascades */
|
||||
OptDeadJumps, /* Remove dead jumps */
|
||||
OptDeadCode, /* Remove dead code */
|
||||
OptRTS, /* Change jsr/rts to jmp */
|
||||
};
|
||||
|
||||
/* Repeat all steps until there are no more changes */
|
||||
@ -261,9 +356,9 @@ void RunOpt (CodeSeg* S)
|
||||
Flags = 1UL;
|
||||
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
||||
if ((OptDisable & Flags) == 0) {
|
||||
OptFuncs[I] (S);
|
||||
OptFuncs[I] (S);
|
||||
} else if (Verbosity > 0 || Debug) {
|
||||
printf ("Optimizer pass %u skipped\n", I);
|
||||
printf ("Optimizer pass %u skipped\n", I);
|
||||
}
|
||||
Flags <<= 1;
|
||||
}
|
||||
|
@ -52,6 +52,46 @@
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helper functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void MoveLabelsToPool (CodeSeg* S, CodeEntry* E)
|
||||
/* Move the labels of the code entry E to the label pool of the code segment */
|
||||
{
|
||||
unsigned LabelCount = CollCount (&E->Labels);
|
||||
while (LabelCount--) {
|
||||
CodeLabel* L = GetCodeLabel (E, LabelCount);
|
||||
L->Flags &= ~LF_DEF;
|
||||
L->Owner = 0;
|
||||
CollAppend (&S->Labels, L);
|
||||
}
|
||||
CollDeleteAll (&E->Labels);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
|
||||
/* Find the label with the given name. Return the label or NULL if not found */
|
||||
{
|
||||
/* Get the first hash chain entry */
|
||||
CodeLabel* L = S->LabelHash[Hash];
|
||||
|
||||
/* Search the list */
|
||||
while (L) {
|
||||
if (strcmp (Name, L->Name) == 0) {
|
||||
/* Found */
|
||||
break;
|
||||
}
|
||||
L = L->Next;
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Functions for parsing instructions */
|
||||
/*****************************************************************************/
|
||||
@ -387,18 +427,66 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
|
||||
|
||||
|
||||
void DelCodeEntry (CodeSeg* S, unsigned Index)
|
||||
/* Delete an entry from the code segment. This includes deleting any associated
|
||||
/* Delete an entry from the code segment. This includes moving 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);
|
||||
CodeEntry* E = GetCodeEntry (S, Index);
|
||||
|
||||
/* Remove any labels associated with this entry */
|
||||
unsigned Count;
|
||||
while ((Count = CollCount (&E->Labels)) > 0) {
|
||||
DelCodeLabel (S, CollAt (&E->Labels, Count-1));
|
||||
/* If the entry has a labels, we have to move this label to the next insn.
|
||||
* If there is no next insn, move the label into the code segement label
|
||||
* pool. The operation is further complicated by the fact that the next
|
||||
* insn may already have a label. In that case change all reference to
|
||||
* this label and delete the label instead of moving it.
|
||||
*/
|
||||
unsigned Count = CollCount (&E->Labels);
|
||||
if (Count > 0) {
|
||||
|
||||
/* The instruction has labels attached. Check if there is a next
|
||||
* instruction.
|
||||
*/
|
||||
if (Index == GetCodeSegEntries (S)-1) {
|
||||
|
||||
/* No next instruction, move to the codeseg label pool */
|
||||
MoveLabelsToPool (S, E);
|
||||
|
||||
} else {
|
||||
|
||||
/* There is a next insn, get it */
|
||||
CodeEntry* N = GetCodeEntry (S, Index+1);
|
||||
|
||||
/* Does this next insn have itself a label? */
|
||||
if (CodeEntryHasLabel (N)) {
|
||||
|
||||
/* The next insn does already have a label - move references */
|
||||
CodeLabel* NewLabel = GetCodeLabel (N, 0);
|
||||
while (Count--) {
|
||||
|
||||
/* Get the next label */
|
||||
CodeLabel* L = GetCodeLabel (E, Count);
|
||||
|
||||
/* Move references */
|
||||
MoveLabelRefs (L, NewLabel);
|
||||
|
||||
/* Delete the label */
|
||||
DelCodeLabel (S, L);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* The next insn does not have a label, just move them */
|
||||
while (Count--) {
|
||||
|
||||
/* Move the label to the new entry */
|
||||
MoveCodeLabel (GetCodeLabel (E, Count), N);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If this insn references a label, remove the reference. And, if the
|
||||
@ -406,7 +494,7 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
|
||||
*/
|
||||
if (E->JumpTo) {
|
||||
|
||||
/* Remove the reference */
|
||||
/* Remove the reference */
|
||||
if (RemoveLabelRef (E->JumpTo, E) == 0) {
|
||||
/* No references remaining, remove the label */
|
||||
DelCodeLabel (S, E->JumpTo);
|
||||
@ -425,6 +513,14 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AddCodeLabel (CodeSeg* S, const char* Name)
|
||||
/* Add a code label for the next instruction to follow */
|
||||
{
|
||||
@ -504,7 +600,7 @@ void AddCodeSegHint (CodeSeg* S, unsigned Hint)
|
||||
CHECK (EntryCount > 0);
|
||||
|
||||
/* Get the last entry */
|
||||
E = CollAt (&S->Entries, EntryCount-1);
|
||||
E = GetCodeEntry (S, EntryCount-1);
|
||||
|
||||
/* Add the hint */
|
||||
E->Hints |= Hint;
|
||||
@ -522,19 +618,13 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last)
|
||||
while (Last < Count) {
|
||||
|
||||
/* Get the next entry */
|
||||
CodeEntry* E = CollAt (&S->Entries, Count-1);
|
||||
CodeEntry* E = GetCodeEntry (S, Count-1);
|
||||
|
||||
/* We have to transfer all labels to the code segment label pool */
|
||||
unsigned LabelCount = CollCount (&E->Labels);
|
||||
while (LabelCount--) {
|
||||
CodeLabel* L = CollAt (&E->Labels, LabelCount);
|
||||
L->Flags &= ~LF_DEF;
|
||||
CollAppend (&S->Labels, L);
|
||||
}
|
||||
CollDeleteAll (&E->Labels);
|
||||
MoveLabelsToPool (S, E);
|
||||
|
||||
/* Remove the code entry */
|
||||
FreeCodeEntry (CollAt (&S->Entries, Count-1));
|
||||
FreeCodeEntry (E);
|
||||
CollDelete (&S->Entries, Count-1);
|
||||
--Count;
|
||||
}
|
||||
@ -576,25 +666,6 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
|
||||
|
||||
|
||||
|
||||
CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
|
||||
/* Find the label with the given name. Return the label or NULL if not found */
|
||||
{
|
||||
/* Get the first hash chain entry */
|
||||
CodeLabel* L = S->LabelHash[Hash];
|
||||
|
||||
/* Search the list */
|
||||
while (L) {
|
||||
if (strcmp (Name, L->Name) == 0) {
|
||||
/* Found */
|
||||
break;
|
||||
}
|
||||
L = L->Next;
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MergeCodeLabels (CodeSeg* S)
|
||||
/* Merge code labels. That means: For each instruction, remove all labels but
|
||||
* one and adjust the code entries accordingly.
|
||||
@ -610,7 +681,7 @@ void MergeCodeLabels (CodeSeg* S)
|
||||
unsigned J;
|
||||
|
||||
/* Get a pointer to the next entry */
|
||||
CodeEntry* E = CollAt (&S->Entries, I);
|
||||
CodeEntry* E = GetCodeEntry (S, I);
|
||||
|
||||
/* If this entry has zero labels, continue with the next one */
|
||||
unsigned LabelCount = CollCount (&E->Labels);
|
||||
@ -619,7 +690,7 @@ void MergeCodeLabels (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* We have at least one label. Use the first one as reference label. */
|
||||
RefLab = CollAt (&E->Labels, 0);
|
||||
RefLab = GetCodeLabel (E, 0);
|
||||
|
||||
/* Walk through the remaining labels and change references to these
|
||||
* labels to a reference to the one and only label. Delete the labels
|
||||
@ -628,26 +699,11 @@ void MergeCodeLabels (CodeSeg* S)
|
||||
*/
|
||||
for (J = LabelCount-1; J >= 1; --J) {
|
||||
|
||||
unsigned K;
|
||||
|
||||
/* Get the next label */
|
||||
CodeLabel* L = CollAt (&E->Labels, J);
|
||||
CodeLabel* L = GetCodeLabel (E, J);
|
||||
|
||||
/* Walk through all instructions referencing this label */
|
||||
unsigned RefCount = CollCount (&L->JumpFrom);
|
||||
for (K = 0; K < RefCount; ++K) {
|
||||
|
||||
/* Get the next instruction that references this label */
|
||||
CodeEntry* E = CollAt (&L->JumpFrom, K);
|
||||
|
||||
/* Change the reference */
|
||||
CHECK (E->JumpTo == L);
|
||||
AddLabelRef (RefLab, E);
|
||||
|
||||
}
|
||||
|
||||
/* There are no more instructions jumping to this label now */
|
||||
CollDeleteAll (&L->JumpFrom);
|
||||
/* Move all references from this label to the reference label */
|
||||
MoveLabelRefs (L, RefLab);
|
||||
|
||||
/* Remove the label completely. */
|
||||
DelCodeLabel (S, L);
|
||||
|
@ -51,6 +51,16 @@
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
struct CodeEntry;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
@ -85,11 +95,14 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap) attribute ((forma
|
||||
/* Add a line to the given code segment */
|
||||
|
||||
void DelCodeEntry (CodeSeg* S, unsigned Index);
|
||||
/* Delete an entry from the code segment. This includes deleting any associated
|
||||
/* Delete an entry from the code segment. This includes moving any associated
|
||||
* labels, removing references to labels and even removing the referenced labels
|
||||
* if the reference count drops to zero.
|
||||
*/
|
||||
|
||||
struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index);
|
||||
/* Get an entry from the given code segment */
|
||||
|
||||
void AddCodeLabel (CodeSeg* S, const char* Name);
|
||||
/* Add a code label for the next instruction to follow */
|
||||
|
||||
@ -105,9 +118,6 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last);
|
||||
void OutputCodeSeg (const CodeSeg* S, FILE* F);
|
||||
/* Output the code segment data to a file */
|
||||
|
||||
CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash);
|
||||
/* Find the label with the given name. Return the label or NULL if not found */
|
||||
|
||||
void MergeCodeLabels (CodeSeg* S);
|
||||
/* Merge code labels. That means: For each instruction, remove all labels but
|
||||
* one and adjust the code entries accordingly.
|
||||
|
@ -230,7 +230,7 @@ void PrintType (FILE* F, const type* Type)
|
||||
/* Output translation of type array. */
|
||||
{
|
||||
type T;
|
||||
|
||||
unsigned long Size;
|
||||
|
||||
/* Walk over the complete string */
|
||||
while ((T = *Type++) != T_END) {
|
||||
@ -280,12 +280,20 @@ void PrintType (FILE* F, const type* Type)
|
||||
Type += DECODE_SIZE;
|
||||
break;
|
||||
case T_TYPE_ARRAY:
|
||||
fprintf (F, "array[%lu] of ", Decode (Type));
|
||||
Type += DECODE_SIZE;
|
||||
break;
|
||||
/* Recursive call */
|
||||
PrintType (F, Type + DECODE_SIZE);
|
||||
Size = Decode (Type);
|
||||
if (Size == 0) {
|
||||
fprintf (F, "[]");
|
||||
} else {
|
||||
fprintf (F, "[%lu]", Size);
|
||||
}
|
||||
return;
|
||||
case T_TYPE_PTR:
|
||||
fprintf (F, "pointer to ");
|
||||
break;
|
||||
/* Recursive call */
|
||||
PrintType (F, Type);
|
||||
fprintf (F, "*");
|
||||
return;
|
||||
case T_TYPE_FUNC:
|
||||
fprintf (F, "function returning ");
|
||||
Type += DECODE_SIZE;
|
||||
|
@ -215,7 +215,6 @@ void NewFunc (SymEntry* Func)
|
||||
{
|
||||
int HadReturn;
|
||||
int IsVoidFunc;
|
||||
unsigned Flags;
|
||||
|
||||
/* Get the function descriptor from the function entry */
|
||||
FuncDesc* D = Func->V.F.Func;
|
||||
@ -321,8 +320,7 @@ void NewFunc (SymEntry* Func)
|
||||
RestoreRegVars (!IsVoidFunc);
|
||||
|
||||
/* Generate the exit code */
|
||||
Flags = IsVoidFunc? CF_NONE : CF_REG;
|
||||
g_leave (Flags, 0);
|
||||
g_leave ();
|
||||
|
||||
/* Eat the closing brace */
|
||||
ConsumeRCurly ();
|
||||
@ -337,7 +335,7 @@ void NewFunc (SymEntry* Func)
|
||||
LeaveFunctionLevel ();
|
||||
|
||||
/* Switch back to the old segments */
|
||||
PopSegments ();
|
||||
PopSegments ();
|
||||
|
||||
/* Reset the current function pointer */
|
||||
FreeFunction (CurrentFunc);
|
||||
|
@ -58,17 +58,17 @@ 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_BRA },
|
||||
{ OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ 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_BRA },
|
||||
{ OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ 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_BRA },
|
||||
{ OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ 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 },
|
||||
@ -85,16 +85,16 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
|
||||
{ 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_BRA },
|
||||
{ OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA },
|
||||
{ OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
|
||||
{ OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_BRA },
|
||||
{ OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_NONE },
|
||||
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_NONE },
|
||||
{ OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_NONE },
|
||||
@ -111,8 +111,8 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
|
||||
{ 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_NONE },
|
||||
{ OPC_RTS, "rts", 1, REG_NONE, REG_NONE, 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 },
|
||||
@ -214,6 +214,18 @@ const OPCDesc* GetOPCDesc (opc_t 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).
|
||||
@ -234,7 +246,7 @@ unsigned char GetAMUseInfo (am_t AM)
|
||||
|
||||
|
||||
opc_t GetInverseBranch (opc_t OPC)
|
||||
/* Return a brahcn that reverse the condition of the branch given in OPC */
|
||||
/* Return a branch that reverse the condition of the branch given in OPC */
|
||||
{
|
||||
switch (OPC) {
|
||||
case OPC_BCC: return OPC_BCS;
|
||||
|
@ -119,37 +119,41 @@ typedef enum {
|
||||
OPC_TXA,
|
||||
OPC_TXS,
|
||||
OPC_TYA,
|
||||
OPC_COUNT /* Number of opcodes available */
|
||||
OPC_COUNT /* Number of opcodes available */
|
||||
} opc_t;
|
||||
|
||||
/* Addressing modes (bitmapped). */
|
||||
typedef enum {
|
||||
AM_IMP = 0x0001, /* implicit */
|
||||
AM_ACC = 0x0002, /* accumulator */
|
||||
AM_IMM = 0x0004, /* immidiate */
|
||||
AM_ZP = 0x0008, /* zeropage */
|
||||
AM_ZPX = 0x0010, /* zeropage,X */
|
||||
AM_ABS = 0x0020, /* absolute */
|
||||
AM_ABSX = 0x0040, /* absolute,X */
|
||||
AM_ABSY = 0x0080, /* absolute,Y */
|
||||
AM_ZPX_IND = 0x0100, /* (zeropage,x) */
|
||||
AM_ZP_INDY = 0x0200, /* (zeropage),y */
|
||||
AM_ZP_IND = 0x0400, /* (zeropage) */
|
||||
AM_BRA = 0x0800 /* branch */
|
||||
AM_IMP = 0x0001, /* implicit */
|
||||
AM_ACC = 0x0002, /* accumulator */
|
||||
AM_IMM = 0x0004, /* immidiate */
|
||||
AM_ZP = 0x0008, /* zeropage */
|
||||
AM_ZPX = 0x0010, /* zeropage,X */
|
||||
AM_ABS = 0x0020, /* absolute */
|
||||
AM_ABSX = 0x0040, /* absolute,X */
|
||||
AM_ABSY = 0x0080, /* absolute,Y */
|
||||
AM_ZPX_IND = 0x0100, /* (zeropage,x) */
|
||||
AM_ZP_INDY = 0x0200, /* (zeropage),y */
|
||||
AM_ZP_IND = 0x0400, /* (zeropage) */
|
||||
AM_BRA = 0x0800 /* branch */
|
||||
} am_t;
|
||||
|
||||
/* Opcode info */
|
||||
#define OF_NONE 0x0000U /* No additional information */
|
||||
#define OF_BRA 0x0001U /* Operation is a jump/branch */
|
||||
#define OF_NONE 0x0000U /* No additional information */
|
||||
#define OF_UBRA 0x0001U /* Unconditional branch */
|
||||
#define OF_CBRA 0x0002U /* Conditional branch */
|
||||
#define OF_RET 0x0004U /* Return from function */
|
||||
#define OF_BRA (OF_UBRA|OF_CBRA) /* Operation is a jump/branch */
|
||||
#define OF_DEAD (OF_UBRA|OF_RET) /* Dead end - no exec behind this point */
|
||||
|
||||
/* Opcode description */
|
||||
typedef struct {
|
||||
opc_t OPC; /* Opcode */
|
||||
char Mnemo[4]; /* Mnemonic */
|
||||
unsigned char Size; /* Size, 0 means "check addressing mode" */
|
||||
unsigned char Use; /* Registers used by this insn */
|
||||
unsigned char Chg; /* Registers changed/destroyed by this insn */
|
||||
unsigned char Info; /* Additional information */
|
||||
opc_t OPC; /* Opcode */
|
||||
char Mnemo[4]; /* Mnemonic */
|
||||
unsigned char Size; /* Size, 0 = check addressing mode */
|
||||
unsigned char Use; /* Registers used by this insn */
|
||||
unsigned char Chg; /* Registers changed by this insn */
|
||||
unsigned char Info; /* Additional information */
|
||||
} OPCDesc;
|
||||
|
||||
|
||||
@ -171,13 +175,16 @@ unsigned GetInsnSize (opc_t OPC, am_t AM);
|
||||
const OPCDesc* GetOPCDesc (opc_t OPC);
|
||||
/* Get an opcode description */
|
||||
|
||||
unsigned char GetOPCInfo (opc_t OPC);
|
||||
/* Get opcode information */
|
||||
|
||||
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).
|
||||
*/
|
||||
|
||||
opc_t GetInverseBranch (opc_t OPC);
|
||||
/* Return a brahcn that reverse the condition of the branch given in OPC */
|
||||
/* Return a branch that reverse the condition of the branch given in OPC */
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user