RISC 机器的特性要求您在选择实时操作系统时给与特殊考虑 对于今天复杂的嵌入式应用来说,采用实时操作系统(RTOS)作为软件基础平台是一个良好抉择。RTOS 中有一个核心负责处理器专项任务,例如 CPU 的分配与调度、寄存器上下文变换和存储器管理。核心的周围是完成RTOS服务的例行程序库,它们执行各种系统级功能,在应用程序运行时发挥一定的作用。应用程序被分解为一组任务;RTOS调度器根据某些多任务调度算法让这些任务得以控制 CPU。一个应用任务(通常使用汇编语言以外的其他语言写成)为了得到RTOS服务,需调用相应的应用程序界面(API)功能。应用程序假如是用 C 语言或其它语言写成的,则 RTOS及其 API 库实际上掩盖了处理器的内部工作机理(不管它是 CISC 还是 RISC,是 8 位、16 位、还是 32 位,等等),因而应用软件工程师不必太多地考虑实际使用的处理器。 上述是从外部看到的情景。但到内部去看,从 RTOS 的角度观察,情景就大不相同。RISC 机器不同于 CISC 微处理器和微控制器,这些差别往往要求对有关的操作系统给与一些特殊考虑。RISC 机器是为高速度而发明的,它们运行于很高的时钟速度,通常是在一个周期内执行完指令。他们往往采用多极流水线,因而在指令流出该流水线而进入执行单元的同时,还可以进行指令与数据的预取以及转移地址的估算。当流水线的流动被打断时,比如遇到某些转移指令或跳跃指令时,其性能便受到伤害。所以,如果把这种情况减少到最低程度,就可以达到最大的性能。简而言之,RISC 机器就像是 1 级方程式赛车,在笔直的车道上跑得很快,但在拐角处必须减速。 在采用多任务 RTOS时应用程序中有许多“拐角”,这是因为“笔直的”应用程序或RTOS可能引起正常的处理流发生改变。例如在多任务应用中,许多个任务都共用处理器,它们都调用RTOS服务,使RTOS在其内部做许多工作(并非都是“笔直车道”),以便完成所请求 的操作,并决定接着应运行哪个任务,再把 CPU 的控制权交给该任务。所有这些都会引起处理流发生改变,而外部中断则更易引起这种改变。由此可见,高速笔直应用程序开足马力一直运行下去的希望落空了。如果 RTOS在通过“拐角”时减速,应用程序的性能也要遭殃。 因此,RISC处理器上的RTOS成功的一个关键是有能力迅速通过这些“拐角”。 每当 RTOS 服务请求或中断引起任务的处理流发生改变时,CPU 的寄存器上下文就必须进行相应的管理,以保证同一任务重现获得 CPU 的控制权时处理工作能正确继续下去。RISC 机器通常采用数量很大的寄存器,这要求 RTOS设计时给与特殊考虑。当应用任务调用一个 RTOS服务时,RTOS究竟需要多少个寄存器来保存上下文?RTOS中的功能需用多少个寄存器?中断需用多少个?如果保存用的寄存器太少,RTOS显然就会出错;这是设计RTOS之初的唯一考虑。反过来,如果要处理的寄存器太多,虽然问题不太明显,但性能肯定要下降。幸运的是,RTOS设计师在作出这些决定时可以从处理器的应用二进制界面(ABI)技术规范得到帮助。 ABI 通常是在 RISC 处理器厂商的支持下写成的(例如 PowerPC 嵌入式 ABI 就是在Motorola 公司的赞助下写成的),它是对编译器、汇编器和调试器以及 RTOS构件等软件工具的开发人员很有用的一套规则。ABI中含有:在函数调用期间用于传递变量的寄存器用途,堆栈帧规则,留用的寄存器,以及对编译器或调试器设计师有用的其他信息的定义。对于RTOS时基本上自给自足的软件,因此ABI中的大部分规范不考虑 RTOS设计师的需要。但是,堆栈帧规则和保留寄存器定义对于设计高效的 RTOS很有用。 以保留寄存器为例。他们是非易失性的,在上下文保存与恢复操作期间需要由 RTOS管理的处理器上下文部分就不必把保留寄存器考虑进去。由于只需保存和恢复易失性的寄存器,所以每当RTOS在处理器的上下文进行操作时,RTOS可节省几个周期。鉴于每秒钟发生的上下文管理操作达数万次之多,因而即使节省几个周期也可使 CPU 有更多的时间去做其它工作。 RTOS设计师将乐意利用ABI的堆栈帧规则来确保:任务栈定界于正确的边界上,栈指示器被调整到正确的数值,在保存上下文期间 RTOS 建立的帧反映了 ABI 所规定的格式。遵守ABI规范会得到重大的好处:可以用遵循ABI标准的调试器去查看堆栈。 按照处理器的 ABI 规范来实现 RTOS 还会带来另一个看不到的好处:可与各种工具互操作。遵循 ABI 标准的 RTOS 应兼容于任何 ABI 标准的工具链。这样的兼容性会使 RTOS开发者和用户感到高兴。RTOS开发者之所以高兴,是因为再也不必为了与所有的非兼容工具配合工作而被迫进行软件移植。用户之所以高兴,是因为RTOS、运行库和调试器现在可以浑然一体进行工作。双方都节省了时间,提高了工作效率。 选择语言 在开发RISC处理器上的 RTOS时,RTOS设计师还必须选用最佳的语言。RISC处理器是很复杂的,它们的汇编语言往往最适合不怕反复调试的人使用。那些爱闹情绪的人往往改用较简单的解决方法,例如使用编译器来轻松地产生程序码。不管采用哪一种语言,选择编译器是非常重要的,因为编译器决定了产生的RTOS程序码在 RISC处理器上运行的好坏。例如,循环的编写方法可能影响到指令流水线的连续性。流水线的处理流中断将需要清理和重新注入处理流,引起处理效率下降,其积累效应会极大地降低效能。RTOS 设计师在为RISC 处理器编写程序时通常要采用不同于应用程序开发者的方法,使流水线只在万不得已时才中断。 使处理流发生中断的另一个途径是通过中断或其它类型的例外操作。中断不仅会引起正常处理流中断,还要求为它进行中断服务,因而会使系统性能变差,如果处理不当的话还会影响其响应速度。虽然几乎每种系统都是如此,但基于RISC处理器的系统尤为明显,这是因为它们很大的处理器上下文和硬件中断设计对软件来说是很不友好的。中断是正常处理的一种例外情况;流行的 RTOS设计都尽可能快地去处理中断,但对于运行 RTOS的 RISC处理器来说,要定义“快捷”的含义并不总是轻而易举。 每当发生中断时,有关的中断服务例程(ISR)必须保存某些或全部的处理器上下文,辨认中断源,向引起中断的设备提供服务,再恢复正常的处理通路。在 ISR 处理工作中,保存处理器上下文的这部分工作通常是这样完成的;先禁止处理器的中断系统,使可恢复的状态可以顺利保存而不会被破坏。但是,由于中断被禁止,其它的设备就不能请求服务,必须等到ISR重新启动中断,允许新的中断被识别。当处理器有大量的寄存器需要保存时(典型的 RISC 机器就是如此),保存上下文所需的时间要占用很多的机器周期,增加了系统的中断等待时间,降低了中断响应的速度。在理想情况下,一旦处理器的上下文保存好了,就应当允许接受新的中断,但是,这会带来一种复杂局面:已经激活的 ISR 可能被另一个设备所中断。 如果系统有中断优先级或分开的向量,则很容易管理多个中断。但是,如果像PowerPC或ARM中那样,所有的外部中断都要通过一个或两个向量输入,则重入式中断服务就是不得不面对的实际问题。虽然允许中断肯定可以改善对其他中断请求的响应速度,但处理重入式中断是复杂的任务,RTOS必须能适应这种情况,不让任一中断只得到部分的服务。那么,哪一种方法能更快完成中断服务呢?是采用较简单的RTOS,在ISR工作期间一直禁止中断,完全避免重入式中断的出现?还是及时允许中断输入,让 ISR和 RTOS有处理重入式中断的能力。 对于上述的问题有可能没有一个恰当的答案,这是因为在决定快与慢是应用软件的考虑起着主要作用。为了让操作系统知道中断引起的事件,ISR可能需要调用一个或多个RTOS服务。那么,在第一种处理方法中是否需要在 RTOS服务期间也禁止中断?如果这么做的话,中断等待时间肯定会明显加长,使系统响应明显变差。简而言之,中断响应的快慢最终可能要看究竟需要哪一类系统响应。如果采用简单的RTOS,则 ISR程序可能较简单,但代价是系统响应较差。如果采用智能的 RTOS和较复杂的ISR程序,则系统响应性能可能较好。 最终的分析意见如下:对于使用RISC处理器的嵌入式应用来说,应用需要与所选择的RTOS 存在千丝万缕的联系。但有一点需要牢记,非常适合于应用软件和 RISC 处理器的RTOS将能在笔直通道上快跑,还能以较快速度通过拐角。反之,如果配合不好的话,他在直道上仍然像一条猎狗,但在拐角处就变成一支普通狗。
|