1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-17 00:29:31 +00:00

Pragma trampoline

This commit is contained in:
Lauri Kasanen 2017-05-02 19:06:19 +03:00
parent 9c86c03a96
commit 2890b3a810
5 changed files with 155 additions and 1 deletions

View 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;

View 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);
}
}

View 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;

View 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 */
};

View 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;