模拟器如何工作?当我看到 NES/SNES 或 C64 模拟器时,我感到很震惊。

http://www.tommowalker.co.uk/snemzelda.png

您是否必须通过解释其特定的汇编指令来模拟这些机器的处理器?还有什么内容呢?它们通常是如何设计的?

您能为有兴趣编写模拟器(特别是游戏系统)的人提供任何建议吗?

有帮助吗?

解决方案

仿真是一个多方面的领域。以下是基本思想和功能组件。我将把它分成几部分,然后通过编辑填写详细信息。我要描述的许多内容都需要处理器内部工作原理的知识——组装知识是必要的。如果我对某些事情有点太模糊,请提出问题,以便我可以继续改进这个答案。

基本思想:

仿真通过处理处理器和各个组件的行为来工作。您构建系统的每个单独部分,然后将各个部分连接起来,就像硬件中的电线一样。

处理器仿真:

处理处理器模拟的方法有以下三种:

  • 解释
  • 动态重新编译
  • 静态重新编译

通过所有这些路径,您有相同的总体目标:执行一段代码来修改处理器状态并与“硬件”交互。处理器状态是给定处理器目标的处理器寄存器、中断处理程序等的集合。对于 6502,您将有许多代表寄存器的 8 位整数: A, X, Y, P, , 和 S;你还有一个 16 位的 PC 登记。

通过解释,您可以从 IP (指令指针——也称为 PC, ,程序计数器)并从内存中读取指令。您的代码解析此指令并使用此信息来更改处理器指定的处理器状态。解释的核心问题是 非常 慢的;每次处理给定的指令时,您都必须对其进行解码并执行必要的操作。

通过动态重新编译,您可以像解释一样迭代代码,但您不只是执行操作码,而是构建操作列表。一旦到达分支指令,您就可以将此操作列表编译为主机平台的机器代码,然后缓存此编译后的代码并执行它。然后,当您再次命中给定的指令组时,只需执行缓存中的代码即可。(顺便说一句,大多数人实际上并没有制作指令列表,而是将它们即时编译为机器代码——这使得优化变得更加困难,但这超出了这个答案的范围,除非有足够多的人感兴趣)

使用静态重新编译,您可以执行与动态重新编译相同的操作,但是您遵循分支。您最终会构建代表程序中所有代码的代码块,然后可以在没有进一步干扰的情况下执行该代码。如果没有以下问题的话,这将是一个很好的机制:

  • 最初不在程序中的代码(例如压缩、加密、运行时生成/修改等)不会被重新编译,因此它不会运行
  • 已经证明,查找给定二进制文件中的所有代码相当于 停机问题

这些因素结合在一起使得静态重新编译在 99% 的情况下完全不可行。有关更多信息,Michael Steil 对静态重新编译做了一些出色的研究——这是我所见过的最好的研究。

处理器模拟的另一方面是与硬件交互的方式。这确实有两个方面:

  • 处理器时序
  • 中断处理

处理器时序:

某些平台——尤其是较旧的游戏机,如 NES、SNES 等——要求您的模拟器具有严格的时序才能完全兼容。对于 NES,您拥有 PPU(像素处理单元),它要求 CPU 在精确的时刻将像素放入内存中。如果您使用解释,您可以轻松计算周期并模拟正确的计时;使用动态/静态重新编译,事情会变得更加复杂。

中断处理:

中断是CPU与硬件通信的主要机制。一般来说,您的硬件组件会告诉 CPU 它关心什么中断。这非常简单——当您的代码引发给定中断时,您将查看中断处理程序表并调用适当的回调。

硬件仿真:

模拟给定的硬件设备有两个方面:

  • 模拟设备的功能
  • 模拟实际设备接口

以硬盘驱动器为例。通过创建后备存储、读/写/格式化例程等来模拟该功能。这部分通常非常简单。

设备的实际接口有点复杂。这通常是内存映射寄存器的某种组合(例如设备监视变化以进行信号发送的内存部分)和中断。对于硬盘驱动器,您可能有一个内存映射区域,您可以在其中放置读取命令、写入等,然后读回该数据。

我会更详细地介绍,但是您可以使用一百万种方法。如果您在这里有任何具体问题,请随时询问,我将添加信息。

资源:

我想我已经在这里给出了很好的介绍,但是还有一个 的额外区域。我非常乐意帮助解决任何问题;由于极其复杂,我对其中大部分内容都非常模糊。

强制性维基百科链接:

通用仿真资源:

  • 琐法 ——这就是我开始仿真的地方,首先下载仿真器,最终掠夺他们巨大的文档档案。这绝对是您所能拥有的最好的资源。
  • NGEmu -- 直接资源不多,但他们的论坛是无与伦比的。
  • ROM黑客网 -- 文档部分包含有关流行控制台的机器架构的资源

模拟器项目参考:

  • 铁巴别塔 -- 这是一个 .NET 仿真平台,用 Nemerle 编写,可即时将代码重新编译为 C#。免责声明:这是我的项目,所以请原谅无耻的插件。
  • BSnes -- 一款出色的 SNES 模拟器,其目标是实现完美的循环精度。
  • 玛梅 -- 街机模拟器。很好的参考。
  • 6502asm.com -- 这是一个 JavaScript 6502 模拟器,带有一个很酷的小论坛。
  • Dynarec'd 6502asm ——这是我在一两天内完成的一个小技巧。我从 6502asm.com 获取了现有的模拟器,并将其更改为动态地将代码重新编译为 JavaScript,从而大幅提高速度。

处理器重新编译参考:

  • Michael Steil(上面提到的)对静态重新编译的研究最终在 这张纸 你可以找到来源等 这里.

附录:

自从提交这个答案以来已经过去了一年多了,随着它所受到的关注,我认为是时候更新一些东西了。

也许现在仿真中最令人兴奋的事情是 库CPU, ,由前面提到的迈克尔·斯泰尔发起。它是一个旨在支持大量 CPU 内核的库,它使用 LLVM 进行重新编译(静态和动态!)。它具有巨大的潜力,我认为它将为仿真做出巨大的贡献。

emu-文档 它还引起了我的注意,其中包含一个很大的系统文档存储库,这对于仿真目的非常有用。我在那里呆的时间不多,但看起来他们有很多很棒的资源。

我很高兴这篇文章对我有所帮助,我希望我能在今年年底/明年初完成我关于这个主题的书。

其他提示

一个名叫维克多·莫亚·德尔·巴里奥(Victor Moya del Barrio)的人就这个主题写了他的论文。152 页有很多很好的信息。您可以下载 PDF 这里.

如果您不想注册 抄写, ,您可以通过谷歌搜索 PDF 标题, 《仿真编程技术的研究》. 。PDF 有几个不同的来源。

仿真可以令人望而生畏但实际上比模拟相当容易。

任何处理器通常具有描述状态,相互作用等良好的书面说明书

如果你不关心性能的话,那么你可以很容易地使用非常优雅的面向对象的程序模仿最旧的处理器。例如,X86处理器将需要的东西来保持寄存器(容易),东西保持的存储器(易)的状态下,和一些会采取每个传入命令并将其应用到该机器的当前状态的状态。如果你真的想要的准确性,也将效仿内存转换,缓存,等等,但是这是可行的。

事实上,许多芯片和CPU制造商的测试程序对芯片的仿真器,然后对芯片本身,这有助于他们了解是否有芯片的规格问题,或在实际执行芯片在硬件中。例如,可以写一个芯片规格将导致死锁,当一个最后期限在硬件发生时,看它是否能够在说明书中复制,因为这表示比在芯片实现一些更大的问题是很重要的。

当然,对于视频游戏模拟器通常关心的表现让他们不要用幼稚的实现,它们还包括与主机系统的OS接口,例如使用绘图和音码。

考虑到旧的视频游戏很慢的性能(NES / SNES等),模拟是现代系统很容易。事实上,它甚至更令人惊奇的是,你可以只下载了一组每SNES游戏有史以来或任何雅达利2600游戏有史以来的考虑,当这些系统很受欢迎不必每个墨盒免费接入将是一个梦想成真。

创建了我自己的 80 年代 BBC 微型计算机模拟器(在 Google 中输入 VBeeb)后,有很多事情需要了解。

  • 你并不是在模仿真实的东西,那只是一个复制品。相反,你正在模仿 状态. 。一个很好的例子是计算器,真实的计算器有按钮、屏幕、外壳等。但要模拟计算器,您只需要模拟按钮是向上还是向下、LCD 的哪些部分打开等。基本上,一组数字代表计算器中可以更改的所有可能的组合。
  • 您只需要模拟器的界面就可以像真实的东西一样出现和运行。越有说服力,仿真就越接近。幕后发生的事情可以是您喜欢的任何事情。但是,为了便于编写模拟器,真实系统之间会发生心理映射,即芯片、显示器、键盘、电路板和抽象的计算机代码。
  • 要模拟计算机系统,最简单的方法是将其分成更小的块并单独模拟这些块。然后把所有的东西串起来就是成品。很像一组带有输入和输出的黑匣子,非常适合面向对象编程。您可以进一步细分这些块以使生活更轻松。

实际上,您通常希望为仿真的速度和保真度而编写。这是因为目标系统上的软件(可能)比源系统上的原始硬件运行得更慢。这可能会限制编程语言、编译器、目标系统等的选择。
除此之外,您必须限制您准备模拟的内容,例如,不一定要模拟微处理器中晶体管的电压状态,但可能有必要模拟微处理器的寄存器组的状态。
一般来说,仿真的细节级别越小,原始系统的保真度就越高。
最后,旧系统的信息可能不完整或不存在。因此,掌握原始设备至关重要,或者至少欣赏其他人编写的另一个优秀模拟器!

是的,你有“手”来解释整个二进制机器码混乱。不仅如此,大部分的时间你还必须模拟不具有在目标机器上的等效一些外来的硬件。

在简单的方法是解释指令的一个接一个。这工作得很好,但它的速度慢。更快的方法是重新编译 - 转换源的机器代码到目标机器代码。这是更复杂,因为大多数指令不会映射一个对一个。相反,你将不得不作出精心的变通涉及额外的代码。但最终它的速度更快。大多数现代仿真器做到这一点。

  

仿真器是很难创建,因为有许多黑客(如在异常   效果),定时,你需要模拟的问题,等等。

有关这方面的一个例子,请参见 http://queue.acm.org/detail .CFM?ID = 1755886

这也将告诉你为什么你“需要”多1GHz的CPU用于模拟1MHz的一个。

还检查了Darek Mihocka的 Emulators.com 了解关于即时编译器指令级的优化非常好的建议,和许多其他东西构建高效的仿真器。

我从来没有做过任何事情那么花哨,以模拟游戏机,但其中的作业是写在安德鲁Tanenbaums的构造的计算机组织。这很有趣的给了我很多啊哈时刻。您可能要选择在跳水之前预订到写一个真正的模拟器。

在模拟真实的系统或你自己的事忠告? 我可以说,模拟器通过模拟整个硬件工作。也许不是下到电路(如走动位像汉王会做。移动字节是最终结果,以便复制字节是罚款)。模拟器是很难建立,因为有许多黑客(如不寻常的效果),定时,你需要模拟的问题,等等。如果一个(输入)块是错误的,整个系统可以做向下或充其量有一个错误/故障。

共享源设备仿真包含可建源代码的掌上电脑/智能手机仿真器(需要Visual Studio中,运行在Windows上)。我制作的二进制版本的V1和V2。

有很多铲球仿真问题: - 从客户机虚拟有效地址转换到宾客物理托管虚拟 - JIT的客人代码编译 - 外围设备,如网络适配器,触摸屏和音频的模拟 - UI集成,主机键盘和鼠标 - 保存/状态的恢复,用于从低功率模式恢复的模拟

要添加由@Cody Brocious结果,所提供的答案 在虚拟化你在哪里模拟一个新的系统(CPU,I / O等)到虚拟机的上下文中,我们可以看到仿真器以下几类。

解读:bochs的是解释器的一个例子,它是一个86 PC模拟器,它需要从客系统的每个指令转换它在另一组指令的以产生预期effect.Yes这是非常慢(主机ISA的) ,所以每一个指令经历相同的周期它不缓存任何东西。

动态emalator:QEMU是一个动态的仿真器。它还对客户指令的动态翻译还缓存results.The最好的部分是直接在主机系统上执行的许多指令尽可能使仿真速度更快。也如由科迪提到的,划分码成块(执行1个单流)。

静态仿真器:据我知道有没有静态仿真器,它可以在虚拟化有帮助。

我将如何开始仿真。

1.Get根据各地底层编程的书,你会需要它为任天堂的“假装”操作系统...游戏的孩子......

2.注册了仿真书籍而言,也许OS开发。 (你将不会作出的OS,但最接近它。

下面做1.In在一些开源模拟器,尤其是你想为一个仿真系统的人。

4.copy的更复杂的代码的片段到IDE / compliler。这将节省您写了很长的代码。这是我对操作系统做开发,用linux的分区

scroll top