仿真是一个多方面的领域。以下是基本思想和功能组件。我将把它分成几部分,然后通过编辑填写详细信息。我要描述的许多事情都需要了解处理器的内部工作原理——汇编知识是必要的。如果我对某些事情有点含糊不清,请提出问题,以便我继续改进此答案。
基本思路:
仿真通过处理处理器和各个组件的行为来工作。您构建系统的每个单独部分,然后像硬件中的电线一样连接这些部分。
处理器仿真:
处理处理器仿真的三种方式:
通过所有这些路径,您有相同的总体目标:执行一段代码来修改处理器状态并与“硬件”交互。处理器状态是给定处理器目标的处理器寄存器、中断处理程序等的集合。对于 6502,您将有多个 8 位整数表示寄存器:A、X、Y、P 和 S;你还有一个 16 位的 PC 寄存器。
通过解释,您从IP(指令指针——也称为PC,程序计数器)开始并从内存中读取指令。您的代码解析此指令并使用此信息来更改处理器指定的处理器状态。解释的核心问题是它非常慢。每次处理给定指令时,都必须对其进行解码并执行必要的操作。
通过动态重新编译,您可以像解释一样对代码进行迭代,但您不仅可以执行操作码,还可以构建一个操作列表。一旦到达分支指令,您就可以将此操作列表编译为主机平台的机器代码,然后缓存此编译代码并执行它。然后,当您再次点击给定指令组时,您只需执行缓存中的代码。 (顺便说一句,大多数人实际上并没有列出指令,而是将它们即时编译为机器代码——这使得优化变得更加困难,但这超出了这个答案的范围,除非有足够多的人感兴趣)
使用静态重新编译,您执行的操作与动态重新编译相同,但您遵循分支。您最终构建了代表程序中所有代码的代码块,然后可以在没有进一步干扰的情况下执行这些代码。如果没有以下问题,这将是一个很好的机制:
- 开始时不在程序中的代码(例如压缩、加密、在运行时生成/修改等)不会被重新编译,因此不会运行
- 已证明在给定二进制文件中查找所有代码等同于Halting problem
这些结合在一起,使得静态重新编译在 99% 的情况下完全不可行。有关更多信息,Michael Steil 对静态重新编译进行了一些出色的研究——这是我所见过的最好的。
处理器仿真的另一面是您与硬件交互的方式。这确实有两个方面:
处理器时序:
某些平台(尤其是 NES、SNES 等较旧的控制台)要求您的模拟器具有严格的时序才能完全兼容。使用 NES,您拥有 PPU(像素处理单元),它要求 CPU 在精确的时刻将像素放入内存中。如果您使用解释,您可以轻松地计算周期并模拟正确的时间;使用动态/静态重新编译,事情会变得/很多/更复杂。
中断处理:
中断是 CPU 与硬件通信的主要机制。通常,您的硬件组件会告诉 CPU 它关心什么中断。这很简单——当你的代码抛出一个给定的中断时,你查看中断处理程序表并调用正确的回调。
硬件仿真:
模拟给定硬件设备有两个方面:
以硬盘驱动器为例。通过创建后备存储、读/写/格式化例程等来模拟功能。这部分通常非常简单。
设备的实际界面要复杂一些。这通常是内存映射寄存器(例如,设备监视更改以执行信令的内存部分)和中断的某种组合。对于硬盘驱动器,您可能有一个内存映射区域,您可以在其中放置读取命令、写入等,然后将这些数据读回。
我会更详细地介绍,但您可以使用一百万种方法。如果您在此处有任何具体问题,请随时提出,我会添加信息。
资源:
我认为我在这里给出了很好的介绍,但还有 吨 其他领域。我很乐意为您解答任何问题;由于极其复杂,我对其中的大部分内容都非常模糊。
必填维基百科链接:
通用仿真资源:
-
Zophar -- 这是我开始仿真的地方,首先下载仿真器并最终掠夺他们庞大的文档档案。这是您可能拥有的绝对最佳资源。
-
NGEmu -- 直接资源不多,但他们的论坛是无与伦比的。
-
RomHacking.net -- 文档部分包含有关流行控制台机器架构的资源
仿真器项目参考:
-
IronBabel -- 这是一个 .NET 的仿真平台,用 Nemerle 编写,可即时将代码重新编译为 C#。免责声明:这是我的项目,请原谅无耻的插件。
-
BSnes -- 一个很棒的 SNES 模拟器,目标是循环完美的准确性。
-
MAME -- 街机模拟器。很好的参考。
-
6502asm.com -- 这是一个 JavaScript 6502 模拟器,带有一个很酷的小论坛。
-
dynarec'd 6502asm -- 这是我在一两天内做的一个小技巧。我从 6502asm.com 获取了现有的模拟器并将其更改为将代码动态重新编译为 JavaScript 以大幅提高速度。
处理器重新编译参考:
附录:
自从提交此答案以来已经有一年多的时间了,并且受到了所有关注,我认为是时候更新一些东西了。
也许现在仿真中最令人兴奋的事情是libcpu,由前面提到的 Michael Steil 发起。它是一个旨在支持大量 CPU 内核的库,这些内核使用 LLVM 进行重新编译(静态和动态!)。它有巨大的潜力,我认为它会为仿真做很多事情。
emu-docs 也引起了我的注意,它包含一个很棒的系统文档存储库,这对于仿真目的非常有用。我在那里的时间不多,但看起来他们有很多很棒的资源。
我很高兴这篇文章对我有所帮助,我希望我能在今年年底/明年年初之前完成我关于这个主题的书。