实现协程多任务的无标号单步跳转方法(8051)
0赞
实现协程多任务的无标号单步跳转方法(8051)
-- 微控制器中基于协程的实时协作多任务方法 (4)
目前为止,没有一种8051的C编译器支持Protothreads的addrlabels方法。所以,我们同样要创造一种高效的协程重入方法,来代替目标代码效率较低的switch-case方法。
下面,要说明用C和汇编混合编程的“无标号单步跳转方法”如何在8051中实现。
基本要点已在“实现协程多任务的无标号单步跳转方法[-- 微控制器中基于协程的实时协作多任务方法 (3)]”中说明。
下面是有关8051指令部分。
C语句如前:
EXTERN void SUBROUTINE(void) ;
…
SUBROUTINE() ;
//<- LC is here (后续点LC就在这里)
DoSomething …
汇编语句:
_ SUBROUTINE:
; LC的地址在堆栈中
; (LC_LOW)
; (LC_HIGH) <-SP
POP lc_highbyte ; LC_HIGH
POP lc_lowbyte ; LC_LOW
…
程序代码部分见附件: 用C和汇编混合编程实现协程多任务方法(8051).pdf。
与在ARM Cortex-M用C和汇编混合编程相比,有一点小区别:
1. 在ARM混合编程时,我们将有关cr的参数传递给汇编函数,这是由于三种编译器传递参数的方法一致(使用同一寄存器)。而8051混合编程时,不传递参数给汇编函数。因为8051的几种编译器传递参数的方法各异。为了汇编函数一致起见,我们不使用寄存器传递参数,而使用特定变量传递参数。
2. 在ARM混合编程时,我们多使用uint32_t(32位)类型变量,而8051混合编程时,我们常使用unsigned char(8位)类型变量。因为对32位MCU,使用uint32_t(32位)类型变量,目标代码的效率最高。而对32位MCU,使用unsigned char(8位)类型变量,目标代码的效率最高。
3. 本方法唯独不能在SDCC(8051)编译器中使用。在C语言调用汇编函数时,不管汇编函数是否使用某几个寄存器,SDCC编译器都对这几个寄存器做了压入堆栈和出栈处理,汇编函数被一组PUSH-POP所包围,致使本法无法施展。
例如:
C语句:
…
way_out();
…
汇编结果:
push rb0r7
push rb0r6
push rb0r5
lcall way_out
;<- 这里本是给yield出去的出路,但退路被三个POP挡了!
pop rb0r5
pop rb0r6
pop rb0r7
在way_out里面,根本不使用寄存器r5、r6、r7,三个PUSH-POP是多余的。估计C编译器不知道汇编函数里面的把戏,为保险起见,加了三个PUSH-POP。编译器加强一点优化,估计就不会出现多余的PUSH-POP了。
===
fy_zhu
2013-02-22 SV_CA