diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 7b543aa55..2ebc09b14 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -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; diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 34cf550a2..fb1232fc1 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -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); + } } diff --git a/src/cc65/funcdesc.c b/src/cc65/funcdesc.c index b9561a97c..607094acd 100644 --- a/src/cc65/funcdesc.c +++ b/src/cc65/funcdesc.c @@ -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; diff --git a/src/cc65/funcdesc.h b/src/cc65/funcdesc.h index b79c6a055..b83cfa362 100644 --- a/src/cc65/funcdesc.h +++ b/src/cc65/funcdesc.h @@ -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 */ }; diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c index 707546e1d..c36811f35 100644 --- a/src/cc65/pragma.c +++ b/src/cc65/pragma.c @@ -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;