|
本帖最后由 Andrewz 于 2015-2-2 00:17 编辑
最近打算将ucos-ii移植到atmega128A.用的WINAVR编译器.在坛子里也看了一些资料.
现在对其CPU通用寄存器GPRs有一些疑惑.希望有大侠相助.
引用《建立一个属于自己的AVR的RTOS》一文中
"
在Win AVR中的帮助文件 avr-libc Manual中的Related Pages中的Frequently Asked Questions,其实有一个问题是"What registers are used by the C compiler?" 回答了编译器所需要占用的寄存器。一般情况下,编译器会先用到以下寄存器
1 Call-used registers (r18-r27, r30-r31): 调用函数时作为参数传递,也就是用得最多的寄存器。
2 Call-saved registers (r2-r17, r28-r29): 调用函数时作为结果传递,当中的r28和r29可能会被作为指向堆栈上的变量的指针。
3 Fixed registers (r0, r1): 固定作用。r0用于存放临时数据,r1用于存放0。
”
找了下原文:
Call-used registers (r18-r27, r30-r31):
May be allocated by gcc for local data. You may use them freely in assembler subroutines. Calling C subroutines can clobber any of them - the caller is responsible for saving and restoring.
Call-saved registers (r2-r17, r28-r29):
May be allocated by gcc for local data. Calling C subroutines leaves them unchanged. Assembler subroutines are responsible for saving and restoring these registers, if changed. r29:r28 (Y pointer) is used as a frame pointer (points to local data on stack) if necessary. The requirement for the callee to save/preserve the contents of these registers even applies in situations where the compiler assigns them for argument passing.
这里没弄明白.
试着分析一下:
比如我写了一个主函数,这个主函数正常运行着.那么,其r0-r31可能都存了数据.
SREG则存了总状态.
那么此时,
来了一个子函数,产生了一个call,在这个call的过程中,Call-used registers数据会丢失.
所以在call之前要存Call-used registers到堆栈. <- 从上面的英文来看,在跳转前Call-used registers全部保存.
而此刻的Call-saved registers,在call的时候不会变,所以call完了再存也没关系.
如果能保证其值不变,甚至不存,也没关系.显然,这个保证暂时无法给出. <- 从上面的英文看,Call-saved registers可在子函数里存.
入栈GPRs再出栈GPRs,这样主函数就可以像什么事情都没发生一样继续运行.
这个过程对于用C写程序的人来说,就好像没有发生过一样,编译器做好了.
猜想编译器可以优化上面两种寄存器的出入栈.将无关GPRs优化掉.
对于需要做任务切换的函数,不能用return,return只能退到调用之前的任务.
此时要根据得到的最高优先级就绪编号找到最高优先级就绪任务,并且恢复其所有GPRs,且跳转到其中.
此时,就要抛开编译器,手动上汇编了.
问题来了.
在切换任务的那一刻:
在将SP的任务函数地址赋给PC前,肯定需要将上一个任务的GPRs保管好.即需要PUSHALL
由于已经PUSHALL了,此时32个GPRs可以随便用了.
在切换到下一个任务前,需要将下一个任务的GPRs全部释放出来.
而释放GPRs的前提条件是SP正确,所以,首先得到需要切换到的任务的SP,然后POPALL,这样,就完全恢复了GPRs.
最后一步,RET.此时是返回,不是call,因此不会使得GPRs有改变.完全切换到下一个任务.
以上是本人想法,没有验证过.但是坛子里找到的WINAVR + ucos的例子基本可以这样解读.
编辑之前,我以为切换到下一个任务需要call,而call会破坏Call-used regiters, so 百思不得qi解.
这样一算,总共32个寄存器,加SREG.切一次几百的周期就过去了.125ns*200. 几十个微秒用来切任务,每秒钟切200下,每秒要几毫秒,应该问题不大.
so, 我的问题...
求大侠指导.
|
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|