2

我目前正在编写一个 Gameboy Advance 模拟器,纯粹是为了好玩。它有一个ARM7TDMICPU,我已经编写了大部分 CPU 仿真代码。我的问题是,如何进行测试?

在随机 GBA 软件上测试它并没有太大帮助 - 程序可能会由于与 CPU 无关的原因而崩溃,最好逐个测试,而不是一起测试。

是否有任何可用的程序可以测试ARMCPU,尤其是指令集?我查看了几个ARM模拟器的源代码,但没有找到我要找的东西。如果没有,我将编写自己的程序,但很难使测试全面。

提前致谢!

4

3 回答 3

2

如果您的目的是编写一个全系统仿真器,那么在您担心 CPU 仿真是否有效之前,我会找出您至少需要支持的其他系统并实施它们。图形和内存控制器是最重要的。它们也更容易为它们编写单元测试,并且如果您可以说服自己它们工作正常,那么您将拥有合适的工具来测试您的 CPU 仿真。

话虽如此,如果您确实想先测试 CPU 仿真,我会添加一些调试代码来反汇编指令并在每条指令之前打印所有寄存器的值(可能还有它们可能指向的内存中的值)。然后尝试运行一些游戏。即使它们不会走得太远,您也可以查看大量数据来评估仿真代码是否对寄存器/内存状态进行了正确的更改。

于 2013-01-27T23:39:34.907 回答
2

我同意 R. 首先测试 cpu,和/或与仿真硬件分开测试。有一个坚实的基础开始。

我编写了指令集模拟器并测试了它们以及正在开发的真实处理器。

有明显的定向测试,针对特定指令来查看它们是否有效。例如,仔细查看 ARM 文档,移位具有 if-then-else 定义,如果移位等于 32 则不要移位或类似的东西,创建一个测试来验证 if-then-else 中的每个条件。

无论什么指令集,标志总是很棘手(当然,没有标志的除外)。让您的有符号和无符号溢出正确(进位 = 无符号溢出)以进行加法。然后弄清楚你的目标处理器如何处理减法。通常,您希望反转进位和第二个操作数(进入加法器),其中一种架构与另一种不同的是进位,有些反转进位以进行减法,有些则不。如果有借位减法指令,那么无论进位规则是否会影响借位减法,无论它是否在进位时反转。幸运的是,有 C 编译器可以帮助解决这个问题,假设它们的输出适用于真实处理器(其中的一部分)工作是从处理器错误中整理出编译器错误,并且您会遇到编译器错误)。全零、全一和全零 (0x80000000) 的特殊情况应进行定向测试,以确保它们的(有符号)溢出正常工作。某些操作仅影响某些标志或某些操作将某些标志归零等。确保您创建情况来测试它。ARM 还允许任何有条件的指令和 alu 指令选择性地修改标志,从而使情况变得更糟。

我喜欢使用 zlib 和 jpeg 解码器、mp3 解码器,任何开源的并且可以以裸机方式编译的东西(是的,这些已经提到过可以!),这意味着在这种情况下没有操作系统。例如,现在 zlib 在混合 long 和 int 方面是一场噩梦,因此取决于您的编译器当天在主机上的工作方式(某些编译器,有时使用主机架构而不是目标架构来调整变量的大小交叉编译,这很烦人)。我什至会为它所做的所有类型跳转调用 zlib buggy,所以我已经减少使用它进行测试,因为调试编译所花费的时间而不是它返回的值推动处理器,因为它不推动处理器非常难(尽管我发现使用它的处理器错误)。对于有损的 jpeg 和 mp3 解码器,您需要预先计算的答案,在您的主机上计算。除非您想使用软浮点数,否则您需要整数解决方案而不是浮点数。

在使用编译器进行测试时,了解一些事情,首先你要尝试所有的优化,因为每个编译的测试都有 -O0、-O1、-O2 和 -O3 版本,因为它会创建不同的指令混合并推送处理器以不同的方式。请注意,尽管这可能是您开始遇到编译器错误的地方。同一个编译器的不同版本和不同的编译器会产生不同的输出,不同的指令混合,如果可能的话,最好尽可能多地获得不同的编译器,使用 evals 或其他。在评估编译器时,我发现了许多编译器错误,以至于他们给了我一段时间的完整版本的免费副本。YMMV。另外,这对你来说可能是不可能的,不同的人(不受编码标准严格控制)产生不同的指令组合(asm或更高),在你拥有每条指令之后,理论上,在孤立的情况下工作,你可能会发现当某个指令跟随另一个指令时仍然存在错误,所以尝试创建指令组合很有用,即使您从未发现错误,这也是一个很好的验证。正如我已经提到的那样编译代码,但是您可能还想创建一个 alu 操作序列,例如使用随机发生器来选择操作以及源和目标寄存器(使用混合标志的操作),并在可能的情况下运行该代码在真正的处理器上然后在你的处理器上运行它,看看你是否得到相同的结果。您可能会发现当某个指令跟随另一个指令时仍然存在错误,因此尝试创建指令混合很有用,即使您从未发现错误,这也是一个很好的验证。正如我已经提到的那样编译代码,但是您可能还想创建一个 alu 操作序列,例如使用随机发生器来选择操作以及源和目标寄存器(使用混合标志的操作),并在可能的情况下运行该代码在真正的处理器上然后在你的处理器上运行它,看看你是否得到相同的结果。您可能会发现当某个指令跟随另一个指令时仍然存在错误,因此尝试创建指令混合很有用,即使您从未发现错误,这也是一个很好的验证。正如我已经提到的那样编译代码,但是您可能还想创建一个 alu 操作序列,例如使用随机发生器来选择操作以及源和目标寄存器(使用混合标志的操作),并在可能的情况下运行该代码在真正的处理器上然后在你的处理器上运行它,看看你是否得到相同的结果。

我使用的一个处理器在硬件中构建了一个测试夹具,我可以在其中与测试夹具中的外围设备通信,这将 1)允许我以某种速率发送中断 2)为特定地址创建数据/预取中止。所以我做了一个 zlib 测试,在它运行的时候我用中断敲了它,然后在中断中我查看了指令的返回地址,并在几个字之后武装了预取中止,有时他们命中有时没有,这很好,关键是让主应用程序运行完美,尽管有中断(我会让中断正常继续,中止会解除,备份并让它重试)。至少,您应该能够通过中断来冲击您的测试应用程序,并确保它们继续运行。

不幸的是,GBA 中的大部分逻辑都是图形方面的,因此即使您在处理器上投入了大量精力,您仍然必须调试图形。您可以通过在伪内存解码器上放置一个测试接口来隔离该代码,并让主机应用程序访问虚拟外围设备,而不是总是必须模拟 arm 代码来执行此操作。归根结底,尽管我认为正在玩现成的游戏,这将是最困难的,是的,调试问题可能非常困难。我认为拥有一个坚实的 arm 核心将使调试更容易,少一件需要担心的事情,少一件问题的根源。

另一个问题是,由于 gba 的设计方式,通过在拇指模式下运行 arm 可以显着提升性能,因此您会看到许多拇指模式程序,这是要验证/调试的更多 arm 核心内容。混合模式等

于 2013-01-28T15:46:06.347 回答
1

QEMU 非常适合 ARM CPU/指令集。Balau是入门的好文章。QEMU可以为很多广泛使用的硬件平台做Linux,甚至可以为少数ARM硬件平台做U-Boot/bare metal code。

y对于您的 Gameboy 模拟器,您的图形将如何显示?

于 2013-01-27T23:41:10.397 回答