微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 实时嵌入式系统软件调试问题分析

实时嵌入式系统软件调试问题分析

时间:09-29 来源:互联网 点击:

ALU的操作都会改变其状态。在这种情形中,ISR应该保存其状态并进行恢复,仿佛它是一个已被使用的寄存器一般。

如果中断例程是用C语言编写 的,它们的开发也是为了使用当前的堆栈,则开发商就应该针对堆栈溢出情况进行防护,即每个线程都应该拥有足够多的堆栈,来满足中断或者嵌套的中断堆栈的要求。最好的做法,就是让中断例程的规模尽可能小,推迟处理过程,交给一个线程或者优先级较低的中断。在开发过程中,开发商可以在中断的开始和结束部分添加诊断功能,对基础的架构中的寄存器的状态进行比较。

中断嵌套可以让一个高优先级的中断抢先于低优先级的中断例程执行。开发商应该考虑到堆栈要求的峰值,并为其分配充足的空间(考虑最差的情况,即你的系统中的每一个中断都被一个优先级更高的中断所抢先)。

而操作内存映射寄存器(MMR)时,人们常常采用在线汇编以改善性能。例如,你在屏蔽中断时,可能希望直接设定中断屏蔽寄存器(IMASK)而不是执行RTOS所提供的应用软件编程接口(API)。例如原子增加或减少操作常常是用汇编语言编写的。在C函数中,这些宏汇编可能会被调用,在这种情况下,编译器可能不了解在宏汇编中所使用的寄存器。因此这会导致寄存器的讹误。有些编译器具有汇编的扩展版,可以将关于这些函数的更多的信息传递给编译器,例如已被使用的寄存器、代码在内存中的位置等等。这将使得编译器可以生成恰当的代码。

有时,某些函数是以汇编语言编写的,将被C函数所调用。如果汇编代码并未按照C函数运行时间调用规范来编写,即按照编译器所要求的那样进行,则会导致参数传递(argument passing)无效和讹误。例如,C函数运行时间模型可以规定前两个参量必须通过寄存器R0和R1来传递,则汇编的实现方式就必须按照这种语法来编写。在另一种情况下,运行时间模型可能需要存储堆栈上的函数的返回地址。如果汇编的实现方法并不符合运行时间模型,则它可能会搅乱某些 寄存器,并带来系统的故障。如果开发商使用混合模式的语言来避免这种类型的问题的话,开发商就必须清楚运行时间模型。

编译器:

编译器的优化,即使实现了逻辑上的正确性,有时也仍然会造成故障。采用低水平的设备驱动器时,这一问题特别关键。重排指令是实现更高性能的常用方法,因为处理器常常支持单个周期内执行多条指令。因此,编译器将试图调度指令,使得所有的指令时间片都得到充分的利用,即使这意味着在寄存器使用前很久就载入数据,或者在数值被计算完毕后很久,也让内存保持载入的数据。请看附图,其中描述了这种内存的移动是如何发生的。

例如,假设一个设备必须在向其发任何指令前就完成初始化。编译器可能会移动指令位置,以便改善性能。这可能会造成设备的故障。如果你的设备驱动器调试后的版本是可行的,而采用经过优化的版本时会出现故障,那么你会想查看设备的初始化中是否有被移动的指令。你可能不得不采用恰当的编译器指南以便指导编译器不去对每条基本函数执行这样的优化,而不至于损失性能。

有时,将代码从一个架构移植到另一种架构上,也会带来某种数据类型上的问题。例如,一种架构内的整数可能是32 bit的,而其它的架构中可能是48 bit或者64 bit的。这可能会导致数据的失效或者被截断。

异常所带来的问题

如果异常是与程序的执行相同步的,则这往往是一种不当的操作的结果,例如零作为除数所造成的异常。某些异常则是架构所特有的。处理异常的最佳方法是采用缺省的异常处理器,并在出现异常时检查异常出现的环境。异常所处的环境背景是寄存器量值的集合,包括状态寄存器。大多数架构将拥有一个指令地址寄存器,用来保存造成问题的指令地址。在多数情况下,要知道一个异常是如何发生的并不难,但是,是何种指令路径可以隔离出这一失效,则是调试时棘手的地方。有些架构支持跟踪,即让你可以看到程序顺序执行的指令的历史。这将给出造成异常的指令顺序的某些细节信息。内存和寄存器讹误则是造成异常及程序逻辑错误的主要原因。通过细致检查造成异常的内存指向或者寄存器,将可以缩小问题的范围。

不能执行错误检验的代码会造成内存的讹误

由于性能方面的原因,开发商可能会放弃对错误的检查。跳过错误检查将让内存泄漏等事件无法为人所知,而最终导致内存讹误。例如,如果malloc()出现故障,而由于返回的值并未得到检验,则开发商将开始覆盖在内存的地址0x0地址所写入的量值,在很多嵌入式系统中,这则是一个有效的内存区域。一个技巧是,让某些地址0x0处的内存控制,以便排查出任何一种潜在的讹误

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top