【问题标题】:ARM11 Emulator in CC语言的ARM11仿真器
【发布时间】:2014-07-24 01:31:20
【问题描述】:

我正在尝试编写一个模拟 ARM 二进制文件执行的 C 程序。 所以它现在做了什么,我们从二进制文件中获取指令到一个 uint32_t 数组中,然后我对其进行解码并执行。

问题是我只使用程序计数器来访问数组中的整数,然后我将其递增。但是对于带偏移量、将其扩展到 32 位并将其添加到 PC 的分支指令,PC 应该比正在执行的指令提前 8 个字节。 所以应该会产生管道效应。基本上就是:

  1. 从内存中取出 32 位(4 字节)指令
  2. 指令被解码
  3. 已执行解码指令

因此,当指令在流水线的顶部执行时,正在获取的指令是内存中的两条指令。因此 PC 比正在执行的指令的地址大 8 个字节。

有人知道如何轻松实现该管道吗? 我想我需要为指令重做内存存储,因为它现在只是一个固定大小的数组。 我的想法是对齐内存,然后在每条指令之后将 4 添加到 PC,并通过使用指向数组中第一个元素的指针并将 PC 添加到其中来访问下一条指令。如果这行得通,有人可以告诉我那会是什么样子吗?

【问题讨论】:

  • 不太确定您是否真的需要在模拟器中使用管道 - 除非它是一个周期精确的模拟器。
  • 如果你愿意,你可以准确地模拟管道,但我认为这对于解决这个特定问题没有必要。我在多年前编写的 ARM (v5) 仿真器中所做的类似于instruction = read_word(r15); r15 += 8; decode_and_execute(instruction); r15 -= 4; // point to next instruction。 (所有其他修改 r15 的代码都必须考虑到每条指令后面都有一个减法)
  • 除非你需要自己实现,否则试试qemu

标签: c arm emulation pipeline


【解决方案1】:

您不需要模拟管道。 ARM 已经有一段时间没有在硬件中使用 2-ahead 管道了,他们也模拟了 2-ahead。

我所做的是在任何修改时保持 pc 前一个,然后在 fetch 时我在 pc-4 处获取然后添加 4。任何可以修改 pc 的指令都必须有一个 if pc then pc+= 4.当我计算一个分支 dest 时,我不得不再添加 4 个。为什么我这样做,我不知道。

或者,您可以让 pc 指向当前指令。每次读取电脑时,您都会添加 8 个。这样可能更容易。我使用函数抽象我的指令获取、内存读/写和寄存器读/写,并在 read_register() 函数中添加 if r15 then result+=8;然后返回。

再说一次,我为什么不这样做,我不记得了,我必须破解它才能让它工作。现在现实是我是拇指(v1)模拟器而不是手臂,所以它是+2和+4而不是+4和+8。而且根本没有手臂模式(由我的模拟器支持),所以只有拇指中的几条指令可以实际修改电脑,这样就更容易只针对那些 if reg==15 的指令。

如果你真的想做一个 arm11 模拟器,你需要考虑拇指模式,然后处理 pc 领先 4 或 8,并记住在修改时将 lsbit 从拇指模式中剥离一些必须将 lsbit 设置为切换到或保持拇指模式的指令。幸运的是 arm11 不支持 thumb2 然后它变得非常丑陋,因为它是可变指令长度,你必须提前两条指令,而不仅仅是 4 或 8 个字节(可以提前 4、6 或 8 个字节,你必须将接下来的两条指令解码为在拇指模式下查找)。如果您不想支持拇指模式,您可以轻松地查找在 bx 或 pop 中设置的 lsbit,然后声明您不支持拇指模式并退出。

您的选择是模拟管道,或者您必须插入一个或一些 if reg==15 then... 代码行,并且您必须在使用 pc 的任何地方都这样做(将所有寄存器读取路由到一个函数是一种非常简单的方法)。我应该去修复我的模拟器来做到这一点。如果您最终支持拇指模式,那么您可以简单地说如果在拇指模式下,则在此读取寄存器功能中添加 4 否则添加 8。

【讨论】:

  • 必须记住正确处理 fetch 并且不要获取错误的地址,不要使用 read_register() 函数进行 fetch 或减去 8。
  • 我可能应该在我的问题中添加我不完全确定 PC 应该是什么。它只是指向第一条指令的指针,即数组中的第一个元素吗?那么我只需添加 4、8 等,理论上它应该给我下一条指令?
  • 我想你知道 r15 在执行一条指令时提前两条指令,所以在 arm 模式下提前 8 个字节,它是正在执行的指令的地址 + 8。我做了一个假内存,而不仅仅是数组中的二进制文件,但我认为是内存的数组,不必是 4 gig,通过 mem 读/写函数抽象所有内存访问,然后您可以根据地址将偏移量调整为数组,也许有一个闪存数组单词,一个 ram 字数组...理想情况下,pc 应该是 arm 地址空间中的一个地址,您的 fetch/read/write 函数会根据数组偏移量进行调整
  • 用于该访问。 github.com/dwelch67/thumbulator 我昨晚确实更改了它以调整 read_register() 函数中的 pc,但我没有签入该代码。在模拟器上运行了一些里程,我不想打破它,所以我可能会将昨晚的更改添加到第二个副本或目录中,直到我可以在上面添加更多里程。您可以看到读/写内存功能如何将地址空间分解为 rom、ram 和外围设备。
猜你喜欢
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
相关资源
最近更新 更多