How do emulators work and how are they written?
模拟器如何工作? 当我看到NES / SNES或C64模拟器时,它让我震惊。
您是否必须通过解释其特定的装配说明来模拟这些机器的处理器? 还有什么进入它? 它们通常是如何设计的?
你能为有兴趣编写模拟器(特别是游戏系统)的人提供建议吗?
仿真是一个多方面的领域。以下是基本思想和功能组件。我要把它分成几块,然后通过编辑填写细节。我要描述的许多内容都需要了解处理器的内部工作原理 - 装配知识是必要的。如果我对某些事情有点过于模糊,请提出问题,以便我可以继续改进这个答案。
基本理念:
仿真通过处理处理器和各个组件的行为来工作。您构建系统的每个单独部分,然后像硬件中的电线一样连接这些部分。
处理器仿真:
有三种处理处理器仿真的方法:
通过所有这些路径,您可以拥有相同的总体目标:执行一段代码来修改处理器状态并与"硬件"进行交互。处理器状态是给定处理器目标的处理器寄存器,中断处理程序等的集合体。对于6502,你有许多代表寄存器的8位整数:
通过解释,您可以从
通过动态重新编译,您可以像解释一样迭代代码,但不是仅执行操作码,而是构建操作列表。到达分支指令后,将此操作列表编译为主机平台的机器代码,然后缓存此编译代码并执行它。然后,当您再次点击给定的指令组时,您只需要执行缓存中的代码。 (顺便说一句,大多数人实际上并没有列出指令,而是将它们编译成机器代码 - 这使得优化更加困难,但这超出了这个答案的范围,除非有足够的人感兴趣)
使用静态重新编译时,您可以执行与动态重新编译相同的操作,但是您可以使用分支。您最终构建了一段代表程序中所有代码的代码,然后可以执行这些代码而不会产生进一步的干扰。如果不是出于以下问题,这将是一个很好的机制:
这些结合使得静态重新编译在99%的情况下完全不可行。有关更多信息,Michael Steil对静态重新编译做了一些很好的研究 - 这是我见过的最好的。
处理器仿真的另一面是与硬件交互的方式。这确实有两个方面:
处理器时间:
某些平台 - 尤其是NES,SNES等旧式控制台 - 要求您的仿真器具有完全兼容的严格时序。使用NES,你有PPU(像素处理单元),它要求CPU在精确的时刻将像素放入其内存中。如果使用解释,您可以轻松计算周期并模拟正确的时间;使用动态/静态重新编译,事情是/很多/更复杂。
中断处理:
中断是CPU与硬件通信的主要机制。通常,您的硬件组件会告诉CPU它关心的中断。这非常简单 - 当您的代码抛出给定的中断时,您会查看中断处理程序表并调用正确的回调。
硬件仿真:
模拟给定硬件设备有两个方面:
以硬盘为例。通过创建后备存储,读/写/格式例程等来模拟该功能。这部分通常非常简单。
设备的实际接口有点复杂。这通常是存储器映射寄存器的某种组合(例如,设备监视变化以执行信令的存储器的部分)和中断。对于硬盘驱动器,您可能有一个内存映射区域,您可以在其中放置读取命令,写入等,然后再读取此数据。
我会详细介绍,但有一百万种方法可以用它。如果您有任何具体问题,请随时提问,我会添加信息。
资源:
我想我在这里给了一个很好的介绍,但还有很多其他方面。我很乐意帮助解决任何问题;由于其极大的复杂性,我在大多数情况下都非常模糊。
必需的维基百科链接:
一般仿真资源:
模拟器项目参考:
处理器重新编译参考:
附录:
自提交这个答案以来已经有一年多的时间了,并且已经得到了所有关注,我认为是时候更新一些东西了。
也许现在仿效中最令人兴奋的事情是libcpu,由前面提到的Michael Steil开始。它是一个用于支持大量CPU核的库,它使用LLVM进行重新编译(静态和动态!)。它具有巨大的潜力,我认为它会为仿真做出巨大贡献。
emu-docs也引起了我的注意,它包含了一个很好的系统文档库,这对于仿真来说非常有用。我没有花太多时间在那里,但看起来他们有很多很棒的资源。
我很高兴这篇文章很有帮助,我希望我可以在今年年底/明年年初完成这个问题。
好。
一位名叫Victor Moya del Barrio的人写了关于这个话题的论文。 152页的很多好消息。您可以在此处下载PDF。
如果您不想在scribd注册,可以谷歌搜索PDF标题,"仿真编程技术研究"。 PDF有几个不同的来源。
仿真可能看起来令人生畏,但实际上比模拟更容易。
任何处理器通常都有一个编写良好的规范,用于描述状态,交互等。
如果您根本不关心性能,那么您可以使用非常优雅的面向对象程序轻松模拟大多数旧处理器。例如,X86处理器需要一些东西来维护寄存器的状态(简单),一些东西来维持内存状态(简单),以及一些可以接收每个传入命令并将其应用到机器当前状态的东西。如果你真的想要准确性,你也会模仿内存翻译,缓存等,但这是可行的。
实际上,许多微芯片和CPU制造商针对芯片的仿真器测试程序,然后针对芯片本身进行测试,这有助于他们发现芯片的规格是否存在问题,或者是硬件中芯片的实际实现。例如,可以编写会导致死锁的芯片规范,并且当硬件中出现截止日期时,重要的是看它是否可以在规范中再现,因为这表明比芯片实现中的问题更大的问题。
当然,视频游戏的模拟器通常关心性能,因此它们不使用天真的实现,并且它们还包括与主机系统的OS接口的代码,例如使用绘图和声音。
考虑到旧视频游戏(NES / SNES等)的性能非常低,在现代系统上仿真非常容易。事实上,你可以下载一套有史以来的每一款SNES游戏或任何Atari 2600游戏更令人惊讶,因为当这些系统受欢迎时,可以自由访问每个墨盒,这将是梦想成真。
我知道这个问题有点陈旧,但我想在讨论中加入一些内容。这里的大多数答案都围绕着模拟器解释他们模拟的系统的机器指令。
然而,有一个非常着名的例外,称为"UltraHLE"(WIKIpedia文章)。 UltraHLE是有史以来最着名的模拟器之一,它被广泛认为是不可能的,仿效商用Nintendo 64游戏(在家用电脑上具有不错的性能)。事实上,当UltraHLE诞生时,任天堂仍在为Nintendo 64制作新游戏!
我第一次看到有关印刷杂志中模拟器的文章,之前我只在网上讨论过它们。
UltraHLE的概念是通过模拟C库调用而不是机器级调用来实现不可能的。
值得一看的是Imran Nazar尝试用JavaScript编写Gameboy模拟器。
创建了我自己的80年代BBC微型计算机模拟器(将VBeeb输入Google),有很多事情需要了解。
- 你不是仿效真实的东西,那将是一个复制品。相反,你是在模仿国家。一个很好的例子是计算器,真实的东西有按钮,屏幕,外壳等。但是要模拟计算器,你只需要模拟按钮是向上还是向下,LCD的哪些部分打开等等。基本上,一组数字表示可以在计算器中更改的所有可能的组合。
- 您只需要模拟器的界面出现并表现得像真实的东西。这越有说服力就越接近仿真。幕后发生的事情可以是你喜欢的任何事情。但是,为了便于编写仿真器,在真实系统(即芯片,显示器,键盘,电路板和抽象计算机代码)之间存在心理映射。
- 要模拟计算机系统,最简单的方法是将其分解为更小的块并单独模拟这些块。然后将整批产品串在一起作为成品。就像一组带输入和输出的黑盒子一样,它非常适合面向对象的编程。您可以进一步细分这些块以使生活更轻松。
实际上,您通常希望编写速度和仿真保真度。这是因为目标系统上的软件(可能)运行速度比源系统上的原始硬件慢。这可能会限制编程语言,编译器,目标系统等的选择。
此外,您必须限制您准备模拟的内容,例如,不必模拟微处理器中晶体管的电压状态,但可能需要模拟微处理器寄存器组的状态。
一般来说,仿真的细节程度越小,您对原始系统的保真度就越高。
最后,旧系统的信息可能不完整或不存在。因此,掌握原始设备至关重要,或者至少要撬开别人写的另一个好模拟器!
是的,您必须"手动"解释整个二进制机器代码混乱。不仅如此,大多数时候您还必须模拟一些在目标机器上没有等效物的奇特硬件。
简单的方法是逐个解释说明。这很好,但速度很慢。更快的方法是重新编译 - 将源机器代码转换为目标机器代码。这更复杂,因为大多数指令不会一对一映射。相反,您将不得不进行涉及其他代码的详细解决方案。但最终它要快得多。大多数现代模拟器都这样做。
在开发仿真器时,您将解释系统正在处理的处理器组件(Z80,8080,PS CPU等)。
您还需要模拟系统具有的所有外围设备(视频输出,控制器)。
你应该开始为simpe系统编写模拟器,比如好老的Game Boy(使用Z80处理器,我不是没有误)或者是C64。
Emulator are very hard to create since there are many hacks (as in unusual
effects), timing issues, etc that you need to simulate.
有关此示例,请参阅http://queue.acm.org/detail.cfm?id=1755886。
这也将向您展示为什么您需要一个用于模拟1MHz频率的多GHz CPU。
另外,请查看Darek Mihocka的Emulators.com,获取有关JIT指令级优化的建议,以及构建高效仿真器的许多其他好处。
我从来没有做过任何如此模仿游戏控制台的事情,但我确实参加过一次课程,其任务是为Andrew Tanenbaums Structured Computer Organization中描述的机器编写模拟器。这很有趣,给了我很多时刻。在潜入编写真正的模拟器之前,您可能想要选择该书。
有关模拟真实系统或您自己的事情的建议吗?
我可以说模拟器通过模拟整个硬件来工作。也许没有下到电路(因为移动位像硬件一样。移动字节是最终结果所以复制字节很好)。模拟器非常难以创建,因为您需要模拟许多黑客(如不常见的效果),计时问题等。如果一个(输入)部分错误,整个系统可以关闭或最多有一个错误/故障。
共享源设备模拟器包含PocketPC / Smartphone模拟器的可构建源代码(需要Visual Studio,在Windows上运行)。我在二进制版本的V1和V2上工作过。
它解决了许多仿真问题:
- 从客户虚拟到客户物理到主机虚拟的高效地址转换
- 客户代码的JIT编译
- 模拟外围设备,如网络适配器,触摸屏和音频
- UI集成,用于主机键盘和鼠标
- 保存/恢复状态,用于模拟从低功耗模式恢复
我写了一篇关于用JavaScript模拟Chip-8系统的文章。
这是一个很好的起点,因为系统不是很复杂,但您仍然可以了解操作码,堆栈,寄存器等的工作原理。
我将很快为NES写一篇更长的指南。
添加@Cody Brocious提供的答案
在虚拟化环境中,您要为虚拟机模拟新系统(CPU,I / O等),我们可以看到以下类别的仿真器。
解释:bochs是一个解释器的例子,它是一个x86 PC模拟器,它从客户系统中获取每条指令将其转换为另一组指令(主机ISA)以产生预期的效果。是非常慢,它不是不要缓存任何内容,以便每条指令都经历相同的循环。
动态电子邮件:Qemu是一个动态模拟器。它即时转换客户指令也可以缓存结果。最好的部分是直接在主机系统上执行尽可能多的指令,以便仿真更快。同样如Cody所述,它将代码分成块(1个单独的执行流程)。
静态模拟器:据我所知,没有静态模拟器可以帮助虚拟化。
我将如何开始模拟。
1.获取基于低级编程的书籍,你需要它为任天堂的"假装"操作系统...游戏男孩......
2.专门获取有关模拟的书籍,也许还有开发。 (你不会制作一个操作系统,但最接近它。
3.查看一些开源模拟器,尤其是您想要为其制作模拟器的系统。
4.将更复杂的代码片段复制到IDE / compliler中。这将节省您编写长代码。这是我为os开发所做的,使用linux的一个区