问题和回答 ",关于skyeye 下的 ucOSII 移植
求助,关于skyeye 下的 ucOSII 移植我下载了skyeye下的ucOSII,移植到TI 的ARM7上,可是对于OS_ENTER_CRITICAL() 和 OS_EXIT_CRITICAL()的实现却有一点疑问。
这两个宏实现在skyeye中如下:
_ARMDisableInt:
MRS r0, cpsr
STMFD sp!, {r0} ; push current PSR
ORR r0, r0, #0x80
MSR cpsr, r0 ; disable IRQ Int s
MOV pc, lr
_ARMEnableInt:
LDMFD sp!, {r0} ; pop current PSR
MSR cpsr_c, r0 ; restore original cpsr
MSR cpsr, r0 ; restore original cpsr
MOV pc, lr
基本上是这样的,OS_ENTER_CRITICAL ( disable IRQ) 将CPSR
入栈,SP --; OS_EXIT_CRITICAL ( enable IRQ) 将 CPSR
弹出栈,SP ++;可是在这两个中间,如果有用到局部变量,而C中
的局部变量多半是以SP为base索引的,就会出问题。
或者是我什么地方错了? 请多多指教 。。
---------------------------------------------------------------------------
liming's answer
hi, 你好!
首先,这确实是个好问题,当时我也没有考虑到,现在提出来了,
虽然写论文很忙,但还是仔细想了一下。
我查看了一下源码,并且对比了 ADS 的 armcc 和 GNU 的
arm-elf-gcc 编译后的汇编代码,发现所有用到局部变量的地方都不是
使用 sp 来标识的,而大多是用的 r1,r2 之类的通用寄存器,没有
用 sp+offset 来定位,所以没有影响局部变量的值。
但这种做法,在局部变量很少的情况下是可以的,但是如果很多呢?
我也比较疑惑,于是我做了个实验如下,:
这里我开了一个局部数组,看编译器怎么办?
void Task2(void * pParam)
{
int a;
y=1000;
while (1)
{
a = 1234;
a = 4321;
a = a + a;
y --;
which = 1;
Sleep(6);
}
}
下面的是编译后得到的汇编码,可以着重看我红色标出来的部分 ——
010014b0 <Task2>:
10014b0: e1a0c00d mov r12, sp
10014b4: e92dd9f0 stmdb sp!, {r4, r5, r6, r7, r8, r11, r12, lr, pc}
10014b8: e24cb004 sub r11, r12, #4 ; 0x4
void Task2(void * pParam)
{
int a;
y=1000;
while (1)
10014bc: e3a05e4d mov r5, #1232 ; 0x4d0
10014c0: e2855002 add r5, r5, #2 ; 0x2
10014c4: e3a04d43 mov r4, #4288 ; 0x10c0
10014c8: e2844021 add r4, r4, #33 ; 0x21
10014cc: e0847005 add r7, r4, r5
10014d0: e59f203c ldr r2, ; 1001514 <Task2+0x64>
10014d4: e3a03ffa mov r3, #1000 ; 0x3e8
10014d8: e59f8038 ldr r8, ; 1001518 <Task2+0x68>
10014dc: e1a06002 mov r6, r2
10014e0: e24dde19 sub sp, sp, #400 ; 0x190
10014e4: e5823000 str r3,
{
a = 1234;
10014e8: e50b5028 str r5,
a = 4321;
10014ec: e50b402c str r4,
a = a + a;
10014f0: e50b7030 str r7,
y --;
which = 1;
10014f4: e3a03001 mov r3, #1; 0x1
10014f8: e5962000 ldr r2,
Sleep(6);
10014fc: e3a00006 mov r0, #6; 0x6
1001500: e5883000 str r3,
1001504: e2422001 sub r2, r2, #1 ; 0x1
1001508: e5862000 str r2,
100150c: eb000003 bl 1001520 <Sleep>
}
1001510: eafffff4 b 10014e8 <Task2+0x38>
1001514: 01006060 tsteq r0, r0, rrx
1001518: 01006064 tsteq r0, r4, rrx
}
100151c: e91ba9f0 ldmdb r11, {r4, r5, r6, r7, r8, r11, sp, pc}
相信你已经知道为什么没有影响局部变量的值了。
---------------------------------------------------------------
richard hoo的回复:
多谢,回复很快:-)
看来ADS是先保存了SP的值到寄存器中,然后一直用这个寄存器
来做基值寻址。
我目前在TI DSC25上做开发,用的是TI 的CCS,我仔细看了
汇编和反汇编的代码,它都是直接用SP来寻址的,所以这样写
就有问题。
目前我考虑有两个办法,一个是强行disable IRQ/enable IRQ,
不保存当前的CPSR值; 另外一个办法就是用另外的一个不用的
STACK SP,比如ABT exception 一直不用,用它来push/pop.
不过这样每次disable/enables的时候就要切换工作模式,
比较耗时间。 我正在看ucos2,邵贝贝翻译的2001版本
觉得ucos是基于x86讲的,先看懂x86,再移植到其他系统上
各位大侠:
1,是不是要全部仔细从前往后看,能不能跳着看一些,先上手啊?
2,我要往DSP或者ARM上移植的话,学习哪些内容会比较快一些呢?
3,请搞这个的大侠写点东西吧,让我们快速入门啊,呵呵
也可email联系我,谢谢!! ucosii的书中是基于x86讲的.
不过没有关系.
1 可以跳着看,特别是与具体硬件无关的ucosi部分
2 ARM相关的硬件知识需要有.
3 基于ARM的书籍很多,你可以参考一下.
然后看看与基于skyeye仿真的at91开发板有关的相关文档(可到166.111.68.183/pub/embed 处下载),再用skyeye运行调试一下ucosii 就会有比较快的感受.
页:
[1]