]> git.sur5r.net Git - cc65/commitdiff
Pragma trampoline
authorLauri Kasanen <cand@gmx.com>
Tue, 2 May 2017 16:06:19 +0000 (19:06 +0300)
committerLauri Kasanen <cand@gmx.com>
Tue, 2 May 2017 17:51:53 +0000 (20:51 +0300)
src/cc65/declare.c
src/cc65/expr.c
src/cc65/funcdesc.c
src/cc65/funcdesc.h
src/cc65/pragma.c

index 7b543aa55aa913c52ac21af66656a273c61021f6..2ebc09b1467b8f5c6d4bc4c7687473556b07e2b0 100644 (file)
@@ -58,6 +58,7 @@
 #include "scanner.h"
 #include "standard.h"
 #include "symtab.h"
+#include "trampoline.h"
 #include "typeconv.h"
 
 
@@ -1315,6 +1316,8 @@ static FuncDesc* ParseFuncDecl (void)
 {
     unsigned Offs;
     SymEntry* Sym;
+    SymEntry* Trampoline;
+    unsigned char TrampolineData;
 
     /* Create a new function descriptor */
     FuncDesc* F = NewFuncDesc ();
@@ -1380,6 +1383,13 @@ static FuncDesc* ParseFuncDecl (void)
     /* Leave the lexical level remembering the symbol tables */
     RememberFunctionLevel (F);
 
+    /* Did we have a trampoline for this function? */
+    GetTrampoline((void **) &Trampoline, &TrampolineData);
+    if (Trampoline) {
+        F->Trampoline = Trampoline;
+        F->TrampolineData = TrampolineData;
+    }
+
     /* Return the function descriptor */
     return F;
 }
@@ -1447,6 +1457,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
 
             /* Function declaration */
             FuncDesc* F;
+            SymEntry* PrevEntry;
 
             /* Skip the opening paren */
             NextToken ();
@@ -1460,6 +1471,16 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
                 Qualifiers &= ~T_QUAL_FASTCALL;
             }
 
+            /* Was there a previous entry? If so, copy trampoline info from it */
+            PrevEntry = FindGlobalSym (D->Ident);
+            if (PrevEntry && PrevEntry->Flags & SC_FUNC) {
+                FuncDesc* D = PrevEntry->V.F.Func;
+                if (D->Trampoline && !F->Trampoline) {
+                    F->Trampoline = D->Trampoline;
+                    F->TrampolineData = D->TrampolineData;
+                }
+            }
+
             /* Add the function type. Be sure to bounds check the type buffer */
             NeedTypeSpace (D, 1);
             D->Type[D->Index].C = T_FUNC | Qualifiers;
index 34cf550a2e780b7e59b330297024930cd9d004e0..fb1232fc1d31bf6a571e736850ec1f386eae5a5b 100644 (file)
@@ -536,6 +536,10 @@ static void FunctionCall (ExprDesc* Expr)
     /* Special handling for function pointers */
     if (IsFuncPtr) {
 
+        if (Func->Trampoline) {
+            Warning("Calling a trampolined function via a pointer, trampoline will not be used");
+        }
+
         /* If the function is not a fastcall function, load the pointer to
         ** the function into the primary.
         */
@@ -584,7 +588,47 @@ static void FunctionCall (ExprDesc* Expr)
     } else {
 
         /* Normal function */
-        g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
+        if (Func->Trampoline) {
+            char tmp[64];
+            StrBuf S = AUTO_STRBUF_INITIALIZER;
+
+            /* Store the trampoline data in tmp4 */
+            sprintf(tmp, "ldy #%u", Func->TrampolineData);
+            SB_AppendStr (&S, tmp);
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "sty tmp4");
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            /* Store the original function address in ptr4 */
+            SB_AppendStr (&S, "ldy #<(_");
+            SB_AppendStr (&S, (const char*) Expr->Name);
+            SB_AppendChar (&S, ')');
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "sty ptr4");
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "ldy #>(_");
+            SB_AppendStr (&S, (const char*) Expr->Name);
+            SB_AppendChar (&S, ')');
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "sty ptr4+1");
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_Done (&S);
+
+            g_call (TypeOf (Expr->Type), Func->Trampoline->Name, ParamSize);
+        } else {
+            g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
+        }
 
     }
 
index b9561a97cc4d6a68040a33d2ceadb0f61125f1a7..607094acdbf41dc634131287970a0e16a4ae5c93 100644 (file)
@@ -60,6 +60,8 @@ FuncDesc* NewFuncDesc (void)
     F->ParamCount = 0;
     F->ParamSize  = 0;
     F->LastParam  = 0;
+    F->Trampoline = 0;
+    F->TrampolineData = 0;
 
     /* Return the new struct */
     return F;
index b79c6a055ceb0384c71258c67d1658bc8e667800..b83cfa3623660e2014b10c93c172af71db567958 100644 (file)
@@ -67,6 +67,8 @@ struct FuncDesc {
     unsigned            ParamCount;     /* Number of parameters              */
     unsigned            ParamSize;      /* Size of the parameters            */
     struct SymEntry*    LastParam;      /* Pointer to last parameter         */
+    struct SymEntry*    Trampoline;     /* Pointer to the trampoline         */
+    unsigned char       TrampolineData; /* The trampoline's user data        */
 };
 
 
index 707546e1dd98e91e1c1214c5240e20c280107a06..c36811f356602f47942fa10bcf4c33a44afe2ea6 100644 (file)
@@ -51,6 +51,7 @@
 #include "scanstrbuf.h"
 #include "symtab.h"
 #include "pragma.h"
+#include "trampoline.h"
 
 
 
@@ -87,6 +88,7 @@ typedef enum {
     PRAGMA_SIGNEDCHARS,                                 /* obsolete */
     PRAGMA_STATIC_LOCALS,
     PRAGMA_STATICLOCALS,                                /* obsolete */
+    PRAGMA_TRAMPOLINE,
     PRAGMA_WARN,
     PRAGMA_WRITABLE_STRINGS,
     PRAGMA_ZPSYM,
@@ -122,6 +124,7 @@ static const struct Pragma {
     { "signedchars",            PRAGMA_SIGNEDCHARS        },      /* obsolete */
     { "static-locals",          PRAGMA_STATIC_LOCALS      },
     { "staticlocals",           PRAGMA_STATICLOCALS       },      /* obsolete */
+    { "trampoline",            PRAGMA_TRAMPOLINE         },
     { "warn",                   PRAGMA_WARN               },
     { "writable-strings",       PRAGMA_WRITABLE_STRINGS   },
     { "zpsym",                  PRAGMA_ZPSYM              },
@@ -446,6 +449,84 @@ ExitPoint:
 }
 
 
+static void TrampolinePragma (StrBuf* B)
+/* Handle the trampoline pragma */
+{
+    StrBuf      S = AUTO_STRBUF_INITIALIZER;
+    const char *Name;
+    long Val;
+    SymEntry *Entry;
+
+    /* Check for the "push" or "pop" keywords */
+    switch (ParsePushPop (B)) {
+
+        case PP_NONE:
+            Error ("Push or pop required");
+            break;
+
+        case PP_PUSH:
+            break;
+
+        case PP_POP:
+            PopTrampoline();
+
+            /* Done */
+            goto ExitPoint;
+
+        case PP_ERROR:
+            /* Bail out */
+            goto ExitPoint;
+
+        default:
+            Internal ("Invalid result from ParsePushPop");
+
+    }
+
+    /* A symbol argument must follow */
+    if (!SB_GetSym (B, &S, NULL)) {
+        goto ExitPoint;
+    }
+
+    /* Skip the following comma */
+    if (!GetComma (B)) {
+        /* Error already flagged by GetComma */
+        Error ("Value required for trampoline data");
+        goto ExitPoint;
+    }
+
+    if (!GetNumber (B, &Val)) {
+        Error ("Value required for trampoline data");
+        goto ExitPoint;
+    }
+
+    if (Val < 0 || Val > 255) {
+        Error ("Value must be between 0-255");
+        goto ExitPoint;
+    }
+
+    /* Get the string */
+    Name = SB_GetConstBuf (&S);
+    Entry = FindSym(Name);
+
+    /* Check if the name is valid */
+    if (Entry && Entry->Flags & (SC_FUNC | SC_STORAGE)) {
+
+        PushTrampoline(Entry, Val);
+        Entry->Flags |= SC_REF;
+
+    } else {
+
+        /* Segment name is invalid */
+        Error ("Trampoline does not exist or is not a function or array");
+
+    }
+
+ExitPoint:
+    /* Call the string buf destructor */
+    SB_Done (&S);
+}
+
+
 
 static void CharMapPragma (StrBuf* B)
 /* Change the character map */
@@ -791,6 +872,10 @@ static void ParsePragma (void)
             FlagPragma (&B, &StaticLocals);
             break;
 
+       case PRAGMA_TRAMPOLINE:
+           TrampolinePragma(&B);
+           break;
+
         case PRAGMA_WARN:
             WarnPragma (&B);
             break;