最近学习ucos的移植代码。看到开关中断处。有点问题
首先ucos支持三种开关中断方式
下面是pc移植的代码(ucos官方)
#define OS_CRITICAL_METHOD 2
#if OS_CRITICAL_METHOD == 1
#define OS_ENTER_CRITICAL() asm CLI /* Disable interrupts */
#define OS_EXIT_CRITICAL() asm STI /* Enable interrupts */
#endif
#if OS_CRITICAL_METHOD == 2
#define OS_ENTER_CRITICAL() asm {PUSHF; CLI} /* Disable interrupts */
#define OS_EXIT_CRITICAL() asm POPF /* Enable interrupts */
#endif
#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR()) /* Disable interrupts */
#define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr)) /* Enable interrupts */
第一种方式最简单,就不再说了。
问题是后面两种方式,这两种方式都是为了解决如下情况,逻辑一样,只是一个存到栈,一个存到变量cpu_sr中了
1.OS_ENTER_CRITICAL()
2.。。。。。。。。。。。代码
3. OS_ENTER_CRITICAL()
4. 。。。。。。。。用户代码
5. OS_EXIT_CRITICAL()
6.。。。。。。。。。。代码
7.OS_EXIT_CRITICAL()
如果这种情况用 第一种方式不能保证 1-7行中断都是关着的,因为第5行调用了开中断指令
所以用后两种方式就很好的解决了这个问题
!!!!!!!
这才有我的问题。问题处在(比如第二种方式)
#if OS_CRITICAL_METHOD == 2
#define OS_ENTER_CRITICAL() asm {PUSHF; CLI} /* Disable interrupts */
#define OS_EXIT_CRITICAL() asm POPF /* Enable interrupts */
这样的话 pushf实现了保存状态标志,在退出 关中断的时候popf出栈恢复 标志寄存器内容
但是pushf不仅会将中断允许标志压入栈,同时会将其他标志,比如ZF。OF压入。那么问题就来了。调用popf恢复的中断状态标志就变成了代码第 3行执行处的标志状态了。。。。。。。。。
里面的ZF OF等标志也会恢复到了第三行的状态,正常的话那么第6行以后的代码执行应该用第5行执行后的状态标志,但是因为pushf popf的调用,那么ZF OF等的标志只是第三行的标志态。。。。岂不是执行程序就不对了
想了很久,很纠结,希望高手指教
QQ:1183557534,有知道的请回帖或联系我
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
不知道 是不是我哪里理解的不对。楼上能点拨一下小弟吗
还有
“用汇编写程序时要注意这些,用C编程时就可以不用担心ZF OF标志了。”用c为啥不用担心呢。。。。。
cpu不就是有一个状态寄存器而已嘛???
void OSStatInit (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
OSTimeDly(2); /* Synchronize with clock tick */
OS_ENTER_CRITICAL();
OSIdleCtr = 0L; /* Clear idle counter */
OS_EXIT_CRITICAL();
OSTimeDly(OS_TICKS_PER_SEC / 10); /* Determine MAX. idle counter value for 1/10 second */
OS_ENTER_CRITICAL();
OSIdleCtrMax = OSIdleCtr; /* Store maximum idle counter count in 1/10 second */
OSStatRdy = OS_TRUE;
OS_EXIT_CRITICAL();
}
OSIdleCtr = 0L;语句功能对于后面的语句OSTimeDly(OS_TICKS_PER_SEC / 10); 功能是独立的,OSTimeDly(OS_TICKS_PER_SEC / 10);并不会用到由于OSIdleCtr = 0L;语句的执行导致的状态标志位变化。
2、比如说一段简单的代码:
int i = 1;
int j = 1;
if(i == 1)
{
j = 2;
}
else
{
j = 3;
}
用汇编编写大概是:
0x08000176 2401 MOVS r4,#0x01
0x08000178 2501 MOVS r5,#0x01
0x0800017A 2C01 CMP r4,#0x01
0x0800017C D101 BNE 0x08000182
0x0800017E 2502 MOVS r5,#0x02
0x08000180 E000 B 0x08000184
0x08000182 2503 MOVS r5,#0x03
其中
0x0800017A 2C01 CMP r4,#0x01
0x0800017C D101 BNE 0x08000182
这两条语句用到了状态标志位。那么有没有可能在0x0800017A 2C01 CMP r4,#0x01语句之前插入一条OS_ENTER_CRITICAL();,而在0x0800017A 2C01 CMP r4,#0x01语句之后插入OS_EXIT_CRITICAL();语句。用汇编可以做到,虽然这样写是错误的,不合逻辑的。但用c语言写的代码中,没有办法做到,因为0x0800017A 2C01 CMP r4,#0x01
0x0800017C D101 BNE 0x08000182
这两条语句在c程序中就一条if(i==1)。所以c语言在一定程度上可以避免这种问题的发生。
一周热门 更多>