熊仔 发表于 2023-9-18 00:33:59

最新版本uC-OS2-2.93.01已移植到STC32G上,请帮忙查错

uCOS-II-2.93.01 for STC32G12K128 请帮忙查错
本移植参考STC论坛网友tzz1983的移植方案,使用定时器4模拟软件中断PendSv
一,使用注意:
本移植整个工程统一使用寄存器组0,用户不能修改寄存器组。寄存器组1,2,3共24字节用于data/edata区。
中断函数执行完毕,执行RETI返回前不建议关闭中断总开关。如果关闭一般认为是程序员的Bug。
系统启动前不能开中断,不然OSIntNesting一直会++。
二,void OSStartHighRdy(void)行数提供了3种方法切换到第一个任务。
<font size="3">//方法1:使用ERET返回,返回前需要从新调整堆栈的内容,由于任务第一次运行,R4,R5,R6 给任何值都没关系。

    //读取任务的SP
    __asm   { MOV   DR4,OSTCBCur    }   
    __asm   { MOV   WR2,@WR6+0x2    }   
    __asm   { MOV   DR60,DR0      }
   
    //寄存器出栈
    __asm   { POP   PSW   }               
    __asm   { POP   DR0   }               
    __asm   { POP   DR4   }               
    __asm   { POP   DR8   }               
    __asm   { POP   DR12    }               
    __asm   { POP   DR16    }               
    __asm   { POP   DR20    }               
    __asm   { POP   DR24    }               
    __asm   { POP   DR28    }               
    __asm   { POP   DR56    }               

    //PC和PSW1出栈
    __asm   { POP   R4      }               
    __asm   { POP   R6      }               
    __asm   { POP   R5      }               
    __asm   { POP   PSW1    }
   
    //把返回地址格式做成ERET的返回格试
    __asm   { PUSHR5    }               
    __asm   { PUSHR4    }               
    __asm   { PUSHR6    }
    __asm   { SETBEA      }
    //用ERET指令转移到任务中去, 0XAA是ERET指令的编码
    __asm   { DB    0AAH    }   

//方法2:使用RETI返回,由于系统刚开始,其他中断都没有开始触发。用RETI完全没问题的。   
   
         //读取任务的SP
    __asm   { MOV   DR4,OSTCBCur    }   
    __asm   { MOV   WR2,@WR6+0x2    }   
    __asm   { MOV   DR60,DR0      }
   
    //寄存器出栈
    __asm   { POP   PSW   }               
    __asm   { POP   DR0   }               
    __asm   { POP   DR4   }               
    __asm   { POP   DR8   }               
    __asm   { POP   DR12    }               
    __asm   { POP   DR16    }               
    __asm   { POP   DR20    }               
    __asm   { POP   DR24    }               
    __asm   { POP   DR28    }               
    __asm   { POP   DR56    }               
    __asm   { SETBEA      }
    __asm   { RETI    }

//方法3:使用PendSvIsr中断切换到第一个任务
//巧妙指向DR0内存位置。SP保存到任务控制块的时候,实际操作是MOV   DR0,DR0,也就是DR0值不变   

    OSTCBCur      = (OS_TCB *)0;   
    PendSv_GenerateSWInterrupt();
    EA = 1;
    while(1);</font>

三,优化了OS_CPU_PendSVHandler中断函数
<font size="3">void OS_CPU_PendSVHandler( void )
{
    //函数入口标号,中断跳转到入口标号,解决huge和large存储模式不一样函数名字不一样的问题。
    __asm   {OS_CPU_PendSVHandler_00:}
    //寄存器入栈
    __asm   { PUSHDR56    }               
    __asm   { PUSHDR28    }               
    __asm   { PUSHDR24    }               
    __asm   { PUSHDR20    }               
    __asm   { PUSHDR16    }               
    __asm   { PUSHDR12    }               
    __asm   { PUSHDR8   }               
    __asm   { PUSHDR4   }               
    __asm   { PUSHDR0   }               
    __asm   { PUSHPSW   }
   
   
    //SP保存到任务控制块                        
    __asm   { MOV   DR0,DR60 }         
    __asm   { MOV   DR4,OSTCBCur }   
    __asm   { MOV   @WR6+0x2,WR2 }
   
   
    //保存并关EA,其实EA=0问题也不大,如果中断返回的时候EA=0,这个很明显是程序员的bug
    __asm   { SETBC                }
    __asm   { JBC   EA,PendSvIsr_01}
    __asm   { CLR   C                }
    __asm   { PendSvIsr_01:          }
    __asm   { PUSHPSW            }

    OSTaskSwHook();
    OSPrioCur = OSPrioHighRdy;
    OSTCBCur= OSTCBHighRdy;

    //恢复EA
    __asm{POP   PSW       }
    __asm{   MOV   EA,C   }


   
    //读取任务的SP
// ;OSTCBCur= OSTCBHighRdy; 的汇编
//      MOV      DR4,OSTCBHighRdy
//      MOV      OSTCBCur,DR4
//说明DR4的值已经是OSTCBCur,下面这条可以屏蔽
//    __asm   { MOV   DR4,OSTCBCur    }   
    __asm   { MOV   WR2,@WR6+0x2    }   
    __asm   { MOV   DR60,DR0      }
   
    //寄存器出栈
    __asm   { POP   PSW   }               
    __asm   { POP   DR0   }               
    __asm   { POP   DR4   }               
    __asm   { POP   DR8   }               
    __asm   { POP   DR12    }               
    __asm   { POP   DR16    }               
    __asm   { POP   DR20    }               
    __asm   { POP   DR24    }               
    __asm   { POP   DR28    }               
    __asm   { POP   DR56    }               

    //中断返回
    __asm   { RETI }         
}</font>

四,函数入口标号,中断跳转到入口标号,解决huge和large存储模式不同,函数名字不一样的问题。
/*-----------------------------------------------------------*
PendSv 向量入口引导
*-----------------------------------------------------------*/


__asm   {OS_CPU_PendSVHandler_00:}


__asm   { CSEG    ATPendSv_EntryAddress}
__asm   { JMP   OS_CPU_PendSVHandler_00}




附件是最新版本的源码:


熊仔 发表于 2023-9-18 08:26:56



需要设置全局可重入。昨天最后整理新建了工程,忘记设置了。

tzz1983 发表于 2023-9-18 09:06:00

熊哥威武! 真是行家一出手,就知有没有!

那个第一次切换任务用中断的方法, 有些烧脑啊, 哈哈, 牛B的, 我在脑海里转了好几圈才转出来, 就是第一次切换没有保存上下文呗, 厉害!
给熊哥几个建议:
1: 切换任务中有三个C语句, 直接全部用汇编替换, 一是便于理解, 二是你在文中有提到, C转汇编时"说明DR4的值已经是OSTCBCur" , 但这里有个隐含的条件是, C编绎一定会这么干! (个人认为编译权并不在我们手里, 万一它以后为DR8了呢,汇合编程还是小心为上).
2: 临界段模式2中 "#define OS_EXIT_CRITICAL() do{ _pop_ (ACC);IE |= ACC;}while(0) "此处个人理解是有BUG的. 此处在将C代码文档中直接插入插入C代码, 访问ACC等同于直接访问内部寄存器A,会不会破坏原文的上下文.并且貌似251这编译也不支持 _pop_ ().
3:临界段模式4过于烦锁, 为了让读者少烧脑, 是不是可以却除

熊仔 发表于 2023-9-18 09:18:18

tzz1983 发表于 2023-9-18 09:06
熊哥威武! 真是行家一出手,就知有没有!

那个第一次切换任务用中断的方法, 有些烧脑啊, 哈哈, 牛B的, 我在 ...

问题1,之前想过,其实我都都弄好了,只保留钩子函数。后来想还是不要改动你太多,毕竟你的成果。
需要在前面把变量调用下才能通过编译。
if(OSPrioCur);
if(OSPrioHighRdy);
if(OSTCBCur);
if(OSTCBHighRdy);
问题2,忘记测试了,C251确实不支持_push_和_pop_,代码思路没有问题的,在STC8验证过的。251有堆栈寻址,貌似不适用
问题3,这个杨老师认为最好的方法,还是保留吧。喜欢的自己选。

tzz1983 发表于 2023-9-18 09:31:12

熊仔 发表于 2023-9-18 09:18
问题1,之前想过,其实我都都弄好了,只保留钩子函数。后来想还是不要改动你太多,毕竟你的成果。
需要在 ...

嗯 ,是的, 我移植时也遇到不能编绎, 用一个无效语句来调用一下, 后来想想直接C不影响结果, 就直接用C了, 但现在你用到了DR4.
另外138警告去处理一下, 这个更改只是为了迎和编绎器, 不算是对原代码的冒犯, 程序员肯定不喜欢warning, 屏蔽太多又不好, 不屏蔽又影响心情

熊仔 发表于 2023-9-18 10:49:44


1,138警告,早上的更新的已经去掉了。
2,屏蔽方法2
3,void OS_CPU_PendSVHandler( void )除了OSTaskSwHook();其他使用汇编汇编


void OS_CPU_PendSVHandler( void )
{
    //下面这样做为了能使用汇编访问变量
    if(OSPrioCur);
    if(OSPrioHighRdy);
    if(OSTCBCur);
    if(OSTCBHighRdy);
    //函数入口标号,中断跳转到入口标号,解决huge和large存储模式不一样函数名字不一样的问题。
__asm{
OS_CPU_PendSVHandler_00:
      //寄存器入栈
      PUSHDR56
      PUSHDR28
      PUSHDR24
      PUSHDR20
      PUSHDR16
      PUSHDR12
      PUSHDR8
      PUSHDR4
      PUSHDR0
      PUSHPSW

      //SP保存到任务控制块
      MOV   DR0,DR60
      MOV   DR4,OSTCBCur
      MOV   @WR6+0x2,WR2

      //保存并关EA,其实EA=0问题也不大,如果中断返回的时候EA=0,这个很明显是程序员的bug
      SETBC
      JBC   EA,PendSvIsr_01
      CLR   C
PendSvIsr_01:
      PUSHPSW
    }
      //这条用C方式就是解决huge和large存储模式不一样函数名字不一样的问题
      OSTaskSwHook();
   
__asm{
      //OSPrioCur = OSPrioHighRdy;
      MOV      OSPrioCur,OSPrioHighRdy;使用data加速
      //OSTCBCur= OSTCBHighRdy;
      MOV      DR4,OSTCBHighRdy
      MOV      OSTCBCur,DR4

      //恢复EA
      POP   PSW
      MOV   EA,C

      //读取任务的SP
      //DR4的值已经是OSTCBCur,下面这条可以屏蔽
      // MOV   DR4,OSTCBCur
      MOV   WR2,@WR6+0x2
      MOV   DR60,DR0

      //寄存器出栈
      POP   PSW
      POP   DR0
      POP   DR4
      POP   DR8
      POP   DR12
      POP   DR16
      POP   DR20                  
      POP   DR24                  
      POP   DR28                  
      POP   DR56                  

      //中断返回
      RETI            
    }
}

源码先不更新。

杨为民 发表于 2023-9-18 11:18:13

祝贺熊仔推出STC32G的移植版,这样“uCOSII-STC32G”、“C251-UCOSII”和“CosyOS”都采用了软中断作为任务切换的方法,可以互相借鉴和交流了

下面只等FreeRTOS软中断的移植版了,各位大侠加油!!

CosyOS 发表于 2023-9-18 12:16:36

本帖最后由 CosyOS 于 2023-9-18 12:26 编辑

CosyOS允许用户自由选择一个未使用的硬件中断,来做为软中断使用。



由于CosyOS在进入任务临界区时是需要关闭系统滴答中断和这个“软中断”的,所以还需用户配置这个“软中断”的开启和关闭。



熊仔 发表于 2023-9-18 12:33:21

*修改版本: V1.01
*修改时间: 2023-09-18
修改:
      1.临界区保护方法2屏蔽
      2.void OS_CPU_PendSVHandler( void )除了OSTaskSwHook();其他使用汇编汇编
      3.解决void OSStartHighRdy(void) 函数里面的方法3,OSTaskSwHook();运行2次问题。
      4.增加putchar.c文件,char putchar(char c)重映射函数不能在全局可重入下使用。文件需要单独设置,才支持支持printf



熊仔 发表于 2023-9-18 13:05:10

CosyOS 发表于 2023-9-18 12:16
CosyOS允许用户自由选择一个未使用的硬件中断,来做为软中断使用。




最好选择能自动清零的中断。当然手动也行,多执行一条清零语句。

你的os代码太庞大了。之前看了一下,没理清,没坚持下去。以后有时间再拜读一下。
页: [1] 2 3 4 5 6 7
查看完整版本: 最新版本uC-OS2-2.93.01已移植到STC32G上,请帮忙查错