大家好,这是我第一次提问,如果有做的不好的地方,还请原谅。
我最近在做HiFive Rev B上移植uCOSII的移植,在信号量的移植上,在函数OSSemPend中,我发现了一个BUG,会导致函数调用的时候,会不保存ra,从而覆盖了原本返回的ra。
Preformatted text
在一个函数的调用的时候,必须要内嵌汇编,才能恢复原来的ra。
在执行OS_EventTaskWait函数的时候,sp没有变化,然后ra变成了另一个返回地址,然后OS_EventTaskWait执行完之后,顺利返回了,但是ra就没有变化。从而造成了BUG,我相信这不是我的编写代码的问题,因为这部分代码是不需要移植的。
事实上,不仅仅是这个函数,我在做延时函数的时候后,我也发现了同样的问题。所以我做了一个实验,发现了在函数调用的时候SP的变化,我发现是有一种优化策略的,如果函数里没有调用函数(编译器判断的),那么SP不变化。我猜想是不是这个编译器的优化策略有关系。
事实上,OSSemPend中很多地方出现了BUG
void OSSemPend(OS_EVENT *pevent, unsigned int timeout, unsigned char *err) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr; #endif //中断不能等待获得 时间过长 //sp????? if (OSIntNesting > 0) { /* See if called from ISR ... */ *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ __asm__ __volatile__("ret\n\t"); // return; } OS_ENTER_CRITICAL(); //信号量大于0 也就是可以直接跑,条件满足。 if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */ //减一 //???????????????? sp __asm__ __volatile__("addi sp,sp,16"); pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; __asm__ __volatile__ ("ret\n\t"); //return; } /* ????????????????????????????????????????? sp */ __asm__ __volatile__("addi sp,sp,16"); /* Otherwise, must wait until event occurs */ //没有信号量要等待了。 //任务的状态设置 OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ //延时 时间 OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ //等待列表记录 __asm__ __volatile__("sw ra,0(sp)\n\t" "addi sp,sp,-4\n\t"); OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ __asm__ __volatile__("addi sp,sp,4\n\t" "lw ra,0(sp)\n\t"); OS_EXIT_CRITICAL(); //任务调度 刚才那个在等OS_EventTaskWait __asm__ __volatile__("sw ra,0(sp)\n\t" "addi sp,sp,-4\n\t"); OS_Sched(); __asm__ __volatile__("addi sp,sp,4\n\t" "lw ra,0(sp)\n\t"); //等别的任务释放信号量 //从而可以回来运行。 //怎么回来这里? /* Find next highest priority task ready */ OS_ENTER_CRITICAL(); //超时 OS_STAT_SEM还存在 时钟节拍那个地方,超时 回来的 //和OSMboxPend不同不用拿到消息指针。 if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { /* Must have timed out if still waiting for event*/ //OS_EventTO工作简单了,因为tick帮他做了 恢复就绪 __asm__ __volatile__("sw ra,0(sp)\n\t" "addi sp,sp,-4\n\t"); OS_EventTO(pevent); __asm__ __volatile__("addi sp,sp,4\n\t" "lw ra,0(sp)\n\t"); OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* Indicate that didn't get event within TO */ __asm__ __volatile__("ret\n\t"); return; //must } //正常获得 OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; // return ; __asm__ __volatile__("ret\n\t"); }
以上是我经过调试,最终能正常运行的修改版本,有很多内嵌代码,但是为什么需要这些代码我弄不明白,我怀疑是编译器的问题。所以希望可以得到大家的帮忙。
第二个向大家帮忙的是,我想知道Vscode中PlatFormIO如何构建工程,由于编译器需要链接.o文件,但是我不会编写Makefile或者说vscode的工程构建·过程,所以我现在都是把OS_CFG.h、uCOSii.h、OS_TASK.h、OS_TIMER.h、OS_SEM.h等文件融合在了INCLUDES.H文件中。所以希望得到大家帮助,我想像keil5那样 可以分开文件构建工程。
我英文不太好,所以英文版的文字都是我利用百度翻译翻译过来的。
Hello everyone, this is my first time to ask questions. If there is something wrong, please forgive me.
Recently, I have been migrating uCOSII on hifive Rev B. in the semaphore migration, I found a bug in the function OSSemPend, which will cause RA not to be saved when the function is called, thus overwriting the original returned RA.
When a function is called, the assembly must be embedded to restore the original RA.
Executing OS_EventTaskWait function, SP does not change, then RA becomes another return address, and After the OS_EventTaskWait is executed, it returns smoothly, but RA does not change. This causes bug. I believe this is not a problem for me to write code, because this part of code does not need to be migrated.
In fact, it’s not just this function. When I code the delay function, I find the same problem. So I did an experiment and found the change rule of SP when the function is called. I found that there is an optimization strategy. If there is no function called in the function (judged by the compiler), the SP does not change. I wonder if the compiler’s optimization strategy matters.
In fact, bugs appear in many parts of the OSSemPend
OSSemPend(code):
void OSSemPend(OS_EVENT *pevent, unsigned int timeout, unsigned char err)
{
#if OS_CRITICAL_METHOD == 3 / Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif//中断不能等待获得 时间过长 //sp????? if (OSIntNesting > 0) { /* See if called from ISR ... */ *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ __asm__ __volatile__("ret\n\t"); // return; } OS_ENTER_CRITICAL(); //信号量大于0 也就是可以直接跑,条件满足。 if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */ //减一 //???????????????? sp __asm__ __volatile__("addi sp,sp,16"); pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; __asm__ __volatile__ ("ret\n\t"); //return; } /* ????????????????????????????????????????? sp */ __asm__ __volatile__("addi sp,sp,16"); /* Otherwise, must wait until event occurs */ //没有信号量要等待了。 //任务的状态设置 OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ //延时 时间 OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ //等待列表记录 __asm__ __volatile__("sw ra,0(sp)\n\t" "addi sp,sp,-4\n\t"); OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ __asm__ __volatile__("addi sp,sp,4\n\t" "lw ra,0(sp)\n\t"); OS_EXIT_CRITICAL(); //任务调度 刚才那个在等OS_EventTaskWait __asm__ __volatile__("sw ra,0(sp)\n\t" "addi sp,sp,-4\n\t"); OS_Sched(); __asm__ __volatile__("addi sp,sp,4\n\t" "lw ra,0(sp)\n\t"); //等别的任务释放信号量 //从而可以回来运行。 //怎么回来这里? /* Find next highest priority task ready */ OS_ENTER_CRITICAL(); //超时 OS_STAT_SEM还存在 时钟节拍那个地方,超时 回来的 //和OSMboxPend不同不用拿到消息指针。 if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { /* Must have timed out if still waiting for event*/ //OS_EventTO工作简单了,因为tick帮他做了 恢复就绪 __asm__ __volatile__("sw ra,0(sp)\n\t" "addi sp,sp,-4\n\t"); OS_EventTO(pevent); __asm__ __volatile__("addi sp,sp,4\n\t" "lw ra,0(sp)\n\t"); OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* Indicate that didn't get event within TO */ __asm__ __volatile__("ret\n\t"); return; //must } //正常获得 OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; // return ; __asm__ __volatile__("ret\n\t");
}
The above is the modified version that I debugged and can run normally. There are many embedded codes, but I can’t understand why I need these codes. I doubt it’s the compiler’s problem. So I hope I can get your help.
The second problem is that I want to know how builds projects in Vscode. Because the compiler needs to link. O files, but I can’t write makefile and vscode’s project build process, so I’m using OS_CFG.h、uCOSii.h、OS_ TASK.h、OS_ TIMER.h、OS_ SEM. H and other files are integrated in the includes. H file. So I hope to get your help. I want to be able to separate file construction projects like keil 5.
My English is not very good, so I use Baidu to translate the English version of the text.