仿真器如何工作以及它们是如何编写的?
仿真器如何工作? 当我看到NES / SNES或C64仿真器时,令我震惊。
你是否必须通过解释其特定的汇编指令来模拟这些机器的处理器? 还有什么呢? 他们通常如何设计?
你可以给有兴趣编写模拟器(特别是游戏系统)的人提供任何建议吗?
仿真是一个多面的区域。 这里有基本的想法和功能组件。 我将把它分解成几部分,然后通过编辑来填写细节。 我要描述的许多事情都需要知道处理器的内部运作 - 组装知识是必要的。 如果我对某些事情有点太模糊,请提出问题,以便我可以继续改进此答案。
基本理念:
仿真通过处理处理器和各个组件的行为来工作。 您可以构建系统中的每个单独部分,然后将这些部分连接成与硬件中的导线相似的部分。
处理器仿真:
处理处理器仿真有三种方式:
通过所有这些路径,您都有相同的总体目标:执行一段代码来修改处理器状态并与“硬件”进行交互。 处理器状态是针对给定处理器目标的处理器寄存器,中断处理程序等的集合。 对于6502,你会有一些代表寄存器的8位整数: A
, X
, Y
, P
和S
; 你也有一个16位的PC
寄存器。
通过解释,您可以从IP
(指令指针 - 也称为PC
,程序计数器)开始,并从内存中读取指令。 您的代码解析此指令并使用此信息来更改处理器指定的处理器状态。 解释的核心问题是速度很慢, 每次处理给定的指令时,都必须解码并执行必要的操作。
通过动态重新编译,您可以像解释一样遍历代码,但不是只执行操作码,而是建立一个操作列表。 一旦你到达一个分支指令,你将这个操作列表编译成你的主机平台的机器代码,然后你缓存这个编译后的代码并执行它。 然后,当您再次访问给定的指令组时,您只需从缓存中执行代码。 (顺便说一下,大多数人实际上并没有列出指令列表,但将它们编译为机器代码 - 这使得优化变得更加困难,但这不在这个答案的范围内,除非有足够的人感兴趣)
通过静态重新编译,您可以在动态重新编译中执行相同的操作,但您需要遵循分支。 您最终构建了一段代码,该代码代表了程序中的所有代码,然后可以在没有进一步干扰的情况下执行代码。 如果不是针对以下问题,这将是一个很好的机制:
这些结合在99%的情况下使静态重新编译完全不可行。 有关更多信息,Michael Steil对静态重新编译做了一些很好的研究 - 我见过的最好的。
处理器仿真的另一方面是与硬件交互的方式。 这确实有两个方面:
处理器时间:
某些平台 - 特别是像NES,SNES等老式控制台 - 需要您的模拟器具有严格的时序才能完全兼容。 在NES中,您有PPU(像素处理单元),它要求CPU在精确时刻将像素放入内存中。 如果你使用解释,你可以很容易地计算周期和模拟正确的时间; 通过动态/静态重新编译,事情是/很多/更复杂。
中断处理:
中断是CPU与硬件通信的主要机制。 一般来说,你的硬件组件会告诉CPU它关心什么中断。 这很简单 - 当你的代码抛出一个给定的中断时,你查看中断处理程序表并调用正确的回调函数。
硬件仿真:
模拟给定的硬件设备有两个方面:
以硬盘驱动器为例。 通过创建后备存储,读/写/格式例程等来模拟功能。这部分通常非常简单。
该设备的实际接口稍微复杂一点。 这通常是存储器映射寄存器(例如,设备监视变化以进行信号发送的存储器的部分)和中断的一些组合。 对于硬盘驱动器,您可能有一个内存映射区,您可以在其中放置读取命令,写入等,然后读取此数据。
我会详细介绍一下,但有一百万种方法可以与之配合。 如果您有任何具体问题,请随时询问,我将添加信息。
资源:
我想我在这里给出一个很好的介绍,但有一吨的其他领域。 我很乐意帮助解决任何问题。 大部分情况下,我一直非常模糊,仅仅是由于巨大的复杂性。
强制维基百科链接:
一般仿真资源:
模拟器项目引用:
处理器重新编译参考:
附录:
自从这个答案提交以来,已经过去了一年多时间,并且在获得所有的关注之后,我认为是时候更新一些东西了。
也许现在最激动人心的是libcpu,由前面提到的Michael Steil开始。 这是一个旨在支持大量CPU内核的库,它们使用LLVM进行重新编译(静态和动态!)。 它具有巨大的潜力,我认为它会为模拟做很棒的事情。
emu-docs也引起了我的注意,它提供了一个很好的系统文档库,这对于仿真目的非常有用。 我没有花太多时间在那里,但看起来他们有很多很棒的资源。
我很高兴这篇文章对我有帮助,我希望我能在年底/明年初完成我的书。
一个名叫维克托莫亚德尔巴里奥的人写了他关于这个话题的论文。 在152页上有很多很好的信息。 你可以在这里下载PDF。
如果你不想在scribd注册,你可以在谷歌的PDF标题,“研究仿真编程技术”。 PDF有几种不同的来源。
仿真看起来令人生畏,但实际上比仿真更容易。
任何处理器通常都有精心编写的规范来描述状态,交互等。
如果您根本不关心性能,那么您可以使用非常优雅的面向对象程序轻松模拟大多数较旧的处理器。 例如,X86处理器需要一些东西来保持寄存器的状态(简单),维持内存状态(简单),以及将每个传入命令应用到机器当前状态的东西。 如果你真的想要精确性,你也可以模拟内存翻译,缓存等,但这是可行的。
事实上,很多微芯片和CPU制造商都会针对芯片的仿真器测试程序,然后对芯片本身进行测试,这有助于他们发现芯片规格或硬件芯片的实际应用是否存在问题。 例如,可以编写一个会导致死锁的芯片规范,并且在硬件中出现最后期限时,重要的是要看它是否可以在规范中复制,因为这意味着比芯片实现中的问题更大的问题。
当然,视频游戏的模拟器通常关心性能,因此他们不使用天真的实现,并且还包括与主机系统的操作系统交互的代码,例如使用绘图和声音。
考虑到旧视频游戏(NES / SNES等)的性能非常低,现代系统上的仿真非常容易。 事实上,更令人惊讶的是,你可以下载一系列每日SNES游戏或任何Atari 2600游戏,因为当这些系统受欢迎时,可以自由访问每个盒式磁带将梦想成真。
链接地址: http://www.djcxy.com/p/8921.html上一篇: How do emulators work and how are they written?
下一篇: .NET String.Format() to add commas in thousands place for a number