|
求助,关于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[100];
y=1000;
while (1)
{
a[98] = 1234;
a[97] = 4321;
a[96] = a[97] + a[98];
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[100];
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, [pc, #3c] ; 1001514 <Task2+0x64>
10014d4: e3a03ffa mov r3, #1000 ; 0x3e8
10014d8: e59f8038 ldr r8, [pc, #38] ; 1001518 <Task2+0x68>
10014dc: e1a06002 mov r6, r2
10014e0: e24dde19 sub sp, sp, #400 ; 0x190
10014e4: e5823000 str r3, [r2]
{
a[98] = 1234;
10014e8: e50b5028 str r5, [r11, -#40]
a[97] = 4321;
10014ec: e50b402c str r4, [r11, -#44]
a[96] = a[97] + a[98];
10014f0: e50b7030 str r7, [r11, -#48]
y --;
which = 1;
10014f4: e3a03001 mov r3, #1 ; 0x1
10014f8: e5962000 ldr r2, [r6]
Sleep(6);
10014fc: e3a00006 mov r0, #6 ; 0x6
1001500: e5883000 str r3, [r8]
1001504: e2422001 sub r2, r2, #1 ; 0x1
1001508: e5862000 str r2, [r6]
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的时候就要切换工作模式,
比较耗时间。 |
|