int calc (char i, int b) reentrant
{
int x;
x = table [i];
return (x * b);
}
Reentrant functions can be called recursively and can be called simultaneously by two or more processes. Reentrant functions are often required in real-time applications or in situations where interrupt code and non-interrupt code must share a function.
As in the above example, you may selectively define (using the reentrant attribute) functions as being reentrant. For each reentrant function, a reentrant stack area is simulated in internal or external memory depending on the memory model as follows:
Small Model reentrant functions simulate the reentrant stack in idata memory.
Compact Model reentrant functions simulate the reentrant stack in pdata memory.
Large Model reentrant function simulate the reentrant stack in xdata memory.
Reentrant functions use the default memory model to determine which memory space to use for the reentrant stack. You may specify (with the small, compact, and large function attributes) which memory model to use for a function. See the section entitled Specifying the Memory Model for a Function for more information about memory models and function declarations.
Reentrant functions must not be called from alien functions.
Reentrant function cannot use the alien attribute specifier to enable PL/M-51 argument passing conventions.
A reentrant function may simultaneously have other attributes like using and interrupt and may include an explicit memory model attribute (small, compact, large).
Return addresses are stored in the 8051 hardware stack. Any other required PUSH and POP operations also affect the 8051 hardware stack.
Reentrant functions using different memory models may be intermixed. However, each reentrant function must be properly prototyped and must include its memory model attribute in the prototype. This is necessary for calling routines to place the function arguments in the proper reentrant stack.
Each of the three possible reentrant models contains its own reentrant stack area and stack pointer. For example, if small and large reentrant functions are declared in a module, both small and large reentrant stacks are created along with two associated stack pointers (one for small and one for large).
The reentrant stack simulation architecture is inefficient, but necessary due to a lack of suitable addressing methods available on the 8051. For this reason, reentrant functions should be used sparingly.
The simulated stack used by reentrant functions has its own stack pointer which is independent of the 8051 stack and stack pointer. The stack and stack pointer are defined and initialized in the file STARTUP.A51. The following table details the stack pointer assembler variable name, data area, and size for each of the three memory models.
Model |
Stack Pointer |
Stack Area |
SMALL |
?C_IBP (1 Byte) |
Indirectly accessible internal memory (idata). 256 bytes max. stack area. |
COMPACT |
?C_PBP (1 Byte) |
Page-addressable external memory (pdata). 256 bytes max. stack area. |
LARGE |
?C_XBP (2 Bytes) |
Externally accessible memory (xdata). 64 KBytes max. stack area. |
The simulated stack area for reentrant functions is organized from top to bottom. The 8051 hardware stack is implemented just the opposite and is organized bottom to top. When using the SMALL memory model, both the simulated stack and the 8051 hardware stack share the same memory area but from opposite directions.
The simulated stack and stack pointers are declared and initialized in the C51 startup code in STARTUP.A51 which can be found in the \FSI\LIB subdirectory. You must modify the startup code to specify which simulated stack(s) to initialize in order to use reentrant functions. You can also modify the starting address for the top of the simulated stack(s) in the startup code. Refer to the section entitled STARTUP.A51 in the Customization Files chapter for more information on reentrant function stack areas.