mirror of
https://github.com/cc65/cc65.git
synced 2025-01-10 19:29:45 +00:00
commit
11b01b908d
@ -1229,6 +1229,30 @@ parameter with the <tt/#pragma/.
|
|||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
|
|
||||||
|
|
||||||
|
<sect1><tt>#pragma wrapped-call (<push&rt;, <name>, <identifier>)</tt><label id="pragma-wrapped-call"><p>
|
||||||
|
|
||||||
|
This pragma sets a wrapper for functions, often used for trampolines.
|
||||||
|
The name is a function returning void and taking no parameters.
|
||||||
|
The identifier is an 8-bit number that's set to tmp4.
|
||||||
|
|
||||||
|
The address of the function is passed in ptr4.
|
||||||
|
|
||||||
|
This is useful for example with banked memory, to automatically
|
||||||
|
switch banks to where this function resides, and then restore
|
||||||
|
the bank when it returns.
|
||||||
|
|
||||||
|
The <tt/#pragma/ requires the push and pop parameters as explained above.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<tscreen><verb>
|
||||||
|
void mytrampoline(void);
|
||||||
|
|
||||||
|
#pragma wrapped-call (push, mytrampoline, 0)
|
||||||
|
void somefunc(void);
|
||||||
|
#pragma wrapped-call (pop)
|
||||||
|
</verb></tscreen>
|
||||||
|
|
||||||
|
|
||||||
<sect1><tt>#pragma writable-strings ([push,] on|off)</tt><label id="pragma-writable-strings"><p>
|
<sect1><tt>#pragma writable-strings ([push,] on|off)</tt><label id="pragma-writable-strings"><p>
|
||||||
|
|
||||||
Changes the storage location of string literals. For historical reasons,
|
Changes the storage location of string literals. For historical reasons,
|
||||||
|
10
libsrc/runtime/callptr4.s
Normal file
10
libsrc/runtime/callptr4.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
;
|
||||||
|
; CC65 runtime: call function via pointer in ptr4
|
||||||
|
;
|
||||||
|
|
||||||
|
.export callptr4
|
||||||
|
.importzp ptr4
|
||||||
|
|
||||||
|
callptr4:
|
||||||
|
jmp (ptr4) ; jump there
|
||||||
|
|
@ -58,6 +58,7 @@
|
|||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "standard.h"
|
#include "standard.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
|
#include "wrappedcall.h"
|
||||||
#include "typeconv.h"
|
#include "typeconv.h"
|
||||||
|
|
||||||
|
|
||||||
@ -1315,6 +1316,8 @@ static FuncDesc* ParseFuncDecl (void)
|
|||||||
{
|
{
|
||||||
unsigned Offs;
|
unsigned Offs;
|
||||||
SymEntry* Sym;
|
SymEntry* Sym;
|
||||||
|
SymEntry* WrappedCall;
|
||||||
|
unsigned char WrappedCallData;
|
||||||
|
|
||||||
/* Create a new function descriptor */
|
/* Create a new function descriptor */
|
||||||
FuncDesc* F = NewFuncDesc ();
|
FuncDesc* F = NewFuncDesc ();
|
||||||
@ -1380,6 +1383,13 @@ static FuncDesc* ParseFuncDecl (void)
|
|||||||
/* Leave the lexical level remembering the symbol tables */
|
/* Leave the lexical level remembering the symbol tables */
|
||||||
RememberFunctionLevel (F);
|
RememberFunctionLevel (F);
|
||||||
|
|
||||||
|
/* Did we have a WrappedCall for this function? */
|
||||||
|
GetWrappedCall((void **) &WrappedCall, &WrappedCallData);
|
||||||
|
if (WrappedCall) {
|
||||||
|
F->WrappedCall = WrappedCall;
|
||||||
|
F->WrappedCallData = WrappedCallData;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the function descriptor */
|
/* Return the function descriptor */
|
||||||
return F;
|
return F;
|
||||||
}
|
}
|
||||||
@ -1447,6 +1457,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||||||
|
|
||||||
/* Function declaration */
|
/* Function declaration */
|
||||||
FuncDesc* F;
|
FuncDesc* F;
|
||||||
|
SymEntry* PrevEntry;
|
||||||
|
|
||||||
/* Skip the opening paren */
|
/* Skip the opening paren */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
@ -1460,6 +1471,16 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||||||
Qualifiers &= ~T_QUAL_FASTCALL;
|
Qualifiers &= ~T_QUAL_FASTCALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Was there a previous entry? If so, copy WrappedCall info from it */
|
||||||
|
PrevEntry = FindGlobalSym (D->Ident);
|
||||||
|
if (PrevEntry && PrevEntry->Flags & SC_FUNC) {
|
||||||
|
FuncDesc* D = PrevEntry->V.F.Func;
|
||||||
|
if (D->WrappedCall && !F->WrappedCall) {
|
||||||
|
F->WrappedCall = D->WrappedCall;
|
||||||
|
F->WrappedCallData = D->WrappedCallData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Add the function type. Be sure to bounds check the type buffer */
|
/* Add the function type. Be sure to bounds check the type buffer */
|
||||||
NeedTypeSpace (D, 1);
|
NeedTypeSpace (D, 1);
|
||||||
D->Type[D->Index].C = T_FUNC | Qualifiers;
|
D->Type[D->Index].C = T_FUNC | Qualifiers;
|
||||||
|
@ -536,6 +536,10 @@ static void FunctionCall (ExprDesc* Expr)
|
|||||||
/* Special handling for function pointers */
|
/* Special handling for function pointers */
|
||||||
if (IsFuncPtr) {
|
if (IsFuncPtr) {
|
||||||
|
|
||||||
|
if (Func->WrappedCall) {
|
||||||
|
Warning("Calling a wrapped function via a pointer, wrapped-call will not be used");
|
||||||
|
}
|
||||||
|
|
||||||
/* If the function is not a fastcall function, load the pointer to
|
/* If the function is not a fastcall function, load the pointer to
|
||||||
** the function into the primary.
|
** the function into the primary.
|
||||||
*/
|
*/
|
||||||
@ -584,7 +588,47 @@ static void FunctionCall (ExprDesc* Expr)
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Normal function */
|
/* Normal function */
|
||||||
g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
|
if (Func->WrappedCall) {
|
||||||
|
char tmp[64];
|
||||||
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
|
/* Store the WrappedCall data in tmp4 */
|
||||||
|
sprintf(tmp, "ldy #%u", Func->WrappedCallData);
|
||||||
|
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->WrappedCall->Name, ParamSize);
|
||||||
|
} else {
|
||||||
|
g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,8 @@ FuncDesc* NewFuncDesc (void)
|
|||||||
F->ParamCount = 0;
|
F->ParamCount = 0;
|
||||||
F->ParamSize = 0;
|
F->ParamSize = 0;
|
||||||
F->LastParam = 0;
|
F->LastParam = 0;
|
||||||
|
F->WrappedCall = 0;
|
||||||
|
F->WrappedCallData = 0;
|
||||||
|
|
||||||
/* Return the new struct */
|
/* Return the new struct */
|
||||||
return F;
|
return F;
|
||||||
|
@ -67,6 +67,8 @@ struct FuncDesc {
|
|||||||
unsigned ParamCount; /* Number of parameters */
|
unsigned ParamCount; /* Number of parameters */
|
||||||
unsigned ParamSize; /* Size of the parameters */
|
unsigned ParamSize; /* Size of the parameters */
|
||||||
struct SymEntry* LastParam; /* Pointer to last parameter */
|
struct SymEntry* LastParam; /* Pointer to last parameter */
|
||||||
|
struct SymEntry* WrappedCall; /* Pointer to the WrappedCall */
|
||||||
|
unsigned char WrappedCallData;/* The WrappedCall's user data */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "scanstrbuf.h"
|
#include "scanstrbuf.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "pragma.h"
|
#include "pragma.h"
|
||||||
|
#include "wrappedcall.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ typedef enum {
|
|||||||
PRAGMA_STATIC_LOCALS,
|
PRAGMA_STATIC_LOCALS,
|
||||||
PRAGMA_STATICLOCALS, /* obsolete */
|
PRAGMA_STATICLOCALS, /* obsolete */
|
||||||
PRAGMA_WARN,
|
PRAGMA_WARN,
|
||||||
|
PRAGMA_WRAPPED_CALL,
|
||||||
PRAGMA_WRITABLE_STRINGS,
|
PRAGMA_WRITABLE_STRINGS,
|
||||||
PRAGMA_ZPSYM,
|
PRAGMA_ZPSYM,
|
||||||
PRAGMA_COUNT
|
PRAGMA_COUNT
|
||||||
@ -123,6 +125,7 @@ static const struct Pragma {
|
|||||||
{ "static-locals", PRAGMA_STATIC_LOCALS },
|
{ "static-locals", PRAGMA_STATIC_LOCALS },
|
||||||
{ "staticlocals", PRAGMA_STATICLOCALS }, /* obsolete */
|
{ "staticlocals", PRAGMA_STATICLOCALS }, /* obsolete */
|
||||||
{ "warn", PRAGMA_WARN },
|
{ "warn", PRAGMA_WARN },
|
||||||
|
{ "wrapped-call", PRAGMA_WRAPPED_CALL },
|
||||||
{ "writable-strings", PRAGMA_WRITABLE_STRINGS },
|
{ "writable-strings", PRAGMA_WRITABLE_STRINGS },
|
||||||
{ "zpsym", PRAGMA_ZPSYM },
|
{ "zpsym", PRAGMA_ZPSYM },
|
||||||
};
|
};
|
||||||
@ -446,6 +449,84 @@ ExitPoint:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void WrappedCallPragma (StrBuf* B)
|
||||||
|
/* Handle the wrapped-call 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:
|
||||||
|
PopWrappedCall();
|
||||||
|
|
||||||
|
/* 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 wrapped-call identifier");
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetNumber (B, &Val)) {
|
||||||
|
Error ("Value required for wrapped-call identifier");
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Val < 0 || Val > 255) {
|
||||||
|
Error ("Identifier 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) {
|
||||||
|
|
||||||
|
PushWrappedCall(Entry, Val);
|
||||||
|
Entry->Flags |= SC_REF;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Segment name is invalid */
|
||||||
|
Error ("Wrapped-call target does not exist or is not a function");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitPoint:
|
||||||
|
/* Call the string buf destructor */
|
||||||
|
SB_Done (&S);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void CharMapPragma (StrBuf* B)
|
static void CharMapPragma (StrBuf* B)
|
||||||
/* Change the character map */
|
/* Change the character map */
|
||||||
@ -791,6 +872,10 @@ static void ParsePragma (void)
|
|||||||
FlagPragma (&B, &StaticLocals);
|
FlagPragma (&B, &StaticLocals);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PRAGMA_WRAPPED_CALL:
|
||||||
|
WrappedCallPragma(&B);
|
||||||
|
break;
|
||||||
|
|
||||||
case PRAGMA_WARN:
|
case PRAGMA_WARN:
|
||||||
WarnPragma (&B);
|
WarnPragma (&B);
|
||||||
break;
|
break;
|
||||||
|
102
src/cc65/wrappedcall.c
Normal file
102
src/cc65/wrappedcall.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* wrappedcall.c */
|
||||||
|
/* */
|
||||||
|
/* WrappedCall management */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2017, Mega Cat Studios */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "chartype.h"
|
||||||
|
#include "check.h"
|
||||||
|
#include "coll.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "intptrstack.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
|
#include "codeent.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "wrappedcall.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* WrappedCalls */
|
||||||
|
static IntPtrStack WrappedCalls;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PushWrappedCall (void *Ptr, unsigned char Val)
|
||||||
|
/* Push the current WrappedCall */
|
||||||
|
{
|
||||||
|
if (IPS_IsFull (&WrappedCalls)) {
|
||||||
|
Error ("WrappedCall stack overflow");
|
||||||
|
} else {
|
||||||
|
IPS_Push (&WrappedCalls, Val, Ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PopWrappedCall (void)
|
||||||
|
/* Remove the current WrappedCall */
|
||||||
|
{
|
||||||
|
if (IPS_GetCount (&WrappedCalls) < 1) {
|
||||||
|
Error ("WrappedCall stack is empty");
|
||||||
|
} else {
|
||||||
|
IPS_Drop (&WrappedCalls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetWrappedCall (void **Ptr, unsigned char *Val)
|
||||||
|
/* Get the current WrappedCall */
|
||||||
|
{
|
||||||
|
if (IPS_GetCount (&WrappedCalls) < 1) {
|
||||||
|
*Ptr = NULL;
|
||||||
|
*Val = 0;
|
||||||
|
} else {
|
||||||
|
long Temp;
|
||||||
|
IPS_Get (&WrappedCalls, &Temp, Ptr);
|
||||||
|
*Val = Temp;
|
||||||
|
}
|
||||||
|
}
|
65
src/cc65/wrappedcall.h
Normal file
65
src/cc65/wrappedcall.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* wrappedcall.h */
|
||||||
|
/* */
|
||||||
|
/* Wrapped-call management */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2017, Mega Cat Studios */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef WRAPPEDCALL_H
|
||||||
|
#define WRAPPEDCALL_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "attrib.h"
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PushWrappedCall (void *Ptr, unsigned char Val);
|
||||||
|
/* Push the current WrappedCall */
|
||||||
|
|
||||||
|
void PopWrappedCall (void);
|
||||||
|
/* Pop the current WrappedCall */
|
||||||
|
|
||||||
|
void GetWrappedCall (void **Ptr, unsigned char *Val);
|
||||||
|
/* Get the current WrappedCall, if any */
|
||||||
|
|
||||||
|
|
||||||
|
/* End of wrappedcall.h */
|
||||||
|
|
||||||
|
#endif
|
90
src/common/intptrstack.c
Normal file
90
src/common/intptrstack.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* intptrstack.c */
|
||||||
|
/* */
|
||||||
|
/* Integer+ptr stack used for program settings */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2017, Mega Cat Studios */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "check.h"
|
||||||
|
#include "intptrstack.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void IPS_Get (const IntPtrStack* S, long *Val, void **Ptr)
|
||||||
|
/* Get the value on top of an int stack */
|
||||||
|
{
|
||||||
|
PRECONDITION (S->Count > 0);
|
||||||
|
if (Val) *Val = S->Stack[S->Count-1].val;
|
||||||
|
if (Ptr) *Ptr = S->Stack[S->Count-1].ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void IPS_Set (IntPtrStack* S, long Val, void *Ptr)
|
||||||
|
/* Set the value on top of an int stack */
|
||||||
|
{
|
||||||
|
PRECONDITION (S->Count > 0);
|
||||||
|
S->Stack[S->Count-1].val = Val;
|
||||||
|
S->Stack[S->Count-1].ptr = Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void IPS_Drop (IntPtrStack* S)
|
||||||
|
/* Drop a value from an int stack */
|
||||||
|
{
|
||||||
|
PRECONDITION (S->Count > 0);
|
||||||
|
--S->Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void IPS_Push (IntPtrStack* S, long Val, void *Ptr)
|
||||||
|
/* Push a value onto an int stack */
|
||||||
|
{
|
||||||
|
PRECONDITION (S->Count < sizeof (S->Stack) / sizeof (S->Stack[0]));
|
||||||
|
S->Stack[S->Count].val = Val;
|
||||||
|
S->Stack[S->Count++].ptr = Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void IPS_Pop (IntPtrStack* S, long *Val, void **Ptr)
|
||||||
|
/* Pop a value from an int stack */
|
||||||
|
{
|
||||||
|
PRECONDITION (S->Count > 0);
|
||||||
|
if (Val) *Val = S->Stack[--S->Count].val;
|
||||||
|
if (Ptr) *Ptr = S->Stack[S->Count].ptr;
|
||||||
|
}
|
121
src/common/intptrstack.h
Normal file
121
src/common/intptrstack.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* intptrstack.h */
|
||||||
|
/* */
|
||||||
|
/* Integer+ptr stack used for program settings */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2017, Mega Cat Studios */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef INTPTRSTACK_H
|
||||||
|
#define INTPTRSTACK_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "inline.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct IntPtrStack IntPtrStack;
|
||||||
|
struct IntPtrInner {
|
||||||
|
long val;
|
||||||
|
void *ptr;
|
||||||
|
};
|
||||||
|
struct IntPtrStack {
|
||||||
|
unsigned Count;
|
||||||
|
struct IntPtrInner Stack[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* An initializer for an empty int stack */
|
||||||
|
#define STATIC_INTPTRSTACK_INITIALIZER { 0, { 0, 0 }, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} } }
|
||||||
|
|
||||||
|
/* Declare an int stack with the given value as first element */
|
||||||
|
#define INTPTRSTACK(Val, Ptr) { 1, { {Val, Ptr}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} } }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int IPS_IsFull (const IntPtrStack* S)
|
||||||
|
/* Return true if there is no space left on the given int stack */
|
||||||
|
{
|
||||||
|
return (S->Count >= sizeof (S->Stack) / sizeof (S->Stack[0]));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define IPS_IsFull(S) ((S)->Count >= sizeof ((S)->Stack) / sizeof ((S)->Stack[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int IPS_IsEmpty (const IntPtrStack* S)
|
||||||
|
/* Return true if there are no values on the given int stack */
|
||||||
|
{
|
||||||
|
return (S->Count == 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define IPS_IsEmpty(S) ((S)->Count == 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE unsigned IPS_GetCount (const IntPtrStack* S)
|
||||||
|
/* Return the number of elements on the given int stack */
|
||||||
|
{
|
||||||
|
return S->Count;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define IPS_GetCount(S) (S)->Count
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void IPS_Get (const IntPtrStack* S, long *Val, void **Ptr);
|
||||||
|
/* Get the value on top of an int stack */
|
||||||
|
|
||||||
|
void IPS_Set (IntPtrStack* S, long Val, void *Ptr);
|
||||||
|
/* Set the value on top of an int stack */
|
||||||
|
|
||||||
|
void IPS_Drop (IntPtrStack* S);
|
||||||
|
/* Drop a value from an int stack */
|
||||||
|
|
||||||
|
void IPS_Push (IntPtrStack* S, long Val, void *Ptr);
|
||||||
|
/* Push a value onto an int stack */
|
||||||
|
|
||||||
|
void IPS_Pop (IntPtrStack* S, long *Val, void **Ptr);
|
||||||
|
/* Pop a value from an int stack */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* End of IntPtrStack.h */
|
||||||
|
|
||||||
|
#endif
|
49
test/val/trampoline.c
Normal file
49
test/val/trampoline.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
!!DESCRIPTION!! wrapped-call pragma used for trampolines
|
||||||
|
!!ORIGIN!! cc65 regression tests
|
||||||
|
!!LICENCE!! Public Domain
|
||||||
|
!!AUTHOR!! Lauri Kasanen
|
||||||
|
*/
|
||||||
|
|
||||||
|
static unsigned char flag;
|
||||||
|
|
||||||
|
static void trampoline_set() {
|
||||||
|
asm("ldy tmp4");
|
||||||
|
asm("sty %v", flag);
|
||||||
|
asm("jsr callptr4");
|
||||||
|
}
|
||||||
|
|
||||||
|
void trampoline_inc() {
|
||||||
|
asm("inc %v", flag);
|
||||||
|
asm("jsr callptr4");
|
||||||
|
}
|
||||||
|
|
||||||
|
void func3() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma wrapped-call(push, trampoline_inc, 0)
|
||||||
|
|
||||||
|
void func2() {
|
||||||
|
func3();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma wrapped-call(push, trampoline_set, 4)
|
||||||
|
|
||||||
|
void func1(void);
|
||||||
|
|
||||||
|
#pragma wrapped-call(pop)
|
||||||
|
#pragma wrapped-call(pop)
|
||||||
|
|
||||||
|
void func1() {
|
||||||
|
func2();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
flag = 0;
|
||||||
|
|
||||||
|
func1();
|
||||||
|
|
||||||
|
return flag == 5 ? 0 : 1;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user