我发现了一些BUG(在HiFive RevB移植uCOSII的过程中)

大家好,这是我第一次提问,如果有做的不好的地方,还请原谅。
我最近在做HiFive Rev B上移植uCOSII的移植,在信号量的移植上,在函数OSSemPend中,我发现了一个BUG,会导致函数调用的时候,会不保存ra,从而覆盖了原本返回的ra。
1 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.

If it is a bug in the SDK code, then please file a bug there. PlatformIO only integrates the external software development kits from the vendor. If a new verseion is released, PlatformIO can then integrate it.

谢谢你,我正在在寻找途径去反馈,最近我又重新创建一次项目,这次发现中断返回mret指令会改变一个不相关的全局变量的数值。真是十分奇怪,哈哈。
Thank you. I’m looking for a way to feed back the problem. Recently, I recreated the project again. This time, I found that the interrupt return instruction “mret ” would change the value of an unrelated global variable. It’s very strange, haha.

So where did you download your copy of uCOS-II from? What platformio.ini are you using? I don’t see uCOS-II referenced inm the official GitHub - sifive/freedom-e-sdk: Open Source Software for Developing on the Freedom E Platform, but FreeRTOS instead.

谢谢你的回复,源码是我的老师给的,用于教学用途,是8086版本的uCOS-II移植版本。下面的图片是我的platformio.ini的内容。
21
在我的重新创建的工程里面,我已经没有遇到这个BUG了,所以我怀疑是我的移植过程是错的,我会继续调试。十分感谢你的帮助。
Thank you for your reply. The source code is given by my teacher for teaching purposes. It is the 8086 version of uCOS-II. The picture below is mine platformio.ini.
In my re creation project, I have not encountered this bug, so I suspect that my migration process is wrong, and I will continue to debug. Thank you very much for your help.