reentrant声明的函数为可重入函数。可重入的函数能够被多个进程同时调用。可重入函数在执行时,另外的进程可以中断当前执行的函数,并且调用同一个函数。正常情况下,C51程序中的函数不能被递归地调用,这是由于函数的参数和局部变量都被保存在固定的地址,在递归调用时操作了相同存储位置,导致数据被覆盖。
使用reentrant声明函数为可递归调用的可重入函数:
int calc (char i, int b) reentrant {
int x;
x = table [i];
return (x * b);
}
可重入函数,能够被递归调用,也能被两个以上的进程同时调用。可重入函数通常在实时应用或者中断与非中断程序共享相同函数这两种情况下被使用。
每个可重入函数都有一个位于内部ram或外部ram的模拟堆栈:
1)SMALL内存模型下,可重入函数模拟堆栈位于idata区;
2)COMPACT内存模型下,可重入函数模拟堆栈位于pdata区;
3)LARGE内存模型下,可重入函数模拟堆栈位于xdata区;
使用reentrant声明可重入函数须遵循的规则:
1)可重入函数不支持位寻址变量,比如bit类型的参数;
2)可重入函数不能被alien函数调用;
3)可重入函数不能被声明为alien属性(alien用于使能PL/M-51参数传递约定);
4)可重入函数可以同时拥有其他属性,比如using、interrupt、small、compact、large;
5)返回地址被保存在硬件堆栈中;
6)使用不同存储模型的可重入函数能够混合,但是各自函数声明时必须指定存储模型;
7)三种内存模型的可重入函数都有自己的对战区和栈指针。比如在相同模块中,定义了small和large类型的可重入函数,则small和large类型的堆栈及其堆栈指针都被创建;
可重入堆栈模拟体系,效率比较低下,但是由于8051自身缺乏适当寻址方法的硬件特性,所以推出这种堆栈模拟体系来满足我们的可重入需求,在应用中 ,我们应该尽量不用或少用可冲入函数。
可重入函数使用的模拟堆栈拥有独立于8051硬件堆栈的栈指针。堆栈和堆栈指针在STARTUP.A51文件中被定义和初始化。
下表列出了三种内存模型下的模拟堆栈指针名称、大小、数据区域:
内存模型 | 指针 | 堆栈信息 |
---|---|---|
SMALL | ?C_IBP (1 字节) | 堆栈位于间接寻址的内部ram(idata). 最大可重入堆栈容量256字节. 访问该模拟堆栈,须要使用 R0 或 R1装载?C_IBP 的值,然后使用 MOV A, @R0/@R1 或 MOV @R0/@R1, A 指令。 |
COMPACT | ?C_PBP (1 字节) | 堆栈位于可页寻址的外部ram。 最大容量256 字节。 访问该模拟堆栈,须要使用 R0 或 R1装载?C_PBP 的值,然后使用MOVX A, @R0/@R1 或 MOVX @R0/@R1, A 指令。 |
LARGE | ?C_XBP (2 字节) | 堆栈位于外部ram。 T最大堆栈容量64KB。 访问该模拟堆栈,须要使用DPTR 装载?C_XBP 的值,然后使用MOVX A, @DPTR 或 MOVX @DPTR, A 指令。 |
STARTUP.A51启动代码声明并初始化了模拟堆栈及其堆栈指针,如果使用可重入函数就必须修改启动代码指出哪个模拟堆栈须要初始化。可以在启动代码中修改模拟堆栈的起始地址。
可重入函数的参数传递,通过模拟堆栈的压栈、出栈完成。
可重入函数的局部变量,也保存在模拟堆栈中,通过模拟堆栈指针访问。
转自:http://blog.csdn.net/armtravel/article/details/17079501