(中国空间技术研究院510所,甘肃兰州730030)
嵌入式操作系统目前发展迅猛,被运用于飞机、雷达、航天等各个领域[1]。BM3803是基于SPARC V8体系结构的32位精简指令国产化嵌入式处理器,可用于板上嵌入式实时计算机系统,具有功能强、抗辐照、高可靠和低功耗等特点,能适合多种航天应用功能及性能要求。在BM3803上,移植操作系统可以使应用工程软件人员从与硬件平台相关的繁琐设计中解放出来,专注于具体的应用软件开发研究。μC/OS-Ⅱ(Micro Control Operation System Two)操作系统是一个可以基于ROM运行、可裁减、抢占式、实时多任务内核,可移植性强,特别适合于微处理器和控制器,达到了DO-178B从E级到A级的标准。
本文结合BM3803的寄存器功能及μC/OS-Ⅱ操作系统的特点,详细介绍了将μC/OS-Ⅱ操作系统移植到BM3803平台的过程,并给出相应测试结果。
对于SPARC架构的CPU来说,其最大的特点是窗口寄存器结构。每组寄存器窗口包含32个窗口寄存器,分为4类:inputs,locals,outputs,globals,每类各8个,通常记为i0~i7,l0~l7,o0~o7和g0~g7,其中g0~g7是全局寄存器,其余24个为窗口的寄存器,相邻寄存器之间的关系如图1所示[2]。
图1 相邻窗口寄存器之间的相互关系
由图1可以注意到相邻寄存器窗口的outputs同时又是下一个窗口的inputs,这被称作寄存器公用。寄存器窗口数为NWINDOWS,该值为21~25,即为2,4,8,16,32五种情况。在BM3803中该值为8。8组寄存器中有一组是当前窗口寄存器(CWP),同时也有一组是无效寄存器(WIM)。窗口寄存器之间通过加减来实现对程序的调度,比较常见操作是SAVE指令和RESTORE指令。SAVE指令能使当前窗口指针CWP减1,起到保存调用程序窗口的作用。RESTORE指令的作用相反,会使CWP加1,从而恢复调用程序的窗口。
8组寄存器一般分为4种状态,分别是Current态、Invalid态、Used态和Unused态,如果假设%WIM的值为0x06,而CWP为2,则8组寄存器窗口的状态分配如下:W2,Current;W3、W4、W5,Used;W6,Invalid;W7、W0、W1,Unused。整体的寄存器窗口寄存器组的原理如图2所示[3]。
除了窗口寄存器外,还有特殊状态寄存器,包括处理器状态寄存器(%PSR)、窗口无效掩码寄存器(%WIM)、异常基址标志寄存器(%TBR)、乘法/除法寄存器(%Y)、程序计数器(%PC,%NPC)和辅助状态寄存器(%ASR)。其中最重要的是处理器状态寄存器和窗口无效掩码寄存器。
PSR一共32位,包含了多种字段来控制处理器和保持状态信息[3]。PSR可以被SAVE,RESTORE,Ticc,RETT以及所有可以修改条件码的指令所修改。PSR的格式如表1所示,其中比较重要的是第0~4位,这组成当前窗口指针(CWP),而第5位(ET)表示能否使用陷阱,1表示可以使用,表1为其字段分配。
图2 窗口寄存器整体示意图
表1 PSR字段的分配
WIM由管理软件控制,硬件利用WIM来决定执行一条SAVE,RESTORE或者RETT指令是否会产生窗口上溢或下溢陷阱。陷阱是一种特殊的中断形式。BM3803有8组寄存器窗口,因此该寄存器的低8位有效。当执行SAVE,RESTORE或者RETT指令时,CWP的当前值与WIM比较。如果SAVE,RESTORE或者RETT指令使CWP指向一个“无效”寄存器组,也就是对应的WIM位等于1(WIM[CWP]=1)的寄存器组的话,就会产生一个窗口上溢或者窗口下溢陷阱。当因为CWP减1而发生窗口上溢陷阱时,通常会将Used状态的寄存器的值保存在RAM中。而当因为CWP加1而发生窗口下溢陷阱时,会将之前因为上溢陷阱保存于RAM中的寄存器的值读取出来,以用于恢复之前的状态。
嵌入式操作系统μC/OS-Ⅱ由Labrosse编写,历经20多年,其具有较高的可靠性和稳定性,达到了多类标准要求。本文使用的是其2.90版,其代码结构可分为3个部分,如图3所示。
图3 μC/OS-Ⅱ的组成结构
由图3可见,μC/OS-Ⅱ的组成包含3个部分,操作系统源代码、与配置相关代码和与移植相关代码。下面分别介绍这3个文件的组成。
(1)操作系统源代码是实现操作系统基本功能的代码文件,组成包括:
os_core.c:操作系统内核文件,主要功能包括内核初始化、任务切换、事件块管理等;
os_task.c:操作系统任务管理文件;
os_time.c:操作系统时间管理文件;
os_flag.c:操作系统事件标志组管理文件;
os_mbox.c:操作系统邮箱消息管理文件;
os_mem.c:操作系统内存管理文件;
os_sem.c:操作系统信号量管理文件;
os_mutex.c:操作系统互斥性信号量管理文件;
os_tmr.c:操作系统定时器管理文件;
os_q.c:操作系统消息队列管理文件;
ucos_ii.c:源代码的包含文件,作用是把源代码所包含的C语言文件放置到一个文件里,使得编译器能够直接编译;
ucos_ii.h:头文件,负责内核函数参数设置。
(2)与配置相关代码主要是为了符合应用的需要而改写的,结构组成包括:
includes.h:与应用相关的包含文件,作用是加载与应用相关的一些头文件,根据实际情况要做相应修改;
os_cfg.h:系统内核配置文件的头文件;
os_dbg.c:内核调试数据和编译函数文件。
(3)与移植相关代码有3个[4]:
os_cpu.h:头文件,负责与处理器相关变量、类型和宏的定义,比如堆栈方向、开关中断的方式等;
os_cpu.s:汇编文件,负责与处理器直接相关的函数,主要是任务切换函数。因为C语言不太方便对寄存器直接进行操作所以用汇编语言编写,同时也是移植的难点;
os_cpu_c.c:负责任务堆栈段的设置和一些HOOK函数的定义。HOOK函数是为应用的管理平台监控任务的各种功能而设计的,可以只声明,不包含任何代码。
操作系统移植的一般过程如图4所示。首先确定整体结构体系;再建立工程,把各个模块加载进工程;再按照目标处理器的具体特点进行代码的改写和调试;再移植完毕后通过编写测试代码来验证移植的正确性和可靠性。
图4 移植操作系统的流程
μC/OS-Ⅱ的整体结构体系如图5所示。系统的硬件包括BM3803开发板、存储设备等;软件部分包括操作系统内核、各种功能的管理文件和驱动设备(UART)等;最上层是根据不同需求设计的应用程序。
图5 系统软件整体结构
本文所使用的开发环境是SPE-C 2.52,这是一款针对BM3803,BM3802,BM3101应用软件的开发平台。它采用GNU的整套集成开发套件作为编译和调试的组件,适合在32位的Windows系统环境下使用。
首先创建工程,将文件分为操作系统源代码、与移植相关代码、与平台相关代码和应用程序源代码分别加载,结构如下:
(1)操作系统源代码;
(2)与移植相关代码:包括os_cpu.h,os_cpu.s和os_cpu_c.c;
(3)与平台相关代码:BM3803mg.h(与平台相关的常数定义)和trap.s(平台的陷阱列表);
(4)应用程序源代码:主要用于测试本文中的移植结果,其中包括serial.c和serial.h串口操作源代码文件及其头文件,os_dbg.c,app_cfg.h和test.c。
下面分别给出移植需要处理的代码[5]:
(1)os_cpu.h
对于os_cpu.h,主要修改的部分是其堆栈长度和堆栈增长方向(由高地址向低地址生长),同时对于任务切换函数(OS_TASK_SW())、时钟节拍中断服务函数(OSTickISR())、开关中断函数等也要有相应的定义。
(2)os_cpu_c.c
对于os_cpu_c.c,重点是堆栈段的设计。BM3803的堆栈段标准定义的程序主要包含栈顶指针(%sp)和栈底指针(%fp),以及一些必须保存的寄存器的值,寄存器的初始化如图6所示。
图6中这些部分都是常规堆栈。根据实际情况,BM3803还有浮点寄存器,所以实际的堆栈长度比图中所示还要长。
图6 堆栈段的设计
(3)os_cpu.s
由于任务切换需要与寄存器进行直接交互,需要采用汇编语言来编写任务切换部分的代码,而该部分代码是移植的最重要内容。本文的任务切换部分代码放置于os_cpu.s文件中。主要包括的函数为OSStart High Rdy(),OSCtxSw(),OSIntCtxSw(),OSTick ISR()以及开关中断函数。函数OSStart HighRdy()的功能是找到优先级最高的任务,并将最高优先级的任务堆栈中的内容复制到寄存器中,就好像刚执行完中断一样,紧接着去执行优先级最高的就绪任务。
任务级任务调度函数和中断级任务调度函数大部分代码类似,不同的是任务级任务调度函数(OSCtxSw())有保存上下文的操作。具体过程是先保存程序寄存器(%PC)和处理器状态寄存器(%PSR)的值,然后申请足够的空间用于保存上下文,再保存当前任务控制块的栈顶位置,最后再保存栈顶指针,返回位置、所在窗口寄存器等。需要注意的是,OSCtxSw()是由软中断(ta指令)实现的,所以在trap.s中的软中断列表(0x80~0x FF)中一定要设置中断入口。后面的过程与OS-IntCtxSw()一致。
中断级任务调度(OSIntCtxSw())由退出中断函数OSInt Exit()调用,在任务发生中断时完成任务的调度,主要工作是将当前任务的任务控制块指针(OSTCBCur)更换为OSStart High Rdy所指的位置[5],从而得到最高优先级任务的任务控制块地址,然后将当前任务优先级转换为最高优先级,再调出最高优先级任务的任务控制块,将最高优先级任务寄存器的值从堆栈中恢复到寄存器中,最后用jmpl和rett从中断处返回,具体的流程如图7所示。
图7 任务调度
函数OSTickISR()负责时钟节拍中断服务[4],其核心功能是通过调用函数OSTime Tick()来跟踪与任务相关的定时器,判断是否超时来完成时间的延迟和超时功能,以保证任务之间的同步。BM3803有两个定时器(timer1和timer2),选择timer1产生一定周期的系统中断来实现时钟节拍,所以在trap.s中要在timer1的位置设置时钟节拍中断服务程序的入口OSTickISR。中断的嵌套是比较关键的问题,由于OSTickISR()在嵌套层数为1时要先保存上下文,再对timer1进行操作,而嵌套层数不为1时直接对timer1进行操作,所以要在函数内进行嵌套层数的判断。在进入OSInt Enter(内核函数,负责中断加1)之前要保存上下文。在调用完OSTimeTick()执行退出中断函数(OSIntExit)时也要对嵌套层数进行判断,如果还处于多层嵌套中,则无需执行任务切换,直接恢复上下文,具体的流程如图8所示。
图8 定时中断服务
开关中断函数是通过直接对寄存器%PSR的操作来实现的。BM3803的陷阱一共有15个优先级,在%PSR的第5位(ET,陷阱使能)使能的情况下IU会将%PSR的第8~11位(PIL,可接受的陷阱优先级)与中断请求等级比较,如果中断请求等级大于或等于PIL字段值,即未屏蔽此中断,则处理器响应该中断请求。利用这一点可以直接将PIL位设为1111,这样所有的中断请求都被屏蔽了,实现了屏蔽中断的功能。同理将PIL位设置为0000就可以实现打开中断的功能。
完成所有的修改后,需要编写测试程序来验证移植的正确性。
编写测试代码的主要目的是验证操作系统是否移植完成、各项基本功能是否正常[6]。本次移植所编写的测试代码是为了验证创建任务、任务延时、定时器设置、时钟中断服务程序和串口操作程序是否能正常运行。
测试代码的结构比较具有针对性。操作系统本身是个无限循环,要保证每时每刻都要有任务存在,因此系统自动创建了空闲任务,空闲任务会在系统启动后立刻开始执行,并且优先级始终设为最低。在设计测试代码时,考虑到空闲任务的存在,要把创建任务的优先级、堆栈空间设置好。首先为任务task1和task2申请堆栈,通过串口初始化函数将串口1的波特率和模式设置好(模式指对串口1控制寄存器的值进行设置,本例用的是0x3,即发送和接收位使能)。初始化μC/OS-Ⅱ后,创建任务task1和task2,task1的优先级为5,task2的优先级为6。通过函数OSStart()启动操作系统。在task1中先设置时钟节拍,再循环以10个节拍的延时后通过串口输出字符“-task1-”,task2也是同样的功能,但延时的时钟节拍数为2,串口输出字符为“-task2-”。具体流程图如图9所示。
图9 测试代码流程图
程序运行后,在PC机上打开串口调试软件后看到的结果为每接收到5次“-task2-”,接收到1次“-task1-”。结果证实了本文的移植方法是合理和正确的,测试结果如图10所示。
图10 测试结果
SPARC架构的CPU使用了窗口寄存器,使得工作效率得到提高,目前已经广泛应用于航天领域。对于SPARC架构的CPU浮点运算功能的开发和使用会成为以后工作的重点。
本文在国产新型CPU BM3803上移植了经典的嵌入式操作系统μC/OS-Ⅱ,实现了多任务、高实时性的嵌入式操作系统在这款CPU上的使用,使得任务调度、时间管理等功能更加完善,为后续应用程序的开发和使用创造了良好条件。同时为这款CPU上移植其他操作系统起到良好的示范作用。
[1]熊毅,张承志.VxWorks平台下的米波雷达点迹凝聚方法研究[J].雷达科学与技术,2009,7(6):443-446.
XIONG Yi,ZHANG Chengzhi.A Plot Clotting Approach of Meter Wave Radar Based on Vx Works[J].Radar Science and Technology,2009,7(6):443-446.(in Chinese)
[2]詹盼盼,郭廷源,高建军,等.基于BM3803处理器的即插即用星载计算机系统设计[J].航天器工程,2013,22(6):92-96.
ZHAN Panpan,GUO Tingyuan,GAO Jianjun,et al.Plug-and-Play On-Board Computer System Design Based on BM3803 Processor[J].Spacecraft Engineering,2013,22(6):92-96.(in Chinese)
[3]冯磊,李飞.SPARC结构与实时内核的移植[J].微计算机信息(嵌入式与SOC),2006,22(12-2):6-8,49.
[4]LABROSSE J.嵌入式实时操作系统μC/OS-Ⅱ[M].2版.邵贝贝,译.北京:北京航空航天大学出版社,2003.
[5]朱东亮.基于LPC1343的UCOS-II移植[J].中国新通信,2013(17):111-112.
[6]任锁平.基于μC/OS-Ⅱ的嵌入式校园导航系统的设计与实现[J].自动化与仪器仪表,2014(11):139-141.