Changed multi-line C comments into another style.
The left side doesn't look unbalanced.
This commit is contained in:
@@ -130,8 +130,8 @@ void ExpInsert (const char* Name, const ObjData* Module)
|
||||
|
||||
const ObjData* ExpFind (const char* Name)
|
||||
/* Check for an identifier in the list. Return NULL if not found, otherwise
|
||||
* return a pointer to the module, that exports the identifer.
|
||||
*/
|
||||
** return a pointer to the module, that exports the identifer.
|
||||
*/
|
||||
{
|
||||
/* Get a pointer to the list with the symbols hash value */
|
||||
HashEntry* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
|
||||
|
||||
@@ -59,8 +59,8 @@ void ExpInsert (const char* Name, const struct ObjData* Module);
|
||||
|
||||
const struct ObjData* ExpFind (const char* Name);
|
||||
/* Check for an identifier in the list. Return NULL if not found, otherwise
|
||||
* return a pointer to the module, that exports the identifer.
|
||||
*/
|
||||
** return a pointer to the module, that exports the identifer.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2003 Ullrich von Bassewitz */
|
||||
/* R<EFBFBD>merstrasse 52 */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
@@ -84,10 +84,10 @@ void WriteVar (FILE* F, unsigned long V)
|
||||
/* Write a variable sized value to the file in special encoding */
|
||||
{
|
||||
/* We will write the value to the file in 7 bit chunks. If the 8th bit
|
||||
* is clear, we're done, if it is set, another chunk follows. This will
|
||||
* allow us to encode smaller values with less bytes, at the expense of
|
||||
* needing 5 bytes if a 32 bit value is written to file.
|
||||
*/
|
||||
** is clear, we're done, if it is set, another chunk follows. This will
|
||||
** allow us to encode smaller values with less bytes, at the expense of
|
||||
** needing 5 bytes if a 32 bit value is written to file.
|
||||
*/
|
||||
do {
|
||||
unsigned char C = (V & 0x7F);
|
||||
V >>= 7;
|
||||
@@ -156,8 +156,8 @@ unsigned long ReadVar (FILE* F)
|
||||
/* Read a variable size value from the file */
|
||||
{
|
||||
/* The value was written to the file in 7 bit chunks LSB first. If there
|
||||
* are more bytes, bit 8 is set, otherwise it is clear.
|
||||
*/
|
||||
** are more bytes, bit 8 is set, otherwise it is clear.
|
||||
*/
|
||||
unsigned char C;
|
||||
unsigned long V = 0;
|
||||
unsigned Shift = 0;
|
||||
|
||||
@@ -216,9 +216,9 @@ static void WriteIndex (void)
|
||||
|
||||
void LibOpen (const char* Name, int MustExist, int NeedTemp)
|
||||
/* Open an existing library and a temporary copy. If MustExist is true, the
|
||||
* old library is expected to exist. If NeedTemp is true, a temporary library
|
||||
* is created.
|
||||
*/
|
||||
** old library is expected to exist. If NeedTemp is true, a temporary library
|
||||
** is created.
|
||||
*/
|
||||
{
|
||||
/* Remember the name */
|
||||
LibName = xstrdup (Name);
|
||||
@@ -268,8 +268,8 @@ void LibOpen (const char* Name, int MustExist, int NeedTemp)
|
||||
|
||||
unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
|
||||
/* Copy data from F to the temp library file, return the start position in
|
||||
* the temporary library file.
|
||||
*/
|
||||
** the temporary library file.
|
||||
*/
|
||||
{
|
||||
unsigned char Buf [4096];
|
||||
|
||||
@@ -311,8 +311,8 @@ void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
|
||||
|
||||
static void LibCheckExports (ObjData* O)
|
||||
/* Insert all exports from the given object file into the global list
|
||||
* checking for duplicates.
|
||||
*/
|
||||
** checking for duplicates.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
@@ -335,8 +335,8 @@ static void LibCheckExports (ObjData* O)
|
||||
|
||||
void LibClose (void)
|
||||
/* Write remaining data, close both files and copy the temp file to the old
|
||||
* filename
|
||||
*/
|
||||
** filename
|
||||
*/
|
||||
{
|
||||
/* Do we have a temporary library? */
|
||||
if (NewLib) {
|
||||
@@ -346,9 +346,9 @@ void LibClose (void)
|
||||
size_t Count;
|
||||
|
||||
/* Walk through the object file list, inserting exports into the
|
||||
* export list checking for duplicates. Copy any data that is still
|
||||
* in the old library into the new one.
|
||||
*/
|
||||
** export list checking for duplicates. Copy any data that is still
|
||||
** in the old library into the new one.
|
||||
*/
|
||||
for (I = 0; I < CollCount (&ObjPool); ++I) {
|
||||
|
||||
/* Get a pointer to the object */
|
||||
|
||||
@@ -61,22 +61,22 @@ extern const char* LibName;
|
||||
|
||||
void LibOpen (const char* Name, int MustExist, int NeedTemp);
|
||||
/* Open an existing library and a temporary copy. If MustExist is true, the
|
||||
* old library is expected to exist. If NeedTemp is true, a temporary library
|
||||
* is created.
|
||||
*/
|
||||
** old library is expected to exist. If NeedTemp is true, a temporary library
|
||||
** is created.
|
||||
*/
|
||||
|
||||
unsigned long LibCopyTo (FILE* F, unsigned long Bytes);
|
||||
/* Copy data from F to the temp library file, return the start position in
|
||||
* the temporary library file.
|
||||
*/
|
||||
** the temporary library file.
|
||||
*/
|
||||
|
||||
void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F);
|
||||
/* Copy data from the library file into another file */
|
||||
|
||||
void LibClose (void);
|
||||
/* Write remaining data, close both files and copy the temp file to the old
|
||||
* filename
|
||||
*/
|
||||
** filename
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -122,8 +122,8 @@ void ClearObjData (ObjData* O)
|
||||
|
||||
ObjData* FindObjData (const char* Module)
|
||||
/* Search for the module with the given name and return it. Return NULL if the
|
||||
* module is not in the list.
|
||||
*/
|
||||
** module is not in the list.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
|
||||
@@ -97,8 +97,8 @@ void ClearObjData (ObjData* O);
|
||||
|
||||
ObjData* FindObjData (const char* Module);
|
||||
/* Search for the module with the given name and return it. Return NULL if the
|
||||
* module is not in the list.
|
||||
*/
|
||||
** module is not in the list.
|
||||
*/
|
||||
|
||||
void DelObjData (const char* Module);
|
||||
/* Delete the object module from the list */
|
||||
|
||||
@@ -168,8 +168,8 @@ static void SkipLineInfoList (FILE* F)
|
||||
|
||||
void ObjReadData (FILE* F, ObjData* O)
|
||||
/* Read object file data from the given file. The function expects the Name
|
||||
* and Start fields to be valid. Header and basic data are read.
|
||||
*/
|
||||
** and Start fields to be valid. Header and basic data are read.
|
||||
*/
|
||||
{
|
||||
unsigned long Count;
|
||||
|
||||
@@ -239,14 +239,14 @@ void ObjAdd (const char* Name)
|
||||
Error ("Could not open `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
|
||||
/* Get the modification time of the object file. There a race condition
|
||||
* here, since we cannot use fileno() (non standard identifier in standard
|
||||
* header file), and therefore not fstat. When using stat with the
|
||||
* file name, there's a risk that the file was deleted and recreated
|
||||
* while it was open. Since mtime and size are only used to check
|
||||
* if a file has changed in the debugger, we will ignore this problem
|
||||
* here.
|
||||
*/
|
||||
/* Get the modification time of the object file. There's a race condition
|
||||
** here, since we cannot use fileno() (non-standard identifier in standard
|
||||
** header file), and therefore not fstat. When using stat with the
|
||||
** file name, there's a risk that the file was deleted and recreated
|
||||
** while it was open. Since mtime and size are only used to check
|
||||
** if a file has changed in the debugger, we will ignore this problem
|
||||
** here.
|
||||
*/
|
||||
if (FileStat (Name, &StatBuf) != 0) {
|
||||
Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
@@ -264,8 +264,8 @@ void ObjAdd (const char* Name)
|
||||
O = NewObjData ();
|
||||
} else {
|
||||
/* Found - check the file modification times of the internal copy
|
||||
* and the external one.
|
||||
*/
|
||||
** and the external one.
|
||||
*/
|
||||
if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
|
||||
Warning ("Replacing module `%s' by older version in library `%s'",
|
||||
O->Name, LibName);
|
||||
@@ -289,8 +289,8 @@ void ObjAdd (const char* Name)
|
||||
ObjReadData (Obj, O);
|
||||
|
||||
/* Copy the complete object data to the library file and update the
|
||||
* starting offset
|
||||
*/
|
||||
** starting offset
|
||||
*/
|
||||
fseek (Obj, 0, SEEK_SET);
|
||||
O->Start = LibCopyTo (Obj, O->Size);
|
||||
|
||||
@@ -323,8 +323,8 @@ void ObjExtract (const char* Name)
|
||||
}
|
||||
|
||||
/* Copy the complete object file data from the library to the new object
|
||||
* file.
|
||||
*/
|
||||
** file.
|
||||
*/
|
||||
LibCopyFrom (O->Start, O->Size, Obj);
|
||||
|
||||
/* Close the file */
|
||||
|
||||
@@ -60,8 +60,8 @@ struct ObjData;
|
||||
|
||||
void ObjReadData (FILE* F, struct ObjData* O);
|
||||
/* Read object file data from the given file. The function expects the Name
|
||||
* and Start fields to be valid. Header and basic data are read.
|
||||
*/
|
||||
** and Start fields to be valid. Header and basic data are read.
|
||||
*/
|
||||
|
||||
void ObjAdd (const char* Name);
|
||||
/* Add an object file to the library */
|
||||
|
||||
@@ -59,9 +59,9 @@ static const char AnonTag[] = "$anon";
|
||||
|
||||
StrBuf* AnonName (StrBuf* Buf, const char* Spec)
|
||||
/* Get a name for an anonymous scope, variable or type. Size is the size of
|
||||
* the buffer passed to the function, Spec will be used as part of the
|
||||
* identifier if given. A pointer to the buffer is returned.
|
||||
*/
|
||||
** the buffer passed to the function, Spec will be used as part of the
|
||||
** identifier if given. A pointer to the buffer is returned.
|
||||
*/
|
||||
{
|
||||
static unsigned ACount = 0;
|
||||
SB_Printf (Buf, "%s-%s-%04X", AnonTag, Spec, ++ACount);
|
||||
|
||||
@@ -51,9 +51,9 @@
|
||||
|
||||
StrBuf* AnonName (StrBuf* Buf, const char* Spec);
|
||||
/* Get a name for an anonymous scope, variable or type. Size is the size of
|
||||
* the buffer passed to the function, Spec will be used as part of the
|
||||
* identifier if given. A pointer to the buffer is returned.
|
||||
*/
|
||||
** the buffer passed to the function, Spec will be used as part of the
|
||||
** identifier if given. A pointer to the buffer is returned.
|
||||
*/
|
||||
|
||||
int IsAnonName (const StrBuf* Name);
|
||||
/* Check if the given symbol name is that of an anonymous symbol */
|
||||
|
||||
@@ -104,9 +104,9 @@ static int GetOverallIfCond (void)
|
||||
/* Get the overall condition based on all conditions on the stack. */
|
||||
{
|
||||
/* Since the last entry contains the overall condition of the parent, we
|
||||
* must check it in combination of the current condition. If there is no
|
||||
* last entry, the overall condition is true.
|
||||
*/
|
||||
** must check it in combination of the current condition. If there is no
|
||||
** last entry, the overall condition is true.
|
||||
*/
|
||||
return (IfCount == 0) ||
|
||||
((IfStack[IfCount-1].Flags & (ifCond | ifParentCond)) == (ifCond | ifParentCond));
|
||||
}
|
||||
@@ -114,7 +114,7 @@ static int GetOverallIfCond (void)
|
||||
|
||||
|
||||
static void CalcOverallIfCond (void)
|
||||
/* Caclulate the overall condition based on all conditions on the stack. */
|
||||
/* Calculate the overall condition, based on all conditions on the stack. */
|
||||
{
|
||||
IfCond = GetOverallIfCond ();
|
||||
}
|
||||
@@ -256,9 +256,9 @@ void DoConditionals (void)
|
||||
NextTok ();
|
||||
|
||||
/* Ignore the new condition if we are inside a false .ELSE
|
||||
* branch. This way we won't get any errors about undefined
|
||||
* symbols or similar...
|
||||
*/
|
||||
** branch. This way we won't get any errors about undefined
|
||||
** symbols or similar...
|
||||
*/
|
||||
if (IfCond) {
|
||||
SetIfCond (D, ConstExpression ());
|
||||
ExpectSep ();
|
||||
@@ -273,8 +273,8 @@ void DoConditionals (void)
|
||||
FreeIf ();
|
||||
|
||||
/* Be sure not to read the next token until the .IF stack
|
||||
* has been cleanup up, since we may be at end of file.
|
||||
*/
|
||||
** has been cleanup up, since we may be at end of file.
|
||||
*/
|
||||
NextTok ();
|
||||
ExpectSep ();
|
||||
|
||||
@@ -440,9 +440,9 @@ void DoConditionals (void)
|
||||
|
||||
int CheckConditionals (void)
|
||||
/* Check if the current token is one that starts a conditional directive, and
|
||||
* call DoConditionals if so. Return true if a conditional directive was found,
|
||||
* return false otherwise.
|
||||
*/
|
||||
** call DoConditionals if so. Return true if a conditional directive was found,
|
||||
** return false otherwise.
|
||||
*/
|
||||
{
|
||||
switch (CurTok.Tok) {
|
||||
case TOK_ELSE:
|
||||
@@ -473,15 +473,15 @@ int CheckConditionals (void)
|
||||
|
||||
void CheckOpenIfs (void)
|
||||
/* Called from the scanner before closing an input file. Will check for any
|
||||
* open .ifs in this file.
|
||||
*/
|
||||
** open .ifs in this file.
|
||||
*/
|
||||
{
|
||||
const LineInfo* LI;
|
||||
|
||||
while (1) {
|
||||
/* Get the current file number and check if the topmost entry on the
|
||||
* .IF stack was inserted with this file number
|
||||
*/
|
||||
** .IF stack was inserted with this file number
|
||||
*/
|
||||
IfDesc* D = GetCurrentIf ();
|
||||
if (D == 0) {
|
||||
/* There are no open .IFs */
|
||||
|
||||
@@ -60,14 +60,14 @@ void DoConditionals (void);
|
||||
|
||||
int CheckConditionals (void);
|
||||
/* Check if the current token is one that starts a conditional directive, and
|
||||
* call DoConditionals if so. Return true if a conditional directive was found,
|
||||
* return false otherwise.
|
||||
*/
|
||||
** call DoConditionals if so. Return true if a conditional directive was found,
|
||||
** return false otherwise.
|
||||
*/
|
||||
|
||||
void CheckOpenIfs (void);
|
||||
/* Called from the scanner before closing an input file. Will check for any
|
||||
* open .ifs in this file.
|
||||
*/
|
||||
** open .ifs in this file.
|
||||
*/
|
||||
|
||||
unsigned GetIfStack (void);
|
||||
/* Get the current .IF stack pointer */
|
||||
|
||||
@@ -130,8 +130,8 @@ static unsigned HexValue (char C)
|
||||
|
||||
static int ValidateType (StrBuf* Type)
|
||||
/* Check if the given type is valid and if so, return a string id for it. If
|
||||
* the type isn't valid, return -1. Type is overwritten when checking.
|
||||
*/
|
||||
** the type isn't valid, return -1. Type is overwritten when checking.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
const char* A;
|
||||
@@ -311,8 +311,8 @@ void DbgInfoLine (void)
|
||||
}
|
||||
|
||||
/* If a parameters follow, this is actual line info. If no parameters
|
||||
* follow, the last line info is terminated.
|
||||
*/
|
||||
** follow, the last line info is terminated.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_SEP) {
|
||||
return;
|
||||
}
|
||||
@@ -445,10 +445,10 @@ void DbgInfoCheck (void)
|
||||
/* Do checks on all hll debug info symbols when assembly is complete */
|
||||
{
|
||||
/* When parsing the debug statements for HLL symbols, we have already
|
||||
* tagged the functions to their asm counterparts. This wasn't done for
|
||||
* C symbols, since we will allow forward declarations. So we have to
|
||||
* resolve the normal C symbols now.
|
||||
*/
|
||||
** tagged the functions to their asm counterparts. This wasn't done for
|
||||
** C symbols, since we will allow forward declarations. So we have to
|
||||
** resolve the normal C symbols now.
|
||||
*/
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&HLLDbgSyms); ++I) {
|
||||
|
||||
@@ -456,8 +456,8 @@ void DbgInfoCheck (void)
|
||||
HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I);
|
||||
|
||||
/* Ignore functions and auto symbols, because the later live on the
|
||||
* stack and don't have corresponding asm symbols.
|
||||
*/
|
||||
** stack and don't have corresponding asm symbols.
|
||||
*/
|
||||
if (HLL_IS_FUNC (S->Flags) || HLL_GET_SC (S->Flags) == HLL_SC_AUTO) {
|
||||
continue;
|
||||
}
|
||||
@@ -501,8 +501,8 @@ void WriteHLLDbgSyms (void)
|
||||
unsigned SC = HLL_GET_SC (S->Flags);
|
||||
|
||||
/* Remember if the symbol has debug info attached
|
||||
* ### This should go into DbgInfoCheck
|
||||
*/
|
||||
** ### This should go into DbgInfoCheck
|
||||
*/
|
||||
if (S->Sym && S->Sym->DebugSymId != ~0U) {
|
||||
S->Flags |= HLL_DATA_SYM;
|
||||
}
|
||||
|
||||
@@ -157,12 +157,12 @@ void GetEA (EffAddr* A)
|
||||
} else {
|
||||
|
||||
/* Remaining stuff:
|
||||
*
|
||||
* adr
|
||||
* adr,x
|
||||
* adr,y
|
||||
* adr,s
|
||||
*/
|
||||
**
|
||||
** adr
|
||||
** adr,x
|
||||
** adr,y
|
||||
** adr,s
|
||||
*/
|
||||
A->Expr = Expression ();
|
||||
|
||||
if (CurTok.Tok == TOK_COMMA) {
|
||||
|
||||
@@ -51,9 +51,9 @@
|
||||
|
||||
static long RegNum ()
|
||||
/* Try to read a register number specified not as a register (Rx) but as a
|
||||
* numeric value between 0 and 15. Return the register number or -1 on
|
||||
* failure.
|
||||
*/
|
||||
** numeric value between 0 and 15. Return the register number or -1 on
|
||||
** failure.
|
||||
*/
|
||||
{
|
||||
long Val;
|
||||
ExprNode* Expr = Expression ();
|
||||
@@ -126,8 +126,8 @@ void GetSweet16EA (EffAddr* A)
|
||||
A->AddrModeSet = AMSW16_BRA;
|
||||
|
||||
/* If the value is a constant between 0 and 15, it may also be a
|
||||
* register number.
|
||||
*/
|
||||
** register number.
|
||||
*/
|
||||
if (IsConstExpr (A->Expr, &Reg) && Reg >= 0 && Reg <= 15) {
|
||||
FreeExpr (A->Expr);
|
||||
A->Reg = (unsigned) Reg;
|
||||
|
||||
@@ -128,10 +128,10 @@ static void AddNotifications (const Collection* LineInfos)
|
||||
unsigned Skipped;
|
||||
|
||||
/* The basic line info is always in slot zero. It has been used to
|
||||
* output the actual error or warning. The following slots may contain
|
||||
* more information. Check them and print additional notifications if
|
||||
* they're present, but limit the number to a reasonable value.
|
||||
*/
|
||||
** output the actual error or warning. The following slots may contain
|
||||
** more information. Check them and print additional notifications if
|
||||
** they're present, but limit the number to a reasonable value.
|
||||
*/
|
||||
for (I = 1, Output = 0, Skipped = 0; I < CollCount (LineInfos); ++I) {
|
||||
/* Get next line info */
|
||||
const LineInfo* LI = CollConstAt (LineInfos, I);
|
||||
|
||||
144
src/ca65/expr.c
144
src/ca65/expr.c
@@ -72,11 +72,11 @@
|
||||
|
||||
|
||||
/* Since all expressions are first packed into expression trees, and each
|
||||
* expression tree node is allocated on the heap, we add some type of special
|
||||
* purpose memory allocation here: Instead of freeing the nodes, we save some
|
||||
* number of freed nodes for later and remember them in a single linked list
|
||||
* using the Left link.
|
||||
*/
|
||||
** expression tree node is allocated on the heap, we add some type of special
|
||||
** purpose memory allocation here: Instead of freeing the nodes, we save some
|
||||
** number of freed nodes for later and remember them in a single linked list
|
||||
** using the Left link.
|
||||
*/
|
||||
#define MAX_FREE_NODES 64
|
||||
static ExprNode* FreeExprNodes = 0;
|
||||
static unsigned FreeNodeCount = 0;
|
||||
@@ -172,9 +172,9 @@ int IsFarRange (long Val)
|
||||
|
||||
int IsEasyConst (const ExprNode* E, long* Val)
|
||||
/* Do some light checking if the given node is a constant. Don't care if E is
|
||||
* a complex expression. If E is a constant, return true and place its value
|
||||
* into Val, provided that Val is not NULL.
|
||||
*/
|
||||
** a complex expression. If E is a constant, return true and place its value
|
||||
** into Val, provided that Val is not NULL.
|
||||
*/
|
||||
{
|
||||
/* Resolve symbols, follow symbol chains */
|
||||
while (E->Op == EXPR_SYMBOL) {
|
||||
@@ -322,8 +322,8 @@ static ExprNode* Symbol (SymEntry* S)
|
||||
/* Mark the symbol as referenced */
|
||||
SymRef (S);
|
||||
/* If the symbol is a variable, return just its value, otherwise
|
||||
* return a reference to the symbol.
|
||||
*/
|
||||
** return a reference to the symbol.
|
||||
*/
|
||||
if (SymIsVar (S)) {
|
||||
return CloneExpr (GetSymExpr (S));
|
||||
} else {
|
||||
@@ -355,16 +355,16 @@ static ExprNode* FuncBlank (void)
|
||||
/* Handle the .BLANK builtin function */
|
||||
{
|
||||
/* We have a list of tokens that ends with the closing paren. Skip
|
||||
* the tokens, and count them. Allow optionally curly braces.
|
||||
*/
|
||||
** the tokens, and count them. Allow optionally curly braces.
|
||||
*/
|
||||
token_t Term = GetTokListTerm (TOK_RPAREN);
|
||||
unsigned Count = 0;
|
||||
while (CurTok.Tok != Term) {
|
||||
|
||||
/* Check for end of line or end of input. Since the calling function
|
||||
* will check for the closing paren, we don't need to print an error
|
||||
* here, just bail out.
|
||||
*/
|
||||
** will check for the closing paren, we don't need to print an error
|
||||
** here, just bail out.
|
||||
*/
|
||||
if (TokIsSep (CurTok.Tok)) {
|
||||
break;
|
||||
}
|
||||
@@ -458,9 +458,9 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
|
||||
TokNode* Node;
|
||||
|
||||
/* A list of tokens follows. Read this list and remember it building a
|
||||
* single linked list of tokens including attributes. The list is
|
||||
* either enclosed in curly braces, or terminated by a comma.
|
||||
*/
|
||||
** single linked list of tokens including attributes. The list is
|
||||
** either enclosed in curly braces, or terminated by a comma.
|
||||
*/
|
||||
token_t Term = GetTokListTerm (TOK_COMMA);
|
||||
while (CurTok.Tok != Term) {
|
||||
|
||||
@@ -494,9 +494,9 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
|
||||
}
|
||||
|
||||
/* Read the second list which is optionally enclosed in curly braces and
|
||||
* terminated by the right parenthesis. Compare each token against the
|
||||
* one in the first list.
|
||||
*/
|
||||
** terminated by the right parenthesis. Compare each token against the
|
||||
** one in the first list.
|
||||
*/
|
||||
Term = GetTokListTerm (TOK_RPAREN);
|
||||
Result = 1;
|
||||
Node = Root;
|
||||
@@ -674,8 +674,8 @@ static ExprNode* FuncSizeOf (void)
|
||||
}
|
||||
|
||||
/* If ScopeName is empty, no explicit scope was specified. We have to
|
||||
* search upper scope levels in this case.
|
||||
*/
|
||||
** search upper scope levels in this case.
|
||||
*/
|
||||
NoScope = SB_IsEmpty (&ScopeName);
|
||||
|
||||
/* First search for a scope with the given name */
|
||||
@@ -686,8 +686,8 @@ static ExprNode* FuncSizeOf (void)
|
||||
}
|
||||
|
||||
/* If we did find a scope with the name, read the symbol defining the
|
||||
* size, otherwise search for a symbol entry with the name and scope.
|
||||
*/
|
||||
** size, otherwise search for a symbol entry with the name and scope.
|
||||
*/
|
||||
if (Scope) {
|
||||
/* Yep, it's a scope */
|
||||
SizeSym = GetSizeOfScope (Scope);
|
||||
@@ -755,8 +755,8 @@ static ExprNode* FuncStrAt (void)
|
||||
}
|
||||
|
||||
/* Get the char, handle as unsigned. Be sure to translate it into
|
||||
* the target character set.
|
||||
*/
|
||||
** the target character set.
|
||||
*/
|
||||
C = TgtTranslateChar (SB_At (&Str, (unsigned)Index));
|
||||
|
||||
ExitPoint:
|
||||
@@ -803,16 +803,16 @@ static ExprNode* FuncTCount (void)
|
||||
/* Handle the .TCOUNT function */
|
||||
{
|
||||
/* We have a list of tokens that ends with the closing paren. Skip
|
||||
* the tokens, and count them. Allow optionally curly braces.
|
||||
*/
|
||||
** the tokens, and count them. Allow optionally curly braces.
|
||||
*/
|
||||
token_t Term = GetTokListTerm (TOK_RPAREN);
|
||||
int Count = 0;
|
||||
while (CurTok.Tok != Term) {
|
||||
|
||||
/* Check for end of line or end of input. Since the calling function
|
||||
* will check for the closing paren, we don't need to print an error
|
||||
* here, just bail out.
|
||||
*/
|
||||
** will check for the closing paren, we don't need to print an error
|
||||
** here, just bail out.
|
||||
*/
|
||||
if (TokIsSep (CurTok.Tok)) {
|
||||
break;
|
||||
}
|
||||
@@ -1131,8 +1131,8 @@ static ExprNode* Term (void)
|
||||
}
|
||||
|
||||
/* Generate a literal expression and delete the old left and
|
||||
* right sides.
|
||||
*/
|
||||
** right sides.
|
||||
*/
|
||||
FreeExpr (Left);
|
||||
FreeExpr (Right);
|
||||
Root = GenLiteralExpr (Val);
|
||||
@@ -1198,8 +1198,8 @@ static ExprNode* SimpleExpr (void)
|
||||
}
|
||||
|
||||
/* Generate a literal expression and delete the old left and
|
||||
* right sides.
|
||||
*/
|
||||
** right sides.
|
||||
*/
|
||||
FreeExpr (Left);
|
||||
FreeExpr (Right);
|
||||
Root = GenLiteralExpr (Val);
|
||||
@@ -1264,8 +1264,8 @@ static ExprNode* BoolExpr (void)
|
||||
}
|
||||
|
||||
/* Generate a literal expression and delete the old left and
|
||||
* right sides.
|
||||
*/
|
||||
** right sides.
|
||||
*/
|
||||
FreeExpr (Left);
|
||||
FreeExpr (Right);
|
||||
Root = GenLiteralExpr (Val);
|
||||
@@ -1327,8 +1327,8 @@ static ExprNode* Expr2 (void)
|
||||
}
|
||||
|
||||
/* Generate a literal expression and delete the old left and
|
||||
* right sides.
|
||||
*/
|
||||
** right sides.
|
||||
*/
|
||||
FreeExpr (Left);
|
||||
FreeExpr (Right);
|
||||
Root = GenLiteralExpr (Val);
|
||||
@@ -1385,8 +1385,8 @@ static ExprNode* Expr1 (void)
|
||||
}
|
||||
|
||||
/* Generate a literal expression and delete the old left and
|
||||
* right sides.
|
||||
*/
|
||||
** right sides.
|
||||
*/
|
||||
FreeExpr (Left);
|
||||
FreeExpr (Right);
|
||||
Root = GenLiteralExpr (Val);
|
||||
@@ -1453,8 +1453,8 @@ static ExprNode* Expr0 (void)
|
||||
|
||||
ExprNode* Expression (void)
|
||||
/* Evaluate an expression, build the expression tree on the heap and return
|
||||
* a pointer to the root of the tree.
|
||||
*/
|
||||
** a pointer to the root of the tree.
|
||||
*/
|
||||
{
|
||||
return Expr0 ();
|
||||
}
|
||||
@@ -1463,9 +1463,9 @@ ExprNode* Expression (void)
|
||||
|
||||
long ConstExpression (void)
|
||||
/* Parse an expression. Check if the expression is const, and print an error
|
||||
* message if not. Return the value of the expression, or a dummy, if it is
|
||||
* not constant.
|
||||
*/
|
||||
** message if not. Return the value of the expression, or a dummy, if it is
|
||||
** not constant.
|
||||
*/
|
||||
{
|
||||
long Val;
|
||||
|
||||
@@ -1620,8 +1620,8 @@ ExprNode* GenSwapExpr (ExprNode* Expr)
|
||||
|
||||
ExprNode* GenBranchExpr (unsigned Offs)
|
||||
/* Return an expression that encodes the difference between current PC plus
|
||||
* offset and the target expression (that is, Expression() - (*+Offs) ).
|
||||
*/
|
||||
** offset and the target expression (that is, Expression() - (*+Offs) ).
|
||||
*/
|
||||
{
|
||||
ExprNode* N;
|
||||
ExprNode* Root;
|
||||
@@ -1637,11 +1637,11 @@ ExprNode* GenBranchExpr (unsigned Offs)
|
||||
FreeExpr (N);
|
||||
|
||||
/* Generate the final expression:
|
||||
* Val - (* + Offs)
|
||||
* Val - ((Seg + PC) + Offs)
|
||||
* Val - Seg - PC - Offs
|
||||
* (Val - PC - Offs) - Seg
|
||||
*/
|
||||
** Val - (* + Offs)
|
||||
** Val - ((Seg + PC) + Offs)
|
||||
** Val - Seg - PC - Offs
|
||||
** (Val - PC - Offs) - Seg
|
||||
*/
|
||||
Root = GenLiteralExpr (Val - GetPC () - Offs);
|
||||
if (GetRelocMode ()) {
|
||||
N = Root;
|
||||
@@ -1653,11 +1653,11 @@ ExprNode* GenBranchExpr (unsigned Offs)
|
||||
} else {
|
||||
|
||||
/* Generate the expression:
|
||||
* N - (* + Offs)
|
||||
* N - ((Seg + PC) + Offs)
|
||||
* N - Seg - PC - Offs
|
||||
* N - (PC + Offs) - Seg
|
||||
*/
|
||||
** N - (* + Offs)
|
||||
** N - ((Seg + PC) + Offs)
|
||||
** N - Seg - PC - Offs
|
||||
** N - (PC + Offs) - Seg
|
||||
*/
|
||||
Root = NewExprNode (EXPR_MINUS);
|
||||
Root->Left = N;
|
||||
Root->Right = GenLiteralExpr (GetPC () + Offs);
|
||||
@@ -1759,9 +1759,9 @@ ExprNode* GenNE (ExprNode* Expr, long Val)
|
||||
|
||||
int IsConstExpr (ExprNode* Expr, long* Val)
|
||||
/* Return true if the given expression is a constant expression, that is, one
|
||||
* with no references to external symbols. If Val is not NULL and the
|
||||
* expression is constant, the constant value is stored here.
|
||||
*/
|
||||
** with no references to external symbols. If Val is not NULL and the
|
||||
** expression is constant, the constant value is stored here.
|
||||
*/
|
||||
{
|
||||
int IsConst;
|
||||
|
||||
@@ -1785,8 +1785,8 @@ int IsConstExpr (ExprNode* Expr, long* Val)
|
||||
|
||||
ExprNode* CloneExpr (ExprNode* Expr)
|
||||
/* Clone the given expression tree. The function will simply clone symbol
|
||||
* nodes, it will not resolve them.
|
||||
*/
|
||||
** nodes, it will not resolve them.
|
||||
*/
|
||||
{
|
||||
ExprNode* Clone;
|
||||
|
||||
@@ -1843,8 +1843,8 @@ void WriteExpr (ExprNode* Expr)
|
||||
}
|
||||
|
||||
/* If the is a leafnode, write the expression attribute, otherwise
|
||||
* write the expression operands.
|
||||
*/
|
||||
** write the expression operands.
|
||||
*/
|
||||
switch (Expr->Op) {
|
||||
|
||||
case EXPR_LITERAL:
|
||||
@@ -1884,12 +1884,12 @@ void WriteExpr (ExprNode* Expr)
|
||||
|
||||
void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
|
||||
/* Mark the address size of the given expression tree as guessed. The address
|
||||
* size passed as argument is the one NOT used, because the actual address
|
||||
* size wasn't known. Example: Zero page addressing was not used because symbol
|
||||
* is undefined, and absolute addressing was available.
|
||||
* This function will actually parse the expression tree for undefined symbols,
|
||||
* and mark these symbols accordingly.
|
||||
*/
|
||||
** size passed as argument is the one NOT used, because the actual address
|
||||
** size wasn't known. Example: Zero page addressing was not used because symbol
|
||||
** is undefined, and absolute addressing was available.
|
||||
** This function will actually parse the expression tree for undefined symbols,
|
||||
** and mark these symbols accordingly.
|
||||
*/
|
||||
{
|
||||
/* Accept NULL expressions */
|
||||
if (Expr == 0) {
|
||||
|
||||
@@ -62,14 +62,14 @@ struct ExprDesc;
|
||||
|
||||
ExprNode* Expression (void);
|
||||
/* Evaluate an expression, build the expression tree on the heap and return
|
||||
* a pointer to the root of the tree.
|
||||
*/
|
||||
** a pointer to the root of the tree.
|
||||
*/
|
||||
|
||||
long ConstExpression (void);
|
||||
/* Parse an expression. Check if the expression is const, and print an error
|
||||
* message if not. Return the value of the expression, or a dummy, if it is
|
||||
* not constant.
|
||||
*/
|
||||
** message if not. Return the value of the expression, or a dummy, if it is
|
||||
** not constant.
|
||||
*/
|
||||
|
||||
void FreeExpr (ExprNode* Root);
|
||||
/* Free the expression tree, Root is pointing to. */
|
||||
@@ -97,8 +97,8 @@ ExprNode* GenSwapExpr (ExprNode* Expr);
|
||||
|
||||
ExprNode* GenBranchExpr (unsigned Offs);
|
||||
/* Return an expression that encodes the difference between current PC plus
|
||||
* offset and the target expression (that is, Expression() - (*+Offs) ).
|
||||
*/
|
||||
** offset and the target expression (that is, Expression() - (*+Offs) ).
|
||||
*/
|
||||
|
||||
ExprNode* GenULabelExpr (unsigned Num);
|
||||
/* Return an expression for an unnamed label with the given index */
|
||||
@@ -120,9 +120,9 @@ ExprNode* GenNE (ExprNode* Expr, long Val);
|
||||
|
||||
int IsConstExpr (ExprNode* Expr, long* Val);
|
||||
/* Return true if the given expression is a constant expression, that is, one
|
||||
* with no references to external symbols. If Val is not NULL and the
|
||||
* expression is constant, the constant value is stored here.
|
||||
*/
|
||||
** with no references to external symbols. If Val is not NULL and the
|
||||
** expression is constant, the constant value is stored here.
|
||||
*/
|
||||
|
||||
int IsByteExpr (ExprNode* Root);
|
||||
/* Return true if this is a byte expression */
|
||||
@@ -138,26 +138,26 @@ int IsFarRange (long Val);
|
||||
|
||||
int IsEasyConst (const ExprNode* E, long* Val);
|
||||
/* Do some light checking if the given node is a constant. Don't care if E is
|
||||
* a complex expression. If E is a constant, return true and place its value
|
||||
* into Val, provided that Val is not NULL.
|
||||
*/
|
||||
** a complex expression. If E is a constant, return true and place its value
|
||||
** into Val, provided that Val is not NULL.
|
||||
*/
|
||||
|
||||
ExprNode* CloneExpr (ExprNode* Expr);
|
||||
/* Clone the given expression tree. The function will simply clone symbol
|
||||
* nodes, it will not resolve them.
|
||||
*/
|
||||
** nodes, it will not resolve them.
|
||||
*/
|
||||
|
||||
void WriteExpr (ExprNode* Expr);
|
||||
/* Write the given expression to the object file */
|
||||
|
||||
void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize);
|
||||
/* Mark the address size of the given expression tree as guessed. The address
|
||||
* size passed as argument is the one NOT used, because the actual address
|
||||
* size wasn't known. Example: Zero page addressing was not used because symbol
|
||||
* is undefined, and absolute addressing was available.
|
||||
* This function will actually parse the expression tree for undefined symbols,
|
||||
* and mark these symbols accordingly.
|
||||
*/
|
||||
** size passed as argument is the one NOT used, because the actual address
|
||||
** size wasn't known. Example: Zero page addressing was not used because symbol
|
||||
** is undefined, and absolute addressing was available.
|
||||
** This function will actually parse the expression tree for undefined symbols,
|
||||
** and mark these symbols accordingly.
|
||||
*/
|
||||
|
||||
ExprNode* FuncBankByte (void);
|
||||
/* Handle the .BANKBYTE builtin function */
|
||||
|
||||
@@ -75,8 +75,8 @@ static const char* FeatureKeys[FEAT_COUNT] = {
|
||||
|
||||
feature_t FindFeature (const StrBuf* Key)
|
||||
/* Find the feature in a table and return the corresponding enum value. If the
|
||||
* feature is invalid, return FEAT_UNKNOWN.
|
||||
*/
|
||||
** feature is invalid, return FEAT_UNKNOWN.
|
||||
*/
|
||||
{
|
||||
feature_t F;
|
||||
|
||||
@@ -96,9 +96,9 @@ feature_t FindFeature (const StrBuf* Key)
|
||||
|
||||
feature_t SetFeature (const StrBuf* Key)
|
||||
/* Find the feature and set the corresponding flag if the feature is known.
|
||||
* In any case, return the feature found. An invalid Key will return
|
||||
* FEAT_UNKNOWN.
|
||||
*/
|
||||
** In any case, return the feature found. An invalid Key will return
|
||||
** FEAT_UNKNOWN.
|
||||
*/
|
||||
{
|
||||
/* Map the string to an enum value */
|
||||
feature_t Feature = FindFeature (Key);
|
||||
|
||||
@@ -80,14 +80,14 @@ typedef enum {
|
||||
|
||||
feature_t FindFeature (const StrBuf* Key);
|
||||
/* Find the feature in a table and return the corresponding enum value. If the
|
||||
* feature is invalid, return FEAT_UNKNOWN.
|
||||
*/
|
||||
** feature is invalid, return FEAT_UNKNOWN.
|
||||
*/
|
||||
|
||||
feature_t SetFeature (const StrBuf* Key);
|
||||
/* Find the feature and set the corresponding flag if the feature is known.
|
||||
* In any case, return the feature found. An invalid Key will return
|
||||
* FEAT_UNKNOWN.
|
||||
*/
|
||||
** In any case, return the feature found. An invalid Key will return
|
||||
** FEAT_UNKNOWN.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ static const void* HT_GetKey (const void* Entry);
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2);
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -132,9 +132,9 @@ static const void* HT_GetKey (const void* Entry)
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2)
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
{
|
||||
return (int)*(const unsigned*)Key1 - (int)*(const unsigned*)Key2;
|
||||
}
|
||||
@@ -183,9 +183,9 @@ const StrBuf* GetFileName (unsigned Name)
|
||||
|
||||
if (Name == 0) {
|
||||
/* Name was defined outside any file scope, use the name of the first
|
||||
* file instead. Errors are then reported with a file position of
|
||||
* line zero in the first file.
|
||||
*/
|
||||
** file instead. Errors are then reported with a file position of
|
||||
** line zero in the first file.
|
||||
*/
|
||||
if (CollCount (&FileTab) == 0) {
|
||||
/* No files defined until now */
|
||||
return &ErrorMsg;
|
||||
@@ -223,8 +223,8 @@ unsigned GetFileIndex (const StrBuf* Name)
|
||||
unsigned AddFile (const StrBuf* Name, FileType Type,
|
||||
unsigned long Size, unsigned long MTime)
|
||||
/* Add a new file to the list of input files. Return the index of the file in
|
||||
* the table.
|
||||
*/
|
||||
** the table.
|
||||
*/
|
||||
{
|
||||
/* Create a new file entry and insert it into the tables */
|
||||
FileEntry* F = NewFileEntry (GetStrBufId (Name), Type, Size, MTime);
|
||||
@@ -295,8 +295,8 @@ static void WriteDep (FILE* F, FileType Types)
|
||||
|
||||
static void CreateDepFile (const char* Name, FileType Types)
|
||||
/* Create a dependency file with the given name and place dependencies for
|
||||
* all files with the given types there.
|
||||
*/
|
||||
** all files with the given types there.
|
||||
*/
|
||||
{
|
||||
/* Open the file */
|
||||
FILE* F = fopen (Name, "w");
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
|
||||
|
||||
/* An enum that describes different types of input files. The members are
|
||||
* choosen so that it is possible to combine them to bitsets
|
||||
*/
|
||||
** choosen so that it is possible to combine them to bitsets
|
||||
*/
|
||||
typedef enum {
|
||||
FT_MAIN = 0x01, /* Main input file */
|
||||
FT_INCLUDE = 0x02, /* Normal include file */
|
||||
@@ -76,8 +76,8 @@ unsigned GetFileIndex (const StrBuf* Name);
|
||||
unsigned AddFile (const StrBuf* Name, FileType Type,
|
||||
unsigned long Size, unsigned long MTime);
|
||||
/* Add a new file to the list of input files. Return the index of the file in
|
||||
* the table.
|
||||
*/
|
||||
** the table.
|
||||
*/
|
||||
|
||||
void WriteFiles (void);
|
||||
/* Write the list of input files to the object file */
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
|
||||
Fragment* NewFragment (unsigned char Type, unsigned short Len)
|
||||
/* Create, initialize and return a new fragment. The fragment will be inserted
|
||||
* into the current segment.
|
||||
*/
|
||||
** into the current segment.
|
||||
*/
|
||||
{
|
||||
/* Create a new fragment */
|
||||
Fragment* F = xmalloc (sizeof (*F));
|
||||
|
||||
@@ -76,8 +76,8 @@ struct Fragment {
|
||||
|
||||
Fragment* NewFragment (unsigned char Type, unsigned short Len);
|
||||
/* Create, initialize and return a new fragment. The fragment will be inserted
|
||||
* into the current segment.
|
||||
*/
|
||||
** into the current segment.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
152
src/ca65/instr.c
152
src/ca65/instr.c
@@ -90,37 +90,37 @@ static void PutSEP (const InsDesc* Ins);
|
||||
|
||||
static void PutTAMn (const InsDesc* Ins);
|
||||
/* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
|
||||
* implicit addressing mode, the opcode byte in the table is actually the
|
||||
* second operand byte. The TAM instruction is the more generic form, it takes
|
||||
* an immediate argument.
|
||||
*/
|
||||
** implicit addressing mode, the opcode byte in the table is actually the
|
||||
** second operand byte. The TAM instruction is the more generic form, it takes
|
||||
** an immediate argument.
|
||||
*/
|
||||
|
||||
static void PutTMA (const InsDesc* Ins);
|
||||
/* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
|
||||
* in the argument byte may be set.
|
||||
*/
|
||||
** in the argument byte may be set.
|
||||
*/
|
||||
|
||||
static void PutTMAn (const InsDesc* Ins);
|
||||
/* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
|
||||
* implicit addressing mode, the opcode byte in the table is actually the
|
||||
* second operand byte. The TAM instruction is the more generic form, it takes
|
||||
* an immediate argument.
|
||||
*/
|
||||
** implicit addressing mode, the opcode byte in the table is actually the
|
||||
** second operand byte. The TAM instruction is the more generic form, it takes
|
||||
** an immediate argument.
|
||||
*/
|
||||
|
||||
static void PutTST (const InsDesc* Ins);
|
||||
/* Emit a TST instruction (HuC6280). */
|
||||
|
||||
static void PutJMP (const InsDesc* Ins);
|
||||
/* Handle the jump instruction for the 6502. Problem is that these chips have
|
||||
* a bug: If the address crosses a page, the upper byte gets not corrected and
|
||||
* the instruction will fail. The PutJmp function will add a linker assertion
|
||||
* to check for this case and is otherwise identical to PutAll.
|
||||
*/
|
||||
** a bug: If the address crosses a page, the upper byte gets not corrected and
|
||||
** the instruction will fail. The PutJmp function will add a linker assertion
|
||||
** to check for this case and is otherwise identical to PutAll.
|
||||
*/
|
||||
|
||||
static void PutRTS (const InsDesc* Ins attribute ((unused)));
|
||||
/* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
|
||||
* the enclosing scope is FAR.
|
||||
*/
|
||||
** the enclosing scope is FAR.
|
||||
*/
|
||||
|
||||
static void PutAll (const InsDesc* Ins);
|
||||
/* Handle all other instructions */
|
||||
@@ -783,8 +783,8 @@ static const InsTable* InsTabs[CPU_COUNT] = {
|
||||
const InsTable* InsTab = (const InsTable*) &InsTab6502;
|
||||
|
||||
/* Table to build the effective 65xx opcode from a base opcode and an
|
||||
* addressing mode.
|
||||
*/
|
||||
** addressing mode.
|
||||
*/
|
||||
static unsigned char EATab[10][AM65I_COUNT] = {
|
||||
{ /* Table 0 */
|
||||
0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
|
||||
@@ -849,8 +849,8 @@ static unsigned char EATab[10][AM65I_COUNT] = {
|
||||
};
|
||||
|
||||
/* Table to build the effective SWEET16 opcode from a base opcode and an
|
||||
* addressing mode.
|
||||
*/
|
||||
** addressing mode.
|
||||
*/
|
||||
static unsigned char Sweet16EATab[2][AMSW16I_COUNT] = {
|
||||
{ /* Table 0 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
@@ -910,21 +910,21 @@ static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
|
||||
|
||||
static int EvalEA (const InsDesc* Ins, EffAddr* A)
|
||||
/* Evaluate the effective address. All fields in A will be valid after calling
|
||||
* this function. The function returns true on success and false on errors.
|
||||
*/
|
||||
** this function. The function returns true on success and false on errors.
|
||||
*/
|
||||
{
|
||||
/* Get the set of possible addressing modes */
|
||||
GetEA (A);
|
||||
|
||||
/* From the possible addressing modes, remove the ones that are invalid
|
||||
* for this instruction or CPU.
|
||||
*/
|
||||
** for this instruction or CPU.
|
||||
*/
|
||||
A->AddrModeSet &= Ins->AddrMode;
|
||||
|
||||
/* If we have an expression, check it and remove any addressing modes that
|
||||
* are too small for the expression size. Since we have to study the
|
||||
* expression anyway, do also replace it by a simpler one if possible.
|
||||
*/
|
||||
** are too small for the expression size. Since we have to study the
|
||||
** expression anyway, do also replace it by a simpler one if possible.
|
||||
*/
|
||||
if (A->Expr) {
|
||||
ExprDesc ED;
|
||||
ED_Init (&ED);
|
||||
@@ -937,10 +937,10 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
|
||||
|
||||
if (ED.AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
/* We don't know how big the expression is. If the instruction
|
||||
* allows just one addressing mode, assume this as address size
|
||||
* for the expression. Otherwise assume the default address size
|
||||
* for data.
|
||||
*/
|
||||
** allows just one addressing mode, assume this as address size
|
||||
** for the expression. Otherwise assume the default address size
|
||||
** for data.
|
||||
*/
|
||||
if ((A->AddrModeSet & ~AM65_ALL_ZP) == 0) {
|
||||
ED.AddrSize = ADDR_SIZE_ZP;
|
||||
} else if ((A->AddrModeSet & ~AM65_ALL_ABS) == 0) {
|
||||
@@ -950,12 +950,12 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
|
||||
} else {
|
||||
ED.AddrSize = DataAddrSize;
|
||||
/* If the default address size of the data segment is unequal
|
||||
* to zero page addressing, but zero page addressing is
|
||||
* allowed by the instruction, mark all symbols in the
|
||||
* expression tree. This mark will be checked at end of
|
||||
* assembly, and a warning is issued, if a zero page symbol
|
||||
* was guessed wrong here.
|
||||
*/
|
||||
** to zero page addressing, but zero page addressing is
|
||||
** allowed by the instruction, mark all symbols in the
|
||||
** expression tree. This mark will be checked at end of
|
||||
** assembly, and a warning is issued, if a zero page symbol
|
||||
** was guessed wrong here.
|
||||
*/
|
||||
if (ED.AddrSize > ADDR_SIZE_ZP && (A->AddrModeSet & AM65_SET_ZP)) {
|
||||
ExprGuessedAddrSize (A->Expr, ADDR_SIZE_ZP);
|
||||
}
|
||||
@@ -987,11 +987,11 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
|
||||
A->AddrModeBit = (0x01UL << A->AddrMode);
|
||||
|
||||
/* If the instruction has a one byte operand and immediate addressing is
|
||||
* allowed but not used, check for an operand expression in the form
|
||||
* <label or >label, where label is a far or absolute label. If found,
|
||||
* emit a warning. This warning protects against a typo, where the '#'
|
||||
* for the immediate operand is omitted.
|
||||
*/
|
||||
** allowed but not used, check for an operand expression in the form
|
||||
** <label or >label, where label is a far or absolute label. If found,
|
||||
** emit a warning. This warning protects against a typo, where the '#'
|
||||
** for the immediate operand is omitted.
|
||||
*/
|
||||
if (A->Expr && (Ins->AddrMode & AM65_ALL_IMM) &&
|
||||
(A->AddrModeSet & (AM65_DIR | AM65_ABS | AM65_ABS_LONG)) &&
|
||||
ExtBytes[A->AddrMode] == 1) {
|
||||
@@ -1011,8 +1011,8 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
|
||||
A->Opcode = Ins->BaseCode | EATab[Ins->ExtCode][A->AddrMode];
|
||||
|
||||
/* If feature force_range is active, and we have immediate addressing mode,
|
||||
* limit the expression to the maximum possible value.
|
||||
*/
|
||||
** limit the expression to the maximum possible value.
|
||||
*/
|
||||
if (A->AddrMode == AM65I_IMM_ACCU || A->AddrMode == AM65I_IMM_INDEX ||
|
||||
A->AddrMode == AM65I_IMM_IMPLICIT) {
|
||||
if (ForceRange && A->Expr) {
|
||||
@@ -1043,9 +1043,9 @@ static void EmitCode (EffAddr* A)
|
||||
case 2:
|
||||
if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
|
||||
/* This is a 16 bit mode that uses an address. If in 65816,
|
||||
* mode, force this address into 16 bit range to allow
|
||||
* addressing inside a 64K segment.
|
||||
*/
|
||||
** mode, force this address into 16 bit range to allow
|
||||
** addressing inside a 64K segment.
|
||||
*/
|
||||
Emit2 (A->Opcode, GenWordExpr (A->Expr));
|
||||
} else {
|
||||
Emit2 (A->Opcode, A->Expr);
|
||||
@@ -1067,8 +1067,8 @@ static void EmitCode (EffAddr* A)
|
||||
|
||||
static long PutImmed8 (const InsDesc* Ins)
|
||||
/* Parse and emit an immediate 8 bit instruction. Return the value of the
|
||||
* operand if it's available and const.
|
||||
*/
|
||||
** operand if it's available and const.
|
||||
*/
|
||||
{
|
||||
EffAddr A;
|
||||
long Val = -1;
|
||||
@@ -1210,10 +1210,10 @@ static void PutSEP (const InsDesc* Ins)
|
||||
|
||||
static void PutTAMn (const InsDesc* Ins)
|
||||
/* Emit a TAMn instruction (HuC6280). Since this is a two byte instruction with
|
||||
* implicit addressing mode, the opcode byte in the table is actually the
|
||||
* second operand byte. The TAM instruction is the more generic form, it takes
|
||||
* an immediate argument.
|
||||
*/
|
||||
** implicit addressing mode, the opcode byte in the table is actually the
|
||||
** second operand byte. The TAM instruction is the more generic form, it takes
|
||||
** an immediate argument.
|
||||
*/
|
||||
{
|
||||
/* Emit the TAM opcode itself */
|
||||
Emit0 (0x53);
|
||||
@@ -1226,8 +1226,8 @@ static void PutTAMn (const InsDesc* Ins)
|
||||
|
||||
static void PutTMA (const InsDesc* Ins)
|
||||
/* Emit a TMA instruction (HuC6280) with an immediate argument. Only one bit
|
||||
* in the argument byte may be set.
|
||||
*/
|
||||
** in the argument byte may be set.
|
||||
*/
|
||||
{
|
||||
/* Use the generic handler */
|
||||
long Val = PutImmed8 (Ins);
|
||||
@@ -1248,10 +1248,10 @@ static void PutTMA (const InsDesc* Ins)
|
||||
|
||||
static void PutTMAn (const InsDesc* Ins)
|
||||
/* Emit a TMAn instruction (HuC6280). Since this is a two byte instruction with
|
||||
* implicit addressing mode, the opcode byte in the table is actually the
|
||||
* second operand byte. The TAM instruction is the more generic form, it takes
|
||||
* an immediate argument.
|
||||
*/
|
||||
** implicit addressing mode, the opcode byte in the table is actually the
|
||||
** second operand byte. The TAM instruction is the more generic form, it takes
|
||||
** an immediate argument.
|
||||
*/
|
||||
{
|
||||
/* Emit the TMA opcode itself */
|
||||
Emit0 (0x43);
|
||||
@@ -1303,10 +1303,10 @@ static void PutTST (const InsDesc* Ins)
|
||||
|
||||
static void PutJMP (const InsDesc* Ins)
|
||||
/* Handle the jump instruction for the 6502. Problem is that these chips have
|
||||
* a bug: If the address crosses a page, the upper byte gets not corrected and
|
||||
* the instruction will fail. The PutJmp function will add a linker assertion
|
||||
* to check for this case and is otherwise identical to PutAll.
|
||||
*/
|
||||
** a bug: If the address crosses a page, the upper byte gets not corrected and
|
||||
** the instruction will fail. The PutJmp function will add a linker assertion
|
||||
** to check for this case and is otherwise identical to PutAll.
|
||||
*/
|
||||
{
|
||||
EffAddr A;
|
||||
|
||||
@@ -1317,9 +1317,9 @@ static void PutJMP (const InsDesc* Ins)
|
||||
if (A.AddrModeBit & AM65_ABS_IND) {
|
||||
|
||||
/* Compare the low byte of the expression to 0xFF to check for
|
||||
* a page cross. Be sure to use a copy of the expression otherwise
|
||||
* things will go weird later.
|
||||
*/
|
||||
** a page cross. Be sure to use a copy of the expression otherwise
|
||||
** things will go weird later.
|
||||
*/
|
||||
ExprNode* E = GenNE (GenByteExpr (CloneExpr (A.Expr)), 0xFF);
|
||||
|
||||
/* Generate the message */
|
||||
@@ -1338,8 +1338,8 @@ static void PutJMP (const InsDesc* Ins)
|
||||
|
||||
static void PutRTS (const InsDesc* Ins attribute ((unused)))
|
||||
/* Handle the RTS instruction for the 816. In smart mode emit a RTL opcode if
|
||||
* the enclosing scope is FAR.
|
||||
*/
|
||||
** the enclosing scope is FAR.
|
||||
*/
|
||||
{
|
||||
if (SmartMode && CurrentScope->AddrSize == ADDR_SIZE_FAR) {
|
||||
Emit0 (0x6B); /* RTL */
|
||||
@@ -1379,8 +1379,8 @@ static void PutSweet16 (const InsDesc* Ins)
|
||||
GetSweet16EA (&A);
|
||||
|
||||
/* From the possible addressing modes, remove the ones that are invalid
|
||||
* for this instruction or CPU.
|
||||
*/
|
||||
** for this instruction or CPU.
|
||||
*/
|
||||
A.AddrModeSet &= Ins->AddrMode;
|
||||
|
||||
/* Check if we have any adressing modes left */
|
||||
@@ -1466,16 +1466,16 @@ cpu_t GetCPU (void)
|
||||
|
||||
int FindInstruction (const StrBuf* Ident)
|
||||
/* Check if Ident is a valid mnemonic. If so, return the index in the
|
||||
* instruction table. If not, return -1.
|
||||
*/
|
||||
** instruction table. If not, return -1.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
const InsDesc* ID;
|
||||
char Key[sizeof (ID->Mnemonic)];
|
||||
|
||||
/* Shortcut for the "none" CPU: If there are no instructions to search
|
||||
* for, bail out early.
|
||||
*/
|
||||
** for, bail out early.
|
||||
*/
|
||||
if (InsTab->Count == 0) {
|
||||
/* Not found */
|
||||
return -1;
|
||||
@@ -1485,8 +1485,8 @@ int FindInstruction (const StrBuf* Ident)
|
||||
I = 0;
|
||||
while (I < SB_GetLen (Ident)) {
|
||||
/* If the identifier is longer than the longest mnemonic, it cannot
|
||||
* be one.
|
||||
*/
|
||||
** be one.
|
||||
*/
|
||||
if (I >= sizeof (Key) - 1) {
|
||||
/* Not found, no need for further action */
|
||||
return -1;
|
||||
|
||||
@@ -51,13 +51,13 @@
|
||||
|
||||
|
||||
/* Constants for the addressing mode. If an opcode is available in zero page
|
||||
* and absolut adressing mode, both bits are set. When checking for valid
|
||||
* modes, the zeropage bit is checked first. Similar, the implicit bit is set
|
||||
* on accu adressing modes, so the 'A' for accu adressing is not needed (but
|
||||
* may be specified).
|
||||
* When assembling for the 6502 or 65C02, all addressing modes that are not
|
||||
* available on these CPUs are removed before doing any checks.
|
||||
*/
|
||||
** and absolut adressing mode, both bits are set. When checking for valid
|
||||
** modes, the zeropage bit is checked first. Similar, the implicit bit is set
|
||||
** on accu adressing modes, so the 'A' for accu adressing is not needed (but
|
||||
** may be specified).
|
||||
** When assembling for the 6502 or 65C02, all addressing modes that are not
|
||||
** available on these CPUs are removed before doing any checks.
|
||||
*/
|
||||
#define AM65_IMPLICIT 0x00000003UL
|
||||
#define AM65_ACCU 0x00000002UL
|
||||
#define AM65_DIR 0x00000004UL
|
||||
@@ -168,8 +168,8 @@ cpu_t GetCPU (void);
|
||||
|
||||
int FindInstruction (const StrBuf* Ident);
|
||||
/* Check if Ident is a valid mnemonic. If so, return the index in the
|
||||
* instruction table. If not, return -1.
|
||||
*/
|
||||
** instruction table. If not, return -1.
|
||||
*/
|
||||
|
||||
void HandleInstruction (unsigned Index);
|
||||
/* Handle the mnemonic with the given index */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000-2003 Ullrich von Bassewitz */
|
||||
/* R<EFBFBD>merstra<EFBFBD>e 52 */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
@@ -120,12 +120,12 @@ void PopInput (void)
|
||||
|
||||
int InputFromStack (void)
|
||||
/* Try to get input from the input stack. Return true if we had such input,
|
||||
* return false otherwise.
|
||||
*/
|
||||
** return false otherwise.
|
||||
*/
|
||||
{
|
||||
/* Repeatedly call the TOS routine until we have a token or if run out of
|
||||
* routines.
|
||||
*/
|
||||
** routines.
|
||||
*/
|
||||
while (IStack) {
|
||||
if (IStack->Func (IStack->Data) != 0) {
|
||||
/* We have a token */
|
||||
@@ -149,8 +149,8 @@ int HavePushedInput (void)
|
||||
|
||||
void CheckInputStack (void)
|
||||
/* Called from the scanner before closing an input file. Will check for any
|
||||
* stuff on the input stack.
|
||||
*/
|
||||
** stuff on the input stack.
|
||||
*/
|
||||
{
|
||||
if (IStack) {
|
||||
Error ("Open %s", IStack->Desc);
|
||||
|
||||
@@ -52,16 +52,16 @@ void PopInput (void);
|
||||
|
||||
int InputFromStack (void);
|
||||
/* Try to get input from the input stack. Return true if we had such input,
|
||||
* return false otherwise.
|
||||
*/
|
||||
** return false otherwise.
|
||||
*/
|
||||
|
||||
int HavePushedInput (void);
|
||||
/* Return true if we have stacked input available, return false if not */
|
||||
|
||||
void CheckInputStack (void);
|
||||
/* Called from the scanner before closing an input file. Will check for any
|
||||
* stuff on the input stack.
|
||||
*/
|
||||
** stuff on the input stack.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ static const void* HT_GetKey (const void* Entry);
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2);
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -145,9 +145,9 @@ static const void* HT_GetKey (const void* Entry)
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2)
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
{
|
||||
/* Convert both parameters to FileInfoKey pointers */
|
||||
const LineInfoKey* K1 = Key1;
|
||||
@@ -272,8 +272,8 @@ void InitLineInfo (void)
|
||||
CollGrow (&LineInfoList, 200);
|
||||
|
||||
/* Create a LineInfo for the default source. This is necessary to allow
|
||||
* error message to be generated without any input file open.
|
||||
*/
|
||||
** error message to be generated without any input file open.
|
||||
*/
|
||||
AsmLineInfo = StartLine (&DefaultPos, LI_TYPE_ASM, 0);
|
||||
}
|
||||
|
||||
@@ -289,9 +289,9 @@ void DoneLineInfo (void)
|
||||
}
|
||||
|
||||
/* Walk over the entries in the hash table and sort them into used and
|
||||
* unused ones. Add the used ones to the line info list and assign them
|
||||
* an id.
|
||||
*/
|
||||
** unused ones. Add the used ones to the line info list and assign them
|
||||
** an id.
|
||||
*/
|
||||
HT_Walk (&LineInfoTab, CheckLineInfo, 0);
|
||||
}
|
||||
|
||||
@@ -304,14 +304,14 @@ void EndLine (LineInfo* LI)
|
||||
CloseSpanList (&LI->OpenSpans);
|
||||
|
||||
/* Move the spans to the list of all spans for this line, then clear the
|
||||
* list of open spans.
|
||||
*/
|
||||
** list of open spans.
|
||||
*/
|
||||
CollTransfer (&LI->Spans, &LI->OpenSpans);
|
||||
CollDeleteAll (&LI->OpenSpans);
|
||||
|
||||
/* Line info is no longer active - remove it from the list of current
|
||||
* line infos.
|
||||
*/
|
||||
** line infos.
|
||||
*/
|
||||
CollDeleteItem (&CurLineInfo, LI);
|
||||
}
|
||||
|
||||
@@ -328,8 +328,8 @@ LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count)
|
||||
Key.Type = LI_MAKE_TYPE (Type, Count);
|
||||
|
||||
/* Try to find a line info with this position and type in the hash table.
|
||||
* If so, reuse it. Otherwise create a new one.
|
||||
*/
|
||||
** If so, reuse it. Otherwise create a new one.
|
||||
*/
|
||||
LI = HT_Find (&LineInfoTab, &Key);
|
||||
if (LI == 0) {
|
||||
/* Allocate a new LineInfo */
|
||||
@@ -350,9 +350,9 @@ LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count)
|
||||
|
||||
void NewAsmLine (void)
|
||||
/* Start a new assembler input line. Use this function when generating new
|
||||
* line of LI_TYPE_ASM. It will check if line and/or file have actually
|
||||
* changed, end the old and start the new line as necessary.
|
||||
*/
|
||||
** line of LI_TYPE_ASM. It will check if line and/or file have actually
|
||||
** changed, end the old and start the new line as necessary.
|
||||
*/
|
||||
{
|
||||
/* Check if we can reuse the old line */
|
||||
if (AsmLineInfo) {
|
||||
@@ -374,8 +374,8 @@ void NewAsmLine (void)
|
||||
|
||||
LineInfo* GetAsmLineInfo (void)
|
||||
/* Return the line info for the current assembler file. The function will
|
||||
* bump the reference counter before returning the line info.
|
||||
*/
|
||||
** bump the reference counter before returning the line info.
|
||||
*/
|
||||
{
|
||||
++AsmLineInfo->RefCount;
|
||||
return AsmLineInfo;
|
||||
@@ -395,9 +395,9 @@ void ReleaseLineInfo (LineInfo* LI)
|
||||
|
||||
void GetFullLineInfo (Collection* LineInfos)
|
||||
/* Return full line infos, that is line infos for currently active Slots. The
|
||||
* infos will be added to the given collection, existing entries will be left
|
||||
* intact. The reference count of all added entries will be increased.
|
||||
*/
|
||||
** infos will be added to the given collection, existing entries will be left
|
||||
** intact. The reference count of all added entries will be increased.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
@@ -414,8 +414,8 @@ void GetFullLineInfo (Collection* LineInfos)
|
||||
|
||||
void ReleaseFullLineInfo (Collection* LineInfos)
|
||||
/* Decrease the reference count for a collection full of LineInfos, then clear
|
||||
* the collection.
|
||||
*/
|
||||
** the collection.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
|
||||
@@ -77,28 +77,28 @@ LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count);
|
||||
|
||||
void NewAsmLine (void);
|
||||
/* Start a new assembler input line. Use this function when generating new
|
||||
* line of LI_TYPE_ASM. It will check if line and/or file have actually
|
||||
* changed, end the old and start the new line as necessary.
|
||||
*/
|
||||
** line of LI_TYPE_ASM. It will check if line and/or file have actually
|
||||
** changed, end the old and start the new line as necessary.
|
||||
*/
|
||||
|
||||
LineInfo* GetAsmLineInfo (void);
|
||||
/* Return the line info for the current assembler file. The function will
|
||||
* bump the reference counter before returning the line info.
|
||||
*/
|
||||
** bump the reference counter before returning the line info.
|
||||
*/
|
||||
|
||||
void ReleaseLineInfo (LineInfo* LI);
|
||||
/* Decrease the reference count for a line info */
|
||||
|
||||
void GetFullLineInfo (Collection* LineInfos);
|
||||
/* Return full line infos, that is line infos for currently active Slots. The
|
||||
* infos will be added to the given collection, existing entries will be left
|
||||
* intact. The reference count of all added entries will be increased.
|
||||
*/
|
||||
** infos will be added to the given collection, existing entries will be left
|
||||
** intact. The reference count of all added entries will be increased.
|
||||
*/
|
||||
|
||||
void ReleaseFullLineInfo (Collection* LineInfos);
|
||||
/* Decrease the reference count for a collection full of LineInfos, then clear
|
||||
* the collection.
|
||||
*/
|
||||
** the collection.
|
||||
*/
|
||||
|
||||
const FilePos* GetSourcePos (const LineInfo* LI);
|
||||
/* Return the source file position from the given line info */
|
||||
|
||||
@@ -131,8 +131,8 @@ void EnableListing (void)
|
||||
{
|
||||
if (SB_GetLen (&ListingName) > 0) {
|
||||
/* If we're about to enable the listing, do this for the current line
|
||||
* also, so we will see the source line that did this.
|
||||
*/
|
||||
** also, so we will see the source line that did this.
|
||||
*/
|
||||
if (ListingEnabled++ == 0) {
|
||||
LineCur->Output = 1;
|
||||
}
|
||||
@@ -172,9 +172,9 @@ void InitListingLine (void)
|
||||
{
|
||||
if (SB_GetLen (&ListingName) > 0) {
|
||||
/* Make the last loaded line the current line */
|
||||
/* ###### This code is a hack! We really need to do it right
|
||||
* as soon as we know, how:-(
|
||||
*/
|
||||
/* ###### This code is a hack! We really need to do it right --
|
||||
** as soon as we know how. :-(
|
||||
*/
|
||||
if (LineCur && LineCur->Next && LineCur->Next != LineLast) {
|
||||
ListLine* L = LineCur;
|
||||
do {
|
||||
@@ -217,8 +217,8 @@ static char* AddHex (char* S, unsigned Val)
|
||||
|
||||
static void PrintPageHeader (FILE* F, const ListLine* L)
|
||||
/* Print the header for a new page. It is assumed that the given line is the
|
||||
* last line of the previous page.
|
||||
*/
|
||||
** last line of the previous page.
|
||||
*/
|
||||
{
|
||||
/* Gte a pointer to the current input file */
|
||||
const StrBuf* CurFile = GetFileName (L->File);
|
||||
@@ -250,8 +250,8 @@ static void PrintLine (FILE* F, const char* Header, const char* Line, const List
|
||||
++PageLines;
|
||||
|
||||
/* Switch to a new page if needed. Do not switch, if the current line is
|
||||
* the last one, to avoid pages that consist of just the header.
|
||||
*/
|
||||
** the last one, to avoid pages that consist of just the header.
|
||||
*/
|
||||
if (PageLength > 0 && PageLines >= PageLength && L->Next != 0) {
|
||||
/* Do a formfeed */
|
||||
putc ('\f', F);
|
||||
@@ -392,16 +392,16 @@ void CreateListing (void)
|
||||
}
|
||||
|
||||
/* Output the data. The format of a listing line is:
|
||||
*
|
||||
* PPPPPPm I 11 22 33 44
|
||||
*
|
||||
* where
|
||||
*
|
||||
* PPPPPP is the PC
|
||||
* m is the mode ('r' or empty)
|
||||
* I is the include level
|
||||
* 11 .. are code or data bytes
|
||||
*/
|
||||
**
|
||||
** PPPPPPm I 11 22 33 44
|
||||
**
|
||||
** where
|
||||
**
|
||||
** PPPPPP is the PC
|
||||
** m is the mode ('r' or empty)
|
||||
** I is the include level
|
||||
** 11 .. are code or data bytes
|
||||
*/
|
||||
Line = L->Line;
|
||||
B = Buf;
|
||||
while (Count) {
|
||||
@@ -420,9 +420,9 @@ void CreateListing (void)
|
||||
Count -= Chunk;
|
||||
|
||||
/* Increment the program counter. Since we don't need the PC stored
|
||||
* in the LineList object for anything else, just increment this
|
||||
* variable.
|
||||
*/
|
||||
** in the LineList object for anything else, just increment this
|
||||
** variable.
|
||||
*/
|
||||
L->PC += Chunk;
|
||||
|
||||
/* Copy the bytes into the line */
|
||||
|
||||
110
src/ca65/macro.c
110
src/ca65/macro.c
@@ -70,9 +70,9 @@ static const void* HT_GetKey (const void* Entry);
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2);
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -176,9 +176,9 @@ static const void* HT_GetKey (const void* Entry)
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2)
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
{
|
||||
return SB_Compare (Key1, Key2);
|
||||
}
|
||||
@@ -399,8 +399,8 @@ void MacDef (unsigned Style)
|
||||
return;
|
||||
} else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
|
||||
/* The identifier is a name of a 6502 instruction, which is not
|
||||
* allowed if not explicitly enabled.
|
||||
*/
|
||||
** allowed if not explicitly enabled.
|
||||
*/
|
||||
Error ("Cannot use an instruction as macro name");
|
||||
MacSkipDef (Style);
|
||||
return;
|
||||
@@ -423,8 +423,8 @@ void MacDef (unsigned Style)
|
||||
NextTok ();
|
||||
|
||||
/* If we have a DEFINE style macro, we may have parameters in braces,
|
||||
* otherwise we may have parameters without braces.
|
||||
*/
|
||||
** otherwise we may have parameters without braces.
|
||||
*/
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
HaveParams = 1;
|
||||
} else {
|
||||
@@ -476,8 +476,8 @@ void MacDef (unsigned Style)
|
||||
}
|
||||
|
||||
/* For class macros, we expect a separator token, for define style macros,
|
||||
* we expect the closing paren.
|
||||
*/
|
||||
** we expect the closing paren.
|
||||
*/
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
ConsumeSep ();
|
||||
} else if (HaveParams) {
|
||||
@@ -485,10 +485,10 @@ void MacDef (unsigned Style)
|
||||
}
|
||||
|
||||
/* Preparse the macro body. We will read the tokens until we reach end of
|
||||
* file, or a .endmacro (or end of line for DEFINE style macros) and store
|
||||
* them into an token list internal to the macro. For classic macros, there
|
||||
* the .LOCAL command is detected and removed at this time.
|
||||
*/
|
||||
** file, or a .endmacro (or end of line for DEFINE style macros) and store
|
||||
** them into an token list internal to the macro. For classic macros, there
|
||||
** the .LOCAL command is detected and removed at this time.
|
||||
*/
|
||||
while (1) {
|
||||
|
||||
/* Check for end of macro */
|
||||
@@ -597,8 +597,8 @@ Done:
|
||||
|
||||
void MacUndef (const StrBuf* Name, unsigned char Style)
|
||||
/* Undefine the macro with the given name and style. A style mismatch is
|
||||
* treated as if the macro didn't exist.
|
||||
*/
|
||||
** treated as if the macro didn't exist.
|
||||
*/
|
||||
{
|
||||
/* Search for the macro */
|
||||
Macro* M = HT_Find (&MacroTab, Name);
|
||||
@@ -624,9 +624,9 @@ void MacUndef (const StrBuf* Name, unsigned char Style)
|
||||
|
||||
static int MacExpand (void* Data)
|
||||
/* If we're currently expanding a macro, set the the scanner token and
|
||||
* attribute to the next value and return true. If we are not expanding
|
||||
* a macro, return false.
|
||||
*/
|
||||
** attribute to the next value and return true. If we are not expanding
|
||||
** a macro, return false.
|
||||
*/
|
||||
{
|
||||
/* Cast the Data pointer to the actual data structure */
|
||||
MacExp* Mac = (MacExp*) Data;
|
||||
@@ -645,8 +645,8 @@ static int MacExpand (void* Data)
|
||||
}
|
||||
|
||||
/* We're expanding a macro. Check if we are expanding one of the
|
||||
* macro parameters.
|
||||
*/
|
||||
** macro parameters.
|
||||
*/
|
||||
ExpandParam:
|
||||
if (Mac->ParamExp) {
|
||||
|
||||
@@ -674,8 +674,8 @@ ExpandParam:
|
||||
}
|
||||
|
||||
/* We're not expanding macro parameters. Check if we have tokens left from
|
||||
* the macro itself.
|
||||
*/
|
||||
** the macro itself.
|
||||
*/
|
||||
if (Mac->Exp) {
|
||||
|
||||
/* Use next macro token */
|
||||
@@ -716,10 +716,10 @@ ExpandParam:
|
||||
while (I) {
|
||||
if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
|
||||
/* This is in fact a local symbol, change the name. Be sure
|
||||
* to generate a local label name if the original name was
|
||||
* a local label, and also generate a name that cannot be
|
||||
* generated by a user.
|
||||
*/
|
||||
** to generate a local label name if the original name was
|
||||
** a local label, and also generate a name that cannot be
|
||||
** generated by a user.
|
||||
*/
|
||||
if (SB_At (&I->Id, 0) == LocalStart) {
|
||||
/* Must generate a local symbol */
|
||||
SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
|
||||
@@ -753,14 +753,14 @@ ExpandParam:
|
||||
Mac->Final = 0;
|
||||
|
||||
/* Problem: When a .define style macro is expanded within the call
|
||||
* of a classic one, the latter may be terminated and removed while
|
||||
* the expansion of the .define style macro is still active. Because
|
||||
* line info slots are "stacked", this runs into a CHECK FAILED. For
|
||||
* now, we will fix that by removing the .define style macro expansion
|
||||
* immediately, once the final token is placed. The better solution
|
||||
* would probably be to not require AllocLineInfoSlot/FreeLineInfoSlot
|
||||
* to be called in FIFO order, but this is a bigger change.
|
||||
*/
|
||||
** of a classic one, the latter may be terminated and removed while
|
||||
** the expansion of the .define style macro is still active. Because
|
||||
** line info slots are "stacked", this runs into a CHECK FAILED. For
|
||||
** now, we will fix that by removing the .define style macro expansion
|
||||
** immediately, once the final token is placed. The better solution
|
||||
** would probably be to not require AllocLineInfoSlot/FreeLineInfoSlot
|
||||
** to be called in FIFO order, but this is a bigger change.
|
||||
*/
|
||||
/* End of macro expansion and pop the input function */
|
||||
FreeMacExp (Mac);
|
||||
PopInput ();
|
||||
@@ -836,8 +836,8 @@ static void StartExpClassic (MacExp* E)
|
||||
++E->ParamCount;
|
||||
|
||||
/* If the macro argument was enclosed in curly braces, end-of-line
|
||||
* is an error. Skip the closing curly brace.
|
||||
*/
|
||||
** is an error. Skip the closing curly brace.
|
||||
*/
|
||||
if (Term == TOK_RCURLY) {
|
||||
if (CurTok.Tok == TOK_SEP) {
|
||||
Error ("End of line encountered within macro argument");
|
||||
@@ -867,8 +867,8 @@ static void StartExpDefine (MacExp* E)
|
||||
/* Start expanding a DEFINE style macro */
|
||||
{
|
||||
/* A define style macro must be called with as many actual parameters
|
||||
* as there are formal ones. Get the parameter count.
|
||||
*/
|
||||
** as there are formal ones. Get the parameter count.
|
||||
*/
|
||||
unsigned Count = E->M->ParamCount;
|
||||
|
||||
/* Skip the current token */
|
||||
@@ -915,8 +915,8 @@ static void StartExpDefine (MacExp* E)
|
||||
++E->ParamCount;
|
||||
|
||||
/* If the macro argument was enclosed in curly braces, end-of-line
|
||||
* is an error. Skip the closing curly brace.
|
||||
*/
|
||||
** is an error. Skip the closing curly brace.
|
||||
*/
|
||||
if (Term == TOK_RCURLY) {
|
||||
if (TokIsSep (CurTok.Tok)) {
|
||||
Error ("End of line encountered within macro argument");
|
||||
@@ -936,10 +936,10 @@ static void StartExpDefine (MacExp* E)
|
||||
}
|
||||
|
||||
/* Macro expansion will overwrite the current token. This is a problem
|
||||
* for define style macros since these are called from the scanner level.
|
||||
* To avoid it, remember the current token and re-insert it, once macro
|
||||
* expansion is done.
|
||||
*/
|
||||
** for define style macros since these are called from the scanner level.
|
||||
** To avoid it, remember the current token and re-insert it, once macro
|
||||
** expansion is done.
|
||||
*/
|
||||
E->Final = NewTokNode ();
|
||||
|
||||
/* Insert a new token input function */
|
||||
@@ -963,8 +963,8 @@ void MacExpandStart (Macro* M)
|
||||
}
|
||||
|
||||
/* Don't allow too many nested macro expansions - otherwise it is possible
|
||||
* to force an endless loop and assembler crash.
|
||||
*/
|
||||
** to force an endless loop and assembler crash.
|
||||
*/
|
||||
if (MacExpansions >= MAX_MACEXPANSIONS) {
|
||||
Error ("Too many nested macro expansions");
|
||||
return;
|
||||
@@ -997,8 +997,8 @@ void MacAbort (void)
|
||||
|
||||
Macro* FindMacro (const StrBuf* Name)
|
||||
/* Try to find the macro with the given name and return it. If no macro with
|
||||
* this name was found, return NULL.
|
||||
*/
|
||||
** this name was found, return NULL.
|
||||
*/
|
||||
{
|
||||
Macro* M = HT_Find (&MacroTab, Name);
|
||||
return (M != 0 && M->Style == MAC_STYLE_CLASSIC)? M : 0;
|
||||
@@ -1008,8 +1008,8 @@ Macro* FindMacro (const StrBuf* Name)
|
||||
|
||||
Macro* FindDefine (const StrBuf* Name)
|
||||
/* Try to find the define style macro with the given name and return it. If no
|
||||
* such macro was found, return NULL.
|
||||
*/
|
||||
** such macro was found, return NULL.
|
||||
*/
|
||||
{
|
||||
Macro* M;
|
||||
|
||||
@@ -1043,8 +1043,8 @@ void DisableDefineStyleMacros (void)
|
||||
|
||||
void EnableDefineStyleMacros (void)
|
||||
/* Re-enable define style macros previously disabled with
|
||||
* DisableDefineStyleMacros.
|
||||
*/
|
||||
** DisableDefineStyleMacros.
|
||||
*/
|
||||
{
|
||||
PRECONDITION (DisableDefines > 0);
|
||||
--DisableDefines;
|
||||
|
||||
@@ -75,8 +75,8 @@ void MacDef (unsigned Style);
|
||||
|
||||
void MacUndef (const struct StrBuf* Name, unsigned char Style);
|
||||
/* Undefine the macro with the given name and style. A style mismatch is
|
||||
* treated as if the macro didn't exist.
|
||||
*/
|
||||
** treated as if the macro didn't exist.
|
||||
*/
|
||||
|
||||
void MacExpandStart (Macro* M);
|
||||
/* Start expanding a macro */
|
||||
@@ -86,13 +86,13 @@ void MacAbort (void);
|
||||
|
||||
Macro* FindMacro (const struct StrBuf* Name);
|
||||
/* Try to find the macro with the given name and return it. If no macro with
|
||||
* this name was found, return NULL.
|
||||
*/
|
||||
** this name was found, return NULL.
|
||||
*/
|
||||
|
||||
Macro* FindDefine (const struct StrBuf* Name);
|
||||
/* Try to find the define style macro with the given name and return it. If no
|
||||
* such macro was found, return NULL.
|
||||
*/
|
||||
** such macro was found, return NULL.
|
||||
*/
|
||||
|
||||
int InMacExpansion (void);
|
||||
/* Return true if we're currently expanding a macro */
|
||||
@@ -102,8 +102,8 @@ void DisableDefineStyleMacros (void);
|
||||
|
||||
void EnableDefineStyleMacros (void);
|
||||
/* Re-enable define style macros previously disabled with
|
||||
* DisableDefineStyleMacros.
|
||||
*/
|
||||
** DisableDefineStyleMacros.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -519,8 +519,8 @@ static void OptListing (const char* Opt, const char* Arg)
|
||||
/* Create a listing file */
|
||||
{
|
||||
/* Since the meaning of -l and --listing has changed, print an error if
|
||||
* the filename is empty or begins with the option char.
|
||||
*/
|
||||
** the filename is empty or begins with the option char.
|
||||
*/
|
||||
if (Arg == 0 || *Arg == '\0' || *Arg == '-') {
|
||||
Fatal ("The meaning of `%s' has changed. It does now "
|
||||
"expect a file name as argument.", Opt);
|
||||
@@ -635,8 +635,8 @@ static void OneLine (void)
|
||||
int Instr = -1;
|
||||
|
||||
/* Initialize the new listing line if we are actually reading from file
|
||||
* and not from internally pushed input.
|
||||
*/
|
||||
** and not from internally pushed input.
|
||||
*/
|
||||
if (!HavePushedInput ()) {
|
||||
InitListingLine ();
|
||||
}
|
||||
@@ -648,8 +648,8 @@ static void OneLine (void)
|
||||
}
|
||||
|
||||
/* If the first token on the line is an identifier, check for a macro or
|
||||
* an instruction.
|
||||
*/
|
||||
** an instruction.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_IDENT) {
|
||||
if (UbiquitousIdents) {
|
||||
/* Macros CAN be instructions, so check for them first */
|
||||
@@ -667,9 +667,9 @@ static void OneLine (void)
|
||||
}
|
||||
|
||||
/* Handle an identifier. This may be a cheap local symbol, or a fully
|
||||
* scoped identifier which may start with a namespace token (for global
|
||||
* namespace)
|
||||
*/
|
||||
** scoped identifier which may start with a namespace token (for global
|
||||
** namespace)
|
||||
*/
|
||||
if (CurTok.Tok == TOK_LOCAL_IDENT ||
|
||||
CurTok.Tok == TOK_NAMESPACE ||
|
||||
(CurTok.Tok == TOK_IDENT && Instr < 0 && Mac == 0)) {
|
||||
@@ -681,8 +681,8 @@ static void OneLine (void)
|
||||
Sym = ParseAnySymName (SYM_ALLOC_NEW);
|
||||
|
||||
/* If a colon follows, this is a label definition. If there
|
||||
* is no colon, it's an assignment.
|
||||
*/
|
||||
** is no colon, it's an assignment.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
/* Determine the symbol flags from the assignment token */
|
||||
@@ -709,8 +709,8 @@ static void OneLine (void)
|
||||
Expr = GenLiteralExpr (ConstExpression ());
|
||||
|
||||
/* Define the symbol with the constant expression following
|
||||
* the '='
|
||||
*/
|
||||
** the '='
|
||||
*/
|
||||
SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_VAR);
|
||||
|
||||
/* Don't allow anything after a symbol definition */
|
||||
@@ -720,8 +720,8 @@ static void OneLine (void)
|
||||
} else {
|
||||
|
||||
/* A label. Remember the current segment, so we can later
|
||||
* determine the size of the data stored under the label.
|
||||
*/
|
||||
** determine the size of the data stored under the label.
|
||||
*/
|
||||
Seg = ActiveSeg;
|
||||
PC = GetPC ();
|
||||
|
||||
@@ -729,9 +729,9 @@ static void OneLine (void)
|
||||
SymDef (Sym, GenCurrentPC (), ADDR_SIZE_DEFAULT, SF_LABEL);
|
||||
|
||||
/* Skip the colon. If NoColonLabels is enabled, allow labels
|
||||
* without a colon if there is no whitespace before the
|
||||
* identifier.
|
||||
*/
|
||||
** without a colon if there is no whitespace before the
|
||||
** identifier.
|
||||
*/
|
||||
if (CurTok.Tok != TOK_COLON) {
|
||||
if (HadWS || !NoColonLabels) {
|
||||
Error ("`:' expected");
|
||||
@@ -746,8 +746,8 @@ static void OneLine (void)
|
||||
}
|
||||
|
||||
/* If we come here, a new identifier may be waiting, which may
|
||||
* be a macro or instruction.
|
||||
*/
|
||||
** be a macro or instruction.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_IDENT) {
|
||||
if (UbiquitousIdents) {
|
||||
/* Macros CAN be instructions, so check for them first */
|
||||
@@ -790,9 +790,9 @@ static void OneLine (void)
|
||||
}
|
||||
|
||||
/* If we have defined a label, remember its size. Sym is also set by
|
||||
* a symbol assignment, but in this case Done is false, so we don't
|
||||
* come here.
|
||||
*/
|
||||
** a symbol assignment, but in this case Done is false, so we don't
|
||||
** come here.
|
||||
*/
|
||||
if (Sym) {
|
||||
unsigned long Size;
|
||||
if (Seg == ActiveSeg) {
|
||||
@@ -916,13 +916,13 @@ int main (int argc, char* argv [])
|
||||
SegInit ();
|
||||
|
||||
/* Enter the base lexical level. We must do that here, since we may
|
||||
* define symbols using -D.
|
||||
*/
|
||||
** define symbols using -D.
|
||||
*/
|
||||
SymEnterLevel (&GlobalNameSpace, SCOPE_FILE, ADDR_SIZE_DEFAULT, 0);
|
||||
|
||||
/* Initialize the line infos. Must be done here, since we need line infos
|
||||
* for symbol definitions.
|
||||
*/
|
||||
** for symbol definitions.
|
||||
*/
|
||||
InitLineInfo ();
|
||||
|
||||
/* Check the parameters */
|
||||
@@ -1104,8 +1104,8 @@ int main (int argc, char* argv [])
|
||||
DoneLineInfo ();
|
||||
|
||||
/* If we didn't have any errors, create the object, listing and
|
||||
* dependency files
|
||||
*/
|
||||
** dependency files
|
||||
*/
|
||||
if (ErrorCount == 0) {
|
||||
CreateObjFile ();
|
||||
if (SB_GetLen (&ListingName) > 0) {
|
||||
|
||||
@@ -70,9 +70,9 @@ static unsigned RawMode = 0; /* Raw token mode flag/counter */
|
||||
|
||||
static int LookAtStrCon (void)
|
||||
/* Make sure the next token is a string constant. If not, print an error
|
||||
* messages skip the remainder of the line and return false. Otherwise return
|
||||
* true.
|
||||
*/
|
||||
** messages skip the remainder of the line and return false. Otherwise return
|
||||
** true.
|
||||
*/
|
||||
{
|
||||
if (CurTok.Tok != TOK_STRCON) {
|
||||
Error ("String constant expected");
|
||||
@@ -93,10 +93,10 @@ static int LookAtStrCon (void)
|
||||
|
||||
static TokList* CollectTokens (unsigned Start, unsigned Count)
|
||||
/* Read a list of tokens that is optionally enclosed in curly braces and
|
||||
* terminated by a right paren. For all tokens starting at the one with index
|
||||
* Start, and ending at (Start+Count-1), place them into a token list, and
|
||||
* return this token list.
|
||||
*/
|
||||
** terminated by a right paren. For all tokens starting at the one with index
|
||||
** Start, and ending at (Start+Count-1), place them into a token list, and
|
||||
** return this token list.
|
||||
*/
|
||||
{
|
||||
|
||||
/* Create the token list */
|
||||
@@ -176,8 +176,8 @@ static void FuncConcat (void)
|
||||
}
|
||||
|
||||
/* We expect a closing parenthesis, but will not skip it but replace it
|
||||
* by the string token just created.
|
||||
*/
|
||||
** by the string token just created.
|
||||
*/
|
||||
if (CurTok.Tok != TOK_RPAREN) {
|
||||
Error ("`)' expected");
|
||||
} else {
|
||||
@@ -220,8 +220,8 @@ static void FuncIdent (void)
|
||||
}
|
||||
|
||||
/* Check that the string contains a valid identifier. While doing so,
|
||||
* determine if it is a cheap local, or global one.
|
||||
*/
|
||||
** determine if it is a cheap local, or global one.
|
||||
*/
|
||||
SB_Reset (&CurTok.SVal);
|
||||
|
||||
/* Check for a cheap local symbol */
|
||||
@@ -248,8 +248,8 @@ static void FuncIdent (void)
|
||||
}
|
||||
|
||||
/* If anything is ok, save and skip the string. Check that the next token
|
||||
* is a right paren, then replace the token by an identifier token.
|
||||
*/
|
||||
** is a right paren, then replace the token by an identifier token.
|
||||
*/
|
||||
SB_Copy (&Buf, &CurTok.SVal);
|
||||
NextTok ();
|
||||
if (CurTok.Tok != TOK_RPAREN) {
|
||||
@@ -289,12 +289,12 @@ static void FuncLeft (void)
|
||||
List = CollectTokens (0, (unsigned) Count);
|
||||
|
||||
/* Since we want to insert the list before the now current token, we have
|
||||
* to save the current token in some way and then skip it. To do this, we
|
||||
* will add the current token at the end of the token list (so the list
|
||||
* will never be empty), push the token list, and then skip the current
|
||||
* token. This will replace the current token by the first token from the
|
||||
* list (which will be the old current token in case the list was empty).
|
||||
*/
|
||||
** to save the current token in some way and then skip it. To do this, we
|
||||
** will add the current token at the end of the token list (so the list
|
||||
** will never be empty), push the token list, and then skip the current
|
||||
** token. This will replace the current token by the first token from the
|
||||
** list (which will be the old current token in case the list was empty).
|
||||
*/
|
||||
AddCurTok (List);
|
||||
|
||||
/* Insert it into the scanner feed */
|
||||
@@ -320,8 +320,8 @@ static void FuncMid (void)
|
||||
ConsumeLParen ();
|
||||
|
||||
/* Start argument. Since the start argument can get negative with
|
||||
* expressions like ".tcount(arg)-2", we correct it to zero silently.
|
||||
*/
|
||||
** expressions like ".tcount(arg)-2", we correct it to zero silently.
|
||||
*/
|
||||
Start = ConstExpression ();
|
||||
if (Start < 0 || Start > 100) {
|
||||
Start = 0;
|
||||
@@ -329,8 +329,8 @@ static void FuncMid (void)
|
||||
ConsumeComma ();
|
||||
|
||||
/* Count argument. Similar as above, we will accept negative counts and
|
||||
* correct them to zero silently.
|
||||
*/
|
||||
** correct them to zero silently.
|
||||
*/
|
||||
Count = ConstExpression ();
|
||||
if (Count < 0) {
|
||||
Count = 0;
|
||||
@@ -341,12 +341,12 @@ static void FuncMid (void)
|
||||
List = CollectTokens ((unsigned) Start, (unsigned) Count);
|
||||
|
||||
/* Since we want to insert the list before the now current token, we have
|
||||
* to save the current token in some way and then skip it. To do this, we
|
||||
* will add the current token at the end of the token list (so the list
|
||||
* will never be empty), push the token list, and then skip the current
|
||||
* token. This will replace the current token by the first token from the
|
||||
* list (which will be the old current token in case the list was empty).
|
||||
*/
|
||||
** to save the current token in some way and then skip it. To do this, we
|
||||
** will add the current token at the end of the token list (so the list
|
||||
** will never be empty), push the token list, and then skip the current
|
||||
** token. This will replace the current token by the first token from the
|
||||
** list (which will be the old current token in case the list was empty).
|
||||
*/
|
||||
AddCurTok (List);
|
||||
|
||||
/* Insert it into the scanner feed */
|
||||
@@ -396,12 +396,12 @@ static void FuncRight (void)
|
||||
}
|
||||
|
||||
/* Since we want to insert the list before the now current token, we have
|
||||
* to save the current token in some way and then skip it. To do this, we
|
||||
* will add the current token at the end of the token list (so the list
|
||||
* will never be empty), push the token list, and then skip the current
|
||||
* token. This will replace the current token by the first token from the
|
||||
* list (which will be the old current token in case the list was empty).
|
||||
*/
|
||||
** to save the current token in some way and then skip it. To do this, we
|
||||
** will add the current token at the end of the token list (so the list
|
||||
** will never be empty), push the token list, and then skip the current
|
||||
** token. This will replace the current token by the first token from the
|
||||
** list (which will be the old current token in case the list was empty).
|
||||
*/
|
||||
AddCurTok (List);
|
||||
|
||||
/* Insert it into the scanner feed */
|
||||
@@ -474,15 +474,15 @@ static void FuncSPrintF (void)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Since a format specifier follows, we do expect anotehr argument for
|
||||
* the .sprintf function.
|
||||
*/
|
||||
/* Since a format specifier follows, we do expect another argument for
|
||||
** the .sprintf function.
|
||||
*/
|
||||
ConsumeComma ();
|
||||
|
||||
/* We will copy the format spec into F1 checking for the things we
|
||||
* support, and later use xsprintf to do the actual formatting. This
|
||||
* is easier than adding another printf implementation...
|
||||
*/
|
||||
** support, and later use xsprintf to do the actual formatting. This
|
||||
** is easier than adding another printf implementation...
|
||||
*/
|
||||
SB_Clear (&F1);
|
||||
SB_AppendChar (&F1, '%');
|
||||
|
||||
@@ -522,8 +522,8 @@ static void FuncSPrintF (void)
|
||||
case 'X':
|
||||
case 'x':
|
||||
/* Our ints are actually longs, so we use the 'l' modifier when
|
||||
* calling xsprintf later. Terminate the format string.
|
||||
*/
|
||||
** calling xsprintf later. Terminate the format string.
|
||||
*/
|
||||
SB_AppendChar (&F1, 'l');
|
||||
SB_AppendChar (&F1, SB_Get (&Format));
|
||||
SB_Terminate (&F1);
|
||||
@@ -576,8 +576,8 @@ static void FuncSPrintF (void)
|
||||
}
|
||||
|
||||
/* Format this argument according to the spec. Be sure to pass
|
||||
* an int as the char value.
|
||||
*/
|
||||
** an int as the char value.
|
||||
*/
|
||||
SB_Printf (&R1, SB_GetConstBuf (&F1), (int) IVal);
|
||||
|
||||
/* Append the formatted argument to the result */
|
||||
@@ -597,8 +597,8 @@ static void FuncSPrintF (void)
|
||||
SB_Terminate (&R);
|
||||
|
||||
/* We expect a closing parenthesis, but will not skip it but replace it
|
||||
* by the string token just created.
|
||||
*/
|
||||
** by the string token just created.
|
||||
*/
|
||||
if (CurTok.Tok != TOK_RPAREN) {
|
||||
Error ("`)' expected");
|
||||
} else {
|
||||
@@ -636,8 +636,8 @@ static void FuncString (void)
|
||||
} else if (CurTok.Tok == TOK_NAMESPACE || CurTok.Tok == TOK_IDENT) {
|
||||
|
||||
/* Parse a fully qualified symbol name. We cannot use
|
||||
* ParseScopedSymName here since the name may be invalid.
|
||||
*/
|
||||
** ParseScopedSymName here since the name may be invalid.
|
||||
*/
|
||||
int NameSpace;
|
||||
do {
|
||||
NameSpace = (CurTok.Tok == TOK_NAMESPACE);
|
||||
@@ -657,8 +657,8 @@ static void FuncString (void)
|
||||
}
|
||||
|
||||
/* We expect a closing parenthesis, but will not skip it but replace it
|
||||
* by the string token just created.
|
||||
*/
|
||||
** by the string token just created.
|
||||
*/
|
||||
if (CurTok.Tok != TOK_RPAREN) {
|
||||
Error ("`)' expected");
|
||||
} else {
|
||||
@@ -680,8 +680,8 @@ void NextTok (void)
|
||||
NextRawTok ();
|
||||
|
||||
/* In raw mode, or when output is suppressed via conditional assembly,
|
||||
* pass the token unchanged.
|
||||
*/
|
||||
** pass the token unchanged.
|
||||
*/
|
||||
if (RawMode == 0 && IfCond) {
|
||||
|
||||
/* Execute token handling functions */
|
||||
@@ -787,8 +787,8 @@ void SkipUntilSep (void)
|
||||
|
||||
void ExpectSep (void)
|
||||
/* Check if we've reached a line separator, and output an error if not. Do
|
||||
* not skip the line separator.
|
||||
*/
|
||||
** not skip the line separator.
|
||||
*/
|
||||
{
|
||||
if (!TokIsSep (CurTok.Tok)) {
|
||||
ErrorSkip ("Unexpected trailing garbage characters");
|
||||
@@ -799,11 +799,11 @@ void ExpectSep (void)
|
||||
|
||||
void EnterRawTokenMode (void)
|
||||
/* Enter raw token mode. In raw mode, token handling functions are not
|
||||
* executed, but the function tokens are passed untouched to the upper
|
||||
* layer. Raw token mode is used when storing macro tokens for later
|
||||
* use.
|
||||
* Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
|
||||
*/
|
||||
** executed, but the function tokens are passed untouched to the upper
|
||||
** layer. Raw token mode is used when storing macro tokens for later
|
||||
** use.
|
||||
** Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
|
||||
*/
|
||||
{
|
||||
++RawMode;
|
||||
}
|
||||
|
||||
@@ -71,16 +71,16 @@ void SkipUntilSep (void);
|
||||
|
||||
void ExpectSep (void);
|
||||
/* Check if we've reached a line separator, and output an error if not. Do
|
||||
* not skip the line separator.
|
||||
*/
|
||||
** not skip the line separator.
|
||||
*/
|
||||
|
||||
void EnterRawTokenMode (void);
|
||||
/* Enter raw token mode. In raw mode, token handling functions are not
|
||||
* executed, but the function tokens are passed untouched to the upper
|
||||
* layer. Raw token mode is used when storing macro tokens for later
|
||||
* use.
|
||||
* Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
|
||||
*/
|
||||
** executed, but the function tokens are passed untouched to the upper
|
||||
** layer. Raw token mode is used when storing macro tokens for later
|
||||
** use.
|
||||
** Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
|
||||
*/
|
||||
|
||||
void LeaveRawTokenMode (void);
|
||||
/* Leave raw token mode. */
|
||||
|
||||
@@ -100,8 +100,8 @@ static ObjHeader Header = {
|
||||
|
||||
static void ObjWriteError (void)
|
||||
/* Called on a write error. Will try to close and remove the file, then
|
||||
* print a fatal error.
|
||||
*/
|
||||
** print a fatal error.
|
||||
*/
|
||||
{
|
||||
/* Remember the error */
|
||||
int Error = errno;
|
||||
@@ -162,8 +162,8 @@ void ObjOpen (void)
|
||||
/* Do we have a name for the output file? */
|
||||
if (OutFile == 0) {
|
||||
/* We don't have an output name explicitly given, construct one from
|
||||
* the name of the input file.
|
||||
*/
|
||||
** the name of the input file.
|
||||
*/
|
||||
OutFile = MakeFilename (InFile, OBJ_EXT);
|
||||
}
|
||||
|
||||
@@ -269,10 +269,10 @@ void ObjWriteVar (unsigned long V)
|
||||
/* Write a variable sized value to the file in special encoding */
|
||||
{
|
||||
/* We will write the value to the file in 7 bit chunks. If the 8th bit
|
||||
* is clear, we're done, if it is set, another chunk follows. This will
|
||||
* allow us to encode smaller values with less bytes, at the expense of
|
||||
* needing 5 bytes if a 32 bit value is written to file.
|
||||
*/
|
||||
** is clear, we're done, if it is set, another chunk follows. This will
|
||||
** allow us to encode smaller values with less bytes, at the expense of
|
||||
** needing 5 bytes if a 32 bit value is written to file.
|
||||
*/
|
||||
do {
|
||||
unsigned char C = (V & 0x7F);
|
||||
V >>= 7;
|
||||
@@ -291,9 +291,9 @@ void ObjWriteStr (const char* S)
|
||||
unsigned Len = strlen (S);
|
||||
|
||||
/* Write the string with the length preceeded (this is easier for
|
||||
* the reading routine than the C format since the length is known in
|
||||
* advance).
|
||||
*/
|
||||
** the reading routine than the C format since the length is known in
|
||||
** advance).
|
||||
*/
|
||||
ObjWriteVar (Len);
|
||||
ObjWriteData (S, Len);
|
||||
}
|
||||
@@ -304,9 +304,9 @@ void ObjWriteBuf (const StrBuf* S)
|
||||
/* Write a string to the object file */
|
||||
{
|
||||
/* Write the string with the length preceeded (this is easier for
|
||||
* the reading routine than the C format since the length is known in
|
||||
* advance).
|
||||
*/
|
||||
** the reading routine than the C format since the length is known in
|
||||
** advance).
|
||||
*/
|
||||
ObjWriteVar (SB_GetLen (S));
|
||||
ObjWriteData (SB_GetConstBuf (S), SB_GetLen (S));
|
||||
}
|
||||
|
||||
@@ -112,12 +112,12 @@ static void DoUnexpected (void);
|
||||
|
||||
static void DoInvalid (void);
|
||||
/* Handle a token that is invalid here, since it should have been handled on
|
||||
* a much lower level of the expression hierarchy. Getting this sort of token
|
||||
* means that the lower level code has bugs.
|
||||
* This function differs to DoUnexpected in that the latter may be triggered
|
||||
* by the user by using keywords in the wrong location. DoUnexpected is not
|
||||
* an error in the assembler itself, while DoInvalid is.
|
||||
*/
|
||||
** a much lower level of the expression hierarchy. Getting this sort of token
|
||||
** means that the lower level code has bugs.
|
||||
** This function differs to DoUnexpected in that the latter may be triggered
|
||||
** by the user by using keywords in the wrong location. DoUnexpected is not
|
||||
** an error in the assembler itself, while DoInvalid is.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -129,8 +129,8 @@ static void DoInvalid (void);
|
||||
|
||||
static unsigned char OptionalAddrSize (void)
|
||||
/* If a colon follows, parse an optional address size spec and return it.
|
||||
* Otherwise return ADDR_SIZE_DEFAULT.
|
||||
*/
|
||||
** Otherwise return ADDR_SIZE_DEFAULT.
|
||||
*/
|
||||
{
|
||||
unsigned AddrSize = ADDR_SIZE_DEFAULT;
|
||||
if (CurTok.Tok == TOK_COLON) {
|
||||
@@ -183,8 +183,8 @@ static void ExportWithAssign (SymEntry* Sym, unsigned char AddrSize, unsigned Fl
|
||||
/* Allow to assign the value of an export in an .export statement */
|
||||
{
|
||||
/* The name and optional address size spec may be followed by an assignment
|
||||
* or equal token.
|
||||
*/
|
||||
** or equal token.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_ASSIGN || CurTok.Tok == TOK_EQ) {
|
||||
|
||||
/* Assignment means the symbol is a label */
|
||||
@@ -249,8 +249,8 @@ static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
|
||||
|
||||
static long IntArg (long Min, long Max)
|
||||
/* Read an integer argument and check a range. Accept the token "unlimited"
|
||||
* and return -1 in this case.
|
||||
*/
|
||||
** and return -1 in this case.
|
||||
*/
|
||||
{
|
||||
if (CurTok.Tok == TOK_IDENT && SB_CompareStr (&CurTok.SVal, "unlimited") == 0) {
|
||||
NextTok ();
|
||||
@@ -301,9 +301,9 @@ static StrBuf* GenArrayType (StrBuf* Type, unsigned SpanSize,
|
||||
const char* ElementType,
|
||||
unsigned ElementTypeLen)
|
||||
/* Create an array (or single data) of the given type. SpanSize is the size
|
||||
* of the span, ElementType is a string that encodes the element data type.
|
||||
* The function returns Type.
|
||||
*/
|
||||
** of the span, ElementType is a string that encodes the element data type.
|
||||
** The function returns Type.
|
||||
*/
|
||||
{
|
||||
/* Get the size of the element type */
|
||||
unsigned ElementSize = GT_GET_SIZE (ElementType[0]);
|
||||
@@ -504,8 +504,8 @@ static void DoAssert (void)
|
||||
NextTok ();
|
||||
|
||||
/* We can have an optional message. If no message is present, use
|
||||
* "Assertion failed".
|
||||
*/
|
||||
** "Assertion failed".
|
||||
*/
|
||||
if (CurTok.Tok == TOK_COMMA) {
|
||||
|
||||
/* Skip the comma */
|
||||
@@ -518,8 +518,8 @@ static void DoAssert (void)
|
||||
}
|
||||
|
||||
/* Translate the message into a string id. We can then skip the input
|
||||
* string.
|
||||
*/
|
||||
** string.
|
||||
*/
|
||||
Msg = GetStrBufId (&CurTok.SVal);
|
||||
NextTok ();
|
||||
|
||||
@@ -1253,14 +1253,14 @@ static void DoIncBin (void)
|
||||
fseek (F, 0, SEEK_END);
|
||||
Size = ftell (F);
|
||||
|
||||
/* Stat the file and remember the values. There a race condition here,
|
||||
* since we cannot use fileno() (non standard identifier in standard
|
||||
* header file), and therefore not fstat. When using stat with the
|
||||
* file name, there's a risk that the file was deleted and recreated
|
||||
* while it was open. Since mtime and size are only used to check
|
||||
* if a file has changed in the debugger, we will ignore this problem
|
||||
* here.
|
||||
*/
|
||||
/* Stat the file and remember the values. There's a race condition here,
|
||||
** since we cannot use fileno() (non-standard identifier in standard
|
||||
** header file), and therefore not fstat. When using stat with the
|
||||
** file name, there's a risk that the file was deleted and recreated
|
||||
** while it was open. Since mtime and size are only used to check
|
||||
** if a file has changed in the debugger, we will ignore this problem
|
||||
** here.
|
||||
*/
|
||||
SB_Terminate (&Name);
|
||||
if (FileStat (SB_GetConstBuf (&Name), &StatBuf) != 0) {
|
||||
Fatal ("Cannot stat input file `%m%p': %s", &Name, strerror (errno));
|
||||
@@ -1364,12 +1364,12 @@ static void DoInterruptor (void)
|
||||
|
||||
static void DoInvalid (void)
|
||||
/* Handle a token that is invalid here, since it should have been handled on
|
||||
* a much lower level of the expression hierarchy. Getting this sort of token
|
||||
* means that the lower level code has bugs.
|
||||
* This function differs to DoUnexpected in that the latter may be triggered
|
||||
* by the user by using keywords in the wrong location. DoUnexpected is not
|
||||
* an error in the assembler itself, while DoInvalid is.
|
||||
*/
|
||||
** a much lower level of the expression hierarchy. Getting this sort of token
|
||||
** means that the lower level code has bugs.
|
||||
** This function differs to DoUnexpected in that the latter may be triggered
|
||||
** by the user by using keywords in the wrong location. DoUnexpected is not
|
||||
** an error in the assembler itself, while DoInvalid is.
|
||||
*/
|
||||
{
|
||||
Internal ("Unexpected token: %m%p", &Keyword);
|
||||
}
|
||||
@@ -1494,8 +1494,8 @@ static void DoOut (void)
|
||||
ErrorSkip ("String constant expected");
|
||||
} else {
|
||||
/* Output the string and be sure to flush the output to keep it in
|
||||
* sync with any error messages if the output is redirected to a file.
|
||||
*/
|
||||
** sync with any error messages if the output is redirected to a file.
|
||||
*/
|
||||
printf ("%.*s\n",
|
||||
(int) SB_GetLen (&CurTok.SVal),
|
||||
SB_GetConstBuf (&CurTok.SVal));
|
||||
@@ -1794,8 +1794,8 @@ static void DoSetCPU (void)
|
||||
SetCPU (CPU);
|
||||
|
||||
/* Skip the identifier. If the CPU switch was successful, the scanner
|
||||
* will treat the input now correctly for the new CPU.
|
||||
*/
|
||||
** will treat the input now correctly for the new CPU.
|
||||
*/
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
@@ -1861,10 +1861,10 @@ static void DoUnDef (void)
|
||||
/* Undefine a define style macro */
|
||||
{
|
||||
/* The function is called with the .UNDEF token in place, because we need
|
||||
* to disable .define macro expansions before reading the next token.
|
||||
* Otherwise the name of the macro would be expanded, so we would never
|
||||
* see it.
|
||||
*/
|
||||
** to disable .define macro expansions before reading the next token.
|
||||
** Otherwise the name of the macro would be expanded, so we would never
|
||||
** see it.
|
||||
*/
|
||||
DisableDefineStyleMacros ();
|
||||
NextTok ();
|
||||
EnableDefineStyleMacros ();
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
|
||||
static TokList* CollectRepeatTokens (void)
|
||||
/* Collect all tokens inside the .REPEAT body in a token list and return
|
||||
* this list. In case of errors, NULL is returned.
|
||||
*/
|
||||
** this list. In case of errors, NULL is returned.
|
||||
*/
|
||||
{
|
||||
/* Create the token list */
|
||||
TokList* List = NewTokList ();
|
||||
@@ -97,8 +97,8 @@ static TokList* CollectRepeatTokens (void)
|
||||
|
||||
static void RepeatTokenCheck (TokList* L)
|
||||
/* Called each time a token from a repeat token list is set. Is used to check
|
||||
* for and replace identifiers that are the repeat counter.
|
||||
*/
|
||||
** for and replace identifiers that are the repeat counter.
|
||||
*/
|
||||
{
|
||||
if (CurTok.Tok == TOK_IDENT &&
|
||||
L->Data != 0 &&
|
||||
@@ -161,8 +161,8 @@ void ParseRepeat (void)
|
||||
List->Check = RepeatTokenCheck;
|
||||
|
||||
/* If the list is empty, or repeat count zero, there is nothing
|
||||
* to repeat.
|
||||
*/
|
||||
** to repeat.
|
||||
*/
|
||||
if (List->Count == 0 || RepCount == 0) {
|
||||
FreeTokList (List);
|
||||
goto Done;
|
||||
|
||||
@@ -313,8 +313,8 @@ static void UseCharSource (CharSource* S)
|
||||
S->Func->NextChar (S);
|
||||
|
||||
/* Setup the next token so it will be skipped on the next call to
|
||||
* NextRawTok().
|
||||
*/
|
||||
** NextRawTok().
|
||||
*/
|
||||
CurTok.Tok = TOK_SEP;
|
||||
}
|
||||
|
||||
@@ -378,8 +378,8 @@ static void IFNextChar (CharSource* S)
|
||||
}
|
||||
|
||||
/* No more data - add an empty line to the listing. This
|
||||
* is a small hack needed to keep the PC output in sync.
|
||||
*/
|
||||
** is a small hack needed to keep the PC output in sync.
|
||||
*/
|
||||
NewListingLine (&EmptyStrBuf, S->V.File.Pos.Name, FCount);
|
||||
C = EOF;
|
||||
return;
|
||||
@@ -401,9 +401,9 @@ static void IFNextChar (CharSource* S)
|
||||
|
||||
|
||||
/* If we come here, we have a new input line. To avoid problems
|
||||
* with strange line terminators, remove all whitespace from the
|
||||
* end of the line, the add a single newline.
|
||||
*/
|
||||
** with strange line terminators, remove all whitespace from the
|
||||
** end of the line, the add a single newline.
|
||||
*/
|
||||
Len = SB_GetLen (&S->V.File.Line);
|
||||
while (Len > 0 && IsSpace (SB_AtUnchecked (&S->V.File.Line, Len-1))) {
|
||||
--Len;
|
||||
@@ -435,11 +435,11 @@ void IFDone (CharSource* S)
|
||||
/* Close the current input file */
|
||||
{
|
||||
/* We're at the end of an include file. Check if we have any
|
||||
* open .IFs, or any open token lists in this file. This
|
||||
* enforcement is artificial, using conditionals that start
|
||||
* in one file and end in another are uncommon, and don't
|
||||
* allowing these things will help finding errors.
|
||||
*/
|
||||
** open .IFs, or any open token lists in this file. This
|
||||
** enforcement is artificial, using conditionals that start
|
||||
** in one file and end in another are uncommon, and don't
|
||||
** allowing these things will help finding errors.
|
||||
*/
|
||||
CheckOpenIfs ();
|
||||
|
||||
/* If we've added search paths for this file, remove them */
|
||||
@@ -454,8 +454,8 @@ void IFDone (CharSource* S)
|
||||
SB_Done (&S->V.File.Line);
|
||||
|
||||
/* Close the input file and decrement the file count. We will ignore
|
||||
* errors here, since we were just reading from the file.
|
||||
*/
|
||||
** errors here, since we were just reading from the file.
|
||||
*/
|
||||
(void) fclose (S->V.File.F);
|
||||
--FCount;
|
||||
}
|
||||
@@ -473,8 +473,8 @@ static const CharSourceFunctions IFFunc = {
|
||||
|
||||
int NewInputFile (const char* Name)
|
||||
/* Open a new input file. Returns true if the file could be successfully opened
|
||||
* and false otherwise.
|
||||
*/
|
||||
** and false otherwise.
|
||||
*/
|
||||
{
|
||||
int RetCode = 0; /* Return code. Assume an error. */
|
||||
char* PathName = 0;
|
||||
@@ -487,8 +487,8 @@ int NewInputFile (const char* Name)
|
||||
|
||||
|
||||
/* If this is the main file, just try to open it. If it's an include file,
|
||||
* search for it using the include path list.
|
||||
*/
|
||||
** search for it using the include path list.
|
||||
*/
|
||||
if (FCount == 0) {
|
||||
/* Main file */
|
||||
F = fopen (Name, "r");
|
||||
@@ -497,8 +497,8 @@ int NewInputFile (const char* Name)
|
||||
}
|
||||
} else {
|
||||
/* We are on include level. Search for the file in the include
|
||||
* directories.
|
||||
*/
|
||||
** directories.
|
||||
*/
|
||||
PathName = SearchFile (IncSearchPath, Name);
|
||||
if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
|
||||
/* Not found or cannot open, print an error and bail out */
|
||||
@@ -510,14 +510,14 @@ int NewInputFile (const char* Name)
|
||||
Name = PathName;
|
||||
}
|
||||
|
||||
/* Stat the file and remember the values. There a race condition here,
|
||||
* since we cannot use fileno() (non standard identifier in standard
|
||||
* header file), and therefore not fstat. When using stat with the
|
||||
* file name, there's a risk that the file was deleted and recreated
|
||||
* while it was open. Since mtime and size are only used to check
|
||||
* if a file has changed in the debugger, we will ignore this problem
|
||||
* here.
|
||||
*/
|
||||
/* Stat the file and remember the values. There's a race condition here,
|
||||
** since we cannot use fileno() (non-standard identifier in standard
|
||||
** header file), and therefore not fstat. When using stat with the
|
||||
** file name, there's a risk that the file was deleted and recreated
|
||||
** while it was open. Since mtime and size are only used to check
|
||||
** if a file has changed in the debugger, we will ignore this problem
|
||||
** here.
|
||||
*/
|
||||
if (FileStat (Name, &Buf) != 0) {
|
||||
Fatal ("Cannot stat input file `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
@@ -704,8 +704,8 @@ static int CmpDotKeyword (const void* K1, const void* K2)
|
||||
|
||||
static token_t FindDotKeyword (void)
|
||||
/* Find the dot keyword in SVal. Return the corresponding token if found,
|
||||
* return TOK_NONE if not found.
|
||||
*/
|
||||
** return TOK_NONE if not found.
|
||||
*/
|
||||
{
|
||||
struct DotKeyword K;
|
||||
struct DotKeyword* R;
|
||||
@@ -733,10 +733,10 @@ static token_t FindDotKeyword (void)
|
||||
|
||||
static void ReadIdent (void)
|
||||
/* Read an identifier from the current input position into Ident. Filling SVal
|
||||
* starts at the current position with the next character in C. It is assumed
|
||||
* that any characters already filled in are ok, and the character in C is
|
||||
* checked.
|
||||
*/
|
||||
** starts at the current position with the next character in C. It is assumed
|
||||
** that any characters already filled in are ok, and the character in C is
|
||||
** checked.
|
||||
*/
|
||||
{
|
||||
/* Read the identifier */
|
||||
do {
|
||||
@@ -787,8 +787,8 @@ static void ReadStringConst (int StringTerm)
|
||||
|
||||
static int Sweet16Reg (const StrBuf* Id)
|
||||
/* Check if the given identifier is a sweet16 register. Return -1 if this is
|
||||
* not the case, return the register number otherwise.
|
||||
*/
|
||||
** not the case, return the register number otherwise.
|
||||
*/
|
||||
{
|
||||
unsigned RegNum;
|
||||
char Check;
|
||||
@@ -960,9 +960,9 @@ Again:
|
||||
}
|
||||
if (IsXDigit (C)) {
|
||||
/* Buf is big enough to allow any decimal and hex number to
|
||||
* overflow, so ignore excess digits here, they will be detected
|
||||
* when we convert the value.
|
||||
*/
|
||||
** overflow, so ignore excess digits here, they will be detected
|
||||
** when we convert the value.
|
||||
*/
|
||||
if (Digits < sizeof (Buf)) {
|
||||
Buf[Digits++] = C;
|
||||
}
|
||||
@@ -1034,8 +1034,8 @@ Again:
|
||||
}
|
||||
|
||||
/* An identifier with a dot. Check if it's a define style
|
||||
* macro.
|
||||
*/
|
||||
** macro.
|
||||
*/
|
||||
if ((M = FindDefine (&CurTok.SVal)) != 0) {
|
||||
/* This is a define style macro - expand it */
|
||||
MacExpandStart (M);
|
||||
@@ -1051,8 +1051,8 @@ Again:
|
||||
}
|
||||
|
||||
/* Indirect op for sweet16 cpu. Must check this before checking for local
|
||||
* symbols, because these may also use the '@' symbol.
|
||||
*/
|
||||
** symbols, because these may also use the '@' symbol.
|
||||
*/
|
||||
if (CPU == CPU_SWEET16 && C == '@') {
|
||||
NextChar ();
|
||||
CurTok.Tok = TOK_AT;
|
||||
@@ -1084,8 +1084,8 @@ Again:
|
||||
ReadIdent ();
|
||||
|
||||
/* Check for special names. Bail out if we have identified the type of
|
||||
* the token. Go on if the token is an identifier.
|
||||
*/
|
||||
** the token. Go on if the token is an identifier.
|
||||
*/
|
||||
if (SB_GetLen (&CurTok.SVal) == 1) {
|
||||
switch (toupper (SB_AtUnchecked (&CurTok.SVal, 0))) {
|
||||
|
||||
@@ -1357,9 +1357,9 @@ CharAgain:
|
||||
|
||||
case '\'':
|
||||
/* Hack: If we allow ' as terminating character for strings, read
|
||||
* the following stuff as a string, and check for a one character
|
||||
* string later.
|
||||
*/
|
||||
** the following stuff as a string, and check for a one character
|
||||
** string later.
|
||||
*/
|
||||
if (LooseStringTerm) {
|
||||
ReadStringConst ('\'');
|
||||
if (SB_GetLen (&CurTok.SVal) == 1) {
|
||||
@@ -1424,8 +1424,8 @@ CharAgain:
|
||||
}
|
||||
|
||||
/* If we go here, we could not identify the current character. Skip it
|
||||
* and try again.
|
||||
*/
|
||||
** and try again.
|
||||
*/
|
||||
Error ("Invalid input character: 0x%02X", C & 0xFF);
|
||||
NextChar ();
|
||||
goto Again;
|
||||
@@ -1435,10 +1435,10 @@ CharAgain:
|
||||
|
||||
int GetSubKey (const char** Keys, unsigned Count)
|
||||
/* Search for a subkey in a table of keywords. The current token must be an
|
||||
* identifier and all keys must be in upper case. The identifier will be
|
||||
* uppercased in the process. The function returns the index of the keyword,
|
||||
* or -1 if the keyword was not found.
|
||||
*/
|
||||
** identifier and all keys must be in upper case. The identifier will be
|
||||
** uppercased in the process. The function returns the index of the keyword,
|
||||
** or -1 if the keyword was not found.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
@@ -1466,9 +1466,9 @@ int GetSubKey (const char** Keys, unsigned Count)
|
||||
|
||||
unsigned char ParseAddrSize (void)
|
||||
/* Check if the next token is a keyword that denotes an address size specifier.
|
||||
* If so, return the corresponding address size constant, otherwise output an
|
||||
* error message and return ADDR_SIZE_DEFAULT.
|
||||
*/
|
||||
** If so, return the corresponding address size constant, otherwise output an
|
||||
** error message and return ADDR_SIZE_DEFAULT.
|
||||
*/
|
||||
{
|
||||
unsigned char AddrSize;
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ int IsIdStart (int C);
|
||||
|
||||
int NewInputFile (const char* Name);
|
||||
/* Open a new input file. Returns true if the file could be successfully opened
|
||||
* and false otherwise.
|
||||
*/
|
||||
** and false otherwise.
|
||||
*/
|
||||
|
||||
void NewInputData (char* Text, int Malloced);
|
||||
/* Add a chunk of input data to the input stream */
|
||||
@@ -86,16 +86,16 @@ void NextRawTok (void);
|
||||
|
||||
int GetSubKey (const char** Keys, unsigned Count);
|
||||
/* Search for a subkey in a table of keywords. The current token must be an
|
||||
* identifier and all keys must be in upper case. The identifier will be
|
||||
* uppercased in the process. The function returns the index of the keyword,
|
||||
* or -1 if the keyword was not found.
|
||||
*/
|
||||
** identifier and all keys must be in upper case. The identifier will be
|
||||
** uppercased in the process. The function returns the index of the keyword,
|
||||
** or -1 if the keyword was not found.
|
||||
*/
|
||||
|
||||
unsigned char ParseAddrSize (void);
|
||||
/* Check if the next token is a keyword that denotes an address size specifier.
|
||||
* If so, return the corresponding address size constant, otherwise output an
|
||||
* error message and return ADDR_SIZE_DEFAULT.
|
||||
*/
|
||||
** If so, return the corresponding address size constant, otherwise output an
|
||||
** error message and return ADDR_SIZE_DEFAULT.
|
||||
*/
|
||||
|
||||
void InitScanner (const char* InFile);
|
||||
/* Initialize the scanner, open the given input file */
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
|
||||
|
||||
/* If OrgPerSeg is false, all segments share the RelocMode flag and a PC
|
||||
* used when in absolute mode. OrgPerSeg may be set by .feature org_per_seg
|
||||
*/
|
||||
** used when in absolute mode. OrgPerSeg may be set by .feature org_per_seg
|
||||
*/
|
||||
static int RelocMode = 1;
|
||||
static unsigned long AbsPC = 0; /* PC if in absolute mode */
|
||||
|
||||
@@ -97,8 +97,8 @@ Segment* ActiveSeg;
|
||||
|
||||
static Segment* NewSegFromDef (SegDef* Def)
|
||||
/* Create a new segment from a segment definition. Used only internally, no
|
||||
* checks.
|
||||
*/
|
||||
** checks.
|
||||
*/
|
||||
{
|
||||
/* Create a new segment */
|
||||
Segment* S = xmalloc (sizeof (*S));
|
||||
@@ -233,8 +233,8 @@ unsigned long GetPC (void)
|
||||
|
||||
void EnterAbsoluteMode (unsigned long PC)
|
||||
/* Enter absolute (non relocatable mode). Depending on the OrgPerSeg flag,
|
||||
* this will either switch the mode globally or for the current segment.
|
||||
*/
|
||||
** this will either switch the mode globally or for the current segment.
|
||||
*/
|
||||
{
|
||||
if (OrgPerSeg) {
|
||||
/* Relocatable mode is switched per segment */
|
||||
@@ -265,8 +265,8 @@ int GetRelocMode (void)
|
||||
|
||||
void EnterRelocMode (void)
|
||||
/* Enter relocatable mode. Depending on the OrgPerSeg flag, this will either
|
||||
* switch the mode globally or for the current segment.
|
||||
*/
|
||||
** switch the mode globally or for the current segment.
|
||||
*/
|
||||
{
|
||||
if (OrgPerSeg) {
|
||||
/* Relocatable mode is switched per segment */
|
||||
@@ -281,25 +281,25 @@ void EnterRelocMode (void)
|
||||
|
||||
void SegAlign (unsigned long Alignment, int FillVal)
|
||||
/* Align the PC segment to Alignment. If FillVal is -1, emit fill fragments
|
||||
* (the actual fill value will be determined by the linker), otherwise use
|
||||
* the given value.
|
||||
*/
|
||||
** (the actual fill value will be determined by the linker), otherwise use
|
||||
** the given value.
|
||||
*/
|
||||
{
|
||||
unsigned char Data [4];
|
||||
unsigned long CombinedAlignment;
|
||||
unsigned long Count;
|
||||
|
||||
/* The segment must have the combined alignment of all separate alignments
|
||||
* in the source. Calculate this alignment and check it for sanity.
|
||||
*/
|
||||
** in the source. Calculate this alignment and check it for sanity.
|
||||
*/
|
||||
CombinedAlignment = LeastCommonMultiple (ActiveSeg->Align, Alignment);
|
||||
if (CombinedAlignment > MAX_ALIGNMENT) {
|
||||
Error ("Combined alignment for active segment is %lu which exceeds %lu",
|
||||
CombinedAlignment, MAX_ALIGNMENT);
|
||||
|
||||
/* Avoid creating large fills for an object file that is thrown away
|
||||
* later.
|
||||
*/
|
||||
** later.
|
||||
*/
|
||||
Count = 1;
|
||||
|
||||
} else {
|
||||
@@ -410,10 +410,10 @@ void SegDone (void)
|
||||
} else if (RelaxChecks == 0) {
|
||||
|
||||
/* We cannot evaluate the expression now, leave the job for
|
||||
* the linker. However, we can check if the address size
|
||||
* matches the fragment size. Mismatches are errors in
|
||||
* most situations.
|
||||
*/
|
||||
** the linker. However, we can check if the address size
|
||||
** matches the fragment size. Mismatches are errors in
|
||||
** most situations.
|
||||
*/
|
||||
if ((F->Len == 1 && ED.AddrSize > ADDR_SIZE_ZP) ||
|
||||
(F->Len == 2 && ED.AddrSize > ADDR_SIZE_ABS) ||
|
||||
(F->Len == 3 && ED.AddrSize > ADDR_SIZE_FAR)) {
|
||||
@@ -496,9 +496,9 @@ void SetSegmentSizes (void)
|
||||
/* Set the default segment sizes according to the memory model */
|
||||
{
|
||||
/* Initialize segment sizes. The segment definitions do already contain
|
||||
* the correct values for the default case (near), so we must only change
|
||||
* things that should be different.
|
||||
*/
|
||||
** the correct values for the default case (near), so we must only change
|
||||
** things that should be different.
|
||||
*/
|
||||
switch (MemoryModel) {
|
||||
|
||||
case MMODEL_NEAR:
|
||||
@@ -530,8 +530,8 @@ static void WriteOneSeg (Segment* Seg)
|
||||
unsigned long EndPos;
|
||||
|
||||
/* Remember the file position, then write a dummy for the size of the
|
||||
* following data
|
||||
*/
|
||||
** following data
|
||||
*/
|
||||
unsigned long SizePos = ObjGetFilePos ();
|
||||
ObjWrite32 (0);
|
||||
|
||||
@@ -544,8 +544,8 @@ static void WriteOneSeg (Segment* Seg)
|
||||
ObjWriteVar (Seg->FragCount); /* Number of fragments */
|
||||
|
||||
/* Now walk through the fragment list for this segment and write the
|
||||
* fragments.
|
||||
*/
|
||||
** fragments.
|
||||
*/
|
||||
Frag = Seg->Root;
|
||||
while (Frag) {
|
||||
|
||||
|
||||
@@ -131,9 +131,9 @@ INLINE unsigned char GetCurrentSegAddrSize (void)
|
||||
|
||||
void SegAlign (unsigned long Alignment, int FillVal);
|
||||
/* Align the PC segment to Alignment. If FillVal is -1, emit fill fragments
|
||||
* (the actual fill value will be determined by the linker), otherwise use
|
||||
* the given value.
|
||||
*/
|
||||
** (the actual fill value will be determined by the linker), otherwise use
|
||||
** the given value.
|
||||
*/
|
||||
|
||||
unsigned char GetSegAddrSize (unsigned SegNum);
|
||||
/* Return the address size of the segment with the given number */
|
||||
@@ -146,13 +146,13 @@ int GetRelocMode (void);
|
||||
|
||||
void EnterAbsoluteMode (unsigned long AbsPC);
|
||||
/* Enter absolute (non relocatable mode). Depending on the OrgPerSeg flag,
|
||||
* this will either switch the mode globally or for the current segment.
|
||||
*/
|
||||
** this will either switch the mode globally or for the current segment.
|
||||
*/
|
||||
|
||||
void EnterRelocMode (void);
|
||||
/* Enter relocatable mode. Depending on the OrgPerSeg flag, this will either
|
||||
* switch the mode globally or for the current segment.
|
||||
*/
|
||||
** switch the mode globally or for the current segment.
|
||||
*/
|
||||
|
||||
void SegDone (void);
|
||||
/* Check the segments for range and other errors. Do cleanup. */
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
|
||||
|
||||
/* The name of the symbol used to encode the size. The name of this entry is
|
||||
* choosen so that it cannot be accessed by the user.
|
||||
*/
|
||||
** choosen so that it cannot be accessed by the user.
|
||||
*/
|
||||
static const StrBuf SizeEntryName = LIT_STRBUF_INITIALIZER (".size");
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ static const StrBuf SizeEntryName = LIT_STRBUF_INITIALIZER (".size");
|
||||
|
||||
int IsSizeOfSymbol (const SymEntry* Sym)
|
||||
/* Return true if the given symbol is the one that encodes the size of some
|
||||
* entity. Sym may also be a NULL pointer in which case false is returned.
|
||||
*/
|
||||
** entity. Sym may also be a NULL pointer in which case false is returned.
|
||||
*/
|
||||
{
|
||||
return (Sym != 0 && SB_Compare (GetSymName (Sym), &SizeEntryName) == 0);
|
||||
}
|
||||
@@ -74,8 +74,8 @@ int IsSizeOfSymbol (const SymEntry* Sym)
|
||||
|
||||
SymEntry* FindSizeOfScope (SymTable* Scope)
|
||||
/* Get the size of a scope. The function returns the symbol table entry that
|
||||
* encodes the size or NULL if there is no such entry.
|
||||
*/
|
||||
** encodes the size or NULL if there is no such entry.
|
||||
*/
|
||||
{
|
||||
return SymFind (Scope, &SizeEntryName, SYM_FIND_EXISTING);
|
||||
}
|
||||
@@ -84,8 +84,8 @@ SymEntry* FindSizeOfScope (SymTable* Scope)
|
||||
|
||||
SymEntry* FindSizeOfSymbol (SymEntry* Sym)
|
||||
/* Get the size of a symbol table entry. The function returns the symbol table
|
||||
* entry that encodes the size of the symbol or NULL if there is no such entry.
|
||||
*/
|
||||
** entry that encodes the size of the symbol or NULL if there is no such entry.
|
||||
*/
|
||||
{
|
||||
return SymFindLocal (Sym, &SizeEntryName, SYM_FIND_EXISTING);
|
||||
}
|
||||
@@ -94,8 +94,8 @@ SymEntry* FindSizeOfSymbol (SymEntry* Sym)
|
||||
|
||||
SymEntry* GetSizeOfScope (SymTable* Scope)
|
||||
/* Get the size of a scope. The function returns the symbol table entry that
|
||||
* encodes the size, and will create a new entry if it does not exist.
|
||||
*/
|
||||
** encodes the size, and will create a new entry if it does not exist.
|
||||
*/
|
||||
{
|
||||
return SymFind (Scope, &SizeEntryName, SYM_ALLOC_NEW);
|
||||
}
|
||||
@@ -104,9 +104,9 @@ SymEntry* GetSizeOfScope (SymTable* Scope)
|
||||
|
||||
SymEntry* GetSizeOfSymbol (SymEntry* Sym)
|
||||
/* Get the size of a symbol table entry. The function returns the symbol table
|
||||
* entry that encodes the size of the symbol and will create a new one if it
|
||||
* does not exist.
|
||||
*/
|
||||
** entry that encodes the size of the symbol and will create a new one if it
|
||||
** does not exist.
|
||||
*/
|
||||
{
|
||||
return SymFindLocal (Sym, &SizeEntryName, SYM_ALLOC_NEW);
|
||||
}
|
||||
|
||||
@@ -62,29 +62,29 @@ struct SymTable;
|
||||
|
||||
int IsSizeOfSymbol (const struct SymEntry* Sym);
|
||||
/* Return true if the given symbol is the one that encodes the size of some
|
||||
* entity. Sym may also be a NULL pointer in which case false is returned.
|
||||
*/
|
||||
** entity. Sym may also be a NULL pointer in which case false is returned.
|
||||
*/
|
||||
|
||||
struct SymEntry* FindSizeOfScope (struct SymTable* Scope);
|
||||
/* Get the size of a scope. The function returns the symbol table entry that
|
||||
* encodes the size or NULL if there is no such entry.
|
||||
*/
|
||||
** encodes the size or NULL if there is no such entry.
|
||||
*/
|
||||
|
||||
struct SymEntry* FindSizeOfSymbol (struct SymEntry* Sym);
|
||||
/* Get the size of a symbol table entry. The function returns the symbol table
|
||||
* entry that encodes the size of the symbol or NULL if there is no such entry.
|
||||
*/
|
||||
** entry that encodes the size of the symbol or NULL if there is no such entry.
|
||||
*/
|
||||
|
||||
struct SymEntry* GetSizeOfScope (struct SymTable* Scope);
|
||||
/* Get the size of a scope. The function returns the symbol table entry that
|
||||
* encodes the size, and will create a new entry if it does not exist.
|
||||
*/
|
||||
** encodes the size, and will create a new entry if it does not exist.
|
||||
*/
|
||||
|
||||
struct SymEntry* GetSizeOfSymbol (struct SymEntry* Sym);
|
||||
/* Get the size of a symbol table entry. The function returns the symbol table
|
||||
* entry that encodes the size of the symbol and will create a new one if it
|
||||
* does not exist.
|
||||
*/
|
||||
** entry that encodes the size of the symbol and will create a new one if it
|
||||
** does not exist.
|
||||
*/
|
||||
|
||||
struct SymEntry* DefSizeOfScope (struct SymTable* Scope, long Size);
|
||||
/* Define the size of a scope and return the size symbol */
|
||||
|
||||
@@ -61,9 +61,9 @@ static const void* HT_GetKey (const void* Entry);
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2);
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -113,9 +113,9 @@ static const void* HT_GetKey (const void* Entry)
|
||||
|
||||
static int HT_Compare (const void* Key1, const void* Key2)
|
||||
/* Compare two keys. The function must return a value less than zero if
|
||||
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
* than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
** Key1 is smaller than Key2, zero if both are equal, and a value greater
|
||||
** than zero if Key1 is greater then Key2.
|
||||
*/
|
||||
{
|
||||
/* Convert both parameters to Span pointers */
|
||||
const Span* S1 = Key1;
|
||||
@@ -144,8 +144,8 @@ static int HT_Compare (const void* Key1, const void* Key2)
|
||||
|
||||
static Span* NewSpan (Segment* Seg, unsigned long Start, unsigned long End)
|
||||
/* Create a new span. The segment is set to Seg, Start and End are set to the
|
||||
* current PC of the segment.
|
||||
*/
|
||||
** current PC of the segment.
|
||||
*/
|
||||
{
|
||||
/* Allocate memory */
|
||||
Span* S = xmalloc (sizeof (Span));
|
||||
@@ -174,13 +174,13 @@ static void FreeSpan (Span* S)
|
||||
|
||||
static Span* MergeSpan (Span* S)
|
||||
/* Check if we have a span with the same data as S already. If so, free S and
|
||||
* return the already existing one. If not, remember S and return it.
|
||||
*/
|
||||
** return the already existing one. If not, remember S and return it.
|
||||
*/
|
||||
{
|
||||
/* Check if we have such a span already. If so use the existing
|
||||
* one and free the one from the collection. If not, add the one to
|
||||
* the hash table and return it.
|
||||
*/
|
||||
** one and free the one from the collection. If not, add the one to
|
||||
** the hash table and return it.
|
||||
*/
|
||||
Span* E = HT_Find (&SpanTab, S);
|
||||
if (E) {
|
||||
/* If S has a type and E not, move the type */
|
||||
@@ -223,9 +223,9 @@ Span* OpenSpan (void)
|
||||
|
||||
Span* CloseSpan (Span* S)
|
||||
/* Close the given span. Be sure to replace the passed span by the one
|
||||
* returned, since the span will get deleted if it is empty or may be
|
||||
* replaced if a duplicate exists.
|
||||
*/
|
||||
** returned, since the span will get deleted if it is empty or may be
|
||||
** replaced if a duplicate exists.
|
||||
*/
|
||||
{
|
||||
/* Set the end offset */
|
||||
if (S->Start == S->Seg->PC) {
|
||||
@@ -237,9 +237,9 @@ Span* CloseSpan (Span* S)
|
||||
S->End = S->Seg->PC;
|
||||
|
||||
/* Check if we have such a span already. If so use the existing
|
||||
* one and free the one from the collection. If not, add the one to
|
||||
* the hash table and return it.
|
||||
*/
|
||||
** one and free the one from the collection. If not, add the one to
|
||||
** the hash table and return it.
|
||||
*/
|
||||
return MergeSpan (S);
|
||||
}
|
||||
}
|
||||
@@ -248,9 +248,9 @@ Span* CloseSpan (Span* S)
|
||||
|
||||
void OpenSpanList (Collection* Spans)
|
||||
/* Open a list of spans for all existing segments to the given collection of
|
||||
* spans. The currently active segment will be inserted first with all others
|
||||
* following.
|
||||
*/
|
||||
** spans. The currently active segment will be inserted first with all others
|
||||
** following.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
@@ -275,8 +275,8 @@ void OpenSpanList (Collection* Spans)
|
||||
|
||||
void CloseSpanList (Collection* Spans)
|
||||
/* Close a list of spans. This will add new segments to the list, mark the end
|
||||
* of existing ones, and remove empty spans from the list.
|
||||
*/
|
||||
** of existing ones, and remove empty spans from the list.
|
||||
*/
|
||||
{
|
||||
unsigned I, J;
|
||||
|
||||
@@ -385,9 +385,9 @@ void WriteSpans (void)
|
||||
CHECK (S->End > S->Start);
|
||||
|
||||
/* Write data for the span We will write the size instead of the
|
||||
* end offset to save some bytes, since most spans are expected
|
||||
* to be rather small.
|
||||
*/
|
||||
** end offset to save some bytes, since most spans are expected
|
||||
** to be rather small.
|
||||
*/
|
||||
ObjWriteVar (S->Seg->Num);
|
||||
ObjWriteVar (S->Start);
|
||||
ObjWriteVar (S->End - S->Start);
|
||||
|
||||
@@ -93,15 +93,15 @@ Span* OpenSpan (void);
|
||||
|
||||
Span* CloseSpan (Span* S);
|
||||
/* Close the given span. Be sure to replace the passed span by the one
|
||||
* returned, since the span will get deleted if it is empty or may be
|
||||
* replaced if a duplicate exists.
|
||||
*/
|
||||
** returned, since the span will get deleted if it is empty or may be
|
||||
** replaced if a duplicate exists.
|
||||
*/
|
||||
|
||||
void OpenSpanList (Collection* Spans);
|
||||
/* Open a list of spans for all existing segments to the given collection of
|
||||
* spans. The currently active segment will be inserted first with all others
|
||||
* following.
|
||||
*/
|
||||
** spans. The currently active segment will be inserted first with all others
|
||||
** following.
|
||||
*/
|
||||
|
||||
void CloseSpanList (Collection* Spans);
|
||||
/* Close all open spans by setting PC to the current PC for the segment. */
|
||||
|
||||
@@ -102,9 +102,9 @@ static long DoStructInternal (long Offs, unsigned Type)
|
||||
long Size = 0;
|
||||
|
||||
/* Outside of other structs, we need a name. Inside another struct or
|
||||
* union, the struct may be anonymous, in which case no new lexical level
|
||||
* is started.
|
||||
*/
|
||||
** union, the struct may be anonymous, in which case no new lexical level
|
||||
** is started.
|
||||
*/
|
||||
int Anon = (CurTok.Tok != TOK_IDENT);
|
||||
if (!Anon) {
|
||||
/* Enter a new scope, then skip the name */
|
||||
@@ -137,8 +137,8 @@ static long DoStructInternal (long Offs, unsigned Type)
|
||||
if (CurTok.Tok == TOK_IDENT) {
|
||||
|
||||
/* Beware: An identifier may also be a macro, in which case we have
|
||||
* to start over.
|
||||
*/
|
||||
** to start over.
|
||||
*/
|
||||
Macro* M = FindMacro (&CurTok.SVal);
|
||||
if (M) {
|
||||
MacExpandStart (M);
|
||||
@@ -245,11 +245,11 @@ static long DoStructInternal (long Offs, unsigned Type)
|
||||
}
|
||||
|
||||
/* If this is not a anon struct, enter a special symbol named ".size"
|
||||
* into the symbol table of the struct that holds the size of the
|
||||
* struct. Since the symbol starts with a dot, it cannot be accessed
|
||||
* by user code.
|
||||
* Leave the struct scope level.
|
||||
*/
|
||||
** into the symbol table of the struct that holds the size of the
|
||||
** struct. Since the symbol starts with a dot, it cannot be accessed
|
||||
** by user code.
|
||||
** Leave the struct scope level.
|
||||
*/
|
||||
if (!Anon) {
|
||||
/* Add a symbol */
|
||||
SymEntry* SizeSym = GetSizeOfScope (CurrentScope);
|
||||
|
||||
@@ -107,8 +107,8 @@ int ED_IsConst (const ExprDesc* D)
|
||||
|
||||
static int ED_IsValid (const ExprDesc* D)
|
||||
/* Return true if the expression is valid, that is, neither the ERROR nor the
|
||||
* TOO_COMPLEX flags are set.
|
||||
*/
|
||||
** TOO_COMPLEX flags are set.
|
||||
*/
|
||||
{
|
||||
return ((D->Flags & (ED_ERROR | ED_TOO_COMPLEX)) == 0);
|
||||
}
|
||||
@@ -164,22 +164,22 @@ static void ED_MergeAddrSize (ExprDesc* ED, const ExprDesc* Right)
|
||||
{
|
||||
if (ED->AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
/* If ED is valid, ADDR_SIZE_DEFAULT gets always overridden, otherwise
|
||||
* it takes precedence over anything else.
|
||||
*/
|
||||
** it takes precedence over anything else.
|
||||
*/
|
||||
if (ED_IsValid (ED)) {
|
||||
ED->AddrSize = Right->AddrSize;
|
||||
}
|
||||
} else if (Right->AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
/* If Right is valid, ADDR_SIZE_DEFAULT gets always overridden,
|
||||
* otherwise it takes precedence over anything else.
|
||||
*/
|
||||
** otherwise it takes precedence over anything else.
|
||||
*/
|
||||
if (!ED_IsValid (Right)) {
|
||||
ED->AddrSize = Right->AddrSize;
|
||||
}
|
||||
} else {
|
||||
/* Neither ED nor Right has a default address size, use the larger of
|
||||
* the two.
|
||||
*/
|
||||
** the two.
|
||||
*/
|
||||
if (Right->AddrSize > ED->AddrSize) {
|
||||
ED->AddrSize = Right->AddrSize;
|
||||
}
|
||||
@@ -190,8 +190,8 @@ static void ED_MergeAddrSize (ExprDesc* ED, const ExprDesc* Right)
|
||||
|
||||
static ED_SymRef* ED_FindSymRef (ExprDesc* ED, SymEntry* Sym)
|
||||
/* Find a symbol reference and return it. Return NULL if the reference does
|
||||
* not exist.
|
||||
*/
|
||||
** not exist.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
ED_SymRef* SymRef;
|
||||
@@ -207,8 +207,8 @@ static ED_SymRef* ED_FindSymRef (ExprDesc* ED, SymEntry* Sym)
|
||||
|
||||
static ED_SecRef* ED_FindSecRef (ExprDesc* ED, unsigned Sec)
|
||||
/* Find a section reference and return it. Return NULL if the reference does
|
||||
* not exist.
|
||||
*/
|
||||
** not exist.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
ED_SecRef* SecRef;
|
||||
@@ -224,8 +224,8 @@ static ED_SecRef* ED_FindSecRef (ExprDesc* ED, unsigned Sec)
|
||||
|
||||
static ED_SymRef* ED_AllocSymRef (ExprDesc* ED, SymEntry* Sym)
|
||||
/* Allocate a new symbol reference and return it. The count of the new
|
||||
* reference will be set to zero, and the reference itself to Sym.
|
||||
*/
|
||||
** reference will be set to zero, and the reference itself to Sym.
|
||||
*/
|
||||
{
|
||||
ED_SymRef* SymRef;
|
||||
|
||||
@@ -251,8 +251,8 @@ static ED_SymRef* ED_AllocSymRef (ExprDesc* ED, SymEntry* Sym)
|
||||
|
||||
static ED_SecRef* ED_AllocSecRef (ExprDesc* ED, unsigned Sec)
|
||||
/* Allocate a new section reference and return it. The count of the new
|
||||
* reference will be set to zero, and the reference itself to Sec.
|
||||
*/
|
||||
** reference will be set to zero, and the reference itself to Sec.
|
||||
*/
|
||||
{
|
||||
ED_SecRef* SecRef;
|
||||
|
||||
@@ -278,8 +278,8 @@ static ED_SecRef* ED_AllocSecRef (ExprDesc* ED, unsigned Sec)
|
||||
|
||||
static ED_SymRef* ED_GetSymRef (ExprDesc* ED, SymEntry* Sym)
|
||||
/* Get a symbol reference and return it. If the symbol reference does not
|
||||
* exist, a new one is created and returned.
|
||||
*/
|
||||
** exist, a new one is created and returned.
|
||||
*/
|
||||
{
|
||||
ED_SymRef* SymRef = ED_FindSymRef (ED, Sym);
|
||||
if (SymRef == 0) {
|
||||
@@ -292,8 +292,8 @@ static ED_SymRef* ED_GetSymRef (ExprDesc* ED, SymEntry* Sym)
|
||||
|
||||
static ED_SecRef* ED_GetSecRef (ExprDesc* ED, unsigned Sec)
|
||||
/* Get a section reference and return it. If the section reference does not
|
||||
* exist, a new one is created and returned.
|
||||
*/
|
||||
** exist, a new one is created and returned.
|
||||
*/
|
||||
{
|
||||
ED_SecRef* SecRef = ED_FindSecRef (ED, Sec);
|
||||
if (SecRef == 0) {
|
||||
@@ -416,8 +416,8 @@ static void ED_Neg (ExprDesc* D)
|
||||
|
||||
static void ED_Move (ExprDesc* From, ExprDesc* To)
|
||||
/* Move the data from one ExprDesc to another. Old data is freed, and From
|
||||
* is prepared to that ED_Done may be called safely.
|
||||
*/
|
||||
** is prepared to that ED_Done may be called safely.
|
||||
*/
|
||||
{
|
||||
/* Delete old data */
|
||||
ED_Done (To);
|
||||
@@ -460,12 +460,12 @@ static unsigned char GetConstAddrSize (long Val)
|
||||
|
||||
static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
|
||||
/* Study a binary expression subtree. This is a helper function for StudyExpr
|
||||
* used for operations that succeed when both operands are known and constant.
|
||||
* It evaluates the two subtrees and checks if they are constant. If they
|
||||
* aren't constant, it will set the TOO_COMPLEX flag, and merge references.
|
||||
* Otherwise the first value is returned in D->Val, the second one in D->Right,
|
||||
* so the actual operation can be done by the caller.
|
||||
*/
|
||||
** used for operations that succeed when both operands are known and constant.
|
||||
** It evaluates the two subtrees and checks if they are constant. If they
|
||||
** aren't constant, it will set the TOO_COMPLEX flag, and merge references.
|
||||
** Otherwise the first value is returned in D->Val, the second one in D->Right,
|
||||
** so the actual operation can be done by the caller.
|
||||
*/
|
||||
{
|
||||
ExprDesc Right;
|
||||
|
||||
@@ -516,10 +516,10 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
|
||||
SymEntry* Sym = Expr->V.Sym;
|
||||
|
||||
/* If the symbol is defined somewhere, it has an expression associated.
|
||||
* In this case, just study the expression associated with the symbol,
|
||||
* but mark the symbol so if we encounter it twice, we know that we have
|
||||
* a circular reference.
|
||||
*/
|
||||
** In this case, just study the expression associated with the symbol,
|
||||
** but mark the symbol so if we encounter it twice, we know that we have
|
||||
** a circular reference.
|
||||
*/
|
||||
if (SymHasExpr (Sym)) {
|
||||
|
||||
if (SymHasUserMark (Sym)) {
|
||||
@@ -542,9 +542,9 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
|
||||
}
|
||||
|
||||
/* If the symbol has an explicit address size, use it. This may
|
||||
* lead to range errors later (maybe even in the linker stage), if
|
||||
* the user lied about the address size, but for now we trust him.
|
||||
*/
|
||||
** lead to range errors later (maybe even in the linker stage), if
|
||||
** the user lied about the address size, but for now we trust him.
|
||||
*/
|
||||
AddrSize = GetSymAddrSize (Sym);
|
||||
if (AddrSize != ADDR_SIZE_DEFAULT) {
|
||||
D->AddrSize = AddrSize;
|
||||
@@ -554,8 +554,8 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
|
||||
} else if (SymIsImport (Sym)) {
|
||||
|
||||
/* The symbol is an import. Track the symbols used and update the
|
||||
* address size.
|
||||
*/
|
||||
** address size.
|
||||
*/
|
||||
ED_SymRef* SymRef = ED_GetSymRef (D, Sym);
|
||||
++SymRef->Count;
|
||||
ED_UpdateAddrSize (D, GetSymAddrSize (Sym));
|
||||
@@ -566,17 +566,17 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
|
||||
SymTable* Parent;
|
||||
|
||||
/* The symbol is undefined. Track symbol usage but set the "too
|
||||
* complex" flag, since we cannot evaluate the final result.
|
||||
*/
|
||||
** complex" flag, since we cannot evaluate the final result.
|
||||
*/
|
||||
ED_SymRef* SymRef = ED_GetSymRef (D, Sym);
|
||||
++SymRef->Count;
|
||||
ED_Invalidate (D);
|
||||
|
||||
/* Since the symbol may be a forward, and we may need a statement
|
||||
* about the address size, check higher lexical levels for a symbol
|
||||
* with the same name and use its address size if we find such a
|
||||
* symbol which is defined.
|
||||
*/
|
||||
** about the address size, check higher lexical levels for a symbol
|
||||
** with the same name and use its address size if we find such a
|
||||
** symbol which is defined.
|
||||
*/
|
||||
AddrSize = GetSymAddrSize (Sym);
|
||||
Parent = GetSymParentScope (Sym);
|
||||
if (AddrSize == ADDR_SIZE_DEFAULT && Parent != 0) {
|
||||
@@ -612,8 +612,8 @@ static void StudyULabel (ExprNode* Expr, ExprDesc* D)
|
||||
/* Study an unnamed label expression node */
|
||||
{
|
||||
/* If we can resolve the label, study the expression associated with it,
|
||||
* otherwise mark the expression as too complex to evaluate.
|
||||
*/
|
||||
** otherwise mark the expression as too complex to evaluate.
|
||||
*/
|
||||
if (ULabCanResolve ()) {
|
||||
/* We can resolve the label */
|
||||
StudyExprInternal (ULabResolve (Expr->V.IVal), D);
|
||||
@@ -707,8 +707,8 @@ static void StudyMul (ExprNode* Expr, ExprDesc* D)
|
||||
StudyExprInternal (Expr->Right, &Right);
|
||||
|
||||
/* We can handle the operation if at least one of both operands is const
|
||||
* and the other one is valid.
|
||||
*/
|
||||
** and the other one is valid.
|
||||
*/
|
||||
if (ED_IsConst (D) && ED_IsValid (&Right)) {
|
||||
|
||||
/* Multiplicate both, result goes into Right */
|
||||
@@ -1480,24 +1480,24 @@ void StudyExpr (ExprNode* Expr, ExprDesc* D)
|
||||
}
|
||||
|
||||
/* If we don't have an address size, assign one if the expression is a
|
||||
* constant.
|
||||
*/
|
||||
** constant.
|
||||
*/
|
||||
if (D->AddrSize == ADDR_SIZE_DEFAULT && ED_IsConst (D)) {
|
||||
D->AddrSize = GetConstAddrSize (D->Val);
|
||||
}
|
||||
|
||||
/* If the expression is valid, throw away the address size and recalculate
|
||||
* it using the data we have. This is more exact than the on-the-fly
|
||||
* calculation done when evaluating the tree, because symbols may have
|
||||
* been removed from the expression, and the final numeric value is now
|
||||
* known.
|
||||
*/
|
||||
** it using the data we have. This is more exact than the on-the-fly
|
||||
** calculation done when evaluating the tree, because symbols may have
|
||||
** been removed from the expression, and the final numeric value is now
|
||||
** known.
|
||||
*/
|
||||
if (ED_IsValid (D)) {
|
||||
unsigned char AddrSize;
|
||||
|
||||
/* If there are symbols or sections, use the largest one. If the
|
||||
* expression resolves to a const, use the address size of the value.
|
||||
*/
|
||||
** expression resolves to a const, use the address size of the value.
|
||||
*/
|
||||
if (D->SymCount > 0 || D->SecCount > 0) {
|
||||
|
||||
D->AddrSize = ADDR_SIZE_DEFAULT;
|
||||
|
||||
@@ -54,12 +54,12 @@
|
||||
|
||||
SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
|
||||
/* Parse a (possibly scoped) identifer. The scope of the name must exist and
|
||||
* is returned as function result, while the last part (the identifier) which
|
||||
* may be either a symbol or a scope depending on the context is returned in
|
||||
* Name. FullName is a string buffer that is used to store the full name of
|
||||
* the identifier including the scope. It is used internally and may be used
|
||||
* by the caller for error messages or similar.
|
||||
*/
|
||||
** is returned as function result, while the last part (the identifier) which
|
||||
** may be either a symbol or a scope depending on the context is returned in
|
||||
** Name. FullName is a string buffer that is used to store the full name of
|
||||
** the identifier including the scope. It is used internally and may be used
|
||||
** by the caller for error messages or similar.
|
||||
*/
|
||||
{
|
||||
SymTable* Scope;
|
||||
|
||||
@@ -89,8 +89,8 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
|
||||
SB_Append (FullName, Name);
|
||||
|
||||
/* The scope must exist, so search for it starting with the current
|
||||
* scope.
|
||||
*/
|
||||
** scope.
|
||||
*/
|
||||
Scope = SymFindAnyScope (CurrentScope, Name);
|
||||
if (Scope == 0) {
|
||||
/* Scope not found */
|
||||
@@ -125,8 +125,8 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
|
||||
NextTok ();
|
||||
|
||||
/* If a namespace token follows, we search for another scope, otherwise
|
||||
* the name is a symbol and we're done.
|
||||
*/
|
||||
** the name is a symbol and we're done.
|
||||
*/
|
||||
if (CurTok.Tok != TOK_NAMESPACE) {
|
||||
/* Symbol */
|
||||
return Scope;
|
||||
@@ -153,8 +153,8 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
|
||||
|
||||
SymEntry* ParseScopedSymName (SymFindAction Action)
|
||||
/* Parse a (possibly scoped) symbol name, search for it in the symbol table
|
||||
* and return the symbol table entry.
|
||||
*/
|
||||
** and return the symbol table entry.
|
||||
*/
|
||||
{
|
||||
StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
|
||||
StrBuf Ident = STATIC_STRBUF_INITIALIZER;
|
||||
@@ -171,12 +171,12 @@ SymEntry* ParseScopedSymName (SymFindAction Action)
|
||||
SB_Done (&ScopeName);
|
||||
|
||||
/* Check if the scope is valid. Errors have already been diagnosed by
|
||||
* the routine, so just exit.
|
||||
*/
|
||||
** the routine, so just exit.
|
||||
*/
|
||||
if (Scope) {
|
||||
/* Search for the symbol and return it. If no scope was specified,
|
||||
* search also in the upper levels.
|
||||
*/
|
||||
** search also in the upper levels.
|
||||
*/
|
||||
if (NoScope && (Action & SYM_ALLOC_NEW) == 0) {
|
||||
Sym = SymFindAny (Scope, &Ident);
|
||||
} else {
|
||||
@@ -184,9 +184,9 @@ SymEntry* ParseScopedSymName (SymFindAction Action)
|
||||
}
|
||||
} else {
|
||||
/* No scope ==> no symbol. To avoid errors in the calling routine that
|
||||
* may not expect NULL to be returned if Action contains SYM_ALLOC_NEW,
|
||||
* create a new symbol.
|
||||
*/
|
||||
** may not expect NULL to be returned if Action contains SYM_ALLOC_NEW,
|
||||
** create a new symbol.
|
||||
*/
|
||||
if (Action & SYM_ALLOC_NEW) {
|
||||
Sym = NewSymEntry (&Ident, SF_NONE);
|
||||
} else {
|
||||
@@ -205,8 +205,8 @@ SymEntry* ParseScopedSymName (SymFindAction Action)
|
||||
|
||||
SymTable* ParseScopedSymTable (void)
|
||||
/* Parse a (possibly scoped) symbol table (scope) name, search for it in the
|
||||
* symbol space and return the symbol table struct.
|
||||
*/
|
||||
** symbol space and return the symbol table struct.
|
||||
*/
|
||||
{
|
||||
StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
|
||||
StrBuf Name = STATIC_STRBUF_INITIALIZER;
|
||||
@@ -223,9 +223,9 @@ SymTable* ParseScopedSymTable (void)
|
||||
SB_Done (&ScopeName);
|
||||
|
||||
/* If we got no error, search for the child scope withint the enclosing one.
|
||||
* Beware: If no explicit parent scope was specified, search in all upper
|
||||
* levels.
|
||||
*/
|
||||
** Beware: If no explicit parent scope was specified, search in all upper
|
||||
** levels.
|
||||
*/
|
||||
if (Scope) {
|
||||
/* Search for the last scope */
|
||||
if (NoScope) {
|
||||
@@ -246,8 +246,8 @@ SymTable* ParseScopedSymTable (void)
|
||||
|
||||
SymEntry* ParseAnySymName (SymFindAction Action)
|
||||
/* Parse a cheap local symbol or a a (possibly scoped) symbol name, search
|
||||
* for it in the symbol table and return the symbol table entry.
|
||||
*/
|
||||
** for it in the symbol table and return the symbol table entry.
|
||||
*/
|
||||
{
|
||||
SymEntry* Sym;
|
||||
|
||||
|
||||
@@ -61,27 +61,27 @@ struct StrBuf;
|
||||
|
||||
struct SymTable* ParseScopedIdent (struct StrBuf* Name, struct StrBuf* FullName);
|
||||
/* Parse a (possibly scoped) identifer. The scope of the name must exist and
|
||||
* is returned as function result, while the last part (the identifier) which
|
||||
* may be either a symbol or a scope depending on the context is returned in
|
||||
* Name. FullName is a string buffer that is used to store the full name of
|
||||
* the identifier including the scope. It is used internally and may be used
|
||||
* by the caller for error messages or similar.
|
||||
*/
|
||||
** is returned as function result, while the last part (the identifier) which
|
||||
** may be either a symbol or a scope depending on the context is returned in
|
||||
** Name. FullName is a string buffer that is used to store the full name of
|
||||
** the identifier including the scope. It is used internally and may be used
|
||||
** by the caller for error messages or similar.
|
||||
*/
|
||||
|
||||
struct SymEntry* ParseScopedSymName (SymFindAction Action);
|
||||
/* Parse a (possibly scoped) symbol name, search for it in the symbol table
|
||||
* and return the symbol table entry.
|
||||
*/
|
||||
** and return the symbol table entry.
|
||||
*/
|
||||
|
||||
struct SymTable* ParseScopedSymTable (void);
|
||||
/* Parse a (possibly scoped) symbol table (scope) name, search for it in the
|
||||
* symbol space and return the symbol table struct.
|
||||
*/
|
||||
** symbol space and return the symbol table struct.
|
||||
*/
|
||||
|
||||
struct SymEntry* ParseAnySymName (SymFindAction Action);
|
||||
/* Parse a cheap local symbol or a a (possibly scoped) symbol name, search
|
||||
* for it in the symbol table and return the symbol table entry.
|
||||
*/
|
||||
** for it in the symbol table and return the symbol table entry.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -115,12 +115,12 @@ SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags)
|
||||
|
||||
int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E)
|
||||
/* Search in the given tree for a name. If we find the symbol, the function
|
||||
* will return 0 and put the entry pointer into E. If we did not find the
|
||||
* symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
|
||||
* E will be set to the last entry, and the result of the function is <0 if
|
||||
* the entry should be inserted on the left side, and >0 if it should get
|
||||
* inserted on the right side.
|
||||
*/
|
||||
** will return 0 and put the entry pointer into E. If we did not find the
|
||||
** symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
|
||||
** E will be set to the last entry, and the result of the function is <0 if
|
||||
** the entry should be inserted on the left side, and >0 if it should get
|
||||
** inserted on the right side.
|
||||
*/
|
||||
{
|
||||
/* Is there a tree? */
|
||||
if (T == 0) {
|
||||
@@ -196,8 +196,8 @@ static void SymReplaceExprRefs (SymEntry* S)
|
||||
CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
|
||||
|
||||
/* We cannot touch the root node, since there are pointers to it.
|
||||
* Replace it by a literal node.
|
||||
*/
|
||||
** Replace it by a literal node.
|
||||
*/
|
||||
E->Op = EXPR_LITERAL;
|
||||
E->V.IVal = Val;
|
||||
}
|
||||
@@ -234,8 +234,8 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
|
||||
return;
|
||||
}
|
||||
/* Delete the current symbol expression, since it will get
|
||||
* replaced
|
||||
*/
|
||||
** replaced
|
||||
*/
|
||||
FreeExpr (S->Expr);
|
||||
S->Expr = 0;
|
||||
}
|
||||
@@ -255,17 +255,17 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags
|
||||
S->Expr = Expr;
|
||||
|
||||
/* In case of a variable symbol, walk over all expressions containing
|
||||
* this symbol and replace the (sub-)expression by the literal value of
|
||||
* the tree. Be sure to replace the expression node in place, since there
|
||||
* may be pointers to it.
|
||||
*/
|
||||
** this symbol and replace the (sub-)expression by the literal value of
|
||||
** the tree. Be sure to replace the expression node in place, since there
|
||||
** may be pointers to it.
|
||||
*/
|
||||
if (Flags & SF_VAR) {
|
||||
SymReplaceExprRefs (S);
|
||||
}
|
||||
|
||||
/* If the symbol is marked as global, export it. Address size is checked
|
||||
* below.
|
||||
*/
|
||||
** below.
|
||||
*/
|
||||
if (S->Flags & SF_GLOBAL) {
|
||||
S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
|
||||
ReleaseFullLineInfo (&S->DefLines);
|
||||
@@ -326,15 +326,15 @@ void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
}
|
||||
|
||||
/* If no address size is given, use the address size of the enclosing
|
||||
* segment.
|
||||
*/
|
||||
** segment.
|
||||
*/
|
||||
if (AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
AddrSize = GetCurrentSegAddrSize ();
|
||||
}
|
||||
|
||||
/* If the symbol is marked as import or global, check the address size,
|
||||
* then do silently remove the global flag.
|
||||
*/
|
||||
** then do silently remove the global flag.
|
||||
*/
|
||||
if (S->Flags & SF_IMPORT) {
|
||||
if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
|
||||
Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
|
||||
@@ -355,9 +355,9 @@ void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
S->AddrSize = AddrSize;
|
||||
|
||||
/* Mark the position of the import as the position of the definition.
|
||||
* Please note: In case of multiple .global or .import statements, the line
|
||||
* infos add up.
|
||||
*/
|
||||
** Please note: In case of multiple .global or .import statements, the line
|
||||
** infos add up.
|
||||
*/
|
||||
GetFullLineInfo (&S->DefLines);
|
||||
}
|
||||
|
||||
@@ -379,8 +379,8 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
}
|
||||
|
||||
/* If the symbol was marked as global before, remove the global flag and
|
||||
* proceed, but check the address size.
|
||||
*/
|
||||
** proceed, but check the address size.
|
||||
*/
|
||||
if (S->Flags & SF_GLOBAL) {
|
||||
if (AddrSize != S->ExportSize) {
|
||||
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||
@@ -388,14 +388,14 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
S->Flags &= ~SF_GLOBAL;
|
||||
|
||||
/* .GLOBAL remembers line infos in case an .IMPORT follows. We have
|
||||
* to remove these here.
|
||||
*/
|
||||
** to remove these here.
|
||||
*/
|
||||
ReleaseFullLineInfo (&S->DefLines);
|
||||
}
|
||||
|
||||
/* If the symbol was already marked as an export, but wasn't defined
|
||||
* before, the address sizes in both definitions must match.
|
||||
*/
|
||||
** before, the address sizes in both definitions must match.
|
||||
*/
|
||||
if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
|
||||
if (S->ExportSize != AddrSize) {
|
||||
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||
@@ -404,8 +404,8 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
S->ExportSize = AddrSize;
|
||||
|
||||
/* If the symbol is already defined, check symbol size against the
|
||||
* exported size.
|
||||
*/
|
||||
** exported size.
|
||||
*/
|
||||
if (S->Flags & SF_DEFINED) {
|
||||
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
||||
/* No export size given, use the real size of the symbol */
|
||||
@@ -429,8 +429,8 @@ void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
|
||||
void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
||||
* either imported or exported.
|
||||
*/
|
||||
** either imported or exported.
|
||||
*/
|
||||
{
|
||||
if (S->Flags & SF_VAR) {
|
||||
/* Variable symbols cannot be exported or imported */
|
||||
@@ -439,8 +439,8 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
}
|
||||
|
||||
/* If the symbol is already marked as import, the address size must match.
|
||||
* Apart from that, ignore the global declaration.
|
||||
*/
|
||||
** Apart from that, ignore the global declaration.
|
||||
*/
|
||||
if (S->Flags & SF_IMPORT) {
|
||||
if (AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
/* Use the size of the current segment */
|
||||
@@ -453,8 +453,8 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
}
|
||||
|
||||
/* If the symbol is already an export: If it is not defined, the address
|
||||
* sizes must match.
|
||||
*/
|
||||
** sizes must match.
|
||||
*/
|
||||
if (S->Flags & SF_EXPORT) {
|
||||
if ((S->Flags & SF_DEFINED) == 0) {
|
||||
/* Symbol is undefined */
|
||||
@@ -471,9 +471,9 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
}
|
||||
|
||||
/* If the symbol is already marked as global, the address size must match.
|
||||
* Use the ExportSize here, since it contains the actual address size
|
||||
* passed to this function.
|
||||
*/
|
||||
** Use the ExportSize here, since it contains the actual address size
|
||||
** passed to this function.
|
||||
*/
|
||||
if (S->Flags & SF_GLOBAL) {
|
||||
if (AddrSize != S->ExportSize) {
|
||||
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||
@@ -482,10 +482,10 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
}
|
||||
|
||||
/* If we come here, the symbol was neither declared as export, import or
|
||||
* global before. Check if it is already defined, in which case it will
|
||||
* become an export. If it is not defined, mark it as global and remember
|
||||
* the given address sizes.
|
||||
*/
|
||||
** global before. Check if it is already defined, in which case it will
|
||||
** become an export. If it is not defined, mark it as global and remember
|
||||
** the given address sizes.
|
||||
*/
|
||||
if (S->Flags & SF_DEFINED) {
|
||||
/* The symbol is defined, export it */
|
||||
S->ExportSize = AddrSize;
|
||||
@@ -501,9 +501,9 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
S->Flags |= (SF_EXPORT | Flags);
|
||||
} else {
|
||||
/* Since we don't know if the symbol will get exported or imported,
|
||||
* remember two different address sizes: One for an import in AddrSize,
|
||||
* and the other one for an export in ExportSize.
|
||||
*/
|
||||
** remember two different address sizes: One for an import in AddrSize,
|
||||
** and the other one for an export in ExportSize.
|
||||
*/
|
||||
S->AddrSize = AddrSize;
|
||||
if (S->AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
/* Use the size of the current segment */
|
||||
@@ -513,8 +513,8 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
S->Flags |= (SF_GLOBAL | Flags);
|
||||
|
||||
/* Remember the current location as location of definition in case
|
||||
* an .IMPORT follows later.
|
||||
*/
|
||||
** an .IMPORT follows later.
|
||||
*/
|
||||
GetFullLineInfo (&S->DefLines);
|
||||
}
|
||||
}
|
||||
@@ -523,8 +523,8 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||
|
||||
void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
|
||||
/* Mark the given symbol as a module constructor/destructor. This will also
|
||||
* mark the symbol as an export. Initializers may never be zero page symbols.
|
||||
*/
|
||||
** mark the symbol as an export. Initializers may never be zero page symbols.
|
||||
*/
|
||||
{
|
||||
/* Check the parameters */
|
||||
#if (CD_TYPE_MIN != 0)
|
||||
@@ -547,9 +547,9 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
||||
}
|
||||
|
||||
/* If the symbol was already marked as an export or global, check if
|
||||
* this was done specifiying the same address size. In case of a global
|
||||
* declaration, silently remove the global flag.
|
||||
*/
|
||||
** this was done specifiying the same address size. In case of a global
|
||||
** declaration, silently remove the global flag.
|
||||
*/
|
||||
if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
|
||||
if (S->ExportSize != AddrSize) {
|
||||
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
||||
@@ -559,8 +559,8 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
||||
S->ExportSize = AddrSize;
|
||||
|
||||
/* If the symbol is already defined, check symbol size against the
|
||||
* exported size.
|
||||
*/
|
||||
** exported size.
|
||||
*/
|
||||
if (S->Flags & SF_DEFINED) {
|
||||
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
||||
/* Use the real size of the symbol */
|
||||
@@ -571,8 +571,8 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
||||
}
|
||||
|
||||
/* If the symbol was already declared as a condes, check if the new
|
||||
* priority value is the same as the old one.
|
||||
*/
|
||||
** priority value is the same as the old one.
|
||||
*/
|
||||
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
|
||||
if (S->ConDesPrio[Type] != Prio) {
|
||||
Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
|
||||
@@ -593,10 +593,10 @@ void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Pri
|
||||
|
||||
void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
|
||||
/* Mark the address size of the given symbol as guessed. The address size
|
||||
* passed as argument is the one NOT used, because the actual address size
|
||||
* wasn't known. Example: Zero page addressing was not used because symbol
|
||||
* is undefined, and absolute addressing was available.
|
||||
*/
|
||||
** passed as argument is the one NOT used, because the actual address size
|
||||
** wasn't known. Example: Zero page addressing was not used because symbol
|
||||
** is undefined, and absolute addressing was available.
|
||||
*/
|
||||
{
|
||||
/* We must have a valid address size passed */
|
||||
PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
|
||||
@@ -619,8 +619,8 @@ void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
|
||||
|
||||
void SymExportFromGlobal (SymEntry* S)
|
||||
/* Called at the end of assembly. Converts a global symbol that is defined
|
||||
* into an export.
|
||||
*/
|
||||
** into an export.
|
||||
*/
|
||||
{
|
||||
/* Remove the global flag and make the symbol an export */
|
||||
S->Flags &= ~SF_GLOBAL;
|
||||
@@ -631,8 +631,8 @@ void SymExportFromGlobal (SymEntry* S)
|
||||
|
||||
void SymImportFromGlobal (SymEntry* S)
|
||||
/* Called at the end of assembly. Converts a global symbol that is undefined
|
||||
* into an import.
|
||||
*/
|
||||
** into an import.
|
||||
*/
|
||||
{
|
||||
/* Remove the global flag and make it an import */
|
||||
S->Flags &= ~SF_GLOBAL;
|
||||
@@ -643,8 +643,8 @@ void SymImportFromGlobal (SymEntry* S)
|
||||
|
||||
int SymIsConst (const SymEntry* S, long* Val)
|
||||
/* Return true if the given symbol has a constant value. If Val is not NULL
|
||||
* and the symbol has a constant value, store it's value there.
|
||||
*/
|
||||
** and the symbol has a constant value, store it's value there.
|
||||
*/
|
||||
{
|
||||
/* Check for constness */
|
||||
return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
|
||||
@@ -654,16 +654,16 @@ int SymIsConst (const SymEntry* S, long* Val)
|
||||
|
||||
SymTable* GetSymParentScope (SymEntry* S)
|
||||
/* Get the parent scope of the symbol (not the one it is defined in). Return
|
||||
* NULL if the symbol is a cheap local, or defined on global level.
|
||||
*/
|
||||
** NULL if the symbol is a cheap local, or defined on global level.
|
||||
*/
|
||||
{
|
||||
if ((S->Flags & SF_LOCAL) != 0) {
|
||||
/* This is a cheap local symbol */
|
||||
return 0;
|
||||
} else if (S->Sym.Tab == 0) {
|
||||
/* Symbol not in a table. This may happen if there have been errors
|
||||
* before. Return NULL in this case to avoid further errors.
|
||||
*/
|
||||
** before. Return NULL in this case to avoid further errors.
|
||||
*/
|
||||
return 0;
|
||||
} else {
|
||||
/* This is a global symbol */
|
||||
@@ -684,8 +684,8 @@ struct ExprNode* GetSymExpr (SymEntry* S)
|
||||
|
||||
const struct ExprNode* SymResolve (const SymEntry* S)
|
||||
/* Helper function for DumpExpr. Resolves a symbol into an expression or return
|
||||
* NULL. Do not call in other contexts!
|
||||
*/
|
||||
** NULL. Do not call in other contexts!
|
||||
*/
|
||||
{
|
||||
return SymHasExpr (S)? S->Expr : 0;
|
||||
}
|
||||
@@ -694,8 +694,8 @@ const struct ExprNode* SymResolve (const SymEntry* S)
|
||||
|
||||
long GetSymVal (SymEntry* S)
|
||||
/* Return the value of a symbol assuming it's constant. FAIL will be called
|
||||
* in case the symbol is undefined or not constant.
|
||||
*/
|
||||
** in case the symbol is undefined or not constant.
|
||||
*/
|
||||
{
|
||||
long Val;
|
||||
CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
|
||||
@@ -724,10 +724,10 @@ unsigned GetSymExportId (const SymEntry* S)
|
||||
|
||||
unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
|
||||
/* Return a set of flags used when writing symbol information into a file.
|
||||
* If the SYM_CONST bit is set, ConstVal will contain the constant value
|
||||
* of the symbol. The result does not include the condes count.
|
||||
* See common/symdefs.h for more information.
|
||||
*/
|
||||
** If the SYM_CONST bit is set, ConstVal will contain the constant value
|
||||
** of the symbol. The result does not include the condes count.
|
||||
** See common/symdefs.h for more information.
|
||||
*/
|
||||
{
|
||||
/* Setup info flags */
|
||||
unsigned Flags = 0;
|
||||
|
||||
@@ -92,11 +92,11 @@ struct SymEntry {
|
||||
Collection DefLines; /* Line infos for definition */
|
||||
Collection RefLines; /* Line infos for references */
|
||||
FilePos* GuessedUse[1]; /* File position where symbol
|
||||
* address size was guessed, and the
|
||||
* smallest possible addressing was NOT
|
||||
* used. Currently only for zero page
|
||||
* addressing
|
||||
*/
|
||||
** address size was guessed, and the
|
||||
** smallest possible addressing was NOT
|
||||
** used. Currently only for zero page
|
||||
** addressing
|
||||
*/
|
||||
struct HLLDbgSym* HLLSym; /* Symbol from high level language */
|
||||
unsigned Flags; /* Symbol flags */
|
||||
unsigned DebugSymId; /* Debug symbol id */
|
||||
@@ -130,12 +130,12 @@ SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags);
|
||||
|
||||
int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E);
|
||||
/* Search in the given tree for a name. If we find the symbol, the function
|
||||
* will return 0 and put the entry pointer into E. If we did not find the
|
||||
* symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
|
||||
* E will be set to the last entry, and the result of the function is <0 if
|
||||
* the entry should be inserted on the left side, and >0 if it should get
|
||||
* inserted on the right side.
|
||||
*/
|
||||
** will return 0 and put the entry pointer into E. If we did not find the
|
||||
** symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
|
||||
** E will be set to the last entry, and the result of the function is <0 if
|
||||
** the entry should be inserted on the left side, and >0 if it should get
|
||||
** inserted on the right side.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void SymAddExprRef (SymEntry* Sym, struct ExprNode* Expr)
|
||||
@@ -174,30 +174,30 @@ void SymExport (SymEntry* Sym, unsigned char AddrSize, unsigned Flags);
|
||||
|
||||
void SymGlobal (SymEntry* Sym, unsigned char AddrSize, unsigned Flags);
|
||||
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
||||
* either imported or exported.
|
||||
*/
|
||||
** either imported or exported.
|
||||
*/
|
||||
|
||||
void SymConDes (SymEntry* Sym, unsigned char AddrSize, unsigned Type, unsigned Prio);
|
||||
/* Mark the given symbol as a module constructor/destructor. This will also
|
||||
* mark the symbol as an export. Initializers may never be zero page symbols.
|
||||
*/
|
||||
** mark the symbol as an export. Initializers may never be zero page symbols.
|
||||
*/
|
||||
|
||||
void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize);
|
||||
/* Mark the address size of the given symbol as guessed. The address size
|
||||
* passed as argument is the one NOT used, because the actual address size
|
||||
* wasn't known. Example: Zero page addressing was not used because symbol
|
||||
* is undefined, and absolute addressing was available.
|
||||
*/
|
||||
** passed as argument is the one NOT used, because the actual address size
|
||||
** wasn't known. Example: Zero page addressing was not used because symbol
|
||||
** is undefined, and absolute addressing was available.
|
||||
*/
|
||||
|
||||
void SymExportFromGlobal (SymEntry* S);
|
||||
/* Called at the end of assembly. Converts a global symbol that is defined
|
||||
* into an export.
|
||||
*/
|
||||
** into an export.
|
||||
*/
|
||||
|
||||
void SymImportFromGlobal (SymEntry* S);
|
||||
/* Called at the end of assembly. Converts a global symbol that is undefined
|
||||
* into an import.
|
||||
*/
|
||||
** into an import.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int SymIsDef (const SymEntry* S)
|
||||
@@ -254,8 +254,8 @@ INLINE int SymIsVar (const SymEntry* S)
|
||||
|
||||
int SymIsConst (const SymEntry* Sym, long* Val);
|
||||
/* Return true if the given symbol has a constant value. If Val is not NULL
|
||||
* and the symbol has a constant value, store it's value there.
|
||||
*/
|
||||
** and the symbol has a constant value, store it's value there.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int SymHasExpr (const SymEntry* S)
|
||||
@@ -303,16 +303,16 @@ INLINE int SymHasUserMark (SymEntry* S)
|
||||
|
||||
struct SymTable* GetSymParentScope (SymEntry* S);
|
||||
/* Get the parent scope of the symbol (not the one it is defined in). Return
|
||||
* NULL if the symbol is a cheap local, or defined on global level.
|
||||
*/
|
||||
** NULL if the symbol is a cheap local, or defined on global level.
|
||||
*/
|
||||
|
||||
struct ExprNode* GetSymExpr (SymEntry* Sym);
|
||||
/* Get the expression for a non-const symbol */
|
||||
|
||||
const struct ExprNode* SymResolve (const SymEntry* Sym);
|
||||
/* Helper function for DumpExpr. Resolves a symbol into an expression or return
|
||||
* NULL. Do not call in other contexts!
|
||||
*/
|
||||
** NULL. Do not call in other contexts!
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE const StrBuf* GetSymName (const SymEntry* S)
|
||||
@@ -327,8 +327,8 @@ INLINE const StrBuf* GetSymName (const SymEntry* S)
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned char GetSymAddrSize (const SymEntry* S)
|
||||
/* Return the address size of the symbol. Beware: This function will just
|
||||
* return the AddrSize member, it will not look at the expression!
|
||||
*/
|
||||
** return the AddrSize member, it will not look at the expression!
|
||||
*/
|
||||
{
|
||||
return S->AddrSize;
|
||||
}
|
||||
@@ -338,8 +338,8 @@ INLINE unsigned char GetSymAddrSize (const SymEntry* S)
|
||||
|
||||
long GetSymVal (SymEntry* Sym);
|
||||
/* Return the value of a symbol assuming it's constant. FAIL will be called
|
||||
* in case the symbol is undefined or not constant.
|
||||
*/
|
||||
** in case the symbol is undefined or not constant.
|
||||
*/
|
||||
|
||||
unsigned GetSymImportId (const SymEntry* Sym);
|
||||
/* Return the import id for the given symbol */
|
||||
@@ -349,10 +349,10 @@ unsigned GetSymExportId (const SymEntry* Sym);
|
||||
|
||||
unsigned GetSymInfoFlags (const SymEntry* Sym, long* ConstVal);
|
||||
/* Return a set of flags used when writing symbol information into a file.
|
||||
* If the SYM_CONST bit is set, ConstVal will contain the constant value
|
||||
* of the symbol. The result does not include the condes count.
|
||||
* See common/symdefs.h for more information.
|
||||
*/
|
||||
** If the SYM_CONST bit is set, ConstVal will contain the constant value
|
||||
** of the symbol. The result does not include the condes count.
|
||||
** See common/symdefs.h for more information.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -207,8 +207,8 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
|
||||
}
|
||||
|
||||
/* If we have a current scope, search for the given name and create a
|
||||
* new one if it doesn't exist. If this is the root scope, just create it.
|
||||
*/
|
||||
** new one if it doesn't exist. If this is the root scope, just create it.
|
||||
*/
|
||||
if (CurrentScope) {
|
||||
|
||||
/* Search for the scope, create a new one */
|
||||
@@ -230,11 +230,11 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
|
||||
CurrentScope->Label = ScopeLabel;
|
||||
|
||||
/* If this is a scope that allows to emit data into segments, add spans
|
||||
* for all currently existing segments. Doing this for just a few scope
|
||||
* types is not really necessary but an optimization, because it does not
|
||||
* allocate memory for useless data (unhandled types here don't occupy
|
||||
* space in any segment).
|
||||
*/
|
||||
** for all currently existing segments. Doing this for just a few scope
|
||||
** types is not really necessary but an optimization, because it does not
|
||||
** allocate memory for useless data (unhandled types here don't occupy
|
||||
** space in any segment).
|
||||
*/
|
||||
if (CurrentScope->Type <= SCOPE_HAS_DATA) {
|
||||
OpenSpanList (&CurrentScope->Spans);
|
||||
}
|
||||
@@ -246,17 +246,17 @@ void SymLeaveLevel (void)
|
||||
/* Leave the current lexical level */
|
||||
{
|
||||
/* If this is a scope that allows to emit data into segments, close the
|
||||
* open the spans.
|
||||
*/
|
||||
** open the spans.
|
||||
*/
|
||||
if (CurrentScope->Type <= SCOPE_HAS_DATA) {
|
||||
CloseSpanList (&CurrentScope->Spans);
|
||||
}
|
||||
|
||||
/* If we have spans, the first one is the segment that was active, when the
|
||||
* scope was opened. Set the size of the scope to the number of data bytes
|
||||
* emitted into this segment. If we have an owner symbol set the size of
|
||||
* this symbol, too.
|
||||
*/
|
||||
** scope was opened. Set the size of the scope to the number of data bytes
|
||||
** emitted into this segment. If we have an owner symbol set the size of
|
||||
** this symbol, too.
|
||||
*/
|
||||
if (CollCount (&CurrentScope->Spans) > 0) {
|
||||
const Span* S = CollAtUnchecked (&CurrentScope->Spans, 0);
|
||||
unsigned long Size = GetSpanSize (S);
|
||||
@@ -304,9 +304,9 @@ SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, SymFindAction Acti
|
||||
|
||||
SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name)
|
||||
/* Find a scope in the given or any of its parent scopes. The function will
|
||||
* never create a new symbol, since this can only be done in one specific
|
||||
* scope.
|
||||
*/
|
||||
** never create a new symbol, since this can only be done in one specific
|
||||
** scope.
|
||||
*/
|
||||
{
|
||||
SymTable* Scope;
|
||||
do {
|
||||
@@ -325,9 +325,9 @@ SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name)
|
||||
|
||||
SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, SymFindAction Action)
|
||||
/* Find a cheap local symbol. If Action contains SYM_ALLOC_NEW and the entry is
|
||||
* not found, create a new one. Return the entry found, or the new entry
|
||||
* created, or - in case Action is SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
** not found, create a new one. Return the entry found, or the new entry
|
||||
** created, or - in case Action is SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
|
||||
{
|
||||
SymEntry* S;
|
||||
@@ -375,10 +375,10 @@ SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, SymFindAction Acti
|
||||
|
||||
SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, SymFindAction Action)
|
||||
/* Find a new symbol table entry in the given table. If Action contains
|
||||
* SYM_ALLOC_NEW and the entry is not found, create a new one. Return the
|
||||
* entry found, or the new entry created, or - in case Action is
|
||||
* SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
** SYM_ALLOC_NEW and the entry is not found, create a new one. Return the
|
||||
** entry found, or the new entry created, or - in case Action is
|
||||
** SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
{
|
||||
SymEntry* S;
|
||||
|
||||
@@ -399,9 +399,9 @@ SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, SymFindAction Action)
|
||||
if (Action & SYM_ALLOC_NEW) {
|
||||
|
||||
/* Otherwise create a new entry, insert and return it. If the scope is
|
||||
* already closed, mark the symbol as fixed so it won't be resolved
|
||||
* by a symbol in the enclosing scopes later.
|
||||
*/
|
||||
** already closed, mark the symbol as fixed so it won't be resolved
|
||||
** by a symbol in the enclosing scopes later.
|
||||
*/
|
||||
SymEntry* N = NewSymEntry (Name, SF_NONE);
|
||||
if (SymTabIsClosed (Scope)) {
|
||||
N->Flags |= SF_FIXED;
|
||||
@@ -427,9 +427,9 @@ SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, SymFindAction Action)
|
||||
|
||||
SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name)
|
||||
/* Find a symbol in the given or any of its parent scopes. The function will
|
||||
* never create a new symbol, since this can only be done in one specific
|
||||
* scope.
|
||||
*/
|
||||
** never create a new symbol, since this can only be done in one specific
|
||||
** scope.
|
||||
*/
|
||||
{
|
||||
/* Generate the name hash */
|
||||
unsigned Hash = HashBuf (Name);
|
||||
@@ -438,9 +438,9 @@ SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name)
|
||||
SymEntry* Sym;
|
||||
do {
|
||||
/* Search in the current table. Ignore entries flagged with SF_UNUSED,
|
||||
* because for such symbols there is a real entry in one of the parent
|
||||
* scopes.
|
||||
*/
|
||||
** because for such symbols there is a real entry in one of the parent
|
||||
** scopes.
|
||||
*/
|
||||
if (SymSearchTree (Scope->Table[Hash % Scope->TableSlots], Name, &Sym) == 0) {
|
||||
if (Sym->Flags & SF_UNUSED) {
|
||||
Sym = 0;
|
||||
@@ -467,15 +467,15 @@ static void SymCheckUndefined (SymEntry* S)
|
||||
/* Handle an undefined symbol */
|
||||
{
|
||||
/* Undefined symbol. It may be...
|
||||
*
|
||||
* - An undefined symbol in a nested lexical level. If the symbol is not
|
||||
* fixed to this level, search for the symbol in the higher levels and
|
||||
* make the entry a trampoline entry if we find one.
|
||||
*
|
||||
* - If the symbol is not found, it is a real undefined symbol. If the
|
||||
* AutoImport flag is set, make it an import. If the AutoImport flag is
|
||||
* not set, it's an error.
|
||||
*/
|
||||
**
|
||||
** - An undefined symbol in a nested lexical level. If the symbol is not
|
||||
** fixed to this level, search for the symbol in the higher levels and
|
||||
** make the entry a trampoline entry if we find one.
|
||||
**
|
||||
** - If the symbol is not found, it is a real undefined symbol. If the
|
||||
** AutoImport flag is set, make it an import. If the AutoImport flag is
|
||||
** not set, it's an error.
|
||||
*/
|
||||
SymEntry* Sym = 0;
|
||||
if ((S->Flags & SF_FIXED) == 0) {
|
||||
SymTable* Tab = GetSymParentScope (S);
|
||||
@@ -483,8 +483,8 @@ static void SymCheckUndefined (SymEntry* S)
|
||||
Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING | SYM_CHECK_ONLY);
|
||||
if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
|
||||
/* We've found a symbol in a higher level that is
|
||||
* either defined in the source, or an import.
|
||||
*/
|
||||
** either defined in the source, or an import.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
/* No matching symbol found in this level. Look further */
|
||||
@@ -495,9 +495,9 @@ static void SymCheckUndefined (SymEntry* S)
|
||||
if (Sym) {
|
||||
|
||||
/* We found the symbol in a higher level. Transfer the flags and
|
||||
* address size from the local symbol to that in the higher level
|
||||
* and check for problems.
|
||||
*/
|
||||
** address size from the local symbol to that in the higher level
|
||||
** and check for problems.
|
||||
*/
|
||||
if (S->Flags & SF_EXPORT) {
|
||||
if (Sym->Flags & SF_IMPORT) {
|
||||
/* The symbol is already marked as import */
|
||||
@@ -574,13 +574,13 @@ void SymCheck (void)
|
||||
}
|
||||
|
||||
/* First pass: Walk through all symbols, checking for undefined's and
|
||||
* changing them to trampoline symbols or make them imports.
|
||||
*/
|
||||
** changing them to trampoline symbols or make them imports.
|
||||
*/
|
||||
S = SymList;
|
||||
while (S) {
|
||||
/* If the symbol is marked as global, mark it as export, if it is
|
||||
* already defined, otherwise mark it as import.
|
||||
*/
|
||||
** already defined, otherwise mark it as import.
|
||||
*/
|
||||
if (S->Flags & SF_GLOBAL) {
|
||||
if (S->Flags & SF_DEFINED) {
|
||||
SymExportFromGlobal (S);
|
||||
@@ -600,10 +600,10 @@ void SymCheck (void)
|
||||
}
|
||||
|
||||
/* Second pass: Walk again through the symbols. Count exports and imports
|
||||
* and set address sizes where this has not happened before. Ignore
|
||||
* undefined's, since we handled them in the last pass, and ignore unused
|
||||
* symbols, since we handled them in the last pass, too.
|
||||
*/
|
||||
** and set address sizes where this has not happened before. Ignore
|
||||
** undefined's, since we handled them in the last pass, and ignore unused
|
||||
** symbols, since we handled them in the last pass, too.
|
||||
*/
|
||||
S = SymList;
|
||||
while (S) {
|
||||
if ((S->Flags & SF_UNUSED) == 0 &&
|
||||
@@ -639,8 +639,8 @@ void SymCheck (void)
|
||||
}
|
||||
|
||||
/* If the symbol is defined but has an unknown address size,
|
||||
* recalculate it.
|
||||
*/
|
||||
** recalculate it.
|
||||
*/
|
||||
if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
ExprDesc ED;
|
||||
ED_Init (&ED);
|
||||
@@ -663,9 +663,9 @@ void SymCheck (void)
|
||||
}
|
||||
|
||||
/* If the address size of the symbol was guessed, check the guess
|
||||
* against the actual address size and print a warning if the two
|
||||
* differ.
|
||||
*/
|
||||
** against the actual address size and print a warning if the two
|
||||
** differ.
|
||||
*/
|
||||
if (S->AddrSize != ADDR_SIZE_DEFAULT) {
|
||||
/* Do we have data for this address size? */
|
||||
if (S->AddrSize <= sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0])) {
|
||||
@@ -725,10 +725,10 @@ void WriteImports (void)
|
||||
ObjWriteVar (ImportCount);
|
||||
|
||||
/* Walk throught list and write all valid imports to the file. An import
|
||||
* is considered valid, if it is either referenced, or the forced bit is
|
||||
* set. Otherwise, the import is ignored (no need to link in something
|
||||
* that isn't used).
|
||||
*/
|
||||
** is considered valid, if it is either referenced, or the forced bit is
|
||||
** set. Otherwise, the import is ignored (no need to link in something
|
||||
** that isn't used).
|
||||
*/
|
||||
S = SymList;
|
||||
while (S) {
|
||||
if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
|
||||
@@ -770,8 +770,8 @@ void WriteExports (void)
|
||||
unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
|
||||
|
||||
/* Check if this symbol has a size. If so, remember it in the
|
||||
* flags.
|
||||
*/
|
||||
** flags.
|
||||
*/
|
||||
long Size;
|
||||
SymEntry* SizeSym = FindSizeOfSymbol (S);
|
||||
if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
|
||||
@@ -855,8 +855,8 @@ void WriteDbgSyms (void)
|
||||
ObjWriteVar (Count);
|
||||
|
||||
/* Walk through list and write all symbols to the file. Ignore size
|
||||
* symbols.
|
||||
*/
|
||||
** symbols.
|
||||
*/
|
||||
S = SymList;
|
||||
while (S) {
|
||||
if (IsDbgSym (S)) {
|
||||
@@ -866,8 +866,8 @@ void WriteDbgSyms (void)
|
||||
unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
|
||||
|
||||
/* Check if this symbol has a size. If so, remember it in the
|
||||
* flags.
|
||||
*/
|
||||
** flags.
|
||||
*/
|
||||
long Size;
|
||||
SymEntry* SizeSym = FindSizeOfSymbol (S);
|
||||
if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
|
||||
@@ -881,8 +881,8 @@ void WriteDbgSyms (void)
|
||||
ObjWrite8 (S->AddrSize);
|
||||
|
||||
/* Write the id of the parent. For normal symbols, this is a
|
||||
* scope (symbol table), for cheap locals, it's a symbol.
|
||||
*/
|
||||
** scope (symbol table), for cheap locals, it's a symbol.
|
||||
*/
|
||||
if (SYM_IS_STD (SymFlags)) {
|
||||
ObjWriteVar (S->Sym.Tab->Id);
|
||||
} else {
|
||||
@@ -959,8 +959,8 @@ void WriteScopes (void)
|
||||
unsigned Flags = 0;
|
||||
|
||||
/* Check if this scope has a size. If so, remember it in the
|
||||
* flags.
|
||||
*/
|
||||
** flags.
|
||||
*/
|
||||
long Size;
|
||||
SymEntry* SizeSym = FindSizeOfScope (S);
|
||||
if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
|
||||
|
||||
@@ -112,28 +112,28 @@ SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, SymFindAction Acti
|
||||
|
||||
SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name);
|
||||
/* Find a scope in the given or any of its parent scopes. The function will
|
||||
* never create a new symbol, since this can only be done in one specific
|
||||
* scope.
|
||||
*/
|
||||
** never create a new symbol, since this can only be done in one specific
|
||||
** scope.
|
||||
*/
|
||||
|
||||
SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, SymFindAction Action);
|
||||
/* Find a cheap local symbol. If Action contains SYM_ALLOC_NEW and the entry is
|
||||
* not found, create a new one. Return the entry found, or the new entry
|
||||
* created, or - in case Action is SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
** not found, create a new one. Return the entry found, or the new entry
|
||||
** created, or - in case Action is SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
|
||||
SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, SymFindAction Action);
|
||||
/* Find a new symbol table entry in the given table. If Action contains
|
||||
* SYM_ALLOC_NEW and the entry is not found, create a new one. Return the
|
||||
* entry found, or the new entry created, or - in case Action is
|
||||
* SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
** SYM_ALLOC_NEW and the entry is not found, create a new one. Return the
|
||||
** entry found, or the new entry created, or - in case Action is
|
||||
** SYM_FIND_EXISTING - return 0.
|
||||
*/
|
||||
|
||||
SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name);
|
||||
/* Find a symbol in the given or any of its parent scopes. The function will
|
||||
* never create a new symbol, since this can only be done in one specific
|
||||
* scope.
|
||||
*/
|
||||
** never create a new symbol, since this can only be done in one specific
|
||||
** scope.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned char GetSymTabType (const SymTable* S)
|
||||
|
||||
@@ -62,8 +62,8 @@ int TokHasIVal (token_t Tok)
|
||||
|
||||
void CopyToken (Token* Dst, const Token* Src)
|
||||
/* Copy a token from Src to Dst. The current value of Dst.SVal is free'd,
|
||||
* so Dst must be initialized.
|
||||
*/
|
||||
** so Dst must be initialized.
|
||||
*/
|
||||
{
|
||||
/* Copy the fields */
|
||||
Dst->Tok = Src->Tok;
|
||||
|
||||
@@ -306,8 +306,8 @@ INLINE int TokIsSep (enum token_t T)
|
||||
|
||||
void CopyToken (Token* Dst, const Token* Src);
|
||||
/* Copy a token. The current value of Dst.SVal is free'd, so Dst must be
|
||||
* initialized.
|
||||
*/
|
||||
** initialized.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -180,9 +180,9 @@ void FreeTokList (TokList* List)
|
||||
|
||||
enum token_t GetTokListTerm (enum token_t Term)
|
||||
/* Determine if the following token list is enclosed in curly braces. This is
|
||||
* the case if the next token is the opening brace. If so, skip it and return
|
||||
* a closing brace, otherwise return Term.
|
||||
*/
|
||||
** the case if the next token is the opening brace. If so, skip it and return
|
||||
** a closing brace, otherwise return Term.
|
||||
*/
|
||||
{
|
||||
if (CurTok.Tok == TOK_LCURLY) {
|
||||
NextTok ();
|
||||
@@ -216,16 +216,16 @@ void AddCurTok (TokList* List)
|
||||
|
||||
static int ReplayTokList (void* List)
|
||||
/* Function that gets the next token from a token list and sets it. This
|
||||
* function may be used together with the PushInput function from the istack
|
||||
* module.
|
||||
*/
|
||||
** function may be used together with the PushInput function from the istack
|
||||
** module.
|
||||
*/
|
||||
{
|
||||
/* Cast the generic pointer to an actual list */
|
||||
TokList* L = List;
|
||||
|
||||
/* If there are no more tokens, decrement the repeat counter. If it goes
|
||||
* zero, delete the list and remove the function from the stack.
|
||||
*/
|
||||
** zero, delete the list and remove the function from the stack.
|
||||
*/
|
||||
if (L->Last == 0) {
|
||||
if (++L->RepCount >= L->RepMax) {
|
||||
/* Done with this list */
|
||||
@@ -249,8 +249,8 @@ static int ReplayTokList (void* List)
|
||||
L->LI = StartLine (&CurTok.Pos, LI_TYPE_ASM, PushCounter);
|
||||
|
||||
/* If a check function is defined, call it, so it may look at the token
|
||||
* just set and changed it as apropriate.
|
||||
*/
|
||||
** just set and changed it as apropriate.
|
||||
*/
|
||||
if (L->Check) {
|
||||
L->Check (L);
|
||||
}
|
||||
@@ -266,9 +266,9 @@ static int ReplayTokList (void* List)
|
||||
|
||||
void PushTokList (TokList* List, const char* Desc)
|
||||
/* Push a token list to be used as input for InputFromStack. This includes
|
||||
* several initializations needed in the token list structure, so don't use
|
||||
* PushInput directly.
|
||||
*/
|
||||
** several initializations needed in the token list structure, so don't use
|
||||
** PushInput directly.
|
||||
*/
|
||||
{
|
||||
/* If the list is empty, just delete it and bail out */
|
||||
if (List->Count == 0) {
|
||||
|
||||
@@ -111,18 +111,18 @@ void FreeTokList (TokList* T);
|
||||
|
||||
token_t GetTokListTerm (token_t Term);
|
||||
/* Determine if the following token list is enclosed in curly braces. This is
|
||||
* the case if the next token is the opening brace. If so, skip it and return
|
||||
* a closing brace, otherwise return Term.
|
||||
*/
|
||||
** the case if the next token is the opening brace. If so, skip it and return
|
||||
** a closing brace, otherwise return Term.
|
||||
*/
|
||||
|
||||
void AddCurTok (TokList* T);
|
||||
/* Add the current token to the token list */
|
||||
|
||||
void PushTokList (TokList* List, const char* Desc);
|
||||
/* Push a token list to be used as input for InputFromStack. This includes
|
||||
* several initializations needed in the token list structure, so don't use
|
||||
* PushInput directly.
|
||||
*/
|
||||
** several initializations needed in the token list structure, so don't use
|
||||
** PushInput directly.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@ static unsigned ULabDefCount = 0; /* Number of defined labels */
|
||||
|
||||
static ULabel* NewULabel (ExprNode* Val)
|
||||
/* Create a new ULabel and insert it into the collection. The created label
|
||||
* structure is returned.
|
||||
*/
|
||||
** structure is returned.
|
||||
*/
|
||||
{
|
||||
/* Allocate memory for the ULabel structure */
|
||||
ULabel* L = xmalloc (sizeof (ULabel));
|
||||
@@ -98,11 +98,11 @@ static ULabel* NewULabel (ExprNode* Val)
|
||||
|
||||
ExprNode* ULabRef (int Which)
|
||||
/* Get an unnamed label. If Which is negative, it is a backreference (a
|
||||
* reference to an already defined label), and the function will return a
|
||||
* segment relative expression. If Which is positive, it is a forward ref,
|
||||
* and the function will return a expression node for an unnamed label that
|
||||
* must be resolved later.
|
||||
*/
|
||||
** reference to an already defined label), and the function will return a
|
||||
** segment relative expression. If Which is positive, it is a forward ref,
|
||||
** and the function will return a expression node for an unnamed label that
|
||||
** must be resolved later.
|
||||
*/
|
||||
{
|
||||
int Index;
|
||||
ULabel* L;
|
||||
@@ -139,8 +139,8 @@ ExprNode* ULabRef (int Which)
|
||||
++L->Ref;
|
||||
|
||||
/* If the label is already defined, return its value, otherwise return
|
||||
* just a reference.
|
||||
*/
|
||||
** just a reference.
|
||||
*/
|
||||
if (L->Val) {
|
||||
return CloneExpr (L->Val);
|
||||
} else {
|
||||
@@ -155,9 +155,9 @@ void ULabDef (void)
|
||||
{
|
||||
if (ULabDefCount < CollCount (&ULabList)) {
|
||||
/* We did already have a forward reference to this label, so has
|
||||
* already been generated, but doesn't have a value. Use the current
|
||||
* PC for the label value.
|
||||
*/
|
||||
** already been generated, but doesn't have a value. Use the current
|
||||
** PC for the label value.
|
||||
*/
|
||||
ULabel* L = CollAtUnchecked (&ULabList, ULabDefCount);
|
||||
CHECK (L->Val == 0);
|
||||
L->Val = GenCurrentPC ();
|
||||
@@ -185,9 +185,9 @@ int ULabCanResolve (void)
|
||||
|
||||
ExprNode* ULabResolve (unsigned Index)
|
||||
/* Return a valid expression for the unnamed label with the given index. This
|
||||
* is used to resolve unnamed labels when assembly is done, so it is an error
|
||||
* if a label is still undefined in this phase.
|
||||
*/
|
||||
** is used to resolve unnamed labels when assembly is done, so it is an error
|
||||
** if a label is still undefined in this phase.
|
||||
*/
|
||||
{
|
||||
/* Get the label and check that it is defined */
|
||||
ULabel* L = CollAt (&ULabList, Index);
|
||||
@@ -201,8 +201,8 @@ ExprNode* ULabResolve (unsigned Index)
|
||||
|
||||
void ULabDone (void)
|
||||
/* Run through all unnamed labels, check for anomalies and errors and do
|
||||
* necessary cleanups.
|
||||
*/
|
||||
** necessary cleanups.
|
||||
*/
|
||||
{
|
||||
/* Check if there are undefined labels */
|
||||
unsigned I = ULabDefCount;
|
||||
@@ -213,8 +213,8 @@ void ULabDone (void)
|
||||
}
|
||||
|
||||
/* Walk over all labels and emit a warning if any unreferenced ones
|
||||
* are found. Remove line infos because they're no longer needed.
|
||||
*/
|
||||
** are found. Remove line infos because they're no longer needed.
|
||||
*/
|
||||
for (I = 0; I < CollCount (&ULabList); ++I) {
|
||||
ULabel* L = CollAtUnchecked (&ULabList, I);
|
||||
if (L->Ref == 0) {
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
|
||||
ExprNode* ULabRef (int Which);
|
||||
/* Get an unnamed label. If Which is negative, it is a backreference (a
|
||||
* reference to an already defined label), and the function will return a
|
||||
* segment relative expression. If Which is positive, it is a forward ref,
|
||||
* and the function will return a expression node for an unnamed label that
|
||||
* must be resolved later.
|
||||
*/
|
||||
** reference to an already defined label), and the function will return a
|
||||
** segment relative expression. If Which is positive, it is a forward ref,
|
||||
** and the function will return a expression node for an unnamed label that
|
||||
** must be resolved later.
|
||||
*/
|
||||
|
||||
void ULabDef (void);
|
||||
/* Define an unnamed label at the current PC */
|
||||
@@ -60,14 +60,14 @@ int ULabCanResolve (void);
|
||||
|
||||
ExprNode* ULabResolve (unsigned Index);
|
||||
/* Return a valid expression for the unnamed label with the given index. This
|
||||
* is used to resolve unnamed labels when assembly is done, so it is an error
|
||||
* if a label is still undefined in this phase.
|
||||
*/
|
||||
** is used to resolve unnamed labels when assembly is done, so it is an error
|
||||
** if a label is still undefined in this phase.
|
||||
*/
|
||||
|
||||
void ULabDone (void);
|
||||
/* Run through all unnamed labels, check for anomalies and errors and do
|
||||
* necessary cleanups.
|
||||
*/
|
||||
** necessary cleanups.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ static const char AnonTag[] = "$anon";
|
||||
|
||||
char* AnonName (char* Buf, const char* Spec)
|
||||
/* Get a name for an anonymous variable or type. The given buffer is expected
|
||||
* to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||
*/
|
||||
** to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||
*/
|
||||
{
|
||||
static unsigned ACount = 0;
|
||||
xsprintf (Buf, IDENTSIZE, "%s-%s-%04X", AnonTag, Spec, ++ACount);
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
|
||||
char* AnonName (char* Buf, const char* Spec);
|
||||
/* Get a name for an anonymous variable or type. The given buffer is expected
|
||||
* to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||
*/
|
||||
** to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||
*/
|
||||
|
||||
int IsAnonName (const char* Name);
|
||||
/* Check if the given symbol name is that of an anonymous symbol */
|
||||
|
||||
@@ -86,8 +86,8 @@ void RemoveCode (const CodeMark* M)
|
||||
|
||||
void MoveCode (const CodeMark* Start, const CodeMark* End, const CodeMark* Target)
|
||||
/* Move the code between Start (inclusive) and End (exclusive) to
|
||||
* (before) Target. The code marks aren't updated.
|
||||
*/
|
||||
** (before) Target. The code marks aren't updated.
|
||||
*/
|
||||
{
|
||||
CS_MoveEntries (CS->Code, Start->Pos, End->Pos - Start->Pos, Target->Pos);
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ void RemoveCode (const CodeMark* M);
|
||||
|
||||
void MoveCode (const CodeMark* Start, const CodeMark* End, const CodeMark* Target);
|
||||
/* Move the code between Start (inclusive) and End (exclusive) to
|
||||
* (before) Target. The code marks aren't updated.
|
||||
*/
|
||||
** (before) Target. The code marks aren't updated.
|
||||
*/
|
||||
|
||||
int CodeRangeIsEmpty (const CodeMark* Start, const CodeMark* End);
|
||||
/* Return true if the given code range is empty (no code between Start and End) */
|
||||
|
||||
@@ -70,9 +70,9 @@ unsigned GetLocalLabel (void)
|
||||
|
||||
const char* LocalLabelName (unsigned L)
|
||||
/* Make a label name from the given label number. The label name will be
|
||||
* created in static storage and overwritten when calling the function
|
||||
* again.
|
||||
*/
|
||||
** created in static storage and overwritten when calling the function
|
||||
** again.
|
||||
*/
|
||||
{
|
||||
static char Buf[64];
|
||||
sprintf (Buf, "L%04X", L);
|
||||
|
||||
@@ -49,9 +49,9 @@ unsigned GetLocalLabel (void);
|
||||
|
||||
const char* LocalLabelName (unsigned L);
|
||||
/* Make a label name from the given label number. The label name will be
|
||||
* created in static storage and overwritten when calling the function
|
||||
* again.
|
||||
*/
|
||||
** created in static storage and overwritten when calling the function
|
||||
** again.
|
||||
*/
|
||||
|
||||
int IsLocalLabelName (const char* Name);
|
||||
/* Return true if Name is the name of a local label */
|
||||
|
||||
@@ -69,8 +69,8 @@ static void AsmRangeError (unsigned Arg)
|
||||
|
||||
static void AsmErrorSkip (void)
|
||||
/* Called in case of an error, skips tokens until the closing paren or a
|
||||
* semicolon is reached.
|
||||
*/
|
||||
** semicolon is reached.
|
||||
*/
|
||||
{
|
||||
static const token_t TokenList[] = { TOK_RPAREN, TOK_SEMI };
|
||||
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
|
||||
@@ -80,8 +80,8 @@ static void AsmErrorSkip (void)
|
||||
|
||||
static SymEntry* AsmGetSym (unsigned Arg, unsigned Type)
|
||||
/* Find the symbol with the name currently in NextTok. The symbol must be of
|
||||
* the given type. On errors, NULL is returned.
|
||||
*/
|
||||
** the given type. On errors, NULL is returned.
|
||||
*/
|
||||
{
|
||||
SymEntry* Sym;
|
||||
|
||||
@@ -257,9 +257,9 @@ static void ParseLVarArg (StrBuf* T, unsigned Arg)
|
||||
}
|
||||
|
||||
/* The symbol may be a parameter to a variadic function. In this case, we
|
||||
* don't have a fixed stack offset, so check it and bail out with an error
|
||||
* if this is the case.
|
||||
*/
|
||||
** don't have a fixed stack offset, so check it and bail out with an error
|
||||
** if this is the case.
|
||||
*/
|
||||
if ((Sym->Flags & SC_PARAM) == SC_PARAM && F_IsVariadic (CurrentFunc)) {
|
||||
Error ("Argument %u has no fixed stack offset", Arg);
|
||||
AsmErrorSkip ();
|
||||
@@ -352,16 +352,16 @@ static void ParseAsm (void)
|
||||
NextToken ();
|
||||
|
||||
/* Parse the statement. It may contain several lines and one or more
|
||||
* of the following place holders:
|
||||
* %b - Numerical 8 bit value
|
||||
* %w - Numerical 16 bit value
|
||||
* %l - Numerical 32 bit value
|
||||
* %v - Assembler name of a (global) variable
|
||||
* %o - Stack offset of a (local) variable
|
||||
* %g - Assembler name of a C label
|
||||
* %s - Any argument converted to a string (almost)
|
||||
* %% - The % sign
|
||||
*/
|
||||
** of the following place holders:
|
||||
** %b - Numerical 8 bit value
|
||||
** %w - Numerical 16 bit value
|
||||
** %l - Numerical 32 bit value
|
||||
** %v - Assembler name of a (global) variable
|
||||
** %o - Stack offset of a (local) variable
|
||||
** %g - Assembler name of a C label
|
||||
** %s - Any argument converted to a string (almost)
|
||||
** %% - The % sign
|
||||
*/
|
||||
Arg = 0;
|
||||
while ((C = SB_Get (&S)) != '\0') {
|
||||
|
||||
@@ -415,9 +415,9 @@ Done:
|
||||
|
||||
void AsmStatement (void)
|
||||
/* This function parses ASM statements. The syntax of the ASM directive
|
||||
* looks like the one defined for C++ (C has no ASM directive), that is,
|
||||
* a string literal in parenthesis.
|
||||
*/
|
||||
** looks like the one defined for C++ (C has no ASM directive), that is,
|
||||
** a string literal in parenthesis.
|
||||
*/
|
||||
{
|
||||
/* Skip the ASM */
|
||||
NextToken ();
|
||||
@@ -434,8 +434,8 @@ void AsmStatement (void)
|
||||
Error ("String literal expected");
|
||||
|
||||
/* Try some smart error recovery: Skip tokens until we reach the
|
||||
* enclosing paren, or a semicolon.
|
||||
*/
|
||||
** enclosing paren, or a semicolon.
|
||||
*/
|
||||
AsmErrorSkip ();
|
||||
|
||||
} else {
|
||||
|
||||
@@ -46,9 +46,9 @@
|
||||
|
||||
void AsmStatement (void);
|
||||
/* This function parses ASM statements. The syntax of the ASM directive
|
||||
* looks like the one defined for C++ (C has no ASM directive), that is,
|
||||
* a string literal in parenthesis.
|
||||
*/
|
||||
** looks like the one defined for C++ (C has no ASM directive), that is,
|
||||
** a string literal in parenthesis.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -75,18 +75,18 @@ void Assignment (ExprDesc* Expr)
|
||||
NextToken ();
|
||||
|
||||
/* cc65 does not have full support for handling structs by value. Since
|
||||
* assigning structs is one of the more useful operations from this
|
||||
* family, allow it here.
|
||||
*/
|
||||
** assigning structs is one of the more useful operations from this
|
||||
** family, allow it here.
|
||||
*/
|
||||
if (IsClassStruct (ltype)) {
|
||||
|
||||
/* Get the size of the left hand side. */
|
||||
unsigned Size = SizeOf (ltype);
|
||||
|
||||
/* If the size is that of a basic type (char, int, long), we will copy
|
||||
* the struct using the primary register, otherwise we use memcpy. In
|
||||
* the former case, push the address only if really needed.
|
||||
*/
|
||||
** the struct using the primary register, otherwise we use memcpy. In
|
||||
** the former case, push the address only if really needed.
|
||||
*/
|
||||
int UseReg = 1;
|
||||
Type* stype;
|
||||
switch (Size) {
|
||||
@@ -143,10 +143,10 @@ void Assignment (ExprDesc* Expr)
|
||||
} else {
|
||||
|
||||
/* We have an rvalue. This can only happen if a function returns
|
||||
* a struct, since there is no other way to generate an expression
|
||||
* that as a struct as an rvalue result. We allow only 1, 2, and 4
|
||||
* byte sized structs and do direct assignment.
|
||||
*/
|
||||
** a struct, since there is no other way to generate an expression
|
||||
** that has a struct as an rvalue result. We allow only 1, 2, and 4
|
||||
** byte sized structs, and do direct assignment.
|
||||
*/
|
||||
if (UseReg) {
|
||||
/* Do the store */
|
||||
Store (Expr, stype);
|
||||
@@ -168,8 +168,8 @@ void Assignment (ExprDesc* Expr)
|
||||
unsigned Flags;
|
||||
|
||||
/* If the bit-field fits within one byte, do the following operations
|
||||
* with bytes.
|
||||
*/
|
||||
** with bytes.
|
||||
*/
|
||||
if (Expr->BitOffs / CHAR_BITS == (Expr->BitOffs + Expr->BitWidth - 1) / CHAR_BITS) {
|
||||
Expr->Type = type_uchar;
|
||||
}
|
||||
@@ -197,14 +197,14 @@ void Assignment (ExprDesc* Expr)
|
||||
MarkedExprWithCheck (hie1, &Expr2);
|
||||
|
||||
/* Do type conversion if necessary. Beware: Do not use char type
|
||||
* here!
|
||||
*/
|
||||
** here!
|
||||
*/
|
||||
TypeConversion (&Expr2, ltype);
|
||||
|
||||
/* Special treatment if the value is constant. */
|
||||
/* Beware: Expr2 may contain side effects, so there must not be
|
||||
* code generated for Expr2.
|
||||
*/
|
||||
** code generated for Expr2.
|
||||
*/
|
||||
if (ED_IsConstAbsInt (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
|
||||
|
||||
/* Get the value and apply the mask */
|
||||
@@ -214,8 +214,8 @@ void Assignment (ExprDesc* Expr)
|
||||
RemoveCode (&PushPos);
|
||||
|
||||
/* If the value is equal to the mask now, all bits are one, and we
|
||||
* can remove the mask operation from above.
|
||||
*/
|
||||
** can remove the mask operation from above.
|
||||
*/
|
||||
if (Val == Mask) {
|
||||
RemoveCode (&AndPos);
|
||||
}
|
||||
|
||||
@@ -94,10 +94,10 @@ void FreeCaseNodeColl (Collection* Nodes)
|
||||
|
||||
int SearchCaseNode (const Collection* Nodes, unsigned char Key, int* Index)
|
||||
/* Search for a node in the given collection. If the node has been found,
|
||||
* set Index to the index of the node and return true. If the node was not
|
||||
* found, set Index the the insertion position of the node and return
|
||||
* false.
|
||||
*/
|
||||
** set Index to the index of the node and return true. If the node was not
|
||||
** found, set Index the the insertion position of the node and return
|
||||
** false.
|
||||
*/
|
||||
{
|
||||
/* Do a binary search */
|
||||
int First = 0;
|
||||
@@ -134,8 +134,8 @@ int SearchCaseNode (const Collection* Nodes, unsigned char Key, int* Index)
|
||||
|
||||
unsigned InsertCaseValue (Collection* Nodes, unsigned long Val, unsigned Depth)
|
||||
/* Insert a new case value into a CaseNode tree with the given depth. Return
|
||||
* the code label for the value.
|
||||
*/
|
||||
** the code label for the value.
|
||||
*/
|
||||
{
|
||||
CaseNode* N = 0;
|
||||
unsigned CaseLabel = GetLocalLabel (); /* Code label */
|
||||
@@ -155,8 +155,8 @@ unsigned InsertCaseValue (Collection* Nodes, unsigned long Val, unsigned Depth)
|
||||
CollInsert (Nodes, N, Index);
|
||||
|
||||
/* If this is not the last round, create the collection for
|
||||
* the subnodes, otherwise get a label for the code.
|
||||
*/
|
||||
** the subnodes, otherwise get a label for the code.
|
||||
*/
|
||||
if (Depth > 0) {
|
||||
N->Nodes = NewCollection ();
|
||||
} else {
|
||||
@@ -168,8 +168,8 @@ unsigned InsertCaseValue (Collection* Nodes, unsigned long Val, unsigned Depth)
|
||||
N = CollAt (Nodes, Index);
|
||||
|
||||
/* If this is the last round and we found a node, we have a
|
||||
* duplicate case label in a switch.
|
||||
*/
|
||||
** duplicate case label in a switch.
|
||||
*/
|
||||
if (Depth == 0) {
|
||||
Error ("Duplicate case label");
|
||||
}
|
||||
|
||||
@@ -115,15 +115,15 @@ void FreeCaseNodeColl (Collection* Nodes);
|
||||
|
||||
int SearchCaseNode (const Collection* Nodes, unsigned char Key, int* Index);
|
||||
/* Search for a node in the given collection. If the node has been found,
|
||||
* set Index to the index of the node and return true. If the node was not
|
||||
* found, set Index the the insertion position of the node and return
|
||||
* false.
|
||||
*/
|
||||
** set Index to the index of the node and return true. If the node was not
|
||||
** found, set Index the the insertion position of the node and return
|
||||
** false.
|
||||
*/
|
||||
|
||||
unsigned InsertCaseValue (Collection* Nodes, unsigned long Val, unsigned Depth);
|
||||
/* Insert a new case value into a CaseNode tree with the given depth. Return
|
||||
* the code label for the value.
|
||||
*/
|
||||
** the code label for the value.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -96,8 +96,8 @@ static char* GetArgCopy (const char* Arg)
|
||||
|
||||
static int NumArg (const char* Arg, unsigned long* Num)
|
||||
/* If the given argument is numerical, convert it and return true. Otherwise
|
||||
* set Num to zero and return false.
|
||||
*/
|
||||
** set Num to zero and return false.
|
||||
*/
|
||||
{
|
||||
char* End;
|
||||
unsigned long Val;
|
||||
@@ -113,8 +113,8 @@ static int NumArg (const char* Arg, unsigned long* Num)
|
||||
}
|
||||
|
||||
/* Convert the value. strtol is not exactly what we want here, but it's
|
||||
* cheap and may be replaced by something fancier later.
|
||||
*/
|
||||
** cheap and may be replaced by something fancier later.
|
||||
*/
|
||||
Val = strtoul (Arg, &End, Base);
|
||||
|
||||
/* Check if the conversion was successful */
|
||||
@@ -141,16 +141,16 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
|
||||
const ZPInfo* Info;
|
||||
|
||||
/* If this is a subroutine call, or a jump to an external function,
|
||||
* lookup the information about this function and use it. The jump itself
|
||||
* does not change any registers, so we don't need to use the data from D.
|
||||
*/
|
||||
** lookup the information about this function and use it. The jump itself
|
||||
** does not change any registers, so we don't need to use the data from D.
|
||||
*/
|
||||
if ((E->Info & (OF_UBRA | OF_CALL)) != 0 && E->JumpTo == 0) {
|
||||
/* A subroutine call or jump to external symbol (function exit) */
|
||||
GetFuncInfo (E->Arg, &E->Use, &E->Chg);
|
||||
} else {
|
||||
/* Some other instruction. Use the values from the opcode description
|
||||
* plus addressing mode info.
|
||||
*/
|
||||
** plus addressing mode info.
|
||||
*/
|
||||
E->Use = D->Use | GetAMUseInfo (E->AM);
|
||||
E->Chg = D->Chg;
|
||||
|
||||
@@ -218,11 +218,11 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
|
||||
|
||||
const char* MakeHexArg (unsigned Num)
|
||||
/* Convert Num into a string in the form $XY, suitable for passing it as an
|
||||
* argument to NewCodeEntry, and return a pointer to the string.
|
||||
* BEWARE: The function returns a pointer to a static buffer, so the value is
|
||||
* gone if you call it twice (and apart from that it's not thread and signal
|
||||
* safe).
|
||||
*/
|
||||
** argument to NewCodeEntry, and return a pointer to the string.
|
||||
** BEWARE: The function returns a pointer to a static buffer, so the value is
|
||||
** gone if you call it twice (and apart from that it's not thread and signal
|
||||
** safe).
|
||||
*/
|
||||
{
|
||||
static char Buf[16];
|
||||
xsprintf (Buf, sizeof (Buf), "$%02X", (unsigned char) Num);
|
||||
@@ -288,8 +288,8 @@ void FreeCodeEntry (CodeEntry* E)
|
||||
|
||||
void CE_ReplaceOPC (CodeEntry* E, opc_t OPC)
|
||||
/* Replace the opcode of the instruction. This will also replace related info,
|
||||
* Size, Use and Chg, but it will NOT update any arguments or labels.
|
||||
*/
|
||||
** Size, Use and Chg, but it will NOT update any arguments or labels.
|
||||
*/
|
||||
{
|
||||
/* Get the opcode descriptor */
|
||||
const OPCDesc* D = GetOPCDesc (OPC);
|
||||
@@ -325,9 +325,9 @@ void CE_AttachLabel (CodeEntry* E, CodeLabel* L)
|
||||
|
||||
void CE_ClearJumpTo (CodeEntry* E)
|
||||
/* Clear the JumpTo entry and the argument (which contained the name of the
|
||||
* label). Note: The function will not clear the backpointer from the label,
|
||||
* so use it with care.
|
||||
*/
|
||||
** label). Note: The function will not clear the backpointer from the label,
|
||||
** so use it with care.
|
||||
*/
|
||||
{
|
||||
/* Clear the JumpTo entry */
|
||||
E->JumpTo = 0;
|
||||
@@ -366,8 +366,8 @@ void CE_SetArg (CodeEntry* E, const char* Arg)
|
||||
|
||||
void CE_SetNumArg (CodeEntry* E, long Num)
|
||||
/* Set a new numeric argument for the given code entry that must already
|
||||
* have a numeric argument.
|
||||
*/
|
||||
** have a numeric argument.
|
||||
*/
|
||||
{
|
||||
char Buf[16];
|
||||
|
||||
@@ -404,8 +404,8 @@ int CE_IsConstImm (const CodeEntry* E)
|
||||
|
||||
int CE_IsKnownImm (const CodeEntry* E, unsigned long Num)
|
||||
/* Return true if the argument of E is a constant immediate value that is
|
||||
* equal to Num.
|
||||
*/
|
||||
** equal to Num.
|
||||
*/
|
||||
{
|
||||
return (E->AM == AM65_IMM && CE_HasNumArg (E) && E->Num == Num);
|
||||
}
|
||||
@@ -414,12 +414,12 @@ int CE_IsKnownImm (const CodeEntry* E, unsigned long Num)
|
||||
|
||||
int CE_UseLoadFlags (CodeEntry* E)
|
||||
/* Return true if the instruction uses any flags that are set by a load of
|
||||
* a register (N and Z).
|
||||
*/
|
||||
** a register (N and Z).
|
||||
*/
|
||||
{
|
||||
/* Follow unconditional branches, but beware of endless loops. After this,
|
||||
* E will point to the first entry that is not a branch.
|
||||
*/
|
||||
** E will point to the first entry that is not a branch.
|
||||
*/
|
||||
if (E->Info & OF_UBRA) {
|
||||
Collection C = AUTO_COLLECTION_INITIALIZER;
|
||||
|
||||
@@ -491,8 +491,8 @@ void CE_FreeRegInfo (CodeEntry* E)
|
||||
|
||||
void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
||||
/* Generate register info for this instruction. If an old info exists, it is
|
||||
* overwritten.
|
||||
*/
|
||||
** overwritten.
|
||||
*/
|
||||
{
|
||||
/* Pointers to the register contents */
|
||||
RegContents* In;
|
||||
@@ -522,8 +522,8 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
||||
|
||||
case OP65_ADC:
|
||||
/* We don't know the value of the carry, so the result is
|
||||
* always unknown.
|
||||
*/
|
||||
** always unknown.
|
||||
*/
|
||||
Out->RegA = UNKNOWN_REGVAL;
|
||||
break;
|
||||
|
||||
|
||||
@@ -90,11 +90,11 @@ struct CodeEntry {
|
||||
|
||||
const char* MakeHexArg (unsigned Num);
|
||||
/* Convert Num into a string in the form $XY, suitable for passing it as an
|
||||
* argument to NewCodeEntry, and return a pointer to the string.
|
||||
* BEWARE: The function returns a pointer to a static buffer, so the value is
|
||||
* gone if you call it twice (and apart from that it's not thread and signal
|
||||
* safe).
|
||||
*/
|
||||
** argument to NewCodeEntry, and return a pointer to the string.
|
||||
** BEWARE: The function returns a pointer to a static buffer, so the value is
|
||||
** gone if you call it twice (and apart from that it's not thread and signal
|
||||
** safe).
|
||||
*/
|
||||
|
||||
CodeEntry* NewCodeEntry (opc_t OPC, am_t AM, const char* Arg,
|
||||
CodeLabel* JumpTo, LineInfo* LI);
|
||||
@@ -105,8 +105,8 @@ void FreeCodeEntry (CodeEntry* E);
|
||||
|
||||
void CE_ReplaceOPC (CodeEntry* E, opc_t OPC);
|
||||
/* Replace the opcode of the instruction. This will also replace related info,
|
||||
* Size, Use and Chg, but it will NOT update any arguments or labels.
|
||||
*/
|
||||
** Size, Use and Chg, but it will NOT update any arguments or labels.
|
||||
*/
|
||||
|
||||
int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2);
|
||||
/* Check if both code entries are equal */
|
||||
@@ -116,9 +116,9 @@ void CE_AttachLabel (CodeEntry* E, CodeLabel* L);
|
||||
|
||||
void CE_ClearJumpTo (CodeEntry* E);
|
||||
/* Clear the JumpTo entry and the argument (which contained the name of the
|
||||
* label). Note: The function will not clear the backpointer from the label,
|
||||
* so use it with care.
|
||||
*/
|
||||
** label). Note: The function will not clear the backpointer from the label,
|
||||
** so use it with care.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int CE_HasLabel (const CodeEntry* E)
|
||||
@@ -198,16 +198,16 @@ void CE_SetArg (CodeEntry* E, const char* Arg);
|
||||
|
||||
void CE_SetNumArg (CodeEntry* E, long Num);
|
||||
/* Set a new numeric argument for the given code entry that must already
|
||||
* have a numeric argument.
|
||||
*/
|
||||
** have a numeric argument.
|
||||
*/
|
||||
|
||||
int CE_IsConstImm (const CodeEntry* E);
|
||||
/* Return true if the argument of E is a constant immediate value */
|
||||
|
||||
int CE_IsKnownImm (const CodeEntry* E, unsigned long Num);
|
||||
/* Return true if the argument of E is a constant immediate value that is
|
||||
* equal to Num.
|
||||
*/
|
||||
** equal to Num.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int CE_IsCallTo (const CodeEntry* E, const char* Name)
|
||||
@@ -221,16 +221,16 @@ INLINE int CE_IsCallTo (const CodeEntry* E, const char* Name)
|
||||
|
||||
int CE_UseLoadFlags (CodeEntry* E);
|
||||
/* Return true if the instruction uses any flags that are set by a load of
|
||||
* a register (N and Z).
|
||||
*/
|
||||
** a register (N and Z).
|
||||
*/
|
||||
|
||||
void CE_FreeRegInfo (CodeEntry* E);
|
||||
/* Free an existing register info struct */
|
||||
|
||||
void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs);
|
||||
/* Generate register info for this instruction. If an old info exists, it is
|
||||
* overwritten.
|
||||
*/
|
||||
** overwritten.
|
||||
*/
|
||||
|
||||
void CE_Output (const CodeEntry* E);
|
||||
/* Output the code entry to the output file */
|
||||
|
||||
@@ -192,8 +192,8 @@ void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime)
|
||||
{
|
||||
if (DebugInfo) {
|
||||
/* We have to place this into the global text segment, so it will
|
||||
* appear before all .dbg line statements.
|
||||
*/
|
||||
** appear before all .dbg line statements.
|
||||
*/
|
||||
TS_AddLine (GS->Text, "\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime);
|
||||
}
|
||||
}
|
||||
@@ -298,15 +298,15 @@ int push (unsigned flags)
|
||||
|
||||
static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
|
||||
/* The value in Offs is an offset to an address in a/x. Make sure, an object
|
||||
* of the type given in Flags can be loaded or stored into this address by
|
||||
* adding part of the offset to the address in ax, so that the remaining
|
||||
* offset fits into an index register. Return the remaining offset.
|
||||
*/
|
||||
** of the type given in Flags can be loaded or stored into this address by
|
||||
** adding part of the offset to the address in ax, so that the remaining
|
||||
** offset fits into an index register. Return the remaining offset.
|
||||
*/
|
||||
{
|
||||
/* If the offset is too large for a byte register, add the high byte
|
||||
* of the offset to the primary. Beware: We need a special correction
|
||||
* if the offset in the low byte will overflow in the operation.
|
||||
*/
|
||||
** of the offset to the primary. Beware: We need a special correction
|
||||
** if the offset in the low byte will overflow in the operation.
|
||||
*/
|
||||
unsigned O = Offs & ~0xFFU;
|
||||
if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
|
||||
/* We need to add the low byte also */
|
||||
@@ -351,8 +351,8 @@ void g_aliasdatalabel (unsigned label, unsigned baselabel, long offs)
|
||||
/* Define label as a local alias for baselabel+offs */
|
||||
{
|
||||
/* We need an intermediate buffer here since LocalLabelName uses a
|
||||
* static buffer which changes with each call.
|
||||
*/
|
||||
** static buffer which changes with each call.
|
||||
*/
|
||||
StrBuf L = AUTO_STRBUF_INITIALIZER;
|
||||
SB_AppendStr (&L, LocalLabelName (label));
|
||||
SB_Terminate (&L);
|
||||
@@ -427,10 +427,10 @@ void g_importmainargs (void)
|
||||
|
||||
|
||||
/* Remember the argument size of a function. The variable is set by g_enter
|
||||
* and used by g_leave. If the functions gets its argument size by the caller
|
||||
* (variable param list or function without prototype), g_enter will set the
|
||||
* value to -1.
|
||||
*/
|
||||
** and used by g_leave. If the function gets its argument size by the caller
|
||||
** (variable param list or function without prototype), g_enter will set the
|
||||
** value to -1.
|
||||
*/
|
||||
static int funcargs;
|
||||
|
||||
|
||||
@@ -602,9 +602,9 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
|
||||
} else if (StackOffs <= RegOffs) {
|
||||
|
||||
/* More bytes, but the relation between the register offset in the
|
||||
* register bank and the stack offset allows us to generate short
|
||||
* code that uses just one index register.
|
||||
*/
|
||||
** register bank and the stack offset allows us to generate short
|
||||
** code that uses just one index register.
|
||||
*/
|
||||
unsigned Label = GetLocalLabel ();
|
||||
AddCodeLine ("ldy #$%02X", StackOffs);
|
||||
g_defcodelabel (Label);
|
||||
@@ -616,9 +616,9 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
|
||||
|
||||
} else {
|
||||
|
||||
/* Ok, this is the generic code. We need to save X because the
|
||||
* caller will only save A.
|
||||
*/
|
||||
/* OK, this is the generic code. We need to save X because the
|
||||
** caller will only save A.
|
||||
*/
|
||||
unsigned Label = GetLocalLabel ();
|
||||
AddCodeLine ("stx tmp1");
|
||||
AddCodeLine ("ldy #$%02X", (unsigned char) (StackOffs + Bytes - 1));
|
||||
@@ -840,13 +840,13 @@ void g_getlocal (unsigned Flags, int Offs)
|
||||
|
||||
void g_getind (unsigned Flags, unsigned Offs)
|
||||
/* Fetch the specified object type indirect through the primary register
|
||||
* into the primary register
|
||||
*/
|
||||
** into the primary register
|
||||
*/
|
||||
{
|
||||
/* If the offset is greater than 255, add the part that is > 255 to
|
||||
* the primary. This way we get an easy addition and use the low byte
|
||||
* as the offset
|
||||
*/
|
||||
** the primary. This way we get an easy addition and use the low byte
|
||||
** as the offset
|
||||
*/
|
||||
Offs = MakeByteOffs (Flags, Offs);
|
||||
|
||||
/* Handle the indirect fetch */
|
||||
@@ -958,8 +958,8 @@ void g_leasp (int Offs)
|
||||
|
||||
void g_leavariadic (int Offs)
|
||||
/* Fetch the address of a parameter in a variadic function into the primary
|
||||
* register
|
||||
*/
|
||||
** register
|
||||
*/
|
||||
{
|
||||
unsigned ArgSizeOffs;
|
||||
|
||||
@@ -967,8 +967,8 @@ void g_leavariadic (int Offs)
|
||||
Offs -= StackPtr;
|
||||
|
||||
/* Get the offset of the parameter which is stored at sp+0 on function
|
||||
* entry and check if this offset is reachable with a byte offset.
|
||||
*/
|
||||
** entry and check if this offset is reachable with a byte offset.
|
||||
*/
|
||||
CHECK (StackPtr <= 0);
|
||||
ArgSizeOffs = -StackPtr;
|
||||
CheckLocalOffs (ArgSizeOffs);
|
||||
@@ -1106,14 +1106,14 @@ void g_putlocal (unsigned Flags, int Offs, long Val)
|
||||
|
||||
void g_putind (unsigned Flags, unsigned Offs)
|
||||
/* Store the specified object type in the primary register at the address
|
||||
* on the top of the stack
|
||||
*/
|
||||
** on the top of the stack
|
||||
*/
|
||||
{
|
||||
/* We can handle offsets below $100 directly, larger offsets must be added
|
||||
* to the address. Since a/x is in use, best code is achieved by adding
|
||||
* just the high byte. Be sure to check if the low byte will overflow while
|
||||
* while storing.
|
||||
*/
|
||||
** to the address. Since a/x is in use, best code is achieved by adding
|
||||
** just the high byte. Be sure to check if the low byte will overflow while
|
||||
** while storing.
|
||||
*/
|
||||
if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
|
||||
|
||||
/* Overflow - we need to add the low byte also */
|
||||
@@ -1321,9 +1321,9 @@ void g_reglong (unsigned Flags)
|
||||
|
||||
unsigned g_typeadjust (unsigned lhs, unsigned rhs)
|
||||
/* Adjust the integer operands before doing a binary operation. lhs is a flags
|
||||
* value, that corresponds to the value on TOS, rhs corresponds to the value
|
||||
* in (e)ax. The return value is the the flags value for the resulting type.
|
||||
*/
|
||||
** value, that corresponds to the value on TOS, rhs corresponds to the value
|
||||
** in (e)ax. The return value is the the flags value for the resulting type.
|
||||
*/
|
||||
{
|
||||
unsigned ltype, rtype;
|
||||
unsigned result;
|
||||
@@ -1352,11 +1352,11 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs)
|
||||
}
|
||||
|
||||
/* Determine the result type for the operation:
|
||||
* - The result is const if both operands are const.
|
||||
* - The result is unsigned if one of the operands is unsigned.
|
||||
* - The result is long if one of the operands is long.
|
||||
* - Otherwise the result is int sized.
|
||||
*/
|
||||
** - The result is const if both operands are const.
|
||||
** - The result is unsigned if one of the operands is unsigned.
|
||||
** - The result is long if one of the operands is long.
|
||||
** - Otherwise the result is int sized.
|
||||
*/
|
||||
result = (lhs & CF_CONST) & (rhs & CF_CONST);
|
||||
result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
|
||||
if (rtype == CF_LONG || ltype == CF_LONG) {
|
||||
@@ -1371,8 +1371,8 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs)
|
||||
|
||||
unsigned g_typecast (unsigned lhs, unsigned rhs)
|
||||
/* Cast the value in the primary register to the operand size that is flagged
|
||||
* by the lhs value. Return the result value.
|
||||
*/
|
||||
** by the lhs value. Return the result value.
|
||||
*/
|
||||
{
|
||||
unsigned ltype, rtype;
|
||||
|
||||
@@ -1392,17 +1392,17 @@ unsigned g_typecast (unsigned lhs, unsigned rhs)
|
||||
}
|
||||
|
||||
/* Do not need any other action. If the left type is int, and the primary
|
||||
* register is long, it will be automagically truncated. If the right hand
|
||||
* side is const, it is not located in the primary register and handled by
|
||||
* the expression parser code.
|
||||
*/
|
||||
** register is long, it will be automagically truncated. If the right hand
|
||||
** side is const, it is not located in the primary register and handled by
|
||||
** the expression parser code.
|
||||
*/
|
||||
|
||||
/* Result is const if the right hand side was const */
|
||||
lhs |= (rhs & CF_CONST);
|
||||
|
||||
/* The resulting type is that of the left hand side (that's why you called
|
||||
* this function :-)
|
||||
*/
|
||||
** this function :-)
|
||||
*/
|
||||
return lhs;
|
||||
}
|
||||
|
||||
@@ -1410,10 +1410,10 @@ unsigned g_typecast (unsigned lhs, unsigned rhs)
|
||||
|
||||
void g_scale (unsigned flags, long val)
|
||||
/* Scale the value in the primary register by the given value. If val is positive,
|
||||
* scale up, is val is negative, scale down. This function is used to scale
|
||||
* the operands or results of pointer arithmetic by the size of the type, the
|
||||
* pointer points to.
|
||||
*/
|
||||
** scale up, is val is negative, scale down. This function is used to scale
|
||||
** the operands or results of pointer arithmetic by the size of the type, the
|
||||
** pointer points to.
|
||||
*/
|
||||
{
|
||||
int p2;
|
||||
|
||||
@@ -1813,9 +1813,9 @@ void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
|
||||
/* Emit += for the location with address in ax */
|
||||
{
|
||||
/* If the offset is too large for a byte register, add the high byte
|
||||
* of the offset to the primary. Beware: We need a special correction
|
||||
* if the offset in the low byte will overflow in the operation.
|
||||
*/
|
||||
** of the offset to the primary. Beware: We need a special correction
|
||||
** if the offset in the low byte will overflow in the operation.
|
||||
*/
|
||||
offs = MakeByteOffs (flags, offs);
|
||||
|
||||
/* Check the size and determine operation */
|
||||
@@ -2009,9 +2009,9 @@ void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
|
||||
/* Emit -= for the location with address in ax */
|
||||
{
|
||||
/* If the offset is too large for a byte register, add the high byte
|
||||
* of the offset to the primary. Beware: We need a special correction
|
||||
* if the offset in the low byte will overflow in the operation.
|
||||
*/
|
||||
** of the offset to the primary. Beware: We need a special correction
|
||||
** if the offset in the low byte will overflow in the operation.
|
||||
*/
|
||||
offs = MakeByteOffs (flags, offs);
|
||||
|
||||
/* Check the size and determine operation */
|
||||
@@ -2168,8 +2168,8 @@ void g_restore (unsigned flags)
|
||||
|
||||
void g_cmp (unsigned flags, unsigned long val)
|
||||
/* Immidiate compare. The primary register will not be changed, Z flag
|
||||
* will be set.
|
||||
*/
|
||||
** will be set.
|
||||
*/
|
||||
{
|
||||
unsigned L;
|
||||
|
||||
@@ -2204,11 +2204,11 @@ void g_cmp (unsigned flags, unsigned long val)
|
||||
|
||||
static void oper (unsigned Flags, unsigned long Val, const char** Subs)
|
||||
/* Encode a binary operation. subs is a pointer to four strings:
|
||||
* 0 --> Operate on ints
|
||||
* 1 --> Operate on unsigneds
|
||||
* 2 --> Operate on longs
|
||||
* 3 --> Operate on unsigned longs
|
||||
*/
|
||||
** 0 --> Operate on ints
|
||||
** 1 --> Operate on unsigneds
|
||||
** 2 --> Operate on longs
|
||||
** 3 --> Operate on unsigned longs
|
||||
*/
|
||||
{
|
||||
/* Determine the offset into the array */
|
||||
if (Flags & CF_UNSIGNED) {
|
||||
@@ -2326,8 +2326,8 @@ void g_push (unsigned flags, unsigned long val)
|
||||
|
||||
void g_swap (unsigned flags)
|
||||
/* Swap the primary register and the top of the stack. flags give the type
|
||||
* of *both* values (must have same size).
|
||||
*/
|
||||
** of *both* values (must have same size).
|
||||
*/
|
||||
{
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
|
||||
@@ -2421,8 +2421,8 @@ void g_drop (unsigned Space)
|
||||
{
|
||||
if (Space > 255) {
|
||||
/* Inline the code since calling addysp repeatedly is quite some
|
||||
* overhead.
|
||||
*/
|
||||
** overhead.
|
||||
*/
|
||||
AddCodeLine ("pha");
|
||||
AddCodeLine ("lda #$%02X", (unsigned char) Space);
|
||||
AddCodeLine ("clc");
|
||||
@@ -2450,8 +2450,8 @@ void g_space (int Space)
|
||||
g_drop (-Space);
|
||||
} else if (Space > 255) {
|
||||
/* Inline the code since calling subysp repeatedly is quite some
|
||||
* overhead.
|
||||
*/
|
||||
** overhead.
|
||||
*/
|
||||
AddCodeLine ("pha");
|
||||
AddCodeLine ("lda sp");
|
||||
AddCodeLine ("sec");
|
||||
@@ -2547,8 +2547,8 @@ void g_mul (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
@@ -2624,8 +2624,8 @@ void g_mul (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff.
|
||||
*/
|
||||
** into the normal, non-optimized stuff.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR; /* Handle chars as ints */
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
|
||||
@@ -2695,8 +2695,8 @@ void g_or (unsigned flags, unsigned long val)
|
||||
};
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
@@ -2744,9 +2744,9 @@ void g_or (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -2766,8 +2766,8 @@ void g_xor (unsigned flags, unsigned long val)
|
||||
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
@@ -2812,9 +2812,9 @@ void g_xor (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -2833,8 +2833,8 @@ void g_and (unsigned Flags, unsigned long Val)
|
||||
};
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (Flags & CF_CONST) {
|
||||
|
||||
switch (Flags & CF_TYPEMASK) {
|
||||
@@ -2904,9 +2904,9 @@ void g_and (unsigned Flags, unsigned long Val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
Flags &= ~CF_FORCECHAR;
|
||||
g_push (Flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -2925,8 +2925,8 @@ void g_asr (unsigned flags, unsigned long val)
|
||||
};
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
@@ -3035,9 +3035,9 @@ void g_asr (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -3057,8 +3057,8 @@ void g_asl (unsigned flags, unsigned long val)
|
||||
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
@@ -3134,9 +3134,9 @@ void g_asl (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -3419,10 +3419,10 @@ void g_dec (unsigned flags, unsigned long val)
|
||||
|
||||
|
||||
/*
|
||||
* Following are the conditional operators. They compare the TOS against
|
||||
* the primary and put a literal 1 in the primary if the condition is
|
||||
* true, otherwise they clear the primary register
|
||||
*/
|
||||
** Following are the conditional operators. They compare the TOS against
|
||||
** the primary and put a literal 1 in the primary if the condition is
|
||||
** true, otherwise they clear the primary register
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -3436,8 +3436,8 @@ void g_eq (unsigned flags, unsigned long val)
|
||||
unsigned L;
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
@@ -3467,9 +3467,9 @@ void g_eq (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -3490,8 +3490,8 @@ void g_ne (unsigned flags, unsigned long val)
|
||||
unsigned L;
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
switch (flags & CF_TYPEMASK) {
|
||||
@@ -3521,9 +3521,9 @@ void g_ne (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -3544,14 +3544,14 @@ void g_lt (unsigned flags, unsigned long val)
|
||||
unsigned Label;
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
/* Because the handling of the overflow flag is too complex for
|
||||
* inlining, we can handle only unsigned compares, and signed
|
||||
* compares against zero here.
|
||||
*/
|
||||
** inlining, we can handle only unsigned compares, and signed
|
||||
** compares against zero here.
|
||||
*/
|
||||
if (flags & CF_UNSIGNED) {
|
||||
|
||||
/* Give a warning in some special cases */
|
||||
@@ -3683,9 +3683,9 @@ void g_lt (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -3705,8 +3705,8 @@ void g_le (unsigned flags, unsigned long val)
|
||||
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
/* Look at the type */
|
||||
@@ -3718,8 +3718,8 @@ void g_le (unsigned flags, unsigned long val)
|
||||
/* Unsigned compare */
|
||||
if (val < 0xFF) {
|
||||
/* Use < instead of <= because the former gives
|
||||
* better code on the 6502 than the latter.
|
||||
*/
|
||||
** better code on the 6502 than the latter.
|
||||
*/
|
||||
g_lt (flags, val+1);
|
||||
} else {
|
||||
/* Always true */
|
||||
@@ -3730,8 +3730,8 @@ void g_le (unsigned flags, unsigned long val)
|
||||
/* Signed compare */
|
||||
if ((long) val < 0x7F) {
|
||||
/* Use < instead of <= because the former gives
|
||||
* better code on the 6502 than the latter.
|
||||
*/
|
||||
** better code on the 6502 than the latter.
|
||||
*/
|
||||
g_lt (flags, val+1);
|
||||
} else {
|
||||
/* Always true */
|
||||
@@ -3748,8 +3748,8 @@ void g_le (unsigned flags, unsigned long val)
|
||||
/* Unsigned compare */
|
||||
if (val < 0xFFFF) {
|
||||
/* Use < instead of <= because the former gives
|
||||
* better code on the 6502 than the latter.
|
||||
*/
|
||||
** better code on the 6502 than the latter.
|
||||
*/
|
||||
g_lt (flags, val+1);
|
||||
} else {
|
||||
/* Always true */
|
||||
@@ -3773,8 +3773,8 @@ void g_le (unsigned flags, unsigned long val)
|
||||
/* Unsigned compare */
|
||||
if (val < 0xFFFFFFFF) {
|
||||
/* Use < instead of <= because the former gives
|
||||
* better code on the 6502 than the latter.
|
||||
*/
|
||||
** better code on the 6502 than the latter.
|
||||
*/
|
||||
g_lt (flags, val+1);
|
||||
} else {
|
||||
/* Always true */
|
||||
@@ -3798,9 +3798,9 @@ void g_le (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -3820,8 +3820,8 @@ void g_gt (unsigned flags, unsigned long val)
|
||||
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
/* Look at the type */
|
||||
@@ -3832,14 +3832,14 @@ void g_gt (unsigned flags, unsigned long val)
|
||||
if (flags & CF_UNSIGNED) {
|
||||
if (val == 0) {
|
||||
/* If we have a compare > 0, we will replace it by
|
||||
* != 0 here, since both are identical but the
|
||||
* latter is easier to optimize.
|
||||
*/
|
||||
** != 0 here, since both are identical but the
|
||||
** latter is easier to optimize.
|
||||
*/
|
||||
g_ne (flags, val);
|
||||
} else if (val < 0xFF) {
|
||||
/* Use >= instead of > because the former gives
|
||||
* better code on the 6502 than the latter.
|
||||
*/
|
||||
** better code on the 6502 than the latter.
|
||||
*/
|
||||
g_ge (flags, val+1);
|
||||
} else {
|
||||
/* Never true */
|
||||
@@ -3849,8 +3849,8 @@ void g_gt (unsigned flags, unsigned long val)
|
||||
} else {
|
||||
if ((long) val < 0x7F) {
|
||||
/* Use >= instead of > because the former gives
|
||||
* better code on the 6502 than the latter.
|
||||
*/
|
||||
** better code on the 6502 than the latter.
|
||||
*/
|
||||
g_ge (flags, val+1);
|
||||
} else {
|
||||
/* Never true */
|
||||
@@ -3867,14 +3867,14 @@ void g_gt (unsigned flags, unsigned long val)
|
||||
/* Unsigned compare */
|
||||
if (val == 0) {
|
||||
/* If we have a compare > 0, we will replace it by
|
||||
* != 0 here, since both are identical but the latter
|
||||
* is easier to optimize.
|
||||
*/
|
||||
** != 0 here, since both are identical but the latter
|
||||
** is easier to optimize.
|
||||
*/
|
||||
g_ne (flags, val);
|
||||
} else if (val < 0xFFFF) {
|
||||
/* Use >= instead of > because the former gives better
|
||||
* code on the 6502 than the latter.
|
||||
*/
|
||||
** code on the 6502 than the latter.
|
||||
*/
|
||||
g_ge (flags, val+1);
|
||||
} else {
|
||||
/* Never true */
|
||||
@@ -3898,14 +3898,14 @@ void g_gt (unsigned flags, unsigned long val)
|
||||
/* Unsigned compare */
|
||||
if (val == 0) {
|
||||
/* If we have a compare > 0, we will replace it by
|
||||
* != 0 here, since both are identical but the latter
|
||||
* is easier to optimize.
|
||||
*/
|
||||
** != 0 here, since both are identical but the latter
|
||||
** is easier to optimize.
|
||||
*/
|
||||
g_ne (flags, val);
|
||||
} else if (val < 0xFFFFFFFF) {
|
||||
/* Use >= instead of > because the former gives better
|
||||
* code on the 6502 than the latter.
|
||||
*/
|
||||
** code on the 6502 than the latter.
|
||||
*/
|
||||
g_ge (flags, val+1);
|
||||
} else {
|
||||
/* Never true */
|
||||
@@ -3929,9 +3929,9 @@ void g_gt (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
@@ -3953,14 +3953,14 @@ void g_ge (unsigned flags, unsigned long val)
|
||||
|
||||
|
||||
/* If the right hand side is const, the lhs is not on stack but still
|
||||
* in the primary register.
|
||||
*/
|
||||
** in the primary register.
|
||||
*/
|
||||
if (flags & CF_CONST) {
|
||||
|
||||
/* Because the handling of the overflow flag is too complex for
|
||||
* inlining, we can handle only unsigned compares, and signed
|
||||
* compares against zero here.
|
||||
*/
|
||||
** inlining, we can handle only unsigned compares, and signed
|
||||
** compares against zero here.
|
||||
*/
|
||||
if (flags & CF_UNSIGNED) {
|
||||
|
||||
/* Give a warning in some special cases */
|
||||
@@ -4087,9 +4087,9 @@ void g_ge (unsigned flags, unsigned long val)
|
||||
}
|
||||
|
||||
/* If we go here, we didn't emit code. Push the lhs on stack and fall
|
||||
* into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
* always work with ints.
|
||||
*/
|
||||
** into the normal, non-optimized stuff. Note: The standard stuff will
|
||||
** always work with ints.
|
||||
*/
|
||||
flags &= ~CF_FORCECHAR;
|
||||
g_push (flags & ~CF_CONST, 0);
|
||||
}
|
||||
|
||||
@@ -53,11 +53,11 @@
|
||||
|
||||
|
||||
/* Code generator flags.
|
||||
* Note: The type flags are designed so that a smaller type may override a
|
||||
* larger one by or'ing it into the existing one.
|
||||
* Note^2: The actual type including the sign flag is in the lower bits, so
|
||||
* we can mask the information and use them as a table index.
|
||||
*/
|
||||
** Note: The type flags are designed so that a smaller type may override a
|
||||
** larger one by or'ing it into the existing one.
|
||||
** Note^2: The actual type including the sign flag is in the lower bits, so
|
||||
** we can mask the information and use them as a table index.
|
||||
*/
|
||||
#define CF_NONE 0x0000 /* No special flags */
|
||||
|
||||
/* Values for the actual type */
|
||||
@@ -208,21 +208,21 @@ void g_reglong (unsigned Flags);
|
||||
|
||||
unsigned g_typeadjust (unsigned lhs, unsigned rhs);
|
||||
/* Adjust the integer operands before doing a binary operation. lhs is a flags
|
||||
* value, that corresponds to the value on TOS, rhs corresponds to the value
|
||||
* in (e)ax. The return value is the the flags value for the resulting type.
|
||||
*/
|
||||
** value, that corresponds to the value on TOS, rhs corresponds to the value
|
||||
** in (e)ax. The return value is the the flags value for the resulting type.
|
||||
*/
|
||||
|
||||
unsigned g_typecast (unsigned lhs, unsigned rhs);
|
||||
/* Cast the value in the primary register to the operand size that is flagged
|
||||
* by the lhs value. Return the result value.
|
||||
*/
|
||||
** by the lhs value. Return the result value.
|
||||
*/
|
||||
|
||||
void g_scale (unsigned flags, long val);
|
||||
/* Scale the value in the primary register by the given value. If val is positive,
|
||||
* scale up, is val is negative, scale down. This function is used to scale
|
||||
* the operands or results of pointer arithmetic by the size of the type, the
|
||||
* pointer points to.
|
||||
*/
|
||||
** scale up, is val is negative, scale down. This function is used to scale
|
||||
** the operands or results of pointer arithmetic by the size of the type, the
|
||||
** pointer points to.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -274,16 +274,16 @@ void g_getlocal (unsigned Flags, int Offs);
|
||||
|
||||
void g_getind (unsigned Flags, unsigned Offs);
|
||||
/* Fetch the specified object type indirect through the primary register
|
||||
* into the primary register
|
||||
*/
|
||||
** into the primary register
|
||||
*/
|
||||
|
||||
void g_leasp (int Offs);
|
||||
/* Fetch the address of the specified symbol into the primary register */
|
||||
|
||||
void g_leavariadic (int Offs);
|
||||
/* Fetch the address of a parameter in a variadic function into the primary
|
||||
* register
|
||||
*/
|
||||
** register
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -301,8 +301,8 @@ void g_putlocal (unsigned Flags, int Offs, long Val);
|
||||
|
||||
void g_putind (unsigned flags, unsigned offs);
|
||||
/* Store the specified object type in the primary register at the address
|
||||
* on the top of the stack
|
||||
*/
|
||||
** on the top of the stack
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -376,8 +376,8 @@ void g_restore (unsigned flags);
|
||||
|
||||
void g_cmp (unsigned flags, unsigned long val);
|
||||
/* Immidiate compare. The primary register will not be changed, Z flag
|
||||
* will be set.
|
||||
*/
|
||||
** will be set.
|
||||
*/
|
||||
|
||||
void g_test (unsigned flags);
|
||||
/* Test the value in the primary and set the condition codes */
|
||||
@@ -387,8 +387,8 @@ void g_push (unsigned flags, unsigned long val);
|
||||
|
||||
void g_swap (unsigned flags);
|
||||
/* Swap the primary register and the top of the stack. flags give the type
|
||||
* of *both* values (must have same size).
|
||||
*/
|
||||
** of *both* values (must have same size).
|
||||
*/
|
||||
|
||||
void g_call (unsigned Flags, const char* Label, unsigned ArgSize);
|
||||
/* Call the specified subroutine name */
|
||||
|
||||
@@ -64,8 +64,8 @@ static const char CmpSuffixTab [][4] = {
|
||||
};
|
||||
|
||||
/* Table listing the function names and code info values for known internally
|
||||
* used functions. This table should get auto-generated in the future.
|
||||
*/
|
||||
** used functions. This table should get auto-generated in the future.
|
||||
*/
|
||||
typedef struct FuncInfo FuncInfo;
|
||||
struct FuncInfo {
|
||||
const char* Name; /* Function name */
|
||||
@@ -74,9 +74,9 @@ struct FuncInfo {
|
||||
};
|
||||
|
||||
/* Note for the shift functions: Shifts are done modulo 32, so all shift
|
||||
* routines are marked to use only the A register. The remainder is ignored
|
||||
* anyway.
|
||||
*/
|
||||
** routines are marked to use only the A register. The remainder is ignored
|
||||
** anyway.
|
||||
*/
|
||||
static const FuncInfo FuncInfoTable[] = {
|
||||
{ "addeq0sp", REG_AX, REG_AXY },
|
||||
{ "addeqysp", REG_AXY, REG_AXY },
|
||||
@@ -376,15 +376,15 @@ static int CompareFuncInfo (const void* Key, const void* Info)
|
||||
|
||||
void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
/* For the given function, lookup register information and store it into
|
||||
* the given variables. If the function is unknown, assume it will use and
|
||||
* load all registers.
|
||||
*/
|
||||
** the given variables. If the function is unknown, assume it will use and
|
||||
** load all registers.
|
||||
*/
|
||||
{
|
||||
/* If the function name starts with an underline, it is an external
|
||||
* function. Search for it in the symbol table. If the function does
|
||||
* not start with an underline, it may be a runtime support function.
|
||||
* Search for it in the list of builtin functions.
|
||||
*/
|
||||
** function. Search for it in the symbol table. If the function does
|
||||
** not start with an underline, it may be a runtime support function.
|
||||
** Search for it in the list of builtin functions.
|
||||
*/
|
||||
if (Name[0] == '_') {
|
||||
|
||||
/* Search in the symbol table, skip the leading underscore */
|
||||
@@ -396,11 +396,11 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
FuncDesc* D = E->V.F.Func;
|
||||
|
||||
/* A function may use the A or A/X registers if it is a fastcall
|
||||
* function. If it is not a fastcall function but a variadic one,
|
||||
* it will use the Y register (the parameter size is passed here).
|
||||
* In all other cases, no registers are used. However, we assume
|
||||
* that any function will destroy all registers.
|
||||
*/
|
||||
** function. If it is not a fastcall function but a variadic one,
|
||||
** it will use the Y register (the parameter size is passed here).
|
||||
** In all other cases, no registers are used. However, we assume
|
||||
** that any function will destroy all registers.
|
||||
*/
|
||||
if (IsQualFastcall (E->Type) && D->ParamCount > 0) {
|
||||
/* Will use registers depending on the last param */
|
||||
unsigned LastParamSize = CheckedSizeOf (D->LastParam->Type);
|
||||
@@ -428,9 +428,9 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
} else if (IsDigit (Name[0]) || Name[0] == '$') {
|
||||
|
||||
/* A call to a numeric address. Assume that anything gets used and
|
||||
* destroyed. This is not a real problem, since numeric addresses
|
||||
* are used mostly in inline assembly anyway.
|
||||
*/
|
||||
** destroyed. This is not a real problem, since numeric addresses
|
||||
** are used mostly in inline assembly anyway.
|
||||
*/
|
||||
*Use = REG_ALL;
|
||||
*Chg = REG_ALL;
|
||||
return;
|
||||
@@ -448,10 +448,10 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
*Chg = Info->Chg;
|
||||
} else {
|
||||
/* It's an internal function we have no information for. If in
|
||||
* debug mode, output an additional warning, so we have a chance
|
||||
* to fix it. Otherwise assume that the internal function will
|
||||
* use and change all registers.
|
||||
*/
|
||||
** debug mode, output an additional warning, so we have a chance
|
||||
** to fix it. Otherwise assume that the internal function will
|
||||
** use and change all registers.
|
||||
*/
|
||||
if (Debug) {
|
||||
fprintf (stderr, "No info about internal function `%s'\n", Name);
|
||||
}
|
||||
@@ -462,8 +462,8 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
}
|
||||
|
||||
/* Function not found - assume that the primary register is input, and all
|
||||
* registers are changed
|
||||
*/
|
||||
** registers are changed
|
||||
*/
|
||||
*Use = REG_EAXY;
|
||||
*Chg = REG_ALL;
|
||||
}
|
||||
@@ -478,8 +478,8 @@ static int CompareZPInfo (const void* Name, const void* Info)
|
||||
const ZPInfo* E = (const ZPInfo*) Info;
|
||||
|
||||
/* Do the compare. Be careful because of the length (Info may contain
|
||||
* more than just the zeropage name).
|
||||
*/
|
||||
** more than just the zeropage name).
|
||||
*/
|
||||
if (E->Len == 0) {
|
||||
/* Do a full compare */
|
||||
return strcmp (N, E->Name);
|
||||
@@ -498,8 +498,8 @@ static int CompareZPInfo (const void* Name, const void* Info)
|
||||
|
||||
const ZPInfo* GetZPInfo (const char* Name)
|
||||
/* If the given name is a zero page symbol, return a pointer to the info
|
||||
* struct for this symbol, otherwise return NULL.
|
||||
*/
|
||||
** struct for this symbol, otherwise return NULL.
|
||||
*/
|
||||
{
|
||||
/* Search for the zp location in the list */
|
||||
return bsearch (Name, ZPInfoTable, ZPInfoCount,
|
||||
@@ -523,8 +523,8 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
||||
unsigned R;
|
||||
|
||||
/* Check if we have already visited the current code entry. If so,
|
||||
* bail out.
|
||||
*/
|
||||
** bail out.
|
||||
*/
|
||||
if (CE_HasMark (E)) {
|
||||
break;
|
||||
}
|
||||
@@ -542,8 +542,8 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
||||
}
|
||||
if (R != REG_NONE) {
|
||||
/* We are not interested in the use of any register that has been
|
||||
* used before.
|
||||
*/
|
||||
** used before.
|
||||
*/
|
||||
R &= ~Unused;
|
||||
/* Remember the remaining registers */
|
||||
Used |= R;
|
||||
@@ -552,8 +552,8 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
||||
/* Evaluate the changed registers */
|
||||
if ((R = E->Chg) != REG_NONE) {
|
||||
/* We are not interested in the use of any register that has been
|
||||
* used before.
|
||||
*/
|
||||
** used before.
|
||||
*/
|
||||
R &= ~Used;
|
||||
/* Remember the remaining registers */
|
||||
Unused |= R;
|
||||
@@ -570,8 +570,8 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
||||
}
|
||||
|
||||
/* If we have an unconditional branch, follow this branch if possible,
|
||||
* otherwise we're done.
|
||||
*/
|
||||
** otherwise we're done.
|
||||
*/
|
||||
if ((E->Info & OF_UBRA) != 0) {
|
||||
|
||||
/* Does this jump have a valid target? */
|
||||
@@ -587,9 +587,9 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
||||
}
|
||||
|
||||
/* In case of conditional branches, follow the branch if possible and
|
||||
* follow the normal flow (branch not taken) afterwards. If we cannot
|
||||
* follow the branch, we're done.
|
||||
*/
|
||||
** follow the normal flow (branch not taken) afterwards. If we cannot
|
||||
** follow the branch, we're done.
|
||||
*/
|
||||
} else if ((E->Info & OF_CBRA) != 0) {
|
||||
|
||||
/* Recursively determine register usage at the branch target */
|
||||
@@ -604,8 +604,8 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
||||
} else {
|
||||
|
||||
/* Jump to external label. This will effectively exit the
|
||||
* function, so we use the exitregs information here.
|
||||
*/
|
||||
** function, so we use the exitregs information here.
|
||||
*/
|
||||
U1 = S->ExitRegs;
|
||||
|
||||
}
|
||||
@@ -677,8 +677,8 @@ static unsigned GetRegInfo1 (CodeSeg* S,
|
||||
|
||||
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index, unsigned Wanted)
|
||||
/* Determine register usage information for the instructions starting at the
|
||||
* given index.
|
||||
*/
|
||||
** given index.
|
||||
*/
|
||||
{
|
||||
CodeEntry* E;
|
||||
Collection Visited; /* Visited entries */
|
||||
@@ -748,9 +748,9 @@ int RegEAXUsed (struct CodeSeg* S, unsigned Index)
|
||||
|
||||
unsigned GetKnownReg (unsigned Use, const RegContents* RC)
|
||||
/* Return the register or zero page location from the set in Use, thats
|
||||
* contents are known. If Use does not contain any register, or if the
|
||||
* register in question does not have a known value, return REG_NONE.
|
||||
*/
|
||||
** contents are known. If Use does not contain any register, or if the
|
||||
** register in question does not have a known value, return REG_NONE.
|
||||
*/
|
||||
{
|
||||
if ((Use & REG_A) != 0) {
|
||||
return (RC == 0 || RC->RegA >= 0)? REG_A : REG_NONE;
|
||||
@@ -796,9 +796,9 @@ static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
|
||||
|
||||
cmp_t FindBoolCmpCond (const char* Name)
|
||||
/* Check if the given string is the name of one of the boolean transformer
|
||||
* subroutine, and if so, return the condition that is evaluated by this
|
||||
* routine. Return CMP_INV if the condition is not recognised.
|
||||
*/
|
||||
** subroutine, and if so, return the condition that is evaluated by this
|
||||
** routine. Return CMP_INV if the condition is not recognised.
|
||||
*/
|
||||
{
|
||||
/* Check for the correct subroutine name */
|
||||
if (strncmp (Name, "bool", 4) == 0) {
|
||||
@@ -814,8 +814,8 @@ cmp_t FindBoolCmpCond (const char* Name)
|
||||
|
||||
cmp_t FindTosCmpCond (const char* Name)
|
||||
/* Check if this is a call to one of the TOS compare functions (tosgtax).
|
||||
* Return the condition code or CMP_INV on failure.
|
||||
*/
|
||||
** Return the condition code or CMP_INV on failure.
|
||||
*/
|
||||
{
|
||||
unsigned Len = strlen (Name);
|
||||
|
||||
|
||||
@@ -128,19 +128,19 @@ typedef enum {
|
||||
|
||||
void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg);
|
||||
/* For the given function, lookup register information and store it into
|
||||
* the given variables. If the function is unknown, assume it will use and
|
||||
* load all registers.
|
||||
*/
|
||||
** the given variables. If the function is unknown, assume it will use and
|
||||
** load all registers.
|
||||
*/
|
||||
|
||||
const ZPInfo* GetZPInfo (const char* Name);
|
||||
/* If the given name is a zero page symbol, return a pointer to the info
|
||||
* struct for this symbol, otherwise return NULL.
|
||||
*/
|
||||
** struct for this symbol, otherwise return NULL.
|
||||
*/
|
||||
|
||||
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index, unsigned Wanted);
|
||||
/* Determine register usage information for the instructions starting at the
|
||||
* given index.
|
||||
*/
|
||||
** given index.
|
||||
*/
|
||||
|
||||
int RegAUsed (struct CodeSeg* S, unsigned Index);
|
||||
/* Check if the value in A is used. */
|
||||
@@ -159,20 +159,20 @@ int RegEAXUsed (struct CodeSeg* S, unsigned Index);
|
||||
|
||||
unsigned GetKnownReg (unsigned Use, const struct RegContents* RC);
|
||||
/* Return the register or zero page location from the set in Use, thats
|
||||
* contents are known. If Use does not contain any register, or if the
|
||||
* register in question does not have a known value, return REG_NONE.
|
||||
*/
|
||||
** contents are known. If Use does not contain any register, or if the
|
||||
** register in question does not have a known value, return REG_NONE.
|
||||
*/
|
||||
|
||||
cmp_t FindBoolCmpCond (const char* Name);
|
||||
/* Check if the given string is the name of one of the boolean transformer
|
||||
* subroutine, and if so, return the condition that is evaluated by this
|
||||
* routine. Return CMP_INV if the condition is not recognised.
|
||||
*/
|
||||
** subroutine, and if so, return the condition that is evaluated by this
|
||||
** routine. Return CMP_INV if the condition is not recognised.
|
||||
*/
|
||||
|
||||
cmp_t FindTosCmpCond (const char* Name);
|
||||
/* Check if this is a call to one of the TOS compare functions (tosgtax).
|
||||
* Return the condition code or CMP_INV on failure.
|
||||
*/
|
||||
** Return the condition code or CMP_INV on failure.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -101,8 +101,8 @@ void CL_AddRef (CodeLabel* L, struct CodeEntry* E)
|
||||
|
||||
void CL_MoveRefs (CodeLabel* OldLabel, CodeLabel* NewLabel)
|
||||
/* Move all references to OldLabel to point to NewLabel. OldLabel will have no
|
||||
* more references on return.
|
||||
*/
|
||||
** more references on return.
|
||||
*/
|
||||
{
|
||||
/* Walk through all instructions referencing the old label */
|
||||
unsigned Count = CL_GetRefCount (OldLabel);
|
||||
|
||||
@@ -108,8 +108,8 @@ void CL_AddRef (CodeLabel* L, struct CodeEntry* E);
|
||||
|
||||
void CL_MoveRefs (CodeLabel* OldLabel, CodeLabel* NewLabel);
|
||||
/* Move all references to OldLabel to point to NewLabel. OldLabel will have no
|
||||
* more references on return.
|
||||
*/
|
||||
** more references on return.
|
||||
*/
|
||||
|
||||
void CL_Output (const CodeLabel* L);
|
||||
/* Output the code label to the output file */
|
||||
|
||||
@@ -80,8 +80,8 @@
|
||||
|
||||
static unsigned OptLoad1 (CodeSeg* S)
|
||||
/* Search for a call to ldaxysp where X is not used later and replace it by
|
||||
* a load of just the A register.
|
||||
*/
|
||||
** a load of just the A register.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
unsigned Changes = 0;
|
||||
@@ -161,8 +161,8 @@ static unsigned OptLoad2 (CodeSeg* S)
|
||||
!RegXUsed (S, I+3)) {
|
||||
|
||||
/* A/X are stored into memory somewhere and X is not used
|
||||
* later
|
||||
*/
|
||||
** later
|
||||
*/
|
||||
|
||||
/* lda (sp),y */
|
||||
X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
|
||||
@@ -251,8 +251,8 @@ static unsigned OptLoad3 (CodeSeg* S)
|
||||
CodeEntry* N;
|
||||
|
||||
/* If we had a preceeding load that is identical, remove this one.
|
||||
* If it is not identical, or we didn't have one, remember it.
|
||||
*/
|
||||
** If it is not identical, or we didn't have one, remember it.
|
||||
*/
|
||||
if (Load != 0 &&
|
||||
E->OPC == Load->OPC &&
|
||||
E->AM == Load->AM &&
|
||||
@@ -299,21 +299,21 @@ static unsigned OptLoad3 (CodeSeg* S)
|
||||
|
||||
static unsigned OptDecouple (CodeSeg* S)
|
||||
/* Decouple operations, that is, do the following replacements:
|
||||
*
|
||||
* dex -> ldx #imm
|
||||
* inx -> ldx #imm
|
||||
* dey -> ldy #imm
|
||||
* iny -> ldy #imm
|
||||
* tax -> ldx #imm
|
||||
* txa -> lda #imm
|
||||
* tay -> ldy #imm
|
||||
* tya -> lda #imm
|
||||
* lda zp -> lda #imm
|
||||
* ldx zp -> ldx #imm
|
||||
* ldy zp -> ldy #imm
|
||||
*
|
||||
* Provided that the register values are known of course.
|
||||
*/
|
||||
**
|
||||
** dex -> ldx #imm
|
||||
** inx -> ldx #imm
|
||||
** dey -> ldy #imm
|
||||
** iny -> ldy #imm
|
||||
** tax -> ldx #imm
|
||||
** txa -> lda #imm
|
||||
** tay -> ldy #imm
|
||||
** tya -> lda #imm
|
||||
** lda zp -> lda #imm
|
||||
** ldx zp -> ldx #imm
|
||||
** ldy zp -> ldy #imm
|
||||
**
|
||||
** Provided that the register values are known of course.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -529,9 +529,9 @@ static unsigned OptDecouple (CodeSeg* S)
|
||||
|
||||
static unsigned IsDecSP (const CodeEntry* E)
|
||||
/* Check if this is an insn that decrements the stack pointer. If so, return
|
||||
* the decrement. If not, return zero.
|
||||
* The function expects E to be a subroutine call.
|
||||
*/
|
||||
** the decrement. If not, return zero.
|
||||
** The function expects E to be a subroutine call.
|
||||
*/
|
||||
{
|
||||
if (strncmp (E->Arg, "decsp", 5) == 0) {
|
||||
if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
|
||||
@@ -549,8 +549,8 @@ static unsigned IsDecSP (const CodeEntry* E)
|
||||
|
||||
static unsigned OptStackPtrOps (CodeSeg* S)
|
||||
/* Merge adjacent calls to decsp into one. NOTE: This function won't merge all
|
||||
* known cases!
|
||||
*/
|
||||
** known cases!
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -851,8 +851,8 @@ static int CmpOptStep (const void* Key, const void* Func)
|
||||
|
||||
static OptFunc* FindOptFunc (const char* Name)
|
||||
/* Find an optimizer step by name in the table and return a pointer. Return
|
||||
* NULL if no such step is found.
|
||||
*/
|
||||
** NULL if no such step is found.
|
||||
*/
|
||||
{
|
||||
/* Search for the function in the list */
|
||||
OptFunc** O = bsearch (Name, OptFuncs, OPTFUNC_COUNT, sizeof (OptFuncs[0]), CmpOptStep);
|
||||
@@ -863,8 +863,8 @@ static OptFunc* FindOptFunc (const char* Name)
|
||||
|
||||
static OptFunc* GetOptFunc (const char* Name)
|
||||
/* Find an optimizer step by name in the table and return a pointer. Print an
|
||||
* error and call AbEnd if not found.
|
||||
*/
|
||||
** error and call AbEnd if not found.
|
||||
*/
|
||||
{
|
||||
/* Search for the function in the list */
|
||||
OptFunc* F = FindOptFunc (Name);
|
||||
@@ -1074,8 +1074,8 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
|
||||
unsigned Changes, C;
|
||||
|
||||
/* Don't run the function if it is disabled or if it is prohibited by the
|
||||
* code size factor
|
||||
*/
|
||||
** code size factor
|
||||
*/
|
||||
if (F->Disabled || F->CodeSizeFactor > S->CodeSizeFactor) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1113,10 +1113,10 @@ static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
|
||||
|
||||
static unsigned RunOptGroup1 (CodeSeg* S)
|
||||
/* Run the first group of optimization steps. These steps translate known
|
||||
* patterns emitted by the code generator into more optimal patterns. Order
|
||||
* of the steps is important, because some of the steps done earlier cover
|
||||
* the same patterns as later steps as subpatterns.
|
||||
*/
|
||||
** patterns emitted by the code generator into more optimal patterns. Order
|
||||
** of the steps is important, because some of the steps done earlier cover
|
||||
** the same patterns as later steps as subpatterns.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1168,10 +1168,10 @@ static unsigned RunOptGroup1 (CodeSeg* S)
|
||||
|
||||
static unsigned RunOptGroup2 (CodeSeg* S)
|
||||
/* Run one group of optimization steps. This step involves just decoupling
|
||||
* instructions by replacing them by instructions that do not depend on
|
||||
* previous instructions. This makes it easier to find instructions that
|
||||
* aren't used.
|
||||
*/
|
||||
** instructions by replacing them by instructions that do not depend on
|
||||
** previous instructions. This makes it easier to find instructions that
|
||||
** aren't used.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1185,9 +1185,9 @@ static unsigned RunOptGroup2 (CodeSeg* S)
|
||||
|
||||
static unsigned RunOptGroup3 (CodeSeg* S)
|
||||
/* Run one group of optimization steps. These steps depend on each other,
|
||||
* that means that one step may allow another step to do additional work,
|
||||
* so we will repeat the steps as long as we see any changes.
|
||||
*/
|
||||
** that means that one step may allow another step to do additional work,
|
||||
** so we will repeat the steps as long as we see any changes.
|
||||
*/
|
||||
{
|
||||
unsigned Changes, C;
|
||||
|
||||
@@ -1254,8 +1254,8 @@ static unsigned RunOptGroup3 (CodeSeg* S)
|
||||
|
||||
static unsigned RunOptGroup4 (CodeSeg* S)
|
||||
/* Run another round of pattern replacements. These are done late, since there
|
||||
* may be better replacements before.
|
||||
*/
|
||||
** may be better replacements before.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1287,9 +1287,9 @@ static unsigned RunOptGroup5 (CodeSeg* S)
|
||||
Changes += RunOptFunc (S, &DOpt65C02Stores, 1);
|
||||
if (Changes) {
|
||||
/* The 65C02 replacement codes do often make the use of a register
|
||||
* value unnecessary, so if we have changes, run another load
|
||||
* removal pass.
|
||||
*/
|
||||
** value unnecessary, so if we have changes, run another load
|
||||
** removal pass.
|
||||
*/
|
||||
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||
}
|
||||
}
|
||||
@@ -1302,18 +1302,18 @@ static unsigned RunOptGroup5 (CodeSeg* S)
|
||||
|
||||
static unsigned RunOptGroup6 (CodeSeg* S)
|
||||
/* This one is quite special. It tries to replace "lda (sp),y" by "lda (sp,x)".
|
||||
* The latter is ony cycle slower, but if we're able to remove the necessary
|
||||
* load of the Y register, because X is zero anyway, we gain 1 cycle and
|
||||
* shorten the code by one (transfer) or two bytes (load). So what we do is
|
||||
* to replace the insns, remove unused loads, and then change back all insns
|
||||
* where Y is still zero (meaning that the load has not been removed).
|
||||
*/
|
||||
** The latter is ony cycle slower, but if we're able to remove the necessary
|
||||
** load of the Y register, because X is zero anyway, we gain 1 cycle and
|
||||
** shorten the code by one (transfer) or two bytes (load). So what we do is
|
||||
** to replace the insns, remove unused loads, and then change back all insns
|
||||
** where Y is still zero (meaning that the load has not been removed).
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* This group will only run for a standard 6502, because the 65C02 has a
|
||||
* better addressing mode that covers this case.
|
||||
*/
|
||||
** better addressing mode that covers this case.
|
||||
*/
|
||||
if ((CPUIsets[CPU] & CPU_ISET_65SC02) == 0) {
|
||||
Changes += RunOptFunc (S, &DOptIndLoads1, 1);
|
||||
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||
@@ -1328,21 +1328,21 @@ static unsigned RunOptGroup6 (CodeSeg* S)
|
||||
|
||||
static unsigned RunOptGroup7 (CodeSeg* S)
|
||||
/* The last group of optimization steps. Adjust branches, do size optimizations.
|
||||
*/
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned C;
|
||||
|
||||
/* Optimize for size, that is replace operations by shorter ones, even
|
||||
* if this does hinder further optimizations (no problem since we're
|
||||
* done soon).
|
||||
*/
|
||||
** if this does hinder further optimizations (no problem since we're
|
||||
** done soon).
|
||||
*/
|
||||
C = RunOptFunc (S, &DOptSize1, 1);
|
||||
if (C) {
|
||||
Changes += C;
|
||||
/* Run some optimization passes again, since the size optimizations
|
||||
* may have opened new oportunities.
|
||||
*/
|
||||
** may have opened new oportunities.
|
||||
*/
|
||||
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||
Changes += RunOptFunc (S, &DOptUnusedStores, 1);
|
||||
Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
|
||||
@@ -1353,8 +1353,8 @@ static unsigned RunOptGroup7 (CodeSeg* S)
|
||||
if (C) {
|
||||
Changes += C;
|
||||
/* Run some optimization passes again, since the size optimizations
|
||||
* may have opened new oportunities.
|
||||
*/
|
||||
** may have opened new oportunities.
|
||||
*/
|
||||
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
|
||||
Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
|
||||
Changes += RunOptFunc (S, &DOptStore5, 1);
|
||||
@@ -1366,8 +1366,8 @@ static unsigned RunOptGroup7 (CodeSeg* S)
|
||||
Changes += RunOptFunc (S, &DOptBranchDist, 3);
|
||||
|
||||
/* Replace conditional branches to RTS. If we had changes, we must run dead
|
||||
* code elimination again, since the change may have introduced dead code.
|
||||
*/
|
||||
** code elimination again, since the change may have introduced dead code.
|
||||
*/
|
||||
C = RunOptFunc (S, &DOptRTSJumps2, 1);
|
||||
Changes += C;
|
||||
if (C) {
|
||||
|
||||
@@ -87,8 +87,8 @@ static void CS_PrintFunctionHeader (const CodeSeg* S)
|
||||
|
||||
static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E)
|
||||
/* Move all labels from the label pool to the given entry and remove them
|
||||
* from the pool.
|
||||
*/
|
||||
** from the pool.
|
||||
*/
|
||||
{
|
||||
/* Transfer the labels if we have any */
|
||||
unsigned I;
|
||||
@@ -203,8 +203,8 @@ static const char* SkipSpace (const char* S)
|
||||
static const char* ReadToken (const char* L, const char* Term,
|
||||
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.
|
||||
*/
|
||||
** token is terminated by one of the characters given in term.
|
||||
*/
|
||||
{
|
||||
/* Read/copy the token */
|
||||
unsigned I = 0;
|
||||
@@ -214,8 +214,8 @@ static const char* ReadToken (const char* L, const char* Term,
|
||||
Buf[I] = *L;
|
||||
} else if (I == BufSize-1) {
|
||||
/* Cannot store this character, this is an input error (maybe
|
||||
* identifier too long or similar).
|
||||
*/
|
||||
** identifier too long or similar).
|
||||
*/
|
||||
Error ("ASM code error: syntax error");
|
||||
}
|
||||
++I;
|
||||
@@ -238,11 +238,11 @@ static const char* ReadToken (const char* L, const char* Term,
|
||||
|
||||
static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
||||
/* Parse an instruction nnd generate a code entry from it. If the line contains
|
||||
* errors, output an error message and return NULL.
|
||||
* For simplicity, we don't accept the broad range of input a "real" assembler
|
||||
* does. The instruction and the argument are expected to be separated by
|
||||
* white space, for example.
|
||||
*/
|
||||
** errors, output an error message and return NULL.
|
||||
** For simplicity, we don't accept the broad range of input a "real" assembler
|
||||
** does. The instruction and the argument are expected to be separated by
|
||||
** white space, for example.
|
||||
*/
|
||||
{
|
||||
char Mnemo[IDENTSIZE+10];
|
||||
const OPCDesc* OPC;
|
||||
@@ -265,8 +265,8 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
||||
CS_AddLabel (S, Mnemo);
|
||||
|
||||
/* If we have reached end of line, bail out, otherwise a mnemonic
|
||||
* may follow.
|
||||
*/
|
||||
** may follow.
|
||||
*/
|
||||
if (*L == '\0') {
|
||||
return 0;
|
||||
}
|
||||
@@ -415,10 +415,10 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
||||
}
|
||||
|
||||
/* If the instruction is a branch, check for the label and generate it
|
||||
* if it does not exist. This may lead to unused labels (if the label
|
||||
* is actually an external one) which are removed by the CS_MergeLabels
|
||||
* function later.
|
||||
*/
|
||||
** if it does not exist. This may lead to unused labels (if the label
|
||||
** is actually an external one) which are removed by the CS_MergeLabels
|
||||
** function later.
|
||||
*/
|
||||
Label = 0;
|
||||
if (AM == AM65_BRA) {
|
||||
|
||||
@@ -434,8 +434,8 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
||||
}
|
||||
|
||||
/* We do now have the addressing mode in AM. Allocate a new CodeEntry
|
||||
* structure and initialize it.
|
||||
*/
|
||||
** structure and initialize it.
|
||||
*/
|
||||
E = NewCodeEntry (OPC->OPC, AM, Arg, Label, LI);
|
||||
|
||||
/* Return the new code entry */
|
||||
@@ -469,8 +469,8 @@ CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
|
||||
}
|
||||
|
||||
/* If we have a function given, get the return type of the function.
|
||||
* Assume ANY return type besides void will use the A and X registers.
|
||||
*/
|
||||
** Assume ANY return type besides void will use the A and X registers.
|
||||
*/
|
||||
if (S->Func && !IsTypeVoid ((RetType = GetFuncReturn (Func->Type)))) {
|
||||
if (SizeOf (RetType) == SizeOf (type_long)) {
|
||||
S->ExitRegs = REG_EAX;
|
||||
@@ -564,8 +564,8 @@ void CS_AddLine (CodeSeg* S, LineInfo* LI, const char* Format, ...)
|
||||
|
||||
void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index)
|
||||
/* Insert the code entry at the index given. Following code entries will be
|
||||
* moved to slots with higher indices.
|
||||
*/
|
||||
** moved to slots with higher indices.
|
||||
*/
|
||||
{
|
||||
/* Insert the entry into the collection */
|
||||
CollInsert (&S->Entries, E, Index);
|
||||
@@ -575,27 +575,27 @@ void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index)
|
||||
|
||||
void CS_DelEntry (CodeSeg* S, unsigned Index)
|
||||
/* 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.
|
||||
* Note: Labels are moved forward if possible, that is, they are moved to the
|
||||
* next insn (not the preceeding one).
|
||||
*/
|
||||
** labels, removing references to labels and even removing the referenced labels
|
||||
** if the reference count drops to zero.
|
||||
** Note: Labels are moved forward if possible, that is, they are moved to the
|
||||
** next insn (not the preceeding one).
|
||||
*/
|
||||
{
|
||||
/* Get the code entry for the given index */
|
||||
CodeEntry* E = CS_GetEntry (S, Index);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
** 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 = CE_GetLabelCount (E);
|
||||
if (Count > 0) {
|
||||
|
||||
/* The instruction has labels attached. Check if there is a next
|
||||
* instruction.
|
||||
*/
|
||||
** instruction.
|
||||
*/
|
||||
if (Index == CS_GetEntryCount (S)-1) {
|
||||
|
||||
/* No next instruction, move to the codeseg label pool */
|
||||
@@ -613,8 +613,8 @@ void CS_DelEntry (CodeSeg* S, unsigned Index)
|
||||
}
|
||||
|
||||
/* If this insn references a label, remove the reference. And, if the
|
||||
* the reference count for this label drops to zero, remove this label.
|
||||
*/
|
||||
** the reference count for this label drops to zero, remove this label.
|
||||
*/
|
||||
if (E->JumpTo) {
|
||||
/* Remove the reference */
|
||||
CS_RemoveLabelRef (S, E);
|
||||
@@ -631,12 +631,12 @@ void CS_DelEntry (CodeSeg* S, unsigned Index)
|
||||
|
||||
void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count)
|
||||
/* Delete a range of code entries. This includes removing references to labels,
|
||||
* labels attached to the entries and so on.
|
||||
*/
|
||||
** labels attached to the entries and so on.
|
||||
*/
|
||||
{
|
||||
/* Start deleting the entries from the rear, because this involves less
|
||||
* memory moving.
|
||||
*/
|
||||
** memory moving.
|
||||
*/
|
||||
while (Count--) {
|
||||
CS_DelEntry (S, Start + Count);
|
||||
}
|
||||
@@ -646,14 +646,14 @@ void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count)
|
||||
|
||||
void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos)
|
||||
/* Move a range of entries from one position to another. Start is the index
|
||||
* of the first entry to move, Count is the number of entries and NewPos is
|
||||
* the index of the target entry. The entry with the index Start will later
|
||||
* have the index NewPos. All entries with indices NewPos and above are
|
||||
* moved to higher indices. If the code block is moved to the end of the
|
||||
* current code, and if pending labels exist, these labels will get attached
|
||||
* to the first instruction of the moved block (the first one after the
|
||||
* current code end)
|
||||
*/
|
||||
** of the first entry to move, Count is the number of entries and NewPos is
|
||||
** the index of the target entry. The entry with the index Start will later
|
||||
** have the index NewPos. All entries with indices NewPos and above are
|
||||
** moved to higher indices. If the code block is moved to the end of the
|
||||
** current code, and if pending labels exist, these labels will get attached
|
||||
** to the first instruction of the moved block (the first one after the
|
||||
** current code end)
|
||||
*/
|
||||
{
|
||||
/* Transparently handle an empty range */
|
||||
if (Count == 0) {
|
||||
@@ -661,8 +661,8 @@ void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos
|
||||
}
|
||||
|
||||
/* If NewPos is at the end of the code segment, move any labels from the
|
||||
* label pool to the first instruction of the moved range.
|
||||
*/
|
||||
** label pool to the first instruction of the moved range.
|
||||
*/
|
||||
if (NewPos == CS_GetEntryCount (S)) {
|
||||
CS_MoveLabelsToEntry (S, CS_GetEntry (S, Start));
|
||||
}
|
||||
@@ -675,8 +675,8 @@ void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos
|
||||
|
||||
struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index)
|
||||
/* Get the code entry preceeding the one with the index Index. If there is no
|
||||
* preceeding code entry, return NULL.
|
||||
*/
|
||||
** preceeding code entry, return NULL.
|
||||
*/
|
||||
{
|
||||
if (Index == 0) {
|
||||
/* This is the first entry */
|
||||
@@ -691,8 +691,8 @@ struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index)
|
||||
|
||||
struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index)
|
||||
/* 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.
|
||||
*/
|
||||
{
|
||||
if (Index >= CollCount (&S->Entries)-1) {
|
||||
/* This is the last entry */
|
||||
@@ -708,8 +708,8 @@ struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index)
|
||||
int CS_GetEntries (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.
|
||||
*/
|
||||
** we got the lines, return false if not enough lines were available.
|
||||
*/
|
||||
{
|
||||
/* Check if enough entries are available */
|
||||
if (Start + Count > CollCount (&S->Entries)) {
|
||||
@@ -739,9 +739,9 @@ unsigned CS_GetEntryIndex (CodeSeg* S, struct CodeEntry* E)
|
||||
|
||||
int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count)
|
||||
/* Return true if any of the code entries in the given range has a label
|
||||
* attached. If the code segment does not span the given range, check the
|
||||
* possible span instead.
|
||||
*/
|
||||
** attached. If the code segment does not span the given range, check the
|
||||
** possible span instead.
|
||||
*/
|
||||
{
|
||||
unsigned EntryCount = CS_GetEntryCount(S);
|
||||
|
||||
@@ -752,8 +752,8 @@ int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count)
|
||||
}
|
||||
|
||||
/* Check each entry. Since we have validated the index above, we may
|
||||
* use the unchecked access function in the loop which is faster.
|
||||
*/
|
||||
** use the unchecked access function in the loop which is faster.
|
||||
*/
|
||||
while (Count--) {
|
||||
const CodeEntry* E = CollAtUnchecked (&S->Entries, Start++);
|
||||
if (CE_HasLabel (E)) {
|
||||
@@ -805,8 +805,8 @@ CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name)
|
||||
|
||||
CodeLabel* CS_GenLabel (CodeSeg* S, struct CodeEntry* E)
|
||||
/* If the code entry E does already have a label, return it. Otherwise
|
||||
* create a new label, attach it to E and return it.
|
||||
*/
|
||||
** create a new label, attach it to E and return it.
|
||||
*/
|
||||
{
|
||||
CodeLabel* L;
|
||||
|
||||
@@ -856,10 +856,10 @@ void CS_DelLabel (CodeSeg* S, CodeLabel* L)
|
||||
CollDeleteAll (&L->JumpFrom);
|
||||
|
||||
/* Remove the reference to the owning instruction if it has one. The
|
||||
* function may be called for a label without an owner when deleting
|
||||
* unfinished parts of the code. This is unfortunate since it allows
|
||||
* errors to slip through.
|
||||
*/
|
||||
** function may be called for a label without an owner when deleting
|
||||
** unfinished parts of the code. This is unfortunate since it allows
|
||||
** errors to slip through.
|
||||
*/
|
||||
if (L->Owner) {
|
||||
CollDeleteItem (&L->Owner->Labels, L);
|
||||
}
|
||||
@@ -872,16 +872,16 @@ void CS_DelLabel (CodeSeg* S, CodeLabel* L)
|
||||
|
||||
void CS_MergeLabels (CodeSeg* S)
|
||||
/* Merge code labels. That means: For each instruction, remove all labels but
|
||||
* one and adjust references accordingly.
|
||||
*/
|
||||
** one and adjust references accordingly.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
unsigned J;
|
||||
|
||||
/* First, remove all labels from the label symbol table that don't have an
|
||||
* owner (this means that they are actually external labels but we didn't
|
||||
* know that previously since they may have also been forward references).
|
||||
*/
|
||||
** owner (this means that they are actually external labels but we didn't
|
||||
** know that previously since they may have also been forward references).
|
||||
*/
|
||||
for (I = 0; I < CS_LABEL_HASH_SIZE; ++I) {
|
||||
|
||||
/* Get the first label in this hash chain */
|
||||
@@ -898,9 +898,9 @@ void CS_MergeLabels (CodeSeg* S)
|
||||
/* Get the entry referencing this label */
|
||||
CodeEntry* E = CL_GetRef (X, J);
|
||||
/* And remove the reference. Do NOT call CE_ClearJumpTo
|
||||
* here, because this will also clear the label name,
|
||||
* which is not what we want.
|
||||
*/
|
||||
** here, because this will also clear the label name,
|
||||
** which is not what we want.
|
||||
*/
|
||||
E->JumpTo = 0;
|
||||
}
|
||||
|
||||
@@ -937,10 +937,10 @@ void CS_MergeLabels (CodeSeg* S)
|
||||
RefLab = CE_GetLabel (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
|
||||
* that are no longer used. To increase performance, walk backwards
|
||||
* through the list.
|
||||
*/
|
||||
** labels to a reference to the one and only label. Delete the labels
|
||||
** that are no longer used. To increase performance, walk backwards
|
||||
** through the list.
|
||||
*/
|
||||
for (J = LabelCount-1; J >= 1; --J) {
|
||||
|
||||
/* Get the next label */
|
||||
@@ -954,9 +954,9 @@ void CS_MergeLabels (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* The reference label is the only remaining label. Check if there
|
||||
* are any references to this label, and delete it if this is not
|
||||
* the case.
|
||||
*/
|
||||
** are any references to this label, and delete it if this is not
|
||||
** the case.
|
||||
*/
|
||||
if (CollCount (&RefLab->JumpFrom) == 0) {
|
||||
/* Delete the label */
|
||||
CS_DelLabel (S, RefLab);
|
||||
@@ -968,10 +968,10 @@ void CS_MergeLabels (CodeSeg* S)
|
||||
|
||||
void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New)
|
||||
/* Move all labels from Old to New. The routine will move the labels itself
|
||||
* if New does not have any labels, and move references if there is at least
|
||||
* a label for new. If references are moved, the old label is deleted
|
||||
* afterwards.
|
||||
*/
|
||||
** if New does not have any labels, and move references if there is at least
|
||||
** a label for new. If references are moved, the old label is deleted
|
||||
** afterwards.
|
||||
*/
|
||||
{
|
||||
/* Get the number of labels to move */
|
||||
unsigned OldLabelCount = CE_GetLabelCount (Old);
|
||||
@@ -1011,10 +1011,10 @@ void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New)
|
||||
|
||||
void CS_RemoveLabelRef (CodeSeg* S, struct CodeEntry* E)
|
||||
/* Remove the reference between E and the label it jumps to. The reference
|
||||
* will be removed on both sides and E->JumpTo will be 0 after that. If
|
||||
* the reference was the only one for the label, the label will get
|
||||
* deleted.
|
||||
*/
|
||||
** will be removed on both sides and E->JumpTo will be 0 after that. If
|
||||
** the reference was the only one for the label, the label will get
|
||||
** deleted.
|
||||
*/
|
||||
{
|
||||
/* Get a pointer to the label and make sure it exists */
|
||||
CodeLabel* L = E->JumpTo;
|
||||
@@ -1036,9 +1036,9 @@ void CS_RemoveLabelRef (CodeSeg* S, struct CodeEntry* E)
|
||||
|
||||
void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L)
|
||||
/* Change the reference of E to L instead of the current one. If this
|
||||
* was the only reference to the old label, the old label will get
|
||||
* deleted.
|
||||
*/
|
||||
** was the only reference to the old label, the old label will get
|
||||
** deleted.
|
||||
*/
|
||||
{
|
||||
/* Get the old label */
|
||||
CodeLabel* OldLabel = E->JumpTo;
|
||||
@@ -1057,10 +1057,10 @@ void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L)
|
||||
|
||||
void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last)
|
||||
/* Delete all entries between first and last, both inclusive. The function
|
||||
* can only handle basic blocks (First is the only entry, Last the only exit)
|
||||
* and no open labels. It will call FAIL if any of these preconditions are
|
||||
* violated.
|
||||
*/
|
||||
** can only handle basic blocks (First is the only entry, Last the only exit)
|
||||
** and no open labels. It will call FAIL if any of these preconditions are
|
||||
** violated.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
CodeEntry* FirstEntry;
|
||||
@@ -1069,17 +1069,17 @@ void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last)
|
||||
CHECK (First <= Last && Last < CS_GetEntryCount (S));
|
||||
|
||||
/* If Last is actually the last insn, call CS_DelCodeAfter instead, which
|
||||
* is more flexible in this case.
|
||||
*/
|
||||
** is more flexible in this case.
|
||||
*/
|
||||
if (Last == CS_GetEntryCount (S) - 1) {
|
||||
CS_DelCodeAfter (S, First);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the first entry and check if it has any labels. If it has, move
|
||||
* them to the insn following Last. If Last is the last insn of the code
|
||||
* segment, make them ownerless and move them to the label pool.
|
||||
*/
|
||||
** them to the insn following Last. If Last is the last insn of the code
|
||||
** segment, make them ownerless and move them to the label pool.
|
||||
*/
|
||||
FirstEntry = CS_GetEntry (S, First);
|
||||
if (CE_HasLabel (FirstEntry)) {
|
||||
/* Get the entry following last */
|
||||
@@ -1094,8 +1094,8 @@ void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last)
|
||||
}
|
||||
|
||||
/* First pass: Delete all references to labels. If the reference count
|
||||
* for a label drops to zero, delete it.
|
||||
*/
|
||||
** for a label drops to zero, delete it.
|
||||
*/
|
||||
for (I = Last; I >= First; --I) {
|
||||
|
||||
/* Get the next entry */
|
||||
@@ -1114,9 +1114,9 @@ void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last)
|
||||
}
|
||||
|
||||
/* Second pass: Delete the instructions. If a label attached to an
|
||||
* instruction still has references, it must be references from outside
|
||||
* the deleted area, which is an error.
|
||||
*/
|
||||
** instruction still has references, it must be references from outside
|
||||
** the deleted area, which is an error.
|
||||
*/
|
||||
for (I = Last; I >= First; --I) {
|
||||
|
||||
/* Get the next entry */
|
||||
@@ -1142,8 +1142,8 @@ void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
|
||||
unsigned Count = CS_GetEntryCount (S);
|
||||
|
||||
/* First pass: Delete all references to labels. If the reference count
|
||||
* for a label drops to zero, delete it.
|
||||
*/
|
||||
** for a label drops to zero, delete it.
|
||||
*/
|
||||
unsigned C = Count;
|
||||
while (Last < C--) {
|
||||
|
||||
@@ -1153,8 +1153,8 @@ void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
|
||||
/* Check if this entry has a label reference */
|
||||
if (E->JumpTo) {
|
||||
/* If the label is a label in the label pool and this is the last
|
||||
* reference to the label, remove the label from the pool.
|
||||
*/
|
||||
** reference to the label, remove the label from the pool.
|
||||
*/
|
||||
CodeLabel* L = E->JumpTo;
|
||||
int Index = CollIndex (&S->Labels, L);
|
||||
if (Index >= 0 && CollCount (&L->JumpFrom) == 1) {
|
||||
@@ -1169,10 +1169,10 @@ void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
|
||||
}
|
||||
|
||||
/* Second pass: Delete the instructions. If a label attached to an
|
||||
* instruction still has references, it must be references from outside
|
||||
* the deleted area. Don't delete the label in this case, just make it
|
||||
* ownerless and move it to the label pool.
|
||||
*/
|
||||
** instruction still has references, it must be references from outside
|
||||
** the deleted area. Don't delete the label in this case, just make it
|
||||
** ownerless and move it to the label pool.
|
||||
*/
|
||||
C = Count;
|
||||
while (Last < C--) {
|
||||
|
||||
@@ -1207,10 +1207,10 @@ void CS_ResetMarks (CodeSeg* S, unsigned First, unsigned Last)
|
||||
|
||||
int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
/* Check if the given code segment range is a basic block. That is, check if
|
||||
* First is the only entrance and Last is the only exit. This means that no
|
||||
* jump/branch inside the block may jump to an insn below First or after(!)
|
||||
* Last, and that no insn may jump into this block from the outside.
|
||||
*/
|
||||
** First is the only entrance and Last is the only exit. This means that no
|
||||
** jump/branch inside the block may jump to an insn below First or after(!)
|
||||
** Last, and that no insn may jump into this block from the outside.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
@@ -1221,8 +1221,8 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
CS_ResetMarks (S, First, Last);
|
||||
|
||||
/* Second pass: Walk over the range checking all labels. Note: There may be
|
||||
* label on the first insn which is ok.
|
||||
*/
|
||||
** label on the first insn which is ok.
|
||||
*/
|
||||
I = First + 1;
|
||||
while (I <= Last) {
|
||||
|
||||
@@ -1230,8 +1230,8 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if this entry has one or more labels, if so, check which
|
||||
* entries jump to this label.
|
||||
*/
|
||||
** entries jump to this label.
|
||||
*/
|
||||
unsigned LabelCount = CE_GetLabelCount (E);
|
||||
unsigned LabelIndex;
|
||||
for (LabelIndex = 0; LabelIndex < LabelCount; ++LabelIndex) {
|
||||
@@ -1240,8 +1240,8 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
CodeLabel* L = CE_GetLabel (E, LabelIndex);
|
||||
|
||||
/* Walk over all entries that jump to this label. Check for each
|
||||
* of the entries if it is out of the range.
|
||||
*/
|
||||
** of the entries if it is out of the range.
|
||||
*/
|
||||
unsigned RefCount = CL_GetRefCount (L);
|
||||
unsigned RefIndex;
|
||||
for (RefIndex = 0; RefIndex < RefCount; ++RefIndex) {
|
||||
@@ -1250,10 +1250,10 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
CodeEntry* Ref = CL_GetRef (L, RefIndex);
|
||||
|
||||
/* Walk over out complete range and check if we find the
|
||||
* refering entry. This is cheaper than using CS_GetEntryIndex,
|
||||
* because CS_GetEntryIndex will search the complete code
|
||||
* segment and not just our range.
|
||||
*/
|
||||
** refering entry. This is cheaper than using CS_GetEntryIndex,
|
||||
** because CS_GetEntryIndex will search the complete code
|
||||
** segment and not just our range.
|
||||
*/
|
||||
unsigned J;
|
||||
for (J = First; J <= Last; ++J) {
|
||||
if (Ref == CS_GetEntry (S, J)) {
|
||||
@@ -1262,17 +1262,17 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
}
|
||||
if (J > Last) {
|
||||
/* We did not find the entry. This means that the jump to
|
||||
* out code segment entry E came from outside the range,
|
||||
* which in turn means that the given range is not a basic
|
||||
* block.
|
||||
*/
|
||||
** out code segment entry E came from outside the range,
|
||||
** which in turn means that the given range is not a basic
|
||||
** block.
|
||||
*/
|
||||
CS_ResetMarks (S, First, Last);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we come here, we found the entry. Mark it, so we know
|
||||
* that the branch to the label is in range.
|
||||
*/
|
||||
** that the branch to the label is in range.
|
||||
*/
|
||||
CE_SetMark (Ref);
|
||||
}
|
||||
}
|
||||
@@ -1282,9 +1282,9 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
}
|
||||
|
||||
/* Third pass: Walk again over the range and check all branches. If we
|
||||
* find a branch that is not marked, its target is not inside the range
|
||||
* (since we checked all the labels in the range before).
|
||||
*/
|
||||
** find a branch that is not marked, its target is not inside the range
|
||||
** (since we checked all the labels in the range before).
|
||||
*/
|
||||
I = First;
|
||||
while (I <= Last) {
|
||||
|
||||
@@ -1295,8 +1295,8 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
if (E->Info & (OF_UBRA | OF_CBRA)) {
|
||||
if (!CE_HasMark (E)) {
|
||||
/* No mark means not a basic block. Before bailing out, be sure
|
||||
* to remove the marks from the remaining entries.
|
||||
*/
|
||||
** to remove the marks from the remaining entries.
|
||||
*/
|
||||
CS_ResetMarks (S, I+1, Last);
|
||||
return 0;
|
||||
}
|
||||
@@ -1317,18 +1317,18 @@ int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
|
||||
void CS_OutputPrologue (const CodeSeg* S)
|
||||
/* If the given code segment is a code segment for a function, output the
|
||||
* assembler prologue into the file. That is: Output a comment header, switch
|
||||
* to the correct segment and enter the local function scope. If the code
|
||||
* segment is global, do nothing.
|
||||
*/
|
||||
** assembler prologue into the file. That is: Output a comment header, switch
|
||||
** to the correct segment and enter the local function scope. If the code
|
||||
** segment is global, do nothing.
|
||||
*/
|
||||
{
|
||||
/* Get the function associated with the code segment */
|
||||
SymEntry* Func = S->Func;
|
||||
|
||||
/* If the code segment is associated with a function, print a function
|
||||
* header and enter a local scope. Be sure to switch to the correct
|
||||
* segment before outputing the function label.
|
||||
*/
|
||||
** header and enter a local scope. Be sure to switch to the correct
|
||||
** segment before outputing the function label.
|
||||
*/
|
||||
if (Func) {
|
||||
/* Get the function descriptor */
|
||||
CS_PrintFunctionHeader (S);
|
||||
@@ -1347,8 +1347,8 @@ void CS_OutputPrologue (const CodeSeg* S)
|
||||
|
||||
void CS_OutputEpilogue (const CodeSeg* S)
|
||||
/* If the given code segment is a code segment for a function, output the
|
||||
* assembler epilogue into the file. That is: Close the local function scope.
|
||||
*/
|
||||
** assembler epilogue into the file. That is: Close the local function scope.
|
||||
*/
|
||||
{
|
||||
if (S->Func) {
|
||||
WriteOutput ("\n.endproc\n\n");
|
||||
@@ -1383,16 +1383,16 @@ void CS_Output (CodeSeg* S)
|
||||
/* Get the next entry */
|
||||
const CodeEntry* E = CollConstAt (&S->Entries, I);
|
||||
/* Check if the line info has changed. If so, output the source line
|
||||
* if the option is enabled and output debug line info if the debug
|
||||
* option is enabled.
|
||||
*/
|
||||
** if the option is enabled and output debug line info if the debug
|
||||
** option is enabled.
|
||||
*/
|
||||
if (E->LI != LI) {
|
||||
/* Line info has changed, remember the new line info */
|
||||
LI = E->LI;
|
||||
|
||||
/* Add the source line as a comment. Beware: When line continuation
|
||||
* was used, the line may contain newlines.
|
||||
*/
|
||||
** was used, the line may contain newlines.
|
||||
*/
|
||||
if (AddSource) {
|
||||
const char* L = LI->Line;
|
||||
WriteOutput (";\n; ");
|
||||
@@ -1466,8 +1466,8 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
CurrentRegs = &Regs;
|
||||
|
||||
/* Walk over all insns and note just the changes from one insn to the
|
||||
* next one.
|
||||
*/
|
||||
** next one.
|
||||
*/
|
||||
WasJump = 0;
|
||||
for (I = 0; I < CS_GetEntryCount (S); ++I) {
|
||||
|
||||
@@ -1481,13 +1481,13 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
if (LabelCount > 0) {
|
||||
|
||||
/* Loop over all entry points that jump here. If these entry
|
||||
* points already have register info, check if all values are
|
||||
* known and identical. If all values are identical, and the
|
||||
* preceeding instruction was not an unconditional branch, check
|
||||
* if the register value on exit of the preceeding instruction
|
||||
* is also identical. If all these values are identical, the
|
||||
* value of a register is known, otherwise it is unknown.
|
||||
*/
|
||||
** points already have register info, check if all values are
|
||||
** known and identical. If all values are identical, and the
|
||||
** preceeding instruction was not an unconditional branch, check
|
||||
** if the register value on exit of the preceeding instruction
|
||||
** is also identical. If all these values are identical, the
|
||||
** value of a register is known, otherwise it is unknown.
|
||||
*/
|
||||
CodeLabel* Label = CE_GetLabel (E, 0);
|
||||
unsigned Entry;
|
||||
if (WasJump) {
|
||||
@@ -1509,11 +1509,11 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
CodeEntry* J = CL_GetRef (Label, Entry);
|
||||
if (J->RI == 0) {
|
||||
/* No register info for this entry. This means that the
|
||||
* instruction that jumps here is at higher addresses and
|
||||
* the jump is a backward jump. We need a second run to
|
||||
* get the register info right in this case. Until then,
|
||||
* assume unknown register contents.
|
||||
*/
|
||||
** instruction that jumps here is at higher addresses and
|
||||
** the jump is a backward jump. We need a second run to
|
||||
** get the register info right in this case. Until then,
|
||||
** assume unknown register contents.
|
||||
*/
|
||||
Done = 0;
|
||||
RC_Invalidate (&Regs);
|
||||
break;
|
||||
@@ -1554,9 +1554,9 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
CurrentRegs = &E->RI->Out;
|
||||
|
||||
/* If this insn is a branch on zero flag, we may have more info on
|
||||
* register contents for one of both flow directions, but only if
|
||||
* there is a previous instruction.
|
||||
*/
|
||||
** register contents for one of both flow directions, but only if
|
||||
** there is a previous instruction.
|
||||
*/
|
||||
if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
|
||||
|
||||
/* Get the branch condition */
|
||||
@@ -1584,8 +1584,8 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
|
||||
case OP65_CMP:
|
||||
/* If this is an immidiate compare, the A register has
|
||||
* the value of the compare later.
|
||||
*/
|
||||
** the value of the compare later.
|
||||
*/
|
||||
if (CE_IsConstImm (P)) {
|
||||
if (BC == BC_EQ) {
|
||||
E->RI->Out2.RegA = (unsigned char)P->Num;
|
||||
@@ -1597,8 +1597,8 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
|
||||
case OP65_CPX:
|
||||
/* If this is an immidiate compare, the X register has
|
||||
* the value of the compare later.
|
||||
*/
|
||||
** the value of the compare later.
|
||||
*/
|
||||
if (CE_IsConstImm (P)) {
|
||||
if (BC == BC_EQ) {
|
||||
E->RI->Out2.RegX = (unsigned char)P->Num;
|
||||
@@ -1610,8 +1610,8 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
|
||||
case OP65_CPY:
|
||||
/* If this is an immidiate compare, the Y register has
|
||||
* the value of the compare later.
|
||||
*/
|
||||
** the value of the compare later.
|
||||
*/
|
||||
if (CE_IsConstImm (P)) {
|
||||
if (BC == BC_EQ) {
|
||||
E->RI->Out2.RegY = (unsigned char)P->Num;
|
||||
@@ -1648,9 +1648,9 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
case OP65_TAX:
|
||||
case OP65_TXA:
|
||||
/* If the branch is a beq, both A and X are zero at the
|
||||
* branch target, otherwise they are zero at the next
|
||||
* insn.
|
||||
*/
|
||||
** branch target, otherwise they are zero at the next
|
||||
** insn.
|
||||
*/
|
||||
if (BC == BC_EQ) {
|
||||
E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
|
||||
} else {
|
||||
@@ -1661,9 +1661,9 @@ void CS_GenRegInfo (CodeSeg* S)
|
||||
case OP65_TAY:
|
||||
case OP65_TYA:
|
||||
/* If the branch is a beq, both A and Y are zero at the
|
||||
* branch target, otherwise they are zero at the next
|
||||
* insn.
|
||||
*/
|
||||
** branch target, otherwise they are zero at the next
|
||||
** insn.
|
||||
*/
|
||||
if (BC == BC_EQ) {
|
||||
E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
|
||||
} else {
|
||||
|
||||
@@ -118,38 +118,38 @@ INLINE unsigned CS_GetEntryCount (const CodeSeg* S)
|
||||
|
||||
void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index);
|
||||
/* Insert the code entry at the index given. Following code entries will be
|
||||
* moved to slots with higher indices.
|
||||
*/
|
||||
** moved to slots with higher indices.
|
||||
*/
|
||||
|
||||
void CS_DelEntry (CodeSeg* S, unsigned Index);
|
||||
/* 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.
|
||||
* Note: Labels are moved forward if possible, that is, they are moved to the
|
||||
* next insn (not the preceeding one).
|
||||
*/
|
||||
** labels, removing references to labels and even removing the referenced labels
|
||||
** if the reference count drops to zero.
|
||||
** Note: Labels are moved forward if possible, that is, they are moved to the
|
||||
** next insn (not the preceeding one).
|
||||
*/
|
||||
|
||||
void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count);
|
||||
/* Delete a range of code entries. This includes removing references to labels,
|
||||
* labels attached to the entries and so on.
|
||||
*/
|
||||
** labels attached to the entries and so on.
|
||||
*/
|
||||
|
||||
void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos);
|
||||
/* Move a range of entries from one position to another. Start is the index
|
||||
* of the first entry to move, Count is the number of entries and NewPos is
|
||||
* the index of the target entry. The entry with the index Start will later
|
||||
* have the index NewPos. All entries with indices NewPos and above are
|
||||
* moved to higher indices. If the code block is moved to the end of the
|
||||
* current code, and if pending labels exist, these labels will get attached
|
||||
* to the first instruction of the moved block (the first one after the
|
||||
* current code end)
|
||||
*/
|
||||
** of the first entry to move, Count is the number of entries and NewPos is
|
||||
** the index of the target entry. The entry with the index Start will later
|
||||
** have the index NewPos. All entries with indices NewPos and above are
|
||||
** moved to higher indices. If the code block is moved to the end of the
|
||||
** current code, and if pending labels exist, these labels will get attached
|
||||
** to the first instruction of the moved block (the first one after the
|
||||
** current code end)
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void CS_MoveEntry (CodeSeg* S, unsigned OldPos, unsigned NewPos)
|
||||
/* Move an entry from one position to another. OldPos is the current position
|
||||
* of the entry, NewPos is the new position of the entry.
|
||||
*/
|
||||
** of the entry, NewPos is the new position of the entry.
|
||||
*/
|
||||
{
|
||||
CollMove (&S->Entries, OldPos, NewPos);
|
||||
}
|
||||
@@ -169,34 +169,34 @@ INLINE struct CodeEntry* CS_GetEntry (CodeSeg* S, unsigned Index)
|
||||
|
||||
struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index);
|
||||
/* Get the code entry preceeding the one with the index Index. If there is no
|
||||
* preceeding code entry, return NULL.
|
||||
*/
|
||||
** preceeding code entry, return NULL.
|
||||
*/
|
||||
|
||||
struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index);
|
||||
/* 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 CS_GetEntries (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.
|
||||
*/
|
||||
** we got the lines, return false if not enough lines were available.
|
||||
*/
|
||||
|
||||
unsigned CS_GetEntryIndex (CodeSeg* S, struct CodeEntry* E);
|
||||
/* Return the index of a code entry */
|
||||
|
||||
int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count);
|
||||
/* Return true if any of the code entries in the given range has a label
|
||||
* attached. If the code segment does not span the given range, check the
|
||||
* possible span instead.
|
||||
*/
|
||||
** attached. If the code segment does not span the given range, check the
|
||||
** possible span instead.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int CS_HavePendingLabel (const CodeSeg* S)
|
||||
/* Return true if there are open labels that will get attached to the next
|
||||
* instruction that is added.
|
||||
*/
|
||||
** instruction that is added.
|
||||
*/
|
||||
{
|
||||
return (CollCount (&S->Labels) > 0);
|
||||
}
|
||||
@@ -209,43 +209,43 @@ CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name);
|
||||
|
||||
CodeLabel* CS_GenLabel (CodeSeg* S, struct CodeEntry* E);
|
||||
/* If the code entry E does already have a label, return it. Otherwise
|
||||
* create a new label, attach it to E and return it.
|
||||
*/
|
||||
** create a new label, attach it to E and return it.
|
||||
*/
|
||||
|
||||
void CS_DelLabel (CodeSeg* S, CodeLabel* L);
|
||||
/* Remove references from this label and delete it. */
|
||||
|
||||
void CS_MergeLabels (CodeSeg* S);
|
||||
/* Merge code labels. That means: For each instruction, remove all labels but
|
||||
* one and adjust references accordingly.
|
||||
*/
|
||||
** one and adjust references accordingly.
|
||||
*/
|
||||
|
||||
void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New);
|
||||
/* Move all labels from Old to New. The routine will move the labels itself
|
||||
* if New does not have any labels, and move references if there is at least
|
||||
* a label for new. If references are moved, the old label is deleted
|
||||
* afterwards.
|
||||
*/
|
||||
** if New does not have any labels, and move references if there is at least
|
||||
** a label for new. If references are moved, the old label is deleted
|
||||
** afterwards.
|
||||
*/
|
||||
|
||||
void CS_RemoveLabelRef (CodeSeg* S, struct CodeEntry* E);
|
||||
/* Remove the reference between E and the label it jumps to. The reference
|
||||
* will be removed on both sides and E->JumpTo will be 0 after that. If
|
||||
* the reference was the only one for the label, the label will get
|
||||
* deleted.
|
||||
*/
|
||||
** will be removed on both sides and E->JumpTo will be 0 after that. If
|
||||
** the reference was the only one for the label, the label will get
|
||||
** deleted.
|
||||
*/
|
||||
|
||||
void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L);
|
||||
/* Change the reference of E to L instead of the current one. If this
|
||||
* was the only reference to the old label, the old label will get
|
||||
* deleted.
|
||||
*/
|
||||
** was the only reference to the old label, the old label will get
|
||||
** deleted.
|
||||
*/
|
||||
|
||||
void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last);
|
||||
/* Delete all entries between first and last, both inclusive. The function
|
||||
* can only handle basic blocks (First is the only entry, Last the only exit)
|
||||
* and no open labels. It will call FAIL if any of these preconditions are
|
||||
* violated.
|
||||
*/
|
||||
** can only handle basic blocks (First is the only entry, Last the only exit)
|
||||
** and no open labels. It will call FAIL if any of these preconditions are
|
||||
** violated.
|
||||
*/
|
||||
|
||||
void CS_DelCodeAfter (CodeSeg* S, unsigned Last);
|
||||
/* Delete all entries including the given one */
|
||||
@@ -268,22 +268,22 @@ INLINE void CS_ResetAllMarks (CodeSeg* S)
|
||||
|
||||
int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last);
|
||||
/* Check if the given code segment range is a basic block. That is, check if
|
||||
* First is the only entrance and Last is the only exit. This means that no
|
||||
* jump/branch inside the block may jump to an insn below First or after(!)
|
||||
* Last, and that no insn may jump into this block from the outside.
|
||||
*/
|
||||
** First is the only entrance and Last is the only exit. This means that no
|
||||
** jump/branch inside the block may jump to an insn below First or after(!)
|
||||
** Last, and that no insn may jump into this block from the outside.
|
||||
*/
|
||||
|
||||
void CS_OutputPrologue (const CodeSeg* S);
|
||||
/* If the given code segment is a code segment for a function, output the
|
||||
* assembler prologue into the file. That is: Output a comment header, switch
|
||||
* to the correct segment and enter the local function scope. If the code
|
||||
* segment is global, do nothing.
|
||||
*/
|
||||
** assembler prologue into the file. That is: Output a comment header, switch
|
||||
** to the correct segment and enter the local function scope. If the code
|
||||
** segment is global, do nothing.
|
||||
*/
|
||||
|
||||
void CS_OutputEpilogue (const CodeSeg* S);
|
||||
/* If the given code segment is a code segment for a function, output the
|
||||
* assembler epilogue into the file. That is: Close the local function scope.
|
||||
*/
|
||||
** assembler epilogue into the file. That is: Close the local function scope.
|
||||
*/
|
||||
|
||||
void CS_Output (CodeSeg* S);
|
||||
/* Output the code segment data to a file */
|
||||
|
||||
@@ -141,14 +141,14 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* Check if we must reserve storage for the variable. We do this,
|
||||
*
|
||||
* - if it is not a typedef or function,
|
||||
* - if we don't had a storage class given ("int i")
|
||||
* - if the storage class is explicitly specified as static,
|
||||
* - or if there is an initialization.
|
||||
*
|
||||
* This means that "extern int i;" will not get storage allocated.
|
||||
*/
|
||||
**
|
||||
** - if it is not a typedef or function,
|
||||
** - if we don't had a storage class given ("int i")
|
||||
** - if the storage class is explicitly specified as static,
|
||||
** - or if there is an initialization.
|
||||
**
|
||||
** This means that "extern int i;" will not get storage allocated.
|
||||
*/
|
||||
if ((Decl.StorageClass & SC_FUNC) != SC_FUNC &&
|
||||
(Decl.StorageClass & SC_TYPEMASK) != SC_TYPEDEF &&
|
||||
((Spec.Flags & DS_DEF_STORAGE) != 0 ||
|
||||
@@ -161,10 +161,10 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* If this is a function declarator that is not followed by a comma
|
||||
* or semicolon, it must be followed by a function body. If this is
|
||||
* the case, convert an empty parameter list into one accepting no
|
||||
* parameters (same as void) as required by the standard.
|
||||
*/
|
||||
** or semicolon, it must be followed by a function body. If this is
|
||||
** the case, convert an empty parameter list into one accepting no
|
||||
** parameters (same as void) as required by the standard.
|
||||
*/
|
||||
if ((Decl.StorageClass & SC_FUNC) != 0 &&
|
||||
(CurTok.Tok != TOK_COMMA) &&
|
||||
(CurTok.Tok != TOK_SEMI)) {
|
||||
@@ -191,8 +191,8 @@ static void Parse (void)
|
||||
if (CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
/* We cannot initialize types of unknown size, or
|
||||
* void types in non ANSI mode.
|
||||
*/
|
||||
** void types in ISO modes.
|
||||
*/
|
||||
if (Size == 0) {
|
||||
if (!IsTypeVoid (Decl.Type)) {
|
||||
if (!IsTypeArray (Decl.Type)) {
|
||||
@@ -206,9 +206,9 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* Switch to the data or rodata segment. For arrays, check
|
||||
* the element qualifiers, since not the array but its
|
||||
* elements are const.
|
||||
*/
|
||||
** the element qualifiers, since not the array but its
|
||||
** elements are const.
|
||||
*/
|
||||
if (IsQualConst (GetBaseElementType (Decl.Type))) {
|
||||
g_userodata ();
|
||||
} else {
|
||||
@@ -303,8 +303,8 @@ void Compile (const char* FileName)
|
||||
struct tm* TM;
|
||||
|
||||
/* Since strftime is locale dependent, we need the abbreviated month names
|
||||
* in english.
|
||||
*/
|
||||
** in english.
|
||||
*/
|
||||
static const char MonthNames[12][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
@@ -320,9 +320,9 @@ void Compile (const char* FileName)
|
||||
DefineNumericMacro ("__CC65_STD__", IS_Get (&Standard));
|
||||
|
||||
/* Optimization macros. Since no source code has been parsed for now, the
|
||||
* IS_Get functions access the values in effect now, regardless of any
|
||||
* changes using #pragma later.
|
||||
*/
|
||||
** IS_Get functions access the values in effect now, regardless of any
|
||||
** changes using #pragma later.
|
||||
*/
|
||||
if (IS_Get (&Optimize)) {
|
||||
long CodeSize = IS_Get (&CodeSizeFactor);
|
||||
DefineNumericMacro ("__OPT__", 1);
|
||||
|
||||
@@ -51,29 +51,29 @@
|
||||
|
||||
unsigned OptAdd1 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldy #xx
|
||||
* jsr ldaxysp
|
||||
* jsr pushax
|
||||
* ldy #yy
|
||||
* jsr ldaxysp
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy #xx-1
|
||||
* lda (sp),y
|
||||
* ldy #yy-3
|
||||
* clc
|
||||
* adc (sp),y
|
||||
* pha
|
||||
* ldy #xx
|
||||
* lda (sp),y
|
||||
* ldy #yy-2
|
||||
* adc (sp),y
|
||||
* tax
|
||||
* pla
|
||||
*/
|
||||
**
|
||||
** ldy #xx
|
||||
** jsr ldaxysp
|
||||
** jsr pushax
|
||||
** ldy #yy
|
||||
** jsr ldaxysp
|
||||
** jsr tosaddax
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy #xx-1
|
||||
** lda (sp),y
|
||||
** ldy #yy-3
|
||||
** clc
|
||||
** adc (sp),y
|
||||
** pha
|
||||
** ldy #xx
|
||||
** lda (sp),y
|
||||
** ldy #yy-2
|
||||
** adc (sp),y
|
||||
** tax
|
||||
** pla
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -172,28 +172,28 @@ unsigned OptAdd1 (CodeSeg* S)
|
||||
|
||||
unsigned OptAdd2 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldy #xx
|
||||
* jsr ldaxysp
|
||||
* ldy #yy
|
||||
* jsr addeqysp
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy #xx-1
|
||||
* lda (sp),y
|
||||
* ldy #yy
|
||||
* clc
|
||||
* adc (sp),y
|
||||
* sta (sp),y
|
||||
* ldy #xx
|
||||
* lda (sp),y
|
||||
* ldy #yy+1
|
||||
* adc (sp),y
|
||||
* sta (sp),y
|
||||
*
|
||||
* provided that a/x is not used later.
|
||||
*/
|
||||
**
|
||||
** ldy #xx
|
||||
** jsr ldaxysp
|
||||
** ldy #yy
|
||||
** jsr addeqysp
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy #xx-1
|
||||
** lda (sp),y
|
||||
** ldy #yy
|
||||
** clc
|
||||
** adc (sp),y
|
||||
** sta (sp),y
|
||||
** ldy #xx
|
||||
** lda (sp),y
|
||||
** ldy #yy+1
|
||||
** adc (sp),y
|
||||
** sta (sp),y
|
||||
**
|
||||
** provided that a/x is not used later.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -288,20 +288,20 @@ unsigned OptAdd2 (CodeSeg* S)
|
||||
|
||||
unsigned OptAdd3 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* jsr pushax
|
||||
* ldx #$00
|
||||
* lda xxx
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L1
|
||||
* inx
|
||||
* L1:
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldx #$00
|
||||
** lda xxx
|
||||
** jsr tosaddax
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L1
|
||||
** inx
|
||||
** L1:
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -364,22 +364,22 @@ unsigned OptAdd3 (CodeSeg* S)
|
||||
|
||||
unsigned OptAdd4 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* jsr pushax
|
||||
* lda xxx
|
||||
* ldx yyy
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* pha
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* pla
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** lda xxx
|
||||
** ldx yyy
|
||||
** jsr tosaddax
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** pha
|
||||
** txa
|
||||
** adc yyy
|
||||
** tax
|
||||
** pla
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -453,8 +453,8 @@ unsigned OptAdd4 (CodeSeg* S)
|
||||
|
||||
unsigned OptAdd5 (CodeSeg* S)
|
||||
/* Search for a call to incaxn and replace it by an 8 bit add if the X register
|
||||
* is not used later.
|
||||
*/
|
||||
** is not used later.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -506,14 +506,14 @@ unsigned OptAdd5 (CodeSeg* S)
|
||||
|
||||
unsigned OptAdd6 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* adc ...
|
||||
* bcc L
|
||||
* inx
|
||||
* L:
|
||||
*
|
||||
* and remove the handling of the high byte if X is not used later.
|
||||
*/
|
||||
**
|
||||
** adc ...
|
||||
** bcc L
|
||||
** inx
|
||||
** L:
|
||||
**
|
||||
** and remove the handling of the high byte if X is not used later.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2001-2005, Ullrich von Bassewitz */
|
||||
/* R<EFBFBD>merstrasse 52 */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
@@ -51,102 +51,102 @@
|
||||
|
||||
unsigned OptAdd1 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* jsr pushax
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xxx-2
|
||||
* clc
|
||||
* adc (sp),y
|
||||
* bcc L
|
||||
* inx
|
||||
* L:
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** jsr tosaddax
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xxx-2
|
||||
** clc
|
||||
** adc (sp),y
|
||||
** bcc L
|
||||
** inx
|
||||
** L:
|
||||
*/
|
||||
|
||||
unsigned OptAdd2 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldy #xx
|
||||
* lda (sp),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (sp),y
|
||||
* ldy #$yy
|
||||
* jsr addeqysp
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy #xx-1
|
||||
* lda (sp),y
|
||||
* ldy #yy
|
||||
* clc
|
||||
* adc (sp),y
|
||||
* sta (sp),y
|
||||
* ldy #xx
|
||||
* lda (sp),y
|
||||
* ldy #yy+1
|
||||
* adc (sp),y
|
||||
* sta (sp),y
|
||||
*
|
||||
* provided that a/x is not used later.
|
||||
*/
|
||||
**
|
||||
** ldy #xx
|
||||
** lda (sp),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (sp),y
|
||||
** ldy #$yy
|
||||
** jsr addeqysp
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy #xx-1
|
||||
** lda (sp),y
|
||||
** ldy #yy
|
||||
** clc
|
||||
** adc (sp),y
|
||||
** sta (sp),y
|
||||
** ldy #xx
|
||||
** lda (sp),y
|
||||
** ldy #yy+1
|
||||
** adc (sp),y
|
||||
** sta (sp),y
|
||||
**
|
||||
** provided that a/x is not used later.
|
||||
*/
|
||||
|
||||
unsigned OptAdd3 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* jsr pushax
|
||||
* ldx #$00
|
||||
* lda xxx
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L1
|
||||
* inx
|
||||
* L1:
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldx #$00
|
||||
** lda xxx
|
||||
** jsr tosaddax
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L1
|
||||
** inx
|
||||
** L1:
|
||||
*/
|
||||
|
||||
unsigned OptAdd4 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* jsr pushax
|
||||
* lda xxx
|
||||
* ldx yyy
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* pha
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* pla
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** lda xxx
|
||||
** ldx yyy
|
||||
** jsr tosaddax
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** pha
|
||||
** txa
|
||||
** adc yyy
|
||||
** tax
|
||||
** pla
|
||||
*/
|
||||
|
||||
unsigned OptAdd5 (CodeSeg* S);
|
||||
/* Search for a call to incaxn and replace it by an 8 bit add if the X register
|
||||
* is not used later.
|
||||
*/
|
||||
** is not used later.
|
||||
*/
|
||||
|
||||
unsigned OptAdd6 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* adc ...
|
||||
* bcc L
|
||||
* inx
|
||||
* L:
|
||||
*
|
||||
* and remove the handling of the high byte if X is not used later.
|
||||
*/
|
||||
**
|
||||
** adc ...
|
||||
** bcc L
|
||||
** inx
|
||||
** L:
|
||||
**
|
||||
** and remove the handling of the high byte if X is not used later.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -75,9 +75,9 @@ unsigned Opt65C02Ind (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for addressing mode indirect indexed Y where Y is zero.
|
||||
* Note: All opcodes that are available as (zp),y are also available
|
||||
* as (zp), so we can ignore the actual opcode here.
|
||||
*/
|
||||
** Note: All opcodes that are available as (zp),y are also available
|
||||
** as (zp), so we can ignore the actual opcode here.
|
||||
*/
|
||||
if (E->AM == AM65_ZP_INDY && E->RI->In.RegY == 0) {
|
||||
|
||||
/* Replace it by indirect addressing mode */
|
||||
@@ -187,8 +187,8 @@ unsigned Opt65C02Stores (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for a store with a register value of zero and an addressing
|
||||
* mode available with STZ.
|
||||
*/
|
||||
** mode available with STZ.
|
||||
*/
|
||||
if (((E->OPC == OP65_STA && E->RI->In.RegA == 0) ||
|
||||
(E->OPC == OP65_STX && E->RI->In.RegX == 0) ||
|
||||
(E->OPC == OP65_STY && E->RI->In.RegY == 0)) &&
|
||||
|
||||
@@ -66,11 +66,11 @@ static const unsigned char CmpInvertTab [] = {
|
||||
|
||||
static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
|
||||
/* Helper function for the replacement of routines that return a boolean
|
||||
* followed by a conditional jump. Instead of the boolean value, the condition
|
||||
* codes are evaluated directly.
|
||||
* I is the index of the conditional branch, the sequence is already checked
|
||||
* to be correct.
|
||||
*/
|
||||
** followed by a conditional jump. Instead of the boolean value, the condition
|
||||
** codes are evaluated directly.
|
||||
** I is the index of the conditional branch, the sequence is already checked
|
||||
** to be correct.
|
||||
*/
|
||||
{
|
||||
CodeEntry* N;
|
||||
CodeLabel* L;
|
||||
@@ -91,10 +91,10 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
|
||||
|
||||
case CMP_GT:
|
||||
/* Replace by
|
||||
* beq @L
|
||||
* jpl Target
|
||||
* @L: ...
|
||||
*/
|
||||
** beq @L
|
||||
** jpl Target
|
||||
** @L: ...
|
||||
*/
|
||||
if ((N = CS_GetNextEntry (S, I)) == 0) {
|
||||
/* No such entry */
|
||||
Internal ("Invalid program flow");
|
||||
@@ -115,9 +115,9 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
|
||||
|
||||
case CMP_LE:
|
||||
/* Replace by
|
||||
* jmi Target
|
||||
* jeq Target
|
||||
*/
|
||||
** jmi Target
|
||||
** jeq Target
|
||||
*/
|
||||
CE_ReplaceOPC (E, OP65_JMI);
|
||||
L = E->JumpTo;
|
||||
N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
|
||||
@@ -126,10 +126,10 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
|
||||
|
||||
case CMP_UGT:
|
||||
/* Replace by
|
||||
* beq @L
|
||||
* jcs Target
|
||||
* @L: ...
|
||||
*/
|
||||
** beq @L
|
||||
** jcs Target
|
||||
** @L: ...
|
||||
*/
|
||||
if ((N = CS_GetNextEntry (S, I)) == 0) {
|
||||
/* No such entry */
|
||||
Internal ("Invalid program flow");
|
||||
@@ -150,9 +150,9 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
|
||||
|
||||
case CMP_ULE:
|
||||
/* Replace by
|
||||
* jcc Target
|
||||
* jeq Target
|
||||
*/
|
||||
** jcc Target
|
||||
** jeq Target
|
||||
*/
|
||||
CE_ReplaceOPC (E, OP65_JCC);
|
||||
L = E->JumpTo;
|
||||
N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
|
||||
@@ -169,10 +169,10 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
|
||||
|
||||
|
||||
static int IsImmCmp16 (CodeEntry** L)
|
||||
/* Check if the instructions at L are an immidiate compare of a/x:
|
||||
*
|
||||
*
|
||||
*/
|
||||
/* Check if the instructions at L are an immediate compare of a/x:
|
||||
**
|
||||
**
|
||||
*/
|
||||
{
|
||||
return (L[0]->OPC == OP65_CPX &&
|
||||
L[0]->AM == AM65_IMM &&
|
||||
@@ -213,8 +213,8 @@ static int GetCmpRegVal (const CodeEntry* E)
|
||||
|
||||
unsigned OptBoolTrans (CodeSeg* S)
|
||||
/* Try to remove the call to boolean transformer routines where the call is
|
||||
* not really needed.
|
||||
*/
|
||||
** not really needed.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -235,11 +235,11 @@ unsigned OptBoolTrans (CodeSeg* S)
|
||||
(N->Info & OF_ZBRA) != 0) {
|
||||
|
||||
/* Make the boolean transformer unnecessary by changing the
|
||||
* the conditional jump to evaluate the condition flags that
|
||||
* are set after the compare directly. Note: jeq jumps if
|
||||
* the condition is not met, jne jumps if the condition is met.
|
||||
* Invert the code if we jump on condition not met.
|
||||
*/
|
||||
** the conditional jump to evaluate the condition flags that
|
||||
** are set after the compare directly. Note: jeq jumps if
|
||||
** the condition is not met, jne jumps if the condition is met.
|
||||
** Invert the code if we jump on condition not met.
|
||||
*/
|
||||
if (GetBranchCond (N->OPC) == BC_EQ) {
|
||||
/* Jumps if condition false, invert condition */
|
||||
Cond = CmpInvertTab [Cond];
|
||||
@@ -275,15 +275,15 @@ unsigned OptBoolTrans (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp1 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldx xx
|
||||
* stx tmp1
|
||||
* ora tmp1
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* ora xx
|
||||
*/
|
||||
**
|
||||
** ldx xx
|
||||
** stx tmp1
|
||||
** ora tmp1
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** ora xx
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -332,16 +332,16 @@ unsigned OptCmp1 (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp2 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* stx xx
|
||||
* stx tmp1
|
||||
* ora tmp1
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* stx xx
|
||||
* ora xx
|
||||
*/
|
||||
**
|
||||
** stx xx
|
||||
** stx tmp1
|
||||
** ora tmp1
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** stx xx
|
||||
** ora xx
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -387,17 +387,17 @@ unsigned OptCmp2 (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp3 (CodeSeg* S)
|
||||
/* Search for
|
||||
*
|
||||
* lda/and/ora/eor ...
|
||||
* cmp #$00
|
||||
* jeq/jne
|
||||
* or
|
||||
* lda/and/ora/eor ...
|
||||
* cmp #$00
|
||||
* jsr boolxx
|
||||
*
|
||||
* and remove the cmp.
|
||||
*/
|
||||
**
|
||||
** lda/and/ora/eor ...
|
||||
** cmp #$00
|
||||
** jeq/jne
|
||||
** or
|
||||
** lda/and/ora/eor ...
|
||||
** cmp #$00
|
||||
** jsr boolxx
|
||||
**
|
||||
** and remove the cmp.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -432,9 +432,9 @@ unsigned OptCmp3 (CodeSeg* S)
|
||||
int Delete = 0;
|
||||
|
||||
/* Check for the call to boolxx. We only remove the compare if
|
||||
* the carry flag is not evaluated later, because the load will
|
||||
* not set the carry flag.
|
||||
*/
|
||||
** the carry flag is not evaluated later, because the load will
|
||||
** not set the carry flag.
|
||||
*/
|
||||
if (L[2]->OPC == OP65_JSR) {
|
||||
switch (FindBoolCmpCond (L[2]->Arg)) {
|
||||
|
||||
@@ -459,10 +459,10 @@ unsigned OptCmp3 (CodeSeg* S)
|
||||
|
||||
} else if ((L[2]->Info & OF_FBRA) != 0) {
|
||||
/* The following insn branches on the condition of the load,
|
||||
* so the compare instruction might be removed. For safety,
|
||||
* do some more checks if the carry isn't used later, since
|
||||
* the compare does set the carry, but the load does not.
|
||||
*/
|
||||
** so the compare instruction might be removed. For safety,
|
||||
** do some more checks if the carry isn't used later, since
|
||||
** the compare does set the carry, but the load does not.
|
||||
*/
|
||||
CodeEntry* E;
|
||||
CodeEntry* N;
|
||||
if ((E = CS_GetNextEntry (S, I+2)) != 0 &&
|
||||
@@ -476,9 +476,9 @@ unsigned OptCmp3 (CodeSeg* S)
|
||||
FindBoolCmpCond (N->Arg) == CMP_INV)) {
|
||||
|
||||
/* The following insn branches on the condition of a load,
|
||||
* and there's no use of the carry flag in sight, so the
|
||||
* compare instruction can be removed.
|
||||
*/
|
||||
** and there's no use of the carry flag in sight, so the
|
||||
** compare instruction can be removed.
|
||||
*/
|
||||
Delete = 1;
|
||||
}
|
||||
}
|
||||
@@ -503,24 +503,24 @@ unsigned OptCmp3 (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp4 (CodeSeg* S)
|
||||
/* Search for
|
||||
*
|
||||
* lda x
|
||||
* ldx y
|
||||
* cpx #a
|
||||
* bne L1
|
||||
* cmp #b
|
||||
* L1: jne/jeq L2
|
||||
*
|
||||
* If a is zero, we may remove the compare. If a and b are both zero, we may
|
||||
* replace it by the sequence
|
||||
*
|
||||
* lda x
|
||||
* ora x+1
|
||||
* jne/jeq ...
|
||||
*
|
||||
* L1 may be either the label at the branch instruction, or the target label
|
||||
* of this instruction.
|
||||
*/
|
||||
**
|
||||
** lda x
|
||||
** ldx y
|
||||
** cpx #a
|
||||
** bne L1
|
||||
** cmp #b
|
||||
** L1: jne/jeq L2
|
||||
**
|
||||
** If a is zero, we may remove the compare. If a and b are both zero, we may
|
||||
** replace it by the sequence
|
||||
**
|
||||
** lda x
|
||||
** ora x+1
|
||||
** jne/jeq ...
|
||||
**
|
||||
** L1 may be either the label at the branch instruction, or the target label
|
||||
** of this instruction.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -547,9 +547,9 @@ unsigned OptCmp4 (CodeSeg* S)
|
||||
CS_DelEntries (S, I+2, 3);
|
||||
} else {
|
||||
/* Move the lda instruction after the first branch. This will
|
||||
* improve speed, since the load is delayed after the first
|
||||
* test.
|
||||
*/
|
||||
** improve speed, since the load is delayed after the first
|
||||
** test.
|
||||
*/
|
||||
CS_MoveEntry (S, I, I+4);
|
||||
|
||||
/* We will replace the ldx/cpx by lda/cmp */
|
||||
@@ -557,8 +557,8 @@ unsigned OptCmp4 (CodeSeg* S)
|
||||
CE_ReplaceOPC (L[1], OP65_CMP);
|
||||
|
||||
/* Beware: If the first LDA instruction had a label, we have
|
||||
* to move this label to the top of the sequence again.
|
||||
*/
|
||||
** to move this label to the top of the sequence again.
|
||||
*/
|
||||
if (CE_HasLabel (E)) {
|
||||
CS_MoveLabels (S, E, L[0]);
|
||||
}
|
||||
@@ -581,14 +581,14 @@ unsigned OptCmp4 (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp5 (CodeSeg* S)
|
||||
/* Optimize compares of local variables:
|
||||
*
|
||||
* ldy #o
|
||||
* jsr ldaxysp
|
||||
* cpx #a
|
||||
* bne L1
|
||||
* cmp #b
|
||||
* jne/jeq L2
|
||||
*/
|
||||
**
|
||||
** ldy #o
|
||||
** jsr ldaxysp
|
||||
** cpx #a
|
||||
** bne L1
|
||||
** cmp #b
|
||||
** jne/jeq L2
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -615,12 +615,12 @@ unsigned OptCmp5 (CodeSeg* S)
|
||||
char Buf[20];
|
||||
|
||||
/* The value is zero, we may use the simple code version:
|
||||
* ldy #o-1
|
||||
* lda (sp),y
|
||||
* ldy #o
|
||||
* ora (sp),y
|
||||
* jne/jeq ...
|
||||
*/
|
||||
** ldy #o-1
|
||||
** lda (sp),y
|
||||
** ldy #o
|
||||
** ora (sp),y
|
||||
** jne/jeq ...
|
||||
*/
|
||||
sprintf (Buf, "$%02X", (int)(L[0]->Num-1));
|
||||
X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+1);
|
||||
@@ -643,17 +643,17 @@ unsigned OptCmp5 (CodeSeg* S)
|
||||
char Buf[20];
|
||||
|
||||
/* Change the code to just use the A register. Move the load
|
||||
* of the low byte after the first branch if possible:
|
||||
*
|
||||
* ldy #o
|
||||
* lda (sp),y
|
||||
* cmp #a
|
||||
* bne L1
|
||||
* ldy #o-1
|
||||
* lda (sp),y
|
||||
* cmp #b
|
||||
* jne/jeq ...
|
||||
*/
|
||||
** of the low byte after the first branch if possible:
|
||||
**
|
||||
** ldy #o
|
||||
** lda (sp),y
|
||||
** cmp #a
|
||||
** bne L1
|
||||
** ldy #o-1
|
||||
** lda (sp),y
|
||||
** cmp #b
|
||||
** jne/jeq ...
|
||||
*/
|
||||
X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+3);
|
||||
|
||||
@@ -690,10 +690,10 @@ unsigned OptCmp5 (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp6 (CodeSeg* S)
|
||||
/* Search for calls to compare subroutines followed by a conditional branch
|
||||
* and replace them by cheaper versions, since the branch means that the
|
||||
* boolean value returned by these routines is not needed (we may also check
|
||||
* that explicitly, but for the current code generator it is always true).
|
||||
*/
|
||||
** and replace them by cheaper versions, since the branch means that the
|
||||
** boolean value returned by these routines is not needed (we may also check
|
||||
** that explicitly, but for the current code generator it is always true).
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -715,12 +715,12 @@ unsigned OptCmp6 (CodeSeg* S)
|
||||
!CE_HasLabel (N)) {
|
||||
|
||||
/* The tos... functions will return a boolean value in a/x and
|
||||
* the Z flag says if this value is zero or not. We will call
|
||||
* a cheaper subroutine instead, one that does not return a
|
||||
* boolean value but only valid flags. Note: jeq jumps if
|
||||
* the condition is not met, jne jumps if the condition is met.
|
||||
* Invert the code if we jump on condition not met.
|
||||
*/
|
||||
** the Z flag says if this value is zero or not. We will call
|
||||
** a cheaper subroutine instead, one that does not return a
|
||||
** boolean value but only valid flags. Note: jeq jumps if
|
||||
** the condition is not met, jne jumps if the condition is met.
|
||||
** Invert the code if we jump on condition not met.
|
||||
*/
|
||||
if (GetBranchCond (N->OPC) == BC_EQ) {
|
||||
/* Jumps if condition false, invert condition */
|
||||
Cond = CmpInvertTab [Cond];
|
||||
@@ -752,8 +752,8 @@ unsigned OptCmp6 (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp7 (CodeSeg* S)
|
||||
/* Search for a sequence ldx/txa/branch and remove the txa if A is not
|
||||
* used later.
|
||||
*/
|
||||
** used later.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -796,8 +796,8 @@ unsigned OptCmp7 (CodeSeg* S)
|
||||
|
||||
unsigned OptCmp8 (CodeSeg* S)
|
||||
/* Check for register compares where the contents of the register and therefore
|
||||
* the result of the compare is known.
|
||||
*/
|
||||
** the result of the compare is known.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -817,8 +817,8 @@ unsigned OptCmp8 (CodeSeg* S)
|
||||
CE_IsConstImm (E)) {
|
||||
|
||||
/* We are able to evaluate the compare at compile time. Check if
|
||||
* one or more branches are ahead.
|
||||
*/
|
||||
** one or more branches are ahead.
|
||||
*/
|
||||
unsigned JumpsChanged = 0;
|
||||
CodeEntry* N;
|
||||
while ((N = CS_GetNextEntry (S, I)) != 0 && /* Followed by something.. */
|
||||
@@ -855,10 +855,10 @@ unsigned OptCmp8 (CodeSeg* S)
|
||||
case BC_VC:
|
||||
case BC_VS:
|
||||
/* Not set by the compare operation, bail out (Note:
|
||||
* Just skipping anything here is rather stupid, but
|
||||
* the sequence is never generated by the compiler,
|
||||
* so it's quite safe to skip).
|
||||
*/
|
||||
** Just skipping anything here is rather stupid, but
|
||||
** the sequence is never generated by the compiler,
|
||||
** so it's quite safe to skip).
|
||||
*/
|
||||
goto NextEntry;
|
||||
|
||||
default:
|
||||
@@ -867,9 +867,9 @@ unsigned OptCmp8 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* If the condition is false, we may remove the jump. Otherwise
|
||||
* the branch will always be taken, so we may replace it by a
|
||||
* jump (and bail out).
|
||||
*/
|
||||
** the branch will always be taken, so we may replace it by a
|
||||
** jump (and bail out).
|
||||
*/
|
||||
if (!Cond) {
|
||||
CS_DelEntry (S, I+1);
|
||||
} else {
|
||||
@@ -906,16 +906,16 @@ NextEntry:
|
||||
|
||||
unsigned OptCmp9 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* sbc xx
|
||||
* bvs/bvc L
|
||||
* eor #$80
|
||||
* L: asl a
|
||||
* bcc/bcs somewhere
|
||||
*
|
||||
* If A is not used later (which should be the case), we can branch on the N
|
||||
* flag instead of the carry flag and remove the asl.
|
||||
*/
|
||||
**
|
||||
** sbc xx
|
||||
** bvs/bvc L
|
||||
** eor #$80
|
||||
** L: asl a
|
||||
** bcc/bcs somewhere
|
||||
**
|
||||
** If A is not used later (which should be the case), we can branch on the N
|
||||
** flag instead of the carry flag and remove the asl.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
|
||||
unsigned OptBoolTrans (CodeSeg* S);
|
||||
/* Try to remove the call to boolean transformer routines where the call is
|
||||
* not really needed.
|
||||
*/
|
||||
** not really needed.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -64,107 +64,107 @@ unsigned OptBoolTrans (CodeSeg* S);
|
||||
|
||||
unsigned OptCmp1 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldx xx
|
||||
* stx tmp1
|
||||
* ora tmp1
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* ora xx
|
||||
*/
|
||||
**
|
||||
** ldx xx
|
||||
** stx tmp1
|
||||
** ora tmp1
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** ora xx
|
||||
*/
|
||||
|
||||
unsigned OptCmp2 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* stx xx
|
||||
* stx tmp1
|
||||
* ora tmp1
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* stx xx
|
||||
* ora xx
|
||||
*/
|
||||
**
|
||||
** stx xx
|
||||
** stx tmp1
|
||||
** ora tmp1
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** stx xx
|
||||
** ora xx
|
||||
*/
|
||||
|
||||
unsigned OptCmp3 (CodeSeg* S);
|
||||
/* Search for
|
||||
*
|
||||
* lda/and/ora/eor ...
|
||||
* cmp #$00
|
||||
* jeq/jne
|
||||
* or
|
||||
* lda/and/ora/eor ...
|
||||
* cmp #$00
|
||||
* jsr boolxx
|
||||
*
|
||||
* and remove the cmp.
|
||||
*/
|
||||
**
|
||||
** lda/and/ora/eor ...
|
||||
** cmp #$00
|
||||
** jeq/jne
|
||||
** or
|
||||
** lda/and/ora/eor ...
|
||||
** cmp #$00
|
||||
** jsr boolxx
|
||||
**
|
||||
** and remove the cmp.
|
||||
*/
|
||||
|
||||
unsigned OptCmp4 (CodeSeg* S);
|
||||
/* Search for
|
||||
*
|
||||
* lda x
|
||||
* ldx y
|
||||
* cpx #a
|
||||
* bne L1
|
||||
* cmp #b
|
||||
* jne/jeq L2
|
||||
*
|
||||
* If a is zero, we may remove the compare. If a and b are both zero, we may
|
||||
* replace it by the sequence
|
||||
*
|
||||
* lda x
|
||||
* ora x+1
|
||||
* jne/jeq ...
|
||||
*
|
||||
* L1 may be either the label at the branch instruction, or the target label
|
||||
* of this instruction.
|
||||
*/
|
||||
**
|
||||
** lda x
|
||||
** ldx y
|
||||
** cpx #a
|
||||
** bne L1
|
||||
** cmp #b
|
||||
** jne/jeq L2
|
||||
**
|
||||
** If a is zero, we may remove the compare. If a and b are both zero, we may
|
||||
** replace it by the sequence
|
||||
**
|
||||
** lda x
|
||||
** ora x+1
|
||||
** jne/jeq ...
|
||||
**
|
||||
** L1 may be either the label at the branch instruction, or the target label
|
||||
** of this instruction.
|
||||
*/
|
||||
|
||||
unsigned OptCmp5 (CodeSeg* S);
|
||||
/* Optimize compares of local variables:
|
||||
*
|
||||
* ldy #o
|
||||
* lda (sp),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (sp),y
|
||||
* cpx #a
|
||||
* bne L1
|
||||
* cmp #b
|
||||
* jne/jeq L2
|
||||
*/
|
||||
**
|
||||
** ldy #o
|
||||
** lda (sp),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (sp),y
|
||||
** cpx #a
|
||||
** bne L1
|
||||
** cmp #b
|
||||
** jne/jeq L2
|
||||
*/
|
||||
|
||||
unsigned OptCmp6 (CodeSeg* S);
|
||||
/* Search for calls to compare subroutines followed by a conditional branch
|
||||
* and replace them by cheaper versions, since the branch means that the
|
||||
* boolean value returned by these routines is not needed (we may also check
|
||||
* that explicitly, but for the current code generator it is always true).
|
||||
*/
|
||||
** and replace them by cheaper versions, since the branch means that the
|
||||
** boolean value returned by these routines is not needed (we may also check
|
||||
** that explicitly, but for the current code generator it is always true).
|
||||
*/
|
||||
|
||||
unsigned OptCmp7 (CodeSeg* S);
|
||||
/* Search for a sequence ldx/txa/branch and remove the txa if A is not
|
||||
* used later.
|
||||
*/
|
||||
** used later.
|
||||
*/
|
||||
|
||||
unsigned OptCmp8 (CodeSeg* S);
|
||||
/* Check for register compares where the contents of the register and therefore
|
||||
* the result of the compare is known.
|
||||
*/
|
||||
** the result of the compare is known.
|
||||
*/
|
||||
|
||||
unsigned OptCmp9 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* sbc xx
|
||||
* bvs/bvc L
|
||||
* eor #$80
|
||||
* L: asl a
|
||||
* bcc/bcs somewhere
|
||||
*
|
||||
* If A is not used later (which should be the case), we can branch on the N
|
||||
* flag instead of the carry flag and remove the asl.
|
||||
*/
|
||||
**
|
||||
** sbc xx
|
||||
** bvs/bvc L
|
||||
** eor #$80
|
||||
** L: asl a
|
||||
** bcc/bcs somewhere
|
||||
**
|
||||
** If A is not used later (which should be the case), we can branch on the N
|
||||
** flag instead of the carry flag and remove the asl.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -66,15 +66,15 @@ static int MemAccess (CodeSeg* S, unsigned From, unsigned To, const CodeEntry* N
|
||||
|
||||
|
||||
/* If the argument of N is a zero page location that ends with "+1", we
|
||||
* must also check for word accesses to the location without +1.
|
||||
*/
|
||||
** must also check for word accesses to the location without +1.
|
||||
*/
|
||||
if (N->AM == AM65_ZP && NLen > 2 && strcmp (N->Arg + NLen - 2, "+1") == 0) {
|
||||
What |= Base;
|
||||
}
|
||||
|
||||
/* If the argument is zero page indirect, we must also check for accesses
|
||||
* to "arg+1"
|
||||
*/
|
||||
** to "arg+1"
|
||||
*/
|
||||
if (N->AM == AM65_ZP_INDY || N->AM == AM65_ZPX_IND || N->AM == AM65_ZP_IND) {
|
||||
What |= Word;
|
||||
}
|
||||
@@ -86,8 +86,8 @@ static int MemAccess (CodeSeg* S, unsigned From, unsigned To, const CodeEntry* N
|
||||
CodeEntry* E = CS_GetEntry (S, From);
|
||||
|
||||
/* Check if there is an argument and if this argument equals Arg in
|
||||
* some variants.
|
||||
*/
|
||||
** some variants.
|
||||
*/
|
||||
if (E->Arg[0] != '\0') {
|
||||
|
||||
unsigned ELen;
|
||||
@@ -126,8 +126,8 @@ static int MemAccess (CodeSeg* S, unsigned From, unsigned To, const CodeEntry* N
|
||||
|
||||
static int GetBranchDist (CodeSeg* S, unsigned From, CodeEntry* To)
|
||||
/* Get the branch distance between the two entries and return it. The distance
|
||||
* will be negative for backward jumps and positive for forward jumps.
|
||||
*/
|
||||
** will be negative for backward jumps and positive for forward jumps.
|
||||
*/
|
||||
{
|
||||
/* Get the index of the branch target */
|
||||
unsigned TI = CS_GetEntryIndex (S, To);
|
||||
@@ -265,8 +265,8 @@ unsigned OptRTSJumps2 (CodeSeg* S)
|
||||
|
||||
|
||||
/* Get the jump target and the next entry. There's always a next
|
||||
* entry, because we don't cover the last entry in the loop.
|
||||
*/
|
||||
** entry, because we don't cover the last entry in the loop.
|
||||
*/
|
||||
CodeEntry* X = 0;
|
||||
CodeEntry* T = E->JumpTo->Owner;
|
||||
CodeEntry* N = CS_GetNextEntry (S, I);
|
||||
@@ -275,15 +275,15 @@ unsigned OptRTSJumps2 (CodeSeg* S)
|
||||
if (T->OPC == OP65_RTS) {
|
||||
|
||||
/* It's a jump to RTS. Create a conditional branch around an
|
||||
* RTS insn.
|
||||
*/
|
||||
** RTS insn.
|
||||
*/
|
||||
X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, T->LI);
|
||||
|
||||
} else if (T->OPC == OP65_JMP && T->JumpTo == 0) {
|
||||
|
||||
/* It's a jump to a label outside the function. Create a
|
||||
* conditional branch around a jump to the external label.
|
||||
*/
|
||||
** conditional branch around a jump to the external label.
|
||||
*/
|
||||
X = NewCodeEntry (OP65_JMP, AM65_ABS, T->Arg, T->JumpTo, T->LI);
|
||||
|
||||
}
|
||||
@@ -298,8 +298,8 @@ unsigned OptRTSJumps2 (CodeSeg* S)
|
||||
CS_InsertEntry (S, X, I+1);
|
||||
|
||||
/* Create a conditional branch with the inverse condition
|
||||
* around the replacement insn
|
||||
*/
|
||||
** around the replacement insn
|
||||
*/
|
||||
|
||||
/* Get the new branch opcode */
|
||||
NewBranch = MakeShortBranch (GetInverseBranch (E->OPC));
|
||||
@@ -350,8 +350,8 @@ unsigned OptDeadJumps (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if it's a branch, if it has a local target, and if the target
|
||||
* is the next instruction.
|
||||
*/
|
||||
** is the next instruction.
|
||||
*/
|
||||
if (E->AM == AM65_BRA &&
|
||||
E->JumpTo &&
|
||||
E->JumpTo->Owner == CS_GetNextEntry (S, I)) {
|
||||
@@ -384,8 +384,8 @@ unsigned OptDeadJumps (CodeSeg* S)
|
||||
|
||||
unsigned OptDeadCode (CodeSeg* S)
|
||||
/* Remove dead code (code that follows an unconditional jump or an rts/rti
|
||||
* and has no label)
|
||||
*/
|
||||
** and has no label)
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -400,9 +400,9 @@ unsigned OptDeadCode (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if it's an unconditional branch, and if the next entry has
|
||||
* no labels attached, or if the label is just used so that the insn
|
||||
* can jump to itself.
|
||||
*/
|
||||
** no labels attached, or if the label is just used so that the insn
|
||||
** can jump to itself.
|
||||
*/
|
||||
if ((E->Info & OF_DEAD) != 0 && /* Dead code follows */
|
||||
(N = CS_GetNextEntry (S, I)) != 0 && /* Has next entry */
|
||||
(!CE_HasLabel (N) || /* Don't has a label */
|
||||
@@ -439,11 +439,11 @@ unsigned OptDeadCode (CodeSeg* S)
|
||||
|
||||
unsigned OptJumpCascades (CodeSeg* S)
|
||||
/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
|
||||
* replaced by a jump to the final location. This will in some cases produce
|
||||
* worse code, because some jump targets are no longer reachable by short
|
||||
* branches, but this is quite rare, so there are more advantages than
|
||||
* disadvantages.
|
||||
*/
|
||||
** replaced by a jump to the final location. This will in some cases produce
|
||||
** worse code, because some jump targets are no longer reachable by short
|
||||
** branches, but this is quite rare, so there are more advantages than
|
||||
** disadvantages.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -458,17 +458,17 @@ unsigned OptJumpCascades (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check:
|
||||
* - if it's a branch,
|
||||
* - if it has a jump label,
|
||||
* - if this jump label is not attached to the instruction itself,
|
||||
* - if the target instruction is itself a branch,
|
||||
* - if either the first branch is unconditional or the target of
|
||||
* the second branch is internal to the function.
|
||||
* The latter condition will avoid conditional branches to targets
|
||||
* outside of the function (usually incspx), which won't simplify the
|
||||
* code, since conditional far branches are emulated by a short branch
|
||||
* around a jump.
|
||||
*/
|
||||
** - if it's a branch,
|
||||
** - if it has a jump label,
|
||||
** - if this jump label is not attached to the instruction itself,
|
||||
** - if the target instruction is itself a branch,
|
||||
** - if either the first branch is unconditional or the target of
|
||||
** the second branch is internal to the function.
|
||||
** The latter condition will avoid conditional branches to targets
|
||||
** outside of the function (usually incspx), which won't simplify the
|
||||
** code, since conditional far branches are emulated by a short branch
|
||||
** around a jump.
|
||||
*/
|
||||
if ((E->Info & OF_BRA) != 0 &&
|
||||
(OldLabel = E->JumpTo) != 0 &&
|
||||
(N = OldLabel->Owner) != E &&
|
||||
@@ -476,27 +476,27 @@ unsigned OptJumpCascades (CodeSeg* S)
|
||||
((E->Info & OF_CBRA) == 0 ||
|
||||
N->JumpTo != 0)) {
|
||||
|
||||
/* Check if we can use the final target label. This is the case,
|
||||
* if the target branch is an absolut branch, or if it is a
|
||||
* conditional branch checking the same condition as the first one.
|
||||
*/
|
||||
/* Check if we can use the final target label. That is the case,
|
||||
** if the target branch is an absolute branch; or, if it is a
|
||||
** conditional branch checking the same condition as the first one.
|
||||
*/
|
||||
if ((N->Info & OF_UBRA) != 0 ||
|
||||
((E->Info & OF_CBRA) != 0 &&
|
||||
GetBranchCond (E->OPC) == GetBranchCond (N->OPC))) {
|
||||
|
||||
/* This is a jump cascade and we may jump to the final target,
|
||||
* provided that the other insn does not jump to itself. If
|
||||
* this is the case, we can also jump to ourselves, otherwise
|
||||
* insert a jump to the new instruction and remove the old one.
|
||||
*/
|
||||
** provided that the other insn does not jump to itself. If
|
||||
** this is the case, we can also jump to ourselves, otherwise
|
||||
** insert a jump to the new instruction and remove the old one.
|
||||
*/
|
||||
CodeEntry* X;
|
||||
CodeLabel* LN = N->JumpTo;
|
||||
|
||||
if (LN != 0 && LN->Owner == N) {
|
||||
|
||||
/* We found a jump to a jump to itself. Replace our jump
|
||||
* by a jump to itself.
|
||||
*/
|
||||
** by a jump to itself.
|
||||
*/
|
||||
CodeLabel* LE = CS_GenLabel (S, E);
|
||||
X = NewCodeEntry (E->OPC, E->AM, LE->Name, LE, E->LI);
|
||||
|
||||
@@ -517,10 +517,10 @@ unsigned OptJumpCascades (CodeSeg* S)
|
||||
++Changes;
|
||||
|
||||
/* Check if both are conditional branches, and the condition of
|
||||
* the second is the inverse of that of the first. In this case,
|
||||
* the second branch will never be taken, and we may jump directly
|
||||
* to the instruction behind this one.
|
||||
*/
|
||||
** the second is the inverse of that of the first. In this case,
|
||||
** the second branch will never be taken, and we may jump directly
|
||||
** to the instruction behind this one.
|
||||
*/
|
||||
} else if ((E->Info & OF_CBRA) != 0 && (N->Info & OF_CBRA) != 0) {
|
||||
|
||||
CodeEntry* X; /* Instruction behind N */
|
||||
@@ -537,8 +537,8 @@ unsigned OptJumpCascades (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* We may jump behind this conditional branch. Get the
|
||||
* pointer to the next instruction
|
||||
*/
|
||||
** pointer to the next instruction
|
||||
*/
|
||||
if ((X = CS_GetNextEntry (S, CS_GetEntryIndex (S, N))) == 0) {
|
||||
/* N is the last entry, bail out */
|
||||
goto NextEntry;
|
||||
@@ -575,9 +575,9 @@ NextEntry:
|
||||
|
||||
unsigned 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.
|
||||
*/
|
||||
** 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 Changes = 0;
|
||||
|
||||
@@ -623,10 +623,10 @@ unsigned OptRTS (CodeSeg* S)
|
||||
|
||||
unsigned OptJumpTarget1 (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.
|
||||
*/
|
||||
** 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 Changes = 0;
|
||||
CodeEntry* E1; /* Entry 1 */
|
||||
@@ -642,8 +642,8 @@ unsigned OptJumpTarget1 (CodeSeg* S)
|
||||
E2 = CS_GetNextEntry (S, I);
|
||||
|
||||
/* Check if we have a jump or branch without a label attached, and
|
||||
* a jump target, which is not attached to the jump itself
|
||||
*/
|
||||
** a jump target, which is not attached to the jump itself
|
||||
*/
|
||||
if (E2 != 0 &&
|
||||
(E2->Info & OF_UBRA) != 0 &&
|
||||
!CE_HasLabel (E2) &&
|
||||
@@ -658,8 +658,8 @@ unsigned OptJumpTarget1 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* The entry preceeding the branch target may not be the branch
|
||||
* insn.
|
||||
*/
|
||||
** insn.
|
||||
*/
|
||||
if (T1 == E2) {
|
||||
goto NextEntry;
|
||||
}
|
||||
@@ -674,17 +674,17 @@ unsigned OptJumpTarget1 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* Get the label for the instruction preceeding the jump target.
|
||||
* This routine will create a new label if the instruction does
|
||||
* not already have one.
|
||||
*/
|
||||
** This routine will create a new label if the instruction does
|
||||
** not already have one.
|
||||
*/
|
||||
TL1 = CS_GenLabel (S, T1);
|
||||
|
||||
/* Change the jump target to point to this new label */
|
||||
CS_MoveLabelRef (S, E2, TL1);
|
||||
|
||||
/* If the instruction preceeding the jump has labels attached,
|
||||
* move references to this label to the new label.
|
||||
*/
|
||||
** move references to this label to the new label.
|
||||
*/
|
||||
if (CE_HasLabel (E1)) {
|
||||
CS_MoveLabels (S, E1, T1);
|
||||
}
|
||||
@@ -710,8 +710,8 @@ NextEntry:
|
||||
|
||||
unsigned OptJumpTarget2 (CodeSeg* S)
|
||||
/* If a bcs jumps to a sec insn or a bcc jumps to clc, skip this insn, since
|
||||
* it's job is already done.
|
||||
*/
|
||||
** it's job is already done.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -748,8 +748,8 @@ unsigned OptJumpTarget2 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* Get the owner insn of the jump target and check if it's the one, we
|
||||
* will skip if present.
|
||||
*/
|
||||
** will skip if present.
|
||||
*/
|
||||
T = E->JumpTo->Owner;
|
||||
if (T->OPC != OPC) {
|
||||
goto NextEntry;
|
||||
@@ -763,9 +763,9 @@ unsigned OptJumpTarget2 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* Get the label for the instruction following the jump target.
|
||||
* This routine will create a new label if the instruction does
|
||||
* not already have one.
|
||||
*/
|
||||
** This routine will create a new label if the instruction does
|
||||
** not already have one.
|
||||
*/
|
||||
L = CS_GenLabel (S, N);
|
||||
|
||||
/* Change the jump target to point to this new label */
|
||||
@@ -787,9 +787,9 @@ NextEntry:
|
||||
|
||||
unsigned OptJumpTarget3 (CodeSeg* S)
|
||||
/* Jumps to load instructions of a register, that do already have the matching
|
||||
* register contents may skip the load instruction, since it's job is already
|
||||
* done.
|
||||
*/
|
||||
** register contents may skip the load instruction, since it's job is already
|
||||
** done.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -804,8 +804,8 @@ unsigned OptJumpTarget3 (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if this is a load insn with a label and the next insn is not
|
||||
* a conditional branch that needs the flags from the load.
|
||||
*/
|
||||
** a conditional branch that needs the flags from the load.
|
||||
*/
|
||||
if ((E->Info & OF_LOAD) != 0 &&
|
||||
CE_IsConstImm (E) &&
|
||||
CE_HasLabel (E) &&
|
||||
@@ -825,9 +825,9 @@ unsigned OptJumpTarget3 (CodeSeg* S)
|
||||
CodeLabel* L = CE_GetLabel (E, J);
|
||||
|
||||
/* Loop over all insn that reference this label. Since we may
|
||||
* eventually remove a reference in the loop, we must loop
|
||||
* from end down to start.
|
||||
*/
|
||||
** eventually remove a reference in the loop, we must loop
|
||||
** from end down to start.
|
||||
*/
|
||||
for (K = CL_GetRefCount (L) - 1; K >= 0; --K) {
|
||||
|
||||
/* Get the entry that jumps here */
|
||||
@@ -839,9 +839,9 @@ unsigned OptJumpTarget3 (CodeSeg* S)
|
||||
/* Check if the outgoing value is the one thats's loaded */
|
||||
if (Val == (unsigned char) E->Num) {
|
||||
|
||||
/* Ok, skip the insn. First, generate a label for the
|
||||
* next insn after E.
|
||||
*/
|
||||
/* OK, skip the insn. First, generate a label for the
|
||||
** next insn after E.
|
||||
*/
|
||||
if (LN == 0) {
|
||||
LN = CS_GenLabel (S, N);
|
||||
}
|
||||
@@ -875,16 +875,16 @@ unsigned OptJumpTarget3 (CodeSeg* S)
|
||||
|
||||
unsigned OptCondBranches1 (CodeSeg* S)
|
||||
/* Performs several optimization steps:
|
||||
*
|
||||
* - If an immidiate load of a register is followed by a conditional jump that
|
||||
* is never taken because the load of the register sets the flags in such a
|
||||
* manner, remove the conditional branch.
|
||||
* - If the conditional branch is always taken because of the register load,
|
||||
* replace it by a jmp.
|
||||
* - If a conditional branch jumps around an unconditional branch, remove the
|
||||
* conditional branch and make the jump a conditional branch with the
|
||||
* inverse condition of the first one.
|
||||
*/
|
||||
**
|
||||
** - If an immediate load of a register is followed by a conditional jump that
|
||||
** is never taken because the load of the register sets the flags in such a
|
||||
** manner, remove the conditional branch.
|
||||
** - If the conditional branch is always taken because of the register load,
|
||||
** replace it by a jmp.
|
||||
** - If a conditional branch jumps around an unconditional branch, remove the
|
||||
** conditional branch and make the jump a conditional branch with the
|
||||
** inverse condition of the first one.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -940,11 +940,11 @@ unsigned OptCondBranches1 (CodeSeg* S)
|
||||
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a following entry */
|
||||
(N->Info & OF_UBRA) != 0 && /* ..which is an uncond branch, */
|
||||
!CE_HasLabel (N) && /* ..has no label attached */
|
||||
L->Owner == CS_GetNextEntry (S, I+1)) {/* ..and jump target follows */
|
||||
L->Owner == CS_GetNextEntry (S, I+1)) { /* ..and jump target follows */
|
||||
|
||||
/* Replace the jump by a conditional branch with the inverse branch
|
||||
* condition than the branch around it.
|
||||
*/
|
||||
** condition than the branch around it.
|
||||
*/
|
||||
CE_ReplaceOPC (N, GetInverseBranch (E->OPC));
|
||||
|
||||
/* Remove the conditional branch */
|
||||
@@ -968,8 +968,8 @@ unsigned OptCondBranches1 (CodeSeg* S)
|
||||
|
||||
unsigned OptCondBranches2 (CodeSeg* S)
|
||||
/* If on entry to a "rol a" instruction the accu is zero, and a beq/bne follows,
|
||||
* we can remove the rol and branch on the state of the carry flag.
|
||||
*/
|
||||
** we can remove the rol and branch on the state of the carry flag.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -1103,8 +1103,8 @@ unsigned OptUnusedStores (CodeSeg* S)
|
||||
(E->Chg & REG_ZP) != 0) {
|
||||
|
||||
/* Check for the zero page location. We know that there cannot be
|
||||
* more than one zero page location involved in the store.
|
||||
*/
|
||||
** more than one zero page location involved in the store.
|
||||
*/
|
||||
unsigned R = E->Chg & REG_ZP;
|
||||
|
||||
/* Get register usage and check if the register value is used later */
|
||||
@@ -1185,9 +1185,9 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
|
||||
case OP65_STA:
|
||||
/* If we store into a known zero page location, and this
|
||||
* location does already contain the value to be stored,
|
||||
* remove the store.
|
||||
*/
|
||||
** location does already contain the value to be stored,
|
||||
** remove the store.
|
||||
*/
|
||||
if (RegValIsKnown (In->RegA) && /* Value of A is known */
|
||||
E->AM == AM65_ZP && /* Store into zp */
|
||||
In->RegA == ZPRegVal (E->Chg, In)) { /* Value identical */
|
||||
@@ -1198,9 +1198,9 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
|
||||
case OP65_STX:
|
||||
/* If we store into a known zero page location, and this
|
||||
* location does already contain the value to be stored,
|
||||
* remove the store.
|
||||
*/
|
||||
** location does already contain the value to be stored,
|
||||
** remove the store.
|
||||
*/
|
||||
if (RegValIsKnown (In->RegX) && /* Value of A is known */
|
||||
E->AM == AM65_ZP && /* Store into zp */
|
||||
In->RegX == ZPRegVal (E->Chg, In)) { /* Value identical */
|
||||
@@ -1208,11 +1208,11 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
Delete = 1;
|
||||
|
||||
/* If the value in the X register is known and the same as
|
||||
* that in the A register, replace the store by a STA. The
|
||||
* optimizer will then remove the load instruction for X
|
||||
* later. STX does support the zeropage,y addressing mode,
|
||||
* so be sure to check for that.
|
||||
*/
|
||||
** that in the A register, replace the store by a STA. The
|
||||
** optimizer will then remove the load instruction for X
|
||||
** later. STX does support the zeropage,y addressing mode,
|
||||
** so be sure to check for that.
|
||||
*/
|
||||
} else if (RegValIsKnown (In->RegX) &&
|
||||
In->RegX == In->RegA &&
|
||||
E->AM != AM65_ABSY &&
|
||||
@@ -1224,9 +1224,9 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
|
||||
case OP65_STY:
|
||||
/* If we store into a known zero page location, and this
|
||||
* location does already contain the value to be stored,
|
||||
* remove the store.
|
||||
*/
|
||||
** location does already contain the value to be stored,
|
||||
** remove the store.
|
||||
*/
|
||||
if (RegValIsKnown (In->RegY) && /* Value of Y is known */
|
||||
E->AM == AM65_ZP && /* Store into zp */
|
||||
In->RegY == ZPRegVal (E->Chg, In)) { /* Value identical */
|
||||
@@ -1234,12 +1234,12 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
Delete = 1;
|
||||
|
||||
/* If the value in the Y register is known and the same as
|
||||
* that in the A register, replace the store by a STA. The
|
||||
* optimizer will then remove the load instruction for Y
|
||||
* later. If replacement by A is not possible try a
|
||||
* replacement by X, but check for invalid addressing modes
|
||||
* in this case.
|
||||
*/
|
||||
** that in the A register, replace the store by a STA. The
|
||||
** optimizer will then remove the load instruction for Y
|
||||
** later. If replacement by A is not possible try a
|
||||
** replacement by X, but check for invalid addressing modes
|
||||
** in this case.
|
||||
*/
|
||||
} else if (RegValIsKnown (In->RegY)) {
|
||||
if (In->RegY == In->RegA) {
|
||||
CE_ReplaceOPC (E, OP65_STA);
|
||||
@@ -1253,9 +1253,9 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
|
||||
case OP65_STZ:
|
||||
/* If we store into a known zero page location, and this
|
||||
* location does already contain the value to be stored,
|
||||
* remove the store.
|
||||
*/
|
||||
** location does already contain the value to be stored,
|
||||
** remove the store.
|
||||
*/
|
||||
if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && E->AM == AM65_ZP) {
|
||||
if (ZPRegVal (E->Chg, In) == 0) {
|
||||
Delete = 1;
|
||||
@@ -1348,8 +1348,8 @@ unsigned OptStoreLoad (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if it is a store instruction followed by a load from the
|
||||
* same address which is itself not followed by a conditional branch.
|
||||
*/
|
||||
** same address which is itself not followed by a conditional branch.
|
||||
*/
|
||||
if ((E->Info & OF_STORE) != 0 &&
|
||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||
!CE_HasLabel (N) &&
|
||||
@@ -1409,9 +1409,9 @@ unsigned OptTransfers1 (CodeSeg* S)
|
||||
(E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+2))) {
|
||||
|
||||
/* If the next insn is a conditional branch, check if the insn
|
||||
* preceeding the first xfr will set the flags right, otherwise we
|
||||
* may not remove the sequence.
|
||||
*/
|
||||
** preceeding the first xfr will set the flags right, otherwise we
|
||||
** may not remove the sequence.
|
||||
*/
|
||||
if ((X = CS_GetNextEntry (S, I+1)) == 0) {
|
||||
goto NextEntry;
|
||||
}
|
||||
@@ -1450,8 +1450,8 @@ NextEntry:
|
||||
|
||||
unsigned OptTransfers2 (CodeSeg* S)
|
||||
/* Replace loads followed by a register transfer by a load with the second
|
||||
* register if possible.
|
||||
*/
|
||||
** register if possible.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1465,8 +1465,8 @@ unsigned OptTransfers2 (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if we have a load followed by a transfer where the loaded
|
||||
* register is not used later.
|
||||
*/
|
||||
** register is not used later.
|
||||
*/
|
||||
if ((E->Info & OF_LOAD) != 0 &&
|
||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||
!CE_HasLabel (N) &&
|
||||
@@ -1499,8 +1499,8 @@ unsigned OptTransfers2 (CodeSeg* S)
|
||||
X = NewCodeEntry (OP65_LDA, E->AM, E->Arg, 0, N->LI);
|
||||
} else if (E->OPC == OP65_LDX && N->OPC == OP65_TXA) {
|
||||
/* LDX/TXA. LDA doesn't support zp,y, so we must map it to
|
||||
* abs,y instead.
|
||||
*/
|
||||
** abs,y instead.
|
||||
*/
|
||||
am_t AM = (E->AM == AM65_ZPY)? AM65_ABSY : E->AM;
|
||||
X = NewCodeEntry (OP65_LDA, AM, E->Arg, 0, N->LI);
|
||||
}
|
||||
@@ -1526,8 +1526,8 @@ unsigned OptTransfers2 (CodeSeg* S)
|
||||
|
||||
unsigned OptTransfers3 (CodeSeg* S)
|
||||
/* Replace a register transfer followed by a store of the second register by a
|
||||
* store of the first register if this is possible.
|
||||
*/
|
||||
** store of the first register if this is possible.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned UsedRegs = REG_NONE; /* Track used registers */
|
||||
@@ -1544,8 +1544,8 @@ unsigned OptTransfers3 (CodeSeg* S)
|
||||
} State = Initialize;
|
||||
|
||||
/* Walk over the entries. Look for a xfer instruction that is followed by
|
||||
* a store later, where the value of the register is not used later.
|
||||
*/
|
||||
** a store later, where the value of the register is not used later.
|
||||
*/
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
@@ -1570,8 +1570,8 @@ unsigned OptTransfers3 (CodeSeg* S)
|
||||
|
||||
case FoundXfer:
|
||||
/* If we find a conditional jump, abort the sequence, since
|
||||
* handling them makes things really complicated.
|
||||
*/
|
||||
** handling them makes things really complicated.
|
||||
*/
|
||||
if (E->Info & OF_CBRA) {
|
||||
|
||||
/* Switch back to searching */
|
||||
@@ -1582,8 +1582,8 @@ unsigned OptTransfers3 (CodeSeg* S)
|
||||
} else if ((E->Use & XferEntry->Chg) != 0) {
|
||||
|
||||
/* It it's a store instruction, and the block is a basic
|
||||
* block, proceed. Otherwise restart
|
||||
*/
|
||||
** block, proceed. Otherwise restart
|
||||
*/
|
||||
if ((E->Info & OF_STORE) != 0 &&
|
||||
CS_IsBasicBlock (S, Xfer, I)) {
|
||||
Store = I;
|
||||
@@ -1598,9 +1598,9 @@ unsigned OptTransfers3 (CodeSeg* S)
|
||||
} else if (E->Chg & XferEntry->Chg) {
|
||||
|
||||
/* We *may* add code here to remove the transfer, but I'm
|
||||
* currently not sure about the consequences, so I won't
|
||||
* do that and bail out instead.
|
||||
*/
|
||||
** currently not sure about the consequences, so I won't
|
||||
** do that and bail out instead.
|
||||
*/
|
||||
I = Xfer;
|
||||
State = Initialize;
|
||||
|
||||
@@ -1619,9 +1619,9 @@ unsigned OptTransfers3 (CodeSeg* S)
|
||||
|
||||
case FoundStore:
|
||||
/* We are at the instruction behind the store. If the register
|
||||
* isn't used later, and we have an address mode match, we can
|
||||
* replace the transfer by a store and remove the store here.
|
||||
*/
|
||||
** isn't used later, and we have an address mode match, we can
|
||||
** replace the transfer by a store and remove the store here.
|
||||
*/
|
||||
if ((GetRegInfo (S, I, XferEntry->Chg) & XferEntry->Chg) == 0 &&
|
||||
(StoreEntry->AM == AM65_ABS ||
|
||||
StoreEntry->AM == AM65_ZP) &&
|
||||
@@ -1710,8 +1710,8 @@ unsigned OptTransfers3 (CodeSeg* S)
|
||||
|
||||
unsigned OptTransfers4 (CodeSeg* S)
|
||||
/* Replace a load of a register followed by a transfer insn of the same register
|
||||
* by a load of the second register if possible.
|
||||
*/
|
||||
** by a load of the second register if possible.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned Load = 0; /* Index of load insn */
|
||||
@@ -1726,8 +1726,8 @@ unsigned OptTransfers4 (CodeSeg* S)
|
||||
} State = Search;
|
||||
|
||||
/* Walk over the entries. Look for a load instruction that is followed by
|
||||
* a load later.
|
||||
*/
|
||||
** a load later.
|
||||
*/
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
@@ -1747,8 +1747,8 @@ unsigned OptTransfers4 (CodeSeg* S)
|
||||
|
||||
case FoundLoad:
|
||||
/* If we find a conditional jump, abort the sequence, since
|
||||
* handling them makes things really complicated.
|
||||
*/
|
||||
** handling them makes things really complicated.
|
||||
*/
|
||||
if (E->Info & OF_CBRA) {
|
||||
|
||||
/* Switch back to searching */
|
||||
@@ -1759,8 +1759,8 @@ unsigned OptTransfers4 (CodeSeg* S)
|
||||
} else if ((E->Use & LoadEntry->Chg) != 0) {
|
||||
|
||||
/* It it's a xfer instruction, and the block is a basic
|
||||
* block, proceed. Otherwise restart
|
||||
*/
|
||||
** block, proceed. Otherwise restart
|
||||
*/
|
||||
if ((E->Info & OF_XFR) != 0 &&
|
||||
CS_IsBasicBlock (S, Load, I)) {
|
||||
Xfer = I;
|
||||
@@ -1775,9 +1775,9 @@ unsigned OptTransfers4 (CodeSeg* S)
|
||||
} else if (E->Chg & LoadEntry->Chg) {
|
||||
|
||||
/* We *may* add code here to remove the load, but I'm
|
||||
* currently not sure about the consequences, so I won't
|
||||
* do that and bail out instead.
|
||||
*/
|
||||
** currently not sure about the consequences, so I won't
|
||||
** do that and bail out instead.
|
||||
*/
|
||||
I = Load;
|
||||
State = Search;
|
||||
}
|
||||
@@ -1785,9 +1785,9 @@ unsigned OptTransfers4 (CodeSeg* S)
|
||||
|
||||
case FoundXfer:
|
||||
/* We are at the instruction behind the xfer. If the register
|
||||
* isn't used later, and we have an address mode match, we can
|
||||
* replace the transfer by a load and remove the initial load.
|
||||
*/
|
||||
** isn't used later, and we have an address mode match, we can
|
||||
** replace the transfer by a load and remove the initial load.
|
||||
*/
|
||||
if ((GetRegInfo (S, I, LoadEntry->Chg) & LoadEntry->Chg) == 0 &&
|
||||
(LoadEntry->AM == AM65_ABS ||
|
||||
LoadEntry->AM == AM65_ZP ||
|
||||
@@ -1880,14 +1880,14 @@ unsigned OptPushPop (CodeSeg* S)
|
||||
} State = Searching;
|
||||
|
||||
/* Walk over the entries. Look for a push instruction that is followed by
|
||||
* a pop later, where the pop is not followed by an conditional branch,
|
||||
* and where the value of the A register is not used later on.
|
||||
* Look out for the following problems:
|
||||
*
|
||||
* - There may be another PHA/PLA inside the sequence: Restart it.
|
||||
* - If the PLA has a label, all jumps to this label must be inside
|
||||
* the sequence, otherwise we cannot remove the PHA/PLA.
|
||||
*/
|
||||
** a pop later, where the pop is not followed by an conditional branch,
|
||||
** and where the value of the A register is not used later on.
|
||||
** Look out for the following problems:
|
||||
**
|
||||
** - There may be another PHA/PLA inside the sequence: Restart it.
|
||||
** - If the PLA has a label, all jumps to this label must be inside
|
||||
** the sequence, otherwise we cannot remove the PHA/PLA.
|
||||
*/
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
@@ -1916,8 +1916,8 @@ unsigned OptPushPop (CodeSeg* S)
|
||||
/* Found a matching pop */
|
||||
Pop = I;
|
||||
/* Check that the block between Push and Pop is a basic
|
||||
* block (one entry, one exit). Otherwise ignore it.
|
||||
*/
|
||||
** block (one entry, one exit). Otherwise ignore it.
|
||||
*/
|
||||
if (CS_IsBasicBlock (S, Push, Pop)) {
|
||||
State = FoundPop;
|
||||
} else {
|
||||
@@ -1931,16 +1931,16 @@ unsigned OptPushPop (CodeSeg* S)
|
||||
|
||||
case FoundPop:
|
||||
/* We're at the instruction after the PLA.
|
||||
* Check for the following conditions:
|
||||
* - If this instruction is a store of A that doesn't use
|
||||
* another register, if the instruction does not have a
|
||||
* label, and A is not used later, we may replace the PHA
|
||||
* by the store and remove pla if several other conditions
|
||||
* are met.
|
||||
* - If this instruction is not a conditional branch, and A
|
||||
* is either unused later, or not changed by the code
|
||||
* between push and pop, we may remove PHA and PLA.
|
||||
*/
|
||||
** Check for the following conditions:
|
||||
** - If this instruction is a store of A that doesn't use
|
||||
** another register, if the instruction does not have a
|
||||
** label, and A is not used later, we may replace the PHA
|
||||
** by the store and remove pla if several other conditions
|
||||
** are met.
|
||||
** - If this instruction is not a conditional branch, and A
|
||||
** is either unused later, or not changed by the code
|
||||
** between push and pop, we may remove PHA and PLA.
|
||||
*/
|
||||
if (E->OPC == OP65_STA &&
|
||||
(E->AM == AM65_ABS || E->AM == AM65_ZP) &&
|
||||
!CE_HasLabel (E) &&
|
||||
@@ -1995,8 +1995,8 @@ unsigned OptPushPop (CodeSeg* S)
|
||||
|
||||
unsigned OptPrecalc (CodeSeg* S)
|
||||
/* Replace immediate operations with the accu where the current contents are
|
||||
* known by a load of the final value.
|
||||
*/
|
||||
** known by a load of the final value.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -2052,11 +2052,11 @@ unsigned OptPrecalc (CodeSeg* S)
|
||||
case OP65_ADC:
|
||||
case OP65_SBC:
|
||||
/* If this is an operation with an immediate operand of zero,
|
||||
* and the register is zero, the operation won't give us any
|
||||
* results we don't already have (including the flags), so
|
||||
* remove it. Something like this is generated as a result of
|
||||
* a compare where parts of the values are known to be zero.
|
||||
*/
|
||||
** and the register is zero, the operation won't give us any
|
||||
** results we don't already have (including the flags), so
|
||||
** remove it. Something like this is generated as a result of
|
||||
** a compare where parts of the values are known to be zero.
|
||||
*/
|
||||
if (In->RegA == 0 && CE_IsKnownImm (E, 0x00)) {
|
||||
/* 0-0 or 0+0 -> remove */
|
||||
CS_DelEntry (S, I);
|
||||
@@ -2198,15 +2198,15 @@ unsigned OptBranchDist (CodeSeg* S)
|
||||
|
||||
unsigned OptIndLoads1 (CodeSeg* S)
|
||||
/* Change
|
||||
*
|
||||
* lda (zp),y
|
||||
*
|
||||
* into
|
||||
*
|
||||
* lda (zp,x)
|
||||
*
|
||||
* provided that x and y are both zero.
|
||||
*/
|
||||
**
|
||||
** lda (zp),y
|
||||
**
|
||||
** into
|
||||
**
|
||||
** lda (zp,x)
|
||||
**
|
||||
** provided that x and y are both zero.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -2246,15 +2246,15 @@ unsigned OptIndLoads1 (CodeSeg* S)
|
||||
|
||||
unsigned OptIndLoads2 (CodeSeg* S)
|
||||
/* Change
|
||||
*
|
||||
* lda (zp,x)
|
||||
*
|
||||
* into
|
||||
*
|
||||
* lda (zp),y
|
||||
*
|
||||
* provided that x and y are both zero.
|
||||
*/
|
||||
**
|
||||
** lda (zp,x)
|
||||
**
|
||||
** into
|
||||
**
|
||||
** lda (zp),y
|
||||
**
|
||||
** provided that x and y are both zero.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
|
||||
@@ -60,51 +60,51 @@ unsigned OptDeadJumps (CodeSeg* S);
|
||||
|
||||
unsigned OptDeadCode (CodeSeg* S);
|
||||
/* Remove dead code (code that follows an unconditional jump or an rts/rti
|
||||
* and has no label)
|
||||
*/
|
||||
** and has no label)
|
||||
*/
|
||||
|
||||
unsigned OptJumpCascades (CodeSeg* S);
|
||||
/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
|
||||
* replaced by a jump to the final location. This will in some cases produce
|
||||
* worse code, because some jump targets are no longer reachable by short
|
||||
* branches, but this is quite rare, so there are more advantages than
|
||||
* disadvantages.
|
||||
*/
|
||||
** replaced by a jump to the final location. This will in some cases produce
|
||||
** worse code, because some jump targets are no longer reachable by short
|
||||
** branches, but this is quite rare, so there are more advantages than
|
||||
** disadvantages.
|
||||
*/
|
||||
|
||||
unsigned 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.
|
||||
*/
|
||||
** 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 OptJumpTarget1 (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.
|
||||
*/
|
||||
** 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 OptJumpTarget2 (CodeSeg* S);
|
||||
/* If a bcs jumps to a sec insn or a bcc jumps to clc, skip this insn, since
|
||||
* it's job is already done.
|
||||
*/
|
||||
** it's job is already done.
|
||||
*/
|
||||
|
||||
unsigned OptJumpTarget3 (CodeSeg* S);
|
||||
/* Jumps to load instructions of a register, that do already have the matching
|
||||
* register contents may skip the load instruction, since it's job is already
|
||||
* done.
|
||||
*/
|
||||
** register contents may skip the load instruction, since it's job is already
|
||||
** done.
|
||||
*/
|
||||
|
||||
unsigned OptCondBranches1 (CodeSeg* S);
|
||||
/* If an immidiate load of a register is followed by a conditional jump that
|
||||
* is never taken because the load of the register sets the flags in such a
|
||||
* manner, remove the conditional branch.
|
||||
*/
|
||||
** is never taken because the load of the register sets the flags in such a
|
||||
** manner, remove the conditional branch.
|
||||
*/
|
||||
|
||||
unsigned OptCondBranches2 (CodeSeg* S);
|
||||
/* If on entry to a "rol a" instruction the accu is zero, and a beq/bne follows,
|
||||
* we can remove the rol and branch on the state of the carry.
|
||||
*/
|
||||
** we can remove the rol and branch on the state of the carry.
|
||||
*/
|
||||
|
||||
unsigned OptUnusedLoads (CodeSeg* S);
|
||||
/* Remove loads of registers where the value loaded is not used later. */
|
||||
@@ -123,53 +123,53 @@ unsigned OptTransfers1 (CodeSeg* S);
|
||||
|
||||
unsigned OptTransfers2 (CodeSeg* S);
|
||||
/* Replace loads followed by a register transfer by a load with the second
|
||||
* register if possible.
|
||||
*/
|
||||
** register if possible.
|
||||
*/
|
||||
|
||||
unsigned OptTransfers3 (CodeSeg* S);
|
||||
/* Replace a register transfer followed by a store of the second register by a
|
||||
* store of the first register if this is possible.
|
||||
*/
|
||||
** store of the first register if this is possible.
|
||||
*/
|
||||
|
||||
unsigned OptTransfers4 (CodeSeg* S);
|
||||
/* Replace a load of a register followed by a transfer insn of the same register
|
||||
* by a load of the second register if possible.
|
||||
*/
|
||||
** by a load of the second register if possible.
|
||||
*/
|
||||
|
||||
unsigned OptPushPop (CodeSeg* S);
|
||||
/* Remove a PHA/PLA sequence were A is not used later */
|
||||
|
||||
unsigned OptPrecalc (CodeSeg* S);
|
||||
/* Replace immediate operations with the accu where the current contents are
|
||||
* known by a load of the final value.
|
||||
*/
|
||||
** known by a load of the final value.
|
||||
*/
|
||||
|
||||
unsigned OptBranchDist (CodeSeg* S);
|
||||
/* Change branches for the distance needed. */
|
||||
|
||||
unsigned OptIndLoads1 (CodeSeg* S);
|
||||
/* Change
|
||||
*
|
||||
* lda (zp),y
|
||||
*
|
||||
* into
|
||||
*
|
||||
* lda (zp,x)
|
||||
*
|
||||
* provided that x and y are both zero.
|
||||
*/
|
||||
**
|
||||
** lda (zp),y
|
||||
**
|
||||
** into
|
||||
**
|
||||
** lda (zp,x)
|
||||
**
|
||||
** provided that x and y are both zero.
|
||||
*/
|
||||
|
||||
unsigned OptIndLoads2 (CodeSeg* S);
|
||||
/* Change
|
||||
*
|
||||
* lda (zp,x)
|
||||
*
|
||||
* into
|
||||
*
|
||||
* lda (zp),y
|
||||
*
|
||||
* provided that x and y are both zero.
|
||||
*/
|
||||
**
|
||||
** lda (zp,x)
|
||||
**
|
||||
** into
|
||||
**
|
||||
** lda (zp),y
|
||||
**
|
||||
** provided that x and y are both zero.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -48,13 +48,13 @@
|
||||
|
||||
unsigned OptBNegA1 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* ldx #$00
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
*
|
||||
* Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
**
|
||||
** ldx #$00
|
||||
** lda ..
|
||||
** jsr bnega
|
||||
**
|
||||
** Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -100,13 +100,13 @@ unsigned OptBNegA1 (CodeSeg* S)
|
||||
|
||||
unsigned OptBNegA2 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
* jeq/jne ..
|
||||
*
|
||||
* Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
**
|
||||
** lda ..
|
||||
** jsr bnega
|
||||
** jeq/jne ..
|
||||
**
|
||||
** Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -167,9 +167,9 @@ unsigned OptBNegA2 (CodeSeg* S)
|
||||
|
||||
unsigned OptBNegAX1 (CodeSeg* S)
|
||||
/* On a call to bnegax, if X is zero, the result depends only on the value in
|
||||
* A, so change the call to a call to bnega. This will get further optimized
|
||||
* later if possible.
|
||||
*/
|
||||
** A, so change the call to a call to bnega. This will get further optimized
|
||||
** later if possible.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -205,20 +205,20 @@ unsigned OptBNegAX1 (CodeSeg* S)
|
||||
|
||||
unsigned OptBNegAX2 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* ldy #xx
|
||||
* jsr ldaxysp
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* ldy #xx
|
||||
* lda (sp),y
|
||||
* dey
|
||||
* ora (sp),y
|
||||
* jeq/jne ...
|
||||
*/
|
||||
**
|
||||
** ldy #xx
|
||||
** jsr ldaxysp
|
||||
** jsr bnegax
|
||||
** jne/jeq ...
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** ldy #xx
|
||||
** lda (sp),y
|
||||
** dey
|
||||
** ora (sp),y
|
||||
** jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -278,18 +278,18 @@ unsigned OptBNegAX2 (CodeSeg* S)
|
||||
|
||||
unsigned OptBNegAX3 (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 ...
|
||||
*/
|
||||
**
|
||||
** lda xx
|
||||
** ldx yy
|
||||
** jsr bnegax
|
||||
** jne/jeq ...
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** lda xx
|
||||
** ora xx+1
|
||||
** jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -339,17 +339,17 @@ unsigned OptBNegAX3 (CodeSeg* S)
|
||||
|
||||
unsigned OptBNegAX4 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr xxx
|
||||
* jsr bnega(x)
|
||||
* jeq/jne ...
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* jsr xxx
|
||||
* <boolean test>
|
||||
* jne/jeq ...
|
||||
*/
|
||||
**
|
||||
** jsr xxx
|
||||
** jsr bnega(x)
|
||||
** jeq/jne ...
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** jsr xxx
|
||||
** <boolean test>
|
||||
** jne/jeq ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -419,13 +419,13 @@ unsigned OptBNegAX4 (CodeSeg* S)
|
||||
|
||||
unsigned OptNegAX1 (CodeSeg* S)
|
||||
/* Search for a call to negax and replace it by
|
||||
*
|
||||
* eor #$FF
|
||||
* clc
|
||||
* adc #$01
|
||||
*
|
||||
* if X isn't used later.
|
||||
*/
|
||||
**
|
||||
** eor #$FF
|
||||
** clc
|
||||
** adc #$01
|
||||
**
|
||||
** if X isn't used later.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -475,17 +475,17 @@ unsigned OptNegAX1 (CodeSeg* S)
|
||||
|
||||
unsigned OptNegAX2 (CodeSeg* S)
|
||||
/* Search for a call to negax and replace it by
|
||||
*
|
||||
* ldx #$FF
|
||||
* eor #$FF
|
||||
* clc
|
||||
* adc #$01
|
||||
* bne L1
|
||||
* inx
|
||||
* L1:
|
||||
*
|
||||
* if X is known and zero on entry.
|
||||
*/
|
||||
**
|
||||
** ldx #$FF
|
||||
** eor #$FF
|
||||
** clc
|
||||
** adc #$01
|
||||
** bne L1
|
||||
** inx
|
||||
** L1:
|
||||
**
|
||||
** if X is known and zero on entry.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -565,11 +565,11 @@ unsigned OptNegAX2 (CodeSeg* S)
|
||||
|
||||
unsigned OptComplAX1 (CodeSeg* S)
|
||||
/* Search for a call to complax and replace it by
|
||||
*
|
||||
* eor #$FF
|
||||
*
|
||||
* if X isn't used later.
|
||||
*/
|
||||
**
|
||||
** eor #$FF
|
||||
**
|
||||
** if X isn't used later.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
|
||||
@@ -51,23 +51,23 @@
|
||||
|
||||
unsigned OptBNegA1 (CodeSeg* S);
|
||||
/* Check for
|
||||
*
|
||||
* ldx #$00
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
*
|
||||
* Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
**
|
||||
** ldx #$00
|
||||
** lda ..
|
||||
** jsr bnega
|
||||
**
|
||||
** Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
|
||||
unsigned OptBNegA2 (CodeSeg* S);
|
||||
/* Check for
|
||||
*
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
* jeq/jne ..
|
||||
*
|
||||
* Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
**
|
||||
** lda ..
|
||||
** jsr bnega
|
||||
** jeq/jne ..
|
||||
**
|
||||
** Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -79,56 +79,56 @@ unsigned OptBNegA2 (CodeSeg* S);
|
||||
|
||||
unsigned OptBNegAX1 (CodeSeg* S);
|
||||
/* On a call to bnegax, if X is zero, the result depends only on the value in
|
||||
* A, so change the call to a call to bnega. This will get further optimized
|
||||
* later if possible.
|
||||
*/
|
||||
** A, so change the call to a call to bnega. This will get further optimized
|
||||
** later if possible.
|
||||
*/
|
||||
|
||||
unsigned OptBNegAX2 (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 ...
|
||||
*/
|
||||
**
|
||||
** 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 OptBNegAX3 (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 ...
|
||||
*/
|
||||
**
|
||||
** lda xx
|
||||
** ldx yy
|
||||
** jsr bnegax
|
||||
** jne/jeq ...
|
||||
**
|
||||
** and replace it by
|
||||
**
|
||||
** lda xx
|
||||
** ora xx+1
|
||||
** jeq/jne ...
|
||||
*/
|
||||
|
||||
unsigned OptBNegAX4 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr xxx
|
||||
* jsr bnega(x)
|
||||
* jeq/jne ...
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* jsr xxx
|
||||
* <boolean test>
|
||||
* jne/jeq ...
|
||||
*/
|
||||
**
|
||||
** jsr xxx
|
||||
** jsr bnega(x)
|
||||
** jeq/jne ...
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** jsr xxx
|
||||
** <boolean test>
|
||||
** jne/jeq ...
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -140,27 +140,27 @@ unsigned OptBNegAX4 (CodeSeg* S);
|
||||
|
||||
unsigned OptNegAX1 (CodeSeg* S);
|
||||
/* Search for a call to negax and replace it by
|
||||
*
|
||||
* eor #$FF
|
||||
* clc
|
||||
* adc #$01
|
||||
*
|
||||
* if X isn't used later.
|
||||
*/
|
||||
**
|
||||
** eor #$FF
|
||||
** clc
|
||||
** adc #$01
|
||||
**
|
||||
** if X isn't used later.
|
||||
*/
|
||||
|
||||
unsigned OptNegAX2 (CodeSeg* S);
|
||||
/* Search for a call to negax and replace it by
|
||||
*
|
||||
* ldx #$FF
|
||||
* eor #$FF
|
||||
* clc
|
||||
* adc #$01
|
||||
* bne L1
|
||||
* inx
|
||||
* L1:
|
||||
*
|
||||
* if X is known and zero on entry.
|
||||
*/
|
||||
**
|
||||
** ldx #$FF
|
||||
** eor #$FF
|
||||
** clc
|
||||
** adc #$01
|
||||
** bne L1
|
||||
** inx
|
||||
** L1:
|
||||
**
|
||||
** if X is known and zero on entry.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -172,11 +172,11 @@ unsigned OptNegAX2 (CodeSeg* S);
|
||||
|
||||
unsigned OptComplAX1 (CodeSeg* S);
|
||||
/* Search for a call to complax and replace it by
|
||||
*
|
||||
* eor #$FF
|
||||
*
|
||||
* if X isn't used later.
|
||||
*/
|
||||
**
|
||||
** eor #$FF
|
||||
**
|
||||
** if X isn't used later.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -53,28 +53,28 @@
|
||||
|
||||
unsigned OptPtrLoad1 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* tay
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* tya
|
||||
* ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* txa
|
||||
* clc
|
||||
* adc yyy
|
||||
* sta ptr1+1
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** tay
|
||||
** txa
|
||||
** adc yyy
|
||||
** tax
|
||||
** tya
|
||||
** ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** txa
|
||||
** clc
|
||||
** adc yyy
|
||||
** sta ptr1+1
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -115,9 +115,9 @@ unsigned OptPtrLoad1 (CodeSeg* S)
|
||||
CS_InsertEntry (S, X, IP++);
|
||||
|
||||
/* If the instruction before the clc is a ldx, replace the
|
||||
* txa by an lda with the same location of the ldx. Otherwise
|
||||
* transfer the value in X to A.
|
||||
*/
|
||||
** txa by an lda with the same location of the ldx. Otherwise
|
||||
** transfer the value in X to A.
|
||||
*/
|
||||
if ((P = CS_GetPrevEntry (S, I)) != 0 &&
|
||||
P->OPC == OP65_LDX &&
|
||||
!CE_HasLabel (P)) {
|
||||
@@ -172,29 +172,29 @@ unsigned OptPtrLoad1 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad2 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* adc xxx
|
||||
* pha
|
||||
* txa
|
||||
* iny
|
||||
* adc yyy
|
||||
* tax
|
||||
* pla
|
||||
* ldy
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* adc xxx
|
||||
* sta ptr1
|
||||
* txa
|
||||
* iny
|
||||
* adc yyy
|
||||
* sta ptr1+1
|
||||
* ldy
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** adc xxx
|
||||
** pha
|
||||
** txa
|
||||
** iny
|
||||
** adc yyy
|
||||
** tax
|
||||
** pla
|
||||
** ldy
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** adc xxx
|
||||
** sta ptr1
|
||||
** txa
|
||||
** iny
|
||||
** adc yyy
|
||||
** sta ptr1+1
|
||||
** ldy
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -260,22 +260,22 @@ unsigned OptPtrLoad2 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad3 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda #<(label+0)
|
||||
* ldx #>(label+0)
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda label,y
|
||||
*/
|
||||
**
|
||||
** lda #<(label+0)
|
||||
** ldx #>(label+0)
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda label,y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -319,8 +319,8 @@ unsigned OptPtrLoad3 (CodeSeg* S)
|
||||
char* Label;
|
||||
|
||||
/* We will create all the new stuff behind the current one so
|
||||
* we keep the line references.
|
||||
*/
|
||||
** we keep the line references.
|
||||
*/
|
||||
X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+8);
|
||||
|
||||
@@ -354,25 +354,25 @@ unsigned OptPtrLoad3 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad4 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda #<(label+0)
|
||||
* ldx #>(label+0)
|
||||
* ldy #$xx
|
||||
* clc
|
||||
* adc (sp),y
|
||||
* bcc L
|
||||
* inx
|
||||
* L: ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy #$xx
|
||||
* lda (sp),y
|
||||
* tay
|
||||
* ldx #$00
|
||||
* lda label,y
|
||||
*/
|
||||
**
|
||||
** lda #<(label+0)
|
||||
** ldx #>(label+0)
|
||||
** ldy #$xx
|
||||
** clc
|
||||
** adc (sp),y
|
||||
** bcc L
|
||||
** inx
|
||||
** L: ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy #$xx
|
||||
** lda (sp),y
|
||||
** tay
|
||||
** ldx #$00
|
||||
** lda label,y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -463,22 +463,22 @@ unsigned OptPtrLoad4 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad5 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr pushax
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* jsr tosaddax
|
||||
* ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy yyy
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** jsr tosaddax
|
||||
** ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy yyy
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -549,25 +549,25 @@ unsigned OptPtrLoad5 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad6 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr pushax
|
||||
* ldy #xxx
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* jsr tosaddax
|
||||
* ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy #xxx-2
|
||||
* lda (sp),y
|
||||
* tay
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldy #xxx
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** jsr tosaddax
|
||||
** ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy #xxx-2
|
||||
** lda (sp),y
|
||||
** tay
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -650,35 +650,35 @@ unsigned OptPtrLoad6 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad7 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr aslax1/shlax1
|
||||
* clc
|
||||
* adc xxx
|
||||
* tay
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* tya
|
||||
* ldy zzz
|
||||
* jsr ldaxidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* stx tmp1
|
||||
* asl a
|
||||
* rol tmp1
|
||||
* clc
|
||||
* adc xxx
|
||||
* sta ptr1
|
||||
* lda tmp1
|
||||
* adc yyy
|
||||
* sta ptr1+1
|
||||
* ldy zzz
|
||||
* lda (ptr1),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** jsr aslax1/shlax1
|
||||
** clc
|
||||
** adc xxx
|
||||
** tay
|
||||
** txa
|
||||
** adc yyy
|
||||
** tax
|
||||
** tya
|
||||
** ldy zzz
|
||||
** jsr ldaxidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** stx tmp1
|
||||
** asl a
|
||||
** rol tmp1
|
||||
** clc
|
||||
** adc xxx
|
||||
** sta ptr1
|
||||
** lda tmp1
|
||||
** adc yyy
|
||||
** sta ptr1+1
|
||||
** ldy zzz
|
||||
** lda (ptr1),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -715,15 +715,15 @@ unsigned OptPtrLoad7 (CodeSeg* S)
|
||||
|
||||
|
||||
/* If X is zero on entry to aslax1, we can generate:
|
||||
*
|
||||
* asl a
|
||||
* bcc L1
|
||||
* inx
|
||||
* L1: clc
|
||||
*
|
||||
* instead of the code above. "lda tmp1" needs to be changed
|
||||
* to "txa" in this case.
|
||||
*/
|
||||
**
|
||||
** asl a
|
||||
** bcc L1
|
||||
** inx
|
||||
** L1: clc
|
||||
**
|
||||
** instead of the code above. "lda tmp1" needs to be changed
|
||||
** to "txa" in this case.
|
||||
*/
|
||||
int ShortCode = (L[0]->RI->In.RegX == 0);
|
||||
|
||||
if (ShortCode) {
|
||||
@@ -838,22 +838,22 @@ unsigned OptPtrLoad7 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad11 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xxx
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xxx
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -884,8 +884,8 @@ unsigned OptPtrLoad11 (CodeSeg* S)
|
||||
CodeEntry* X;
|
||||
|
||||
/* We will create all the new stuff behind the current one so
|
||||
* we keep the line references.
|
||||
*/
|
||||
** we keep the line references.
|
||||
*/
|
||||
X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+6);
|
||||
|
||||
@@ -925,35 +925,35 @@ unsigned OptPtrLoad11 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad12 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda regbank+n
|
||||
* ldx regbank+n+1
|
||||
* sta regsave
|
||||
* stx regsave+1
|
||||
* clc
|
||||
* adc #$01
|
||||
* bcc L0005
|
||||
* inx
|
||||
* L: sta regbank+n
|
||||
* stx regbank+n+1
|
||||
* lda regsave
|
||||
* ldx regsave+1
|
||||
* ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy #$00
|
||||
* ldx #$00
|
||||
* lda (regbank+n),y
|
||||
* inc regbank+n
|
||||
* bne L1
|
||||
* inc regbank+n+1
|
||||
* L1: tay <- only if flags are used
|
||||
*
|
||||
* This function must execute before OptPtrLoad7!
|
||||
*
|
||||
*/
|
||||
**
|
||||
** lda regbank+n
|
||||
** ldx regbank+n+1
|
||||
** sta regsave
|
||||
** stx regsave+1
|
||||
** clc
|
||||
** adc #$01
|
||||
** bcc L0005
|
||||
** inx
|
||||
** L: sta regbank+n
|
||||
** stx regbank+n+1
|
||||
** lda regsave
|
||||
** ldx regsave+1
|
||||
** ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy #$00
|
||||
** ldx #$00
|
||||
** lda (regbank+n),y
|
||||
** inc regbank+n
|
||||
** bne L1
|
||||
** inc regbank+n+1
|
||||
** L1: tay <- only if flags are used
|
||||
**
|
||||
** This function must execute before OptPtrLoad7!
|
||||
**
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1012,17 +1012,17 @@ unsigned OptPtrLoad12 (CodeSeg* S)
|
||||
CodeLabel* Label;
|
||||
|
||||
/* Check if the instruction following the sequence uses the flags
|
||||
* set by the load. If so, insert a test of the value in the
|
||||
* accumulator.
|
||||
*/
|
||||
** set by the load. If so, insert a test of the value in the
|
||||
** accumulator.
|
||||
*/
|
||||
if (CE_UseLoadFlags (L[14])) {
|
||||
X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[13]->LI);
|
||||
CS_InsertEntry (S, X, I+14);
|
||||
}
|
||||
|
||||
/* Attach a label to L[14]. This may be either the just inserted
|
||||
* instruction, or the one following the sequence.
|
||||
*/
|
||||
** instruction, or the one following the sequence.
|
||||
*/
|
||||
Label = CS_GenLabel (S, L[14]);
|
||||
|
||||
/* ldy #$xx */
|
||||
@@ -1070,18 +1070,18 @@ unsigned OptPtrLoad12 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad13 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* ldy xx
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xx
|
||||
* ldx #$00
|
||||
* lda (zp),y
|
||||
*/
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** ldy xx
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xx
|
||||
** ldx #$00
|
||||
** lda (zp),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1138,23 +1138,22 @@ unsigned OptPtrLoad13 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad14 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* (anything that doesn't change a/x)
|
||||
* ldy xx
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* (anything that doesn't change a/x)
|
||||
* ldy xx
|
||||
* ldx #$00
|
||||
* lda (zp),y
|
||||
*
|
||||
*/
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** (anything that doesn't change a/x)
|
||||
** ldy xx
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** (anything that doesn't change a/x)
|
||||
** ldy xx
|
||||
** ldx #$00
|
||||
** lda (zp),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -1212,24 +1211,24 @@ unsigned OptPtrLoad14 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad15 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* jsr pushax <- optional
|
||||
* ldy xx
|
||||
* jsr ldaxidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* lda zp <- only if
|
||||
* ldx zp+1 <- call to
|
||||
* jsr pushax <- pushax present
|
||||
* ldy xx
|
||||
* lda (zp),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (zp),y
|
||||
*/
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** jsr pushax <- optional
|
||||
** ldy xx
|
||||
** jsr ldaxidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** lda zp <- only if
|
||||
** ldx zp+1 <- call to
|
||||
** jsr pushax <- pushax present
|
||||
** ldy xx
|
||||
** lda (zp),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (zp),y
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1300,20 +1299,20 @@ unsigned OptPtrLoad15 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad16 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldy ...
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* stx ptr1+1
|
||||
* sta ptr1
|
||||
* ldy ...
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*
|
||||
* This step must be executed *after* OptPtrLoad1!
|
||||
*/
|
||||
**
|
||||
** ldy ...
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** stx ptr1+1
|
||||
** sta ptr1
|
||||
** ldy ...
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
**
|
||||
** This step must be executed *after* OptPtrLoad1!
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -1375,25 +1374,25 @@ unsigned OptPtrLoad16 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrLoad17 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldy ...
|
||||
* jsr ldaxidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy ...
|
||||
* lda (ptr1),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (ptr1),y
|
||||
*
|
||||
* This step must be executed *after* OptPtrLoad9! While code size increases
|
||||
* by more than 200%, inlining will greatly improve visibility for the
|
||||
* optimizer, so often part of the code gets improved later. So we will mark
|
||||
* the step with less than 200% so it gets executed when -Oi is in effect.
|
||||
*/
|
||||
**
|
||||
** ldy ...
|
||||
** jsr ldaxidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy ...
|
||||
** lda (ptr1),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (ptr1),y
|
||||
**
|
||||
** This step must be executed *after* OptPtrLoad9! While code size increases
|
||||
** by more than 200%, inlining will greatly improve visibility for the
|
||||
** optimizer, so often part of the code gets improved later. So we will mark
|
||||
** the step with less than 200% so it gets executed when -Oi is in effect.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
|
||||
@@ -51,310 +51,310 @@
|
||||
|
||||
unsigned OptPtrLoad1 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* tay
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* tya
|
||||
* ldy
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* sta ptr1
|
||||
* txa
|
||||
* adc yyy
|
||||
* sta ptr1+1
|
||||
* ldy
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** tay
|
||||
** txa
|
||||
** adc yyy
|
||||
** tax
|
||||
** tya
|
||||
** ldy
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** sta ptr1
|
||||
** txa
|
||||
** adc yyy
|
||||
** sta ptr1+1
|
||||
** ldy
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad2 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* adc xxx
|
||||
* pha
|
||||
* txa
|
||||
* iny
|
||||
* adc yyy
|
||||
* tax
|
||||
* pla
|
||||
* ldy
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* adc xxx
|
||||
* sta ptr1
|
||||
* txa
|
||||
* iny
|
||||
* adc yyy
|
||||
* sta ptr1+1
|
||||
* ldy
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** adc xxx
|
||||
** pha
|
||||
** txa
|
||||
** iny
|
||||
** adc yyy
|
||||
** tax
|
||||
** pla
|
||||
** ldy
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** adc xxx
|
||||
** sta ptr1
|
||||
** txa
|
||||
** iny
|
||||
** adc yyy
|
||||
** sta ptr1+1
|
||||
** ldy
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad3 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda #<(label+0)
|
||||
* ldx #>(label+0)
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda label,y
|
||||
*/
|
||||
**
|
||||
** lda #<(label+0)
|
||||
** ldx #>(label+0)
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda label,y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad4 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda #<(label+0)
|
||||
* ldx #>(label+0)
|
||||
* ldy #$xx
|
||||
* clc
|
||||
* adc (sp),y
|
||||
* bcc L
|
||||
* inx
|
||||
* L: ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy #$xx
|
||||
* lda (sp),y
|
||||
* tay
|
||||
* ldx #$00
|
||||
* lda label,y
|
||||
*/
|
||||
**
|
||||
** lda #<(label+0)
|
||||
** ldx #>(label+0)
|
||||
** ldy #$xx
|
||||
** clc
|
||||
** adc (sp),y
|
||||
** bcc L
|
||||
** inx
|
||||
** L: ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy #$xx
|
||||
** lda (sp),y
|
||||
** tay
|
||||
** ldx #$00
|
||||
** lda label,y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad5 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr pushax
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* jsr tosaddax
|
||||
* ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy yyy
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** jsr tosaddax
|
||||
** ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy yyy
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad6 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr pushax
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* jsr tosaddax
|
||||
* ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy xxx
|
||||
* lda (sp),y
|
||||
* tay
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** jsr tosaddax
|
||||
** ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy xxx
|
||||
** lda (sp),y
|
||||
** tay
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad7 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr aslax1/shlax1
|
||||
* clc
|
||||
* adc xxx
|
||||
* tay
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* tya
|
||||
* ldy zzz
|
||||
* jsr ldaxidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* stx tmp1
|
||||
* asl a
|
||||
* rol tmp1
|
||||
* clc
|
||||
* adc xxx
|
||||
* sta ptr1
|
||||
* lda tmp1
|
||||
* adc yyy
|
||||
* sta ptr1+1
|
||||
* ldy zzz
|
||||
* lda (ptr1),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** jsr aslax1/shlax1
|
||||
** clc
|
||||
** adc xxx
|
||||
** tay
|
||||
** txa
|
||||
** adc yyy
|
||||
** tax
|
||||
** tya
|
||||
** ldy zzz
|
||||
** jsr ldaxidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** stx tmp1
|
||||
** asl a
|
||||
** rol tmp1
|
||||
** clc
|
||||
** adc xxx
|
||||
** sta ptr1
|
||||
** lda tmp1
|
||||
** adc yyy
|
||||
** sta ptr1+1
|
||||
** ldy zzz
|
||||
** lda (ptr1),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad11 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xxx
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xxx
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad12 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda regbank+n
|
||||
* ldx regbank+n+1
|
||||
* sta regsave
|
||||
* stx regsave+1
|
||||
* clc
|
||||
* adc #$01
|
||||
* bcc L0005
|
||||
* inx
|
||||
* L: sta regbank+n
|
||||
* stx regbank+n+1
|
||||
* lda regsave
|
||||
* ldx regsave+1
|
||||
* ldy #$00
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy #$00
|
||||
* ldx #$00
|
||||
* lda (regbank+n),y
|
||||
* inc regbank+n
|
||||
* bne L1
|
||||
* inc regbank+n+1
|
||||
* L1: tay <- only if flags are used
|
||||
*
|
||||
* This function must execute before OptPtrLoad7!
|
||||
*
|
||||
*/
|
||||
**
|
||||
** lda regbank+n
|
||||
** ldx regbank+n+1
|
||||
** sta regsave
|
||||
** stx regsave+1
|
||||
** clc
|
||||
** adc #$01
|
||||
** bcc L0005
|
||||
** inx
|
||||
** L: sta regbank+n
|
||||
** stx regbank+n+1
|
||||
** lda regsave
|
||||
** ldx regsave+1
|
||||
** ldy #$00
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy #$00
|
||||
** ldx #$00
|
||||
** lda (regbank+n),y
|
||||
** inc regbank+n
|
||||
** bne L1
|
||||
** inc regbank+n+1
|
||||
** L1: tay <- only if flags are used
|
||||
**
|
||||
** This function must execute before OptPtrLoad7!
|
||||
**
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad13 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* ldy xx
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xx
|
||||
* ldx #$00
|
||||
* lda (zp),y
|
||||
*/
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** ldy xx
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xx
|
||||
** ldx #$00
|
||||
** lda (zp),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad14 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* (anything that doesn't change a/x)
|
||||
* ldy xx
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* (anything that doesn't change a/x)
|
||||
* ldy xx
|
||||
* ldx #$00
|
||||
* lda (zp),y
|
||||
*
|
||||
* Must execute before OptPtrLoad10!
|
||||
*/
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** (anything that doesn't change a/x)
|
||||
** ldy xx
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** (anything that doesn't change a/x)
|
||||
** ldy xx
|
||||
** ldx #$00
|
||||
** lda (zp),y
|
||||
**
|
||||
** Must execute before OptPtrLoad10!
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad15 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda zp
|
||||
* ldx zp+1
|
||||
* ldy xx
|
||||
* jsr ldaxidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy xx
|
||||
* lda (zp),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (zp),y
|
||||
*/
|
||||
**
|
||||
** lda zp
|
||||
** ldx zp+1
|
||||
** ldy xx
|
||||
** jsr ldaxidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy xx
|
||||
** lda (zp),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (zp),y
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad16 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldy ...
|
||||
* jsr ldauidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy ...
|
||||
* stx ptr1+1
|
||||
* sta ptr1
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
*
|
||||
* This step must be executed *after* OptPtrLoad1!
|
||||
*/
|
||||
**
|
||||
** ldy ...
|
||||
** jsr ldauidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy ...
|
||||
** stx ptr1+1
|
||||
** sta ptr1
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
**
|
||||
** This step must be executed *after* OptPtrLoad1!
|
||||
*/
|
||||
|
||||
unsigned OptPtrLoad17 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* ldy ...
|
||||
* jsr ldaxidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* ldy ...
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* lda (ptr1),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (ptr1),y
|
||||
*
|
||||
* This step must be executed *after* OptPtrLoad9! While code size increases
|
||||
* by more than 200%, inlining will greatly improve visibility for the
|
||||
* optimizer, so often part of the code gets improved later. So we will mark
|
||||
* the step with less than 200% so it gets executed when -Oi is in effect.
|
||||
*/
|
||||
**
|
||||
** ldy ...
|
||||
** jsr ldaxidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** ldy ...
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** lda (ptr1),y
|
||||
** tax
|
||||
** dey
|
||||
** lda (ptr1),y
|
||||
**
|
||||
** This step must be executed *after* OptPtrLoad9! While code size increases
|
||||
** by more than 200%, inlining will greatly improve visibility for the
|
||||
** optimizer, so often part of the code gets improved later. So we will mark
|
||||
** the step with less than 200% so it gets executed when -Oi is in effect.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -97,9 +97,9 @@ static unsigned OptPtrStore1Sub (CodeSeg* S, unsigned I, CodeEntry** const L)
|
||||
|
||||
static const char* LoadAXZP (CodeSeg* S, unsigned I)
|
||||
/* If the two instructions preceeding S/I are a load of A/X from a two byte
|
||||
* zero byte location, return the name of the zero page location. Otherwise
|
||||
* return NULL.
|
||||
*/
|
||||
** zero byte location, return the name of the zero page location. Otherwise
|
||||
** return NULL.
|
||||
*/
|
||||
{
|
||||
CodeEntry* L[2];
|
||||
unsigned Len;
|
||||
@@ -131,11 +131,11 @@ static const char* LoadAXZP (CodeSeg* S, unsigned I)
|
||||
|
||||
static const char* LoadAXImm (CodeSeg* S, unsigned I)
|
||||
/* If the instructions preceeding S/I are a load of A/X of a constant value
|
||||
* or a word sized address label, return the address of the location as a
|
||||
* string.
|
||||
* Beware: In case of a numeric value, the result is returned in static
|
||||
* storage which is overwritten with each call.
|
||||
*/
|
||||
** or a word sized address label, return the address of the location as a
|
||||
** string.
|
||||
** Beware: In case of a numeric value, the result is returned in static
|
||||
** storage which is overwritten with each call.
|
||||
*/
|
||||
{
|
||||
static StrBuf Buf = STATIC_STRBUF_INITIALIZER;
|
||||
CodeEntry* L[2];
|
||||
@@ -162,9 +162,9 @@ static const char* LoadAXImm (CodeSeg* S, unsigned I)
|
||||
}
|
||||
|
||||
/* Search back for the two instructions loading A and X. Abort
|
||||
* the search if the registers are changed in any other way or
|
||||
* if a label is reached while we don't have both loads.
|
||||
*/
|
||||
** the search if the registers are changed in any other way or
|
||||
** if a label is reached while we don't have both loads.
|
||||
*/
|
||||
ALoad = 0;
|
||||
XLoad = 0;
|
||||
while (I-- > 0) {
|
||||
@@ -223,49 +223,49 @@ static const char* LoadAXImm (CodeSeg* S, unsigned I)
|
||||
|
||||
unsigned OptPtrStore1 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: jsr pushax
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* ldy #$00
|
||||
* jsr staspidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta (ptr1),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta (zp),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta label,y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta $xxxx,y
|
||||
*
|
||||
* depending on the code preceeding the sequence above.
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: jsr pushax
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** ldy #$00
|
||||
** jsr staspidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta (ptr1),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta (zp),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta label,y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta $xxxx,y
|
||||
**
|
||||
** depending on the code preceeding the sequence above.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -309,22 +309,22 @@ unsigned OptPtrStore1 (CodeSeg* S)
|
||||
unsigned IP = I + 9;
|
||||
if ((Loc = LoadAXZP (S, I)) != 0) {
|
||||
/* If the sequence is preceeded by a load of a ZP value,
|
||||
* we can use this ZP value as a pointer using ZP
|
||||
* indirect Y addressing.
|
||||
*/
|
||||
** we can use this ZP value as a pointer using ZP
|
||||
** indirect Y addressing.
|
||||
*/
|
||||
AM = AM65_ZP_INDY;
|
||||
} else if ((Loc = LoadAXImm (S, I)) != 0) {
|
||||
/* If the sequence is preceeded by a load of an immediate
|
||||
* value, we can use this absolute value as an address
|
||||
* using absolute indexed Y addressing.
|
||||
*/
|
||||
** value, we can use this absolute value as an address
|
||||
** using absolute indexed Y addressing.
|
||||
*/
|
||||
AM = AM65_ABSY;
|
||||
}
|
||||
|
||||
/* If we don't have a store location, we use ptr1 with zp
|
||||
* indirect Y addressing. We must store the value in A/X into
|
||||
* ptr1 in this case.
|
||||
*/
|
||||
** indirect Y addressing. We must store the value in A/X into
|
||||
** ptr1 in this case.
|
||||
*/
|
||||
if (Loc == 0) {
|
||||
|
||||
/* Must use ptr1 */
|
||||
@@ -340,10 +340,10 @@ unsigned OptPtrStore1 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* If the index is loaded from (zp),y, we cannot do that directly.
|
||||
* Note: In this case, the Y register will contain the correct
|
||||
* value after removing the old code, so we don't need to load
|
||||
* it here.
|
||||
*/
|
||||
** Note: In this case, the Y register will contain the correct
|
||||
** value after removing the old code, so we don't need to load
|
||||
** it here.
|
||||
*/
|
||||
if (L[1]->AM == AM65_ZP_INDY) {
|
||||
X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
|
||||
CS_InsertEntry (S, X, IP++);
|
||||
@@ -388,54 +388,54 @@ unsigned OptPtrStore1 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrStore2 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: jsr pushax
|
||||
* ldy yyy
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy #$00
|
||||
* jsr staspidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta (ptr1),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta (zp),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta label,y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta $xxxx,y
|
||||
*
|
||||
* depending on the code preceeding the sequence above.
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: jsr pushax
|
||||
** ldy yyy
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy #$00
|
||||
** jsr staspidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta (ptr1),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta (zp),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta label,y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta $xxxx,y
|
||||
**
|
||||
** depending on the code preceeding the sequence above.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
@@ -486,22 +486,22 @@ unsigned OptPtrStore2 (CodeSeg* S)
|
||||
unsigned IP = I + 10;
|
||||
if ((Loc = LoadAXZP (S, I)) != 0) {
|
||||
/* If the sequence is preceeded by a load of a ZP value,
|
||||
* we can use this ZP value as a pointer using ZP
|
||||
* indirect Y addressing.
|
||||
*/
|
||||
** we can use this ZP value as a pointer using ZP
|
||||
** indirect Y addressing.
|
||||
*/
|
||||
AM = AM65_ZP_INDY;
|
||||
} else if ((Loc = LoadAXImm (S, I)) != 0) {
|
||||
/* If the sequence is preceeded by a load of an immediate
|
||||
* value, we can use this absolute value as an address
|
||||
* using absolute indexed Y addressing.
|
||||
*/
|
||||
** value, we can use this absolute value as an address
|
||||
** using absolute indexed Y addressing.
|
||||
*/
|
||||
AM = AM65_ABSY;
|
||||
}
|
||||
|
||||
/* If we don't have a store location, we use ptr1 with zp
|
||||
* indirect Y addressing. We must store the value in A/X into
|
||||
* ptr1 in this case.
|
||||
*/
|
||||
** indirect Y addressing. We must store the value in A/X into
|
||||
** ptr1 in this case.
|
||||
*/
|
||||
if (Loc == 0) {
|
||||
|
||||
/* Must use ptr1 */
|
||||
@@ -517,20 +517,20 @@ unsigned OptPtrStore2 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* Generate four different replacements depending on the addressing
|
||||
* mode of the store and from where the index is loaded:
|
||||
*
|
||||
* 1. If the index is not loaded ZP indirect Y, we can use Y for
|
||||
* the store index.
|
||||
*
|
||||
* 2. If the index is loaded ZP indirect Y and we store absolute
|
||||
* indexed, we need Y to load the index and will therefore
|
||||
* use X as index for the store. The disadvantage is that we
|
||||
* need to reload X later.
|
||||
*
|
||||
* 3. If the index is loaded ZP indirect Y and we store ZP indirect
|
||||
* Y, we must use Y for load and store and must therefore save
|
||||
* the A register when loading Y the second time.
|
||||
*/
|
||||
** mode of the store and from where the index is loaded:
|
||||
**
|
||||
** 1. If the index is not loaded ZP indirect Y, we can use Y for
|
||||
** the store index.
|
||||
**
|
||||
** 2. If the index is loaded ZP indirect Y and we store absolute
|
||||
** indexed, we need Y to load the index and will therefore
|
||||
** use X as index for the store. The disadvantage is that we
|
||||
** need to reload X later.
|
||||
**
|
||||
** 3. If the index is loaded ZP indirect Y and we store ZP indirect
|
||||
** Y, we must use Y for load and store and must therefore save
|
||||
** the A register when loading Y the second time.
|
||||
*/
|
||||
if (L[1]->AM != AM65_ZP_INDY) {
|
||||
|
||||
/* Case 1 */
|
||||
@@ -630,29 +630,28 @@ unsigned OptPtrStore2 (CodeSeg* S)
|
||||
|
||||
unsigned OptPtrStore3 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr pushax
|
||||
* ldy xxx
|
||||
* jsr ldauidx
|
||||
* subop
|
||||
* ldy yyy
|
||||
* jsr staspidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
* subop
|
||||
* ldy yyy
|
||||
* sta (ptr1),y
|
||||
*
|
||||
* In case a/x is loaded from the register bank before the pushax, we can even
|
||||
* use the register bank instead of ptr1.
|
||||
*
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldy xxx
|
||||
** jsr ldauidx
|
||||
** subop
|
||||
** ldy yyy
|
||||
** jsr staspidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
** subop
|
||||
** ldy yyy
|
||||
** sta (ptr1),y
|
||||
**
|
||||
** In case a/x is loaded from the register bank before the pushax, we can even
|
||||
** use the register bank instead of ptr1.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -689,10 +688,10 @@ unsigned OptPtrStore3 (CodeSeg* S)
|
||||
|
||||
|
||||
/* Get the preceeding two instructions and check them. We check
|
||||
* for:
|
||||
* lda regbank+n
|
||||
* ldx regbank+n+1
|
||||
*/
|
||||
** for:
|
||||
** lda regbank+n
|
||||
** ldx regbank+n+1
|
||||
*/
|
||||
if (I > 1) {
|
||||
CodeEntry* P[2];
|
||||
P[0] = CS_GetEntry (S, I-2);
|
||||
@@ -740,8 +739,8 @@ unsigned OptPtrStore3 (CodeSeg* S)
|
||||
}
|
||||
|
||||
/* Delete more old code. Do it here to keep a label attached to
|
||||
* entry I in place.
|
||||
*/
|
||||
** entry I in place.
|
||||
*/
|
||||
CS_DelEntry (S, I); /* jsr pushax */
|
||||
|
||||
/* Remember, we had changes */
|
||||
|
||||
@@ -51,126 +51,125 @@
|
||||
|
||||
unsigned OptPtrStore1 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: jsr pushax
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* ldy #$00
|
||||
* jsr staspidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta (ptr1),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta (zp),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta label,y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda yyy
|
||||
* sta $xxxx,y
|
||||
*
|
||||
* depending on the two instructions preceeding the sequence above.
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: jsr pushax
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** ldy #$00
|
||||
** jsr staspidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta (ptr1),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta (zp),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta label,y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda yyy
|
||||
** sta $xxxx,y
|
||||
**
|
||||
** depending on the two instructions preceeding the sequence above.
|
||||
*/
|
||||
|
||||
unsigned OptPtrStore2 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* bcc L
|
||||
* inx
|
||||
* L: jsr pushax
|
||||
* ldy yyy
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy #$00
|
||||
* jsr staspidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta (ptr1),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta (zp),y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta label,y
|
||||
*
|
||||
* or by
|
||||
*
|
||||
* ldy yyy-2
|
||||
* ldx #$00
|
||||
* lda (sp),y
|
||||
* ldy xxx
|
||||
* sta $xxxx,y
|
||||
*
|
||||
* depending on the code preceeding the sequence above.
|
||||
*/
|
||||
**
|
||||
** clc
|
||||
** adc xxx
|
||||
** bcc L
|
||||
** inx
|
||||
** L: jsr pushax
|
||||
** ldy yyy
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy #$00
|
||||
** jsr staspidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta (ptr1),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta (zp),y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta label,y
|
||||
**
|
||||
** or by
|
||||
**
|
||||
** ldy yyy-2
|
||||
** ldx #$00
|
||||
** lda (sp),y
|
||||
** ldy xxx
|
||||
** sta $xxxx,y
|
||||
**
|
||||
** depending on the code preceeding the sequence above.
|
||||
*/
|
||||
|
||||
unsigned OptPtrStore3 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr pushax
|
||||
* ldy xxx
|
||||
* jsr ldauidx
|
||||
* subop
|
||||
* ldy yyy
|
||||
* jsr staspidx
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* sta ptr1
|
||||
* stx ptr1+1
|
||||
* ldy xxx
|
||||
* ldx #$00
|
||||
* lda (ptr1),y
|
||||
* subop
|
||||
* ldy yyy
|
||||
* sta (ptr1),y
|
||||
*
|
||||
* In case a/x is loaded from the register bank before the pushax, we can even
|
||||
* use the register bank instead of ptr1.
|
||||
*
|
||||
*/
|
||||
**
|
||||
** jsr pushax
|
||||
** ldy xxx
|
||||
** jsr ldauidx
|
||||
** subop
|
||||
** ldy yyy
|
||||
** jsr staspidx
|
||||
**
|
||||
** and replace it by:
|
||||
**
|
||||
** sta ptr1
|
||||
** stx ptr1+1
|
||||
** ldy xxx
|
||||
** ldx #$00
|
||||
** lda (ptr1),y
|
||||
** subop
|
||||
** ldy yyy
|
||||
** sta (ptr1),y
|
||||
**
|
||||
** In case a/x is loaded from the register bank before the pushax, we can even
|
||||
** use the register bank instead of ptr1.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -48,17 +48,17 @@
|
||||
|
||||
unsigned OptPush1 (CodeSeg* S)
|
||||
/* Given a sequence
|
||||
*
|
||||
* jsr ldaxysp
|
||||
* jsr pushax
|
||||
*
|
||||
* If a/x are not used later, and Y is known, replace that by
|
||||
*
|
||||
* ldy #xx+2
|
||||
* jsr pushwysp
|
||||
*
|
||||
* saving 3 bytes and several cycles.
|
||||
*/
|
||||
**
|
||||
** jsr ldaxysp
|
||||
** jsr pushax
|
||||
**
|
||||
** If a/x are not used later, and Y is known, replace that by
|
||||
**
|
||||
** ldy #xx+2
|
||||
** jsr pushwysp
|
||||
**
|
||||
** saving 3 bytes and several cycles.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
unsigned Changes = 0;
|
||||
@@ -115,15 +115,14 @@ unsigned OptPush1 (CodeSeg* S)
|
||||
|
||||
unsigned OptPush2 (CodeSeg* S)
|
||||
/* A sequence
|
||||
*
|
||||
* jsr ldaxidx
|
||||
* jsr pushax
|
||||
*
|
||||
* may get replaced by
|
||||
*
|
||||
* jsr pushwidx
|
||||
*
|
||||
*/
|
||||
**
|
||||
** jsr ldaxidx
|
||||
** jsr pushax
|
||||
**
|
||||
** may get replaced by
|
||||
**
|
||||
** jsr pushwidx
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
unsigned Changes = 0;
|
||||
|
||||
@@ -51,30 +51,29 @@
|
||||
|
||||
unsigned OptPush1 (CodeSeg* S);
|
||||
/* Given a sequence
|
||||
*
|
||||
* ldy #xx
|
||||
* jsr ldaxysp
|
||||
* jsr pushax
|
||||
*
|
||||
* If a/x are not used later, replace that by
|
||||
*
|
||||
* ldy #xx+2
|
||||
* jsr pushwysp
|
||||
*
|
||||
* saving 3 bytes and several cycles.
|
||||
*/
|
||||
**
|
||||
** ldy #xx
|
||||
** jsr ldaxysp
|
||||
** jsr pushax
|
||||
**
|
||||
** If a/x are not used later, replace that by
|
||||
**
|
||||
** ldy #xx+2
|
||||
** jsr pushwysp
|
||||
**
|
||||
** saving 3 bytes and several cycles.
|
||||
*/
|
||||
|
||||
unsigned OptPush2 (CodeSeg* S);
|
||||
/* A sequence
|
||||
*
|
||||
* jsr ldaxidx
|
||||
* jsr pushax
|
||||
*
|
||||
* may get replaced by
|
||||
*
|
||||
* jsr pushwidx
|
||||
*
|
||||
*/
|
||||
**
|
||||
** jsr ldaxidx
|
||||
** jsr pushax
|
||||
**
|
||||
** may get replaced by
|
||||
**
|
||||
** jsr pushwidx
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user