我还写了一些测试,并在 GBA 模拟器中发现了一些错误。我还编写了自己的模拟器(以及在处理器业务测试处理器和板的工作)。
我有一些我经常做的事情。这些是我的一般测试方法。
那里有许多开源库,例如 zlib 和其他压缩库、jpeg、mp3 等。裸机并不难,用数据块和指针伪造 fopen、fread、fwrite。您可以在目标处理器上进行自测的压缩库以及加密和散列。压缩一些东西,解压缩它并将原始文件与未压缩文件进行比较。我经常还会在主机上运行被测代码,计算压缩和解压缩版本的校验和,并给我一个硬编码的校验值,然后我在目标平台上运行。对于 jpeg 或 mp3 或哈希算法,我使用被测代码的主机版本来生成一个黄金值,然后在目标平台上进行比较。
在执行任何操作之前,尽管标志非常难以正确处理,特别是进位标志(和有符号溢出),一些处理器在减法运算时反转进位标志(减法是与第二个操作数相加的加法运算)和进位的补码(正常加法没有进位是进位为零,减法是没有进位,然后是第二个操作数反转的加法和 1 的进位))。如果指令集有借位减法,则进位的反转会影响进位,无论进位是否在进位过程中反转。
对于小于、大于等的无符号和有符号变体,有时从条件分支定义(如果 C 是这个而 V 是那个,如果 C 是这个而 Z 是那个)中可以明显看出该特定处理器如何管理进位(无符号溢出)和有符号溢出标志,而无需在真实硅片上进行实验。我不记得什么处理器做什么,我根据指令集弄清楚,所以我不知道 ARM 做什么。
ARM 与移位操作有细微差别,你必须小心正确实现,阅读每条指令下的伪代码,如果移位量 == 32 则执行此操作 如果移位量 == 0 则执行此操作,否则执行此操作. 使用 arm7,如果故障被禁用,您可以进行未对齐的访问,并且它将在 32 位内旋转数据,或类似的东西。如果地址 0 处的 32 位是 0x12345678,那么在地址 1 处读取的 16 位将在总线上为您提供类似 0x78123456 的内容,然后目标将获得 0x3456。希望大多数人没有依赖它。但是 ARM ARM 中的那个和其他“不可预测的结果”评论从 ARM ARM 更改为 ARM ARM(如果您有一些不同的硬拷贝手册,这将更加明显,旧的白色覆盖的(瘦的和厚的)和蓝色覆盖的)。因此,根据您阅读的手册(对于那些 armv4 处理器),您有时被允许做某事,有时不允许做某事。因此,如果您只依赖一本手册,您可能会发现执行您认为不可预测的事情的代码/二进制文件。
不同的编译器生成不同的代码序列,所以如果你能找到不同的 arm 编译器(clang/llvm 和 gcc 显然是首选),如果可以的话,获取其他编译器的一些 eval 副本(Kiel 可能是一个不错的选择,我认为现在由 arm 拥有它包含 Kiel 和 RVCT arm 编译器)。使用不同的优化设置编译相同的测试代码,测试每一个变体,并为每个编译器重复该过程。如果您只使用一个编译器进行测试,您将在指令序列中留下空白,以及许多指令或变体将永远不会被测试,因为编译器永远不会生成它们。我曾经遇到过这个确切的问题。使用开源代码你也会得到不同的程序员习惯,无论是 asm 还是 C 或其他语言,不同的人都有不同的编程习惯,因此会产生不同的指令序列和指令组合,这些指令可以隐藏或暴露处理器错误。如果这是一个人的爱好项目,你最终会依赖其他人。这里的好处是 gba 或 ds 或任何模拟器,当您开始使用 rom 时,您将拥有大量其他人的代码,不幸的是调试很困难。
我听说过一些传闻,英特尔/x86 设计验证人员使用各种操作系统来击败他们的处理器,这会造成很多混乱和变化。在处理器上跳动,但像 rom 一样,如果出现问题,极难调试。我对缓存和在我工作过的处理器上运行 linux 有个人经验。直到我们移植和引导 Linux 才发现这个 bug,而且这个 bug 很难找到……幸运的是 arm7tdmi 没有缓存。如果您有缓存,则采用我上面描述的那些组合,测试代码乘以优化级别乘以不同的编译器,然后在引导程序或其他地方添加到该代码中,编译一个具有一、二、三、四的版本,
在这种情况下,如果有你试图模拟的真实硬件,你可以做一些事情,比如有一个生成随机 alu 机器代码的程序,使用随机选择的源和目标寄存器生成数十条指令,随机化加法、减法和,或者,不等。随机打开和关闭标志等。预加载所有寄存器,将标志设置为已知状态,运行该代码块,然后捕获寄存器和标志并查看它与真实硬件的比较。您可以生成无限量的单独测试、各种长度等,这比调试执行某些数据或标记属于更复杂程序的一部分的代码序列更容易。
采用测试程序的组合,乘以优化设置,乘以编译器等。然后用中断击败它。改变中断的速率。因为这是一个模拟器,所以你可以做一些我曾经做过的事情。在中断中,检查返回地址,计算一个地址,该地址比该地址早一些指令,记住该地址。从中断返回,当您看到正在获取的地址触发预取中止时,具有预取中止代码,当预取中止触发时停止监视该地址(在模拟中),并让预取中止处理程序的代码返回到中止发生(根据手臂)并让它继续。使用这种设置,我能够在被测处理器上造成相当大的痛苦……尤其是在缓存上……
请注意,很大比例的 gba 游戏是拇指模式,因为在该平台上,主要使用 16 位宽数据总线,拇指模式比手臂模式运行(远)快,即使拇指代码需要大约 10-15% 的指令。以及为二进制文件占用更少的ROM空间。仔细检查 blx 指令,因为我认为基于架构的不同实现 armv4 与 armv6 或 7 不同,因此如果您使用 armv6 或 7 手册作为参考或硬件进行验证,请了解这些差异。
废话,废话,废话 TL;博士。抱歉漫无边际这对我来说是一个有趣的话题......