mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 04:30:10 +00:00
commit
11b01b908d
@ -1229,6 +1229,30 @@ parameter with the <tt/#pragma/.
|
||||
</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>
|
||||
|
||||
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 "standard.h"
|
||||
#include "symtab.h"
|
||||
#include "wrappedcall.h"
|
||||
#include "typeconv.h"
|
||||
|
||||
|
||||
@ -1315,6 +1316,8 @@ static FuncDesc* ParseFuncDecl (void)
|
||||
{
|
||||
unsigned Offs;
|
||||
SymEntry* Sym;
|
||||
SymEntry* WrappedCall;
|
||||
unsigned char WrappedCallData;
|
||||
|
||||
/* 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 WrappedCall for this function? */
|
||||
GetWrappedCall((void **) &WrappedCall, &WrappedCallData);
|
||||
if (WrappedCall) {
|
||||
F->WrappedCall = WrappedCall;
|
||||
F->WrappedCallData = WrappedCallData;
|
||||
}
|
||||
|
||||
/* 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 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 */
|
||||
NeedTypeSpace (D, 1);
|
||||
D->Type[D->Index].C = T_FUNC | Qualifiers;
|
||||
|
@ -536,6 +536,10 @@ static void FunctionCall (ExprDesc* Expr)
|
||||
/* Special handling for function pointers */
|
||||
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
|
||||
** 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->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->ParamSize = 0;
|
||||
F->LastParam = 0;
|
||||
F->WrappedCall = 0;
|
||||
F->WrappedCallData = 0;
|
||||
|
||||
/* Return the new struct */
|
||||
return F;
|
||||
|
@ -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* WrappedCall; /* Pointer to the WrappedCall */
|
||||
unsigned char WrappedCallData;/* The WrappedCall's user data */
|
||||
};
|
||||
|
||||
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "scanstrbuf.h"
|
||||
#include "symtab.h"
|
||||
#include "pragma.h"
|
||||
#include "wrappedcall.h"
|
||||
|
||||
|
||||
|
||||
@ -88,6 +89,7 @@ typedef enum {
|
||||
PRAGMA_STATIC_LOCALS,
|
||||
PRAGMA_STATICLOCALS, /* obsolete */
|
||||
PRAGMA_WARN,
|
||||
PRAGMA_WRAPPED_CALL,
|
||||
PRAGMA_WRITABLE_STRINGS,
|
||||
PRAGMA_ZPSYM,
|
||||
PRAGMA_COUNT
|
||||
@ -123,6 +125,7 @@ static const struct Pragma {
|
||||
{ "static-locals", PRAGMA_STATIC_LOCALS },
|
||||
{ "staticlocals", PRAGMA_STATICLOCALS }, /* obsolete */
|
||||
{ "warn", PRAGMA_WARN },
|
||||
{ "wrapped-call", PRAGMA_WRAPPED_CALL },
|
||||
{ "writable-strings", PRAGMA_WRITABLE_STRINGS },
|
||||
{ "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)
|
||||
/* Change the character map */
|
||||
@ -791,6 +872,10 @@ static void ParsePragma (void)
|
||||
FlagPragma (&B, &StaticLocals);
|
||||
break;
|
||||
|
||||
case PRAGMA_WRAPPED_CALL:
|
||||
WrappedCallPragma(&B);
|
||||
break;
|
||||
|
||||
case PRAGMA_WARN:
|
||||
WarnPragma (&B);
|
||||
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…
Reference in New Issue
Block a user