<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://community.arm.com/utility/feedstylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>How does compiler C51 realize the key word reentrant?</title><link>https://community.arm.com/developer/tools-software/tools/f/keil-forum/15591/how-does-compiler-c51-realize-the-key-word-reentrant</link><description> In the following example,the chip is Dallas390 and the off-chip xdata starts from x:0x20000.Large model and large reentrant function stack is selected. 
The C language source: 
 
unsigned char func1(unsigned char)reentrant;

void main()
{
	unsigned char</description><dc:language>en-US</dc:language><generator>Telligent Community 10</generator><item><title>RE: How does compiler C51 realize the key word reentrant?</title><link>https://community.arm.com/thread/39930?ContentTypeID=1</link><pubDate>Tue, 11 Mar 2003 11:51:02 GMT</pubDate><guid isPermaLink="false">dd9e70c8-6d3c-4c71-b136-2456382a7b5c:9be9df63-6076-4e94-b716-3cc5508c5728</guid><dc:creator>Drew Davis</dc:creator><description>&lt;p&gt;&lt;br /&gt;
A C compiler for a typical architecture will push parameters and local values onto a stack.  This implementation makes a function naturally reentrant (as long as it isn&amp;#39;t deliberately accessing globals and producing untoward side effects).  If you call the routine again, another set of parameters and locals goes onto the stack, so the two calls do not interfere with each other.&lt;br /&gt;
&lt;br /&gt;
The hardware stack pointer in the 8051 can only address internal RAM.  Usually, you have a stack of 128 bytes or less.  This is not a lot of room for the usual stack manipulation.  So you might look for another answer.&lt;br /&gt;
&lt;br /&gt;
By default, the Keil compiler does a lot of compile- (and link-) time analysis to determine the usage patterns of those parameters and locals based on the call tree in the program.  You can optimize the amount of space that would be the stack in this manner, and generate code that directly references memory instead of addressing indirectly via the stack.  The code is smaller and faster -- but routines will no longer be naturally reentrant.  Each call to a routine will use the same memory locations for its parameters and locals, so a second call will trash the data from the first, whether that second call is recursive or from another context (task or interrupt).&lt;br /&gt;
&lt;br /&gt;
Sometimes, of course, the restrictions imposed by this optimization get in the way, and you want a routine that really is reentrant.  When you declare a routine reentrant, the Keil compiler generates code pretty much as you&amp;#39;d expect of a typical compiler.  It pushes excess parameters and locals onto a stack, just like any other compiler.&lt;br /&gt;
&lt;br /&gt;
Since the 8051 doesn&amp;#39;t have hardware support for a stack to speak of -- no spare 16-bit registers with auto-increment and decrement instructions and that sort of thing -- the compiler uses what Keil likes to call a &amp;quot;simulated&amp;quot; stack.  The compiler quite simply declares a 16-bit variable, and uses that as a stack pointer into a region of memory determined by your memory model (xdata for the large model).  There&amp;#39;s no hardware register designated as a stack pointer, but there&amp;#39;s no reason the compiler writers can&amp;#39;t make up their &amp;quot;register&amp;quot; and get the same effect.  It takes more code than on most processors, but that&amp;#39;s the 8051 for you.&lt;br /&gt;
&lt;br /&gt;
You set up the stack space in your STARTUP.A51 file.  See the second section, right after the power-on initialization of memory configuration.&lt;br /&gt;
&lt;br /&gt;
So, in the first couple of lines in your function (the &amp;quot;prologue&amp;quot;), you see the compiler pushing onto this stack.  Load up -1 (0FFFFH) in the DPTR, call ADDXBP, which looks like it adds DPTR to the stack pointer, then move R7 (via A) to the new address.  From the code, it looks like the stack pointer happens to be linked at memory locations 8/9; check your map file for the symbol ?C_XBP if you&amp;#39;re curious.  Those four lines of code implement &amp;quot;push R7&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You then see the implemention of func1().  It returns its value in R7, so it loads up DPTR with the stack pointer, and moves R7 (via A) from the stack.&lt;br /&gt;
&lt;br /&gt;
The end of the routine (the &amp;quot;epilogue&amp;quot;) reverses the initial behavior.  Load up DPTR with the stack pointer, load R7 (via A) from the stack, and add 1 to the stack pointer.  That&amp;#39;s &amp;quot;pop&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>