|
|||||||||||||
Technical Support On-Line Manuals Cx51 User's Guide ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Reentrant FunctionsA reentrant function may be shared by several processes at the same time. When a reentrant function is executing, another process can interrupt the execution and then begin to execute that same reentrant function. Normally, functions in Cx51 cannot be called recursively or in a fashion which causes reentrancy. The reason for this limitation is that function arguments and local variables are stored in fixed memory locations. Recursive calls to the function use the same memory locations. And, in this case, arguments and locals would get corrupted. The reentrant function attribute allows you to declare functions that may be reentrant and, therefore, may be called recursively. For example: 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 upon the memory model used, as follows:
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. Refer to Specifying the Memory Model for a Function for more information about memory models and function declarations. The following rules apply to functions declared with the reentrant attribute.
The reentrant stack simulation architecture is inefficient, but necessary due to a lack of suitable addressing methods available on the 8051. For this reason, use reentrant functions 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 STARTUP.A51 file. The following table details the stack pointer assembler variable name, data area, and size for each of the three memory models.
The simulated stack area for reentrant functions is organized from top to bottom—it stacks down. The 8051 hardware stack is just the opposite and is organized bottom to top—it stacks up. When using the SMALL memory model, both the simulated stack and the 8051 hardware stack share the same memory area but grow towards each other. The simulated stack and stack pointers are declared and initialized in the Cx51 Compiler startup code in STARTUP.A51 which can be found in the 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 STARTUP.A51 for more information on reentrant function stack areas. When calling a function with a reentrant stack, the compiler MUST know that the function has a reentrant stack. The compiler figures this out from the function prototype which should include the reentrant keyword (just like the function definition). The compiler must also know the memory model used by the function (to determine which reentrant stack to stuff arguments on). This is determined either from the memory model specified for the function, or the memory model specified to the compiler, or from the default memory model (small). To pass arguments, the compiler generates code that decrements the stack pointer and then "pushes" arguments onto the stack by storing the argument indirectly through R0/R1 or DPTR. When a reentrant function is called, it decreases the stack pointer (for local variables) and accesses arguments using the stack pointer plus an offset (which corresponds to the number of bytes of local variables). When a reentrant function returns, it adjusts the stack pointer to the value before arguments were pushed. So the caller does not need to perform any stack adjustment after calling a reentrant function. | ||||||||||||
|
Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.