#include "scanner.h"
#include "standard.h"
#include "symtab.h"
+#include "trampoline.h"
#include "typeconv.h"
{
unsigned Offs;
SymEntry* Sym;
+ SymEntry* Trampoline;
+ unsigned char TrampolineData;
/* Create a new function descriptor */
FuncDesc* F = NewFuncDesc ();
/* 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;
}
/* Function declaration */
FuncDesc* F;
+ SymEntry* PrevEntry;
/* Skip the opening paren */
NextToken ();
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;
/* 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.
*/
} 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);
+ }
}
F->ParamCount = 0;
F->ParamSize = 0;
F->LastParam = 0;
+ F->Trampoline = 0;
+ F->TrampolineData = 0;
/* Return the new struct */
return F;
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 */
};
#include "scanstrbuf.h"
#include "symtab.h"
#include "pragma.h"
+#include "trampoline.h"
PRAGMA_SIGNEDCHARS, /* obsolete */
PRAGMA_STATIC_LOCALS,
PRAGMA_STATICLOCALS, /* obsolete */
+ PRAGMA_TRAMPOLINE,
PRAGMA_WARN,
PRAGMA_WRITABLE_STRINGS,
PRAGMA_ZPSYM,
{ "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 },
}
+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 */
FlagPragma (&B, &StaticLocals);
break;
+ case PRAGMA_TRAMPOLINE:
+ TrampolinePragma(&B);
+ break;
+
case PRAGMA_WARN:
WarnPragma (&B);
break;