模拟器是如何工作的?当我看到NES / SNES或C64模拟器时,我感到惊讶。
您是否需要通过解释其特定的汇编指令来模拟这些机器的处理器?还有哪些因素需要考虑?它们通常是如何设计的?
针对有兴趣编写模拟器(尤其是游戏系统)的人,您能给出一些建议吗?
模拟器是如何工作的?当我看到NES / SNES或C64模拟器时,我感到惊讶。
您是否需要通过解释其特定的汇编指令来模拟这些机器的处理器?还有哪些因素需要考虑?它们通常是如何设计的?
针对有兴趣编写模拟器(尤其是游戏系统)的人,您能给出一些建议吗?
这些组合使得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标题,"Study of the techniques for emulation programming"。有几个不同的来源提供PDF。
模拟可能看起来令人生畏,但实际上比模拟要容易得多。
任何处理器通常都有一个写得很好的规范,描述了状态、交互等等。
如果你完全不关心性能,那么你可以使用非常优雅的面向对象程序轻松地模拟大多数旧处理器。例如,X86处理器需要维护寄存器状态(容易)、维护内存状态(容易),以及将每个传入的命令应用于当前机器状态的一些东西。如果你真的想更精确,你还可以模拟内存转换、缓存等等,但这是可行的。
事实上,许多微芯片和CPU制造商会针对芯片的仿真器和芯片本身进行测试,这有助于找出芯片规格或硬件实现中的问题。例如,编写一个芯片规格可能会导致死锁,在硬件中发生截止时间时,重要的是要看是否可以在规格中重现它,因为这表示比芯片实现中的某些问题更大的问题。
当然,视频游戏的仿真器通常关注性能,所以他们不使用幼稚的实现,并且他们还包括与主机系统的操作系统交互的代码,例如使用绘图和声音。
考虑到旧视频游戏(NES/SNES等)的非常缓慢的性能,现代系统上的仿真相当容易。事实上,即使是下载每个SNES游戏或任何Atari 2600游戏的一组,也是很神奇的,考虑到这些系统流行时,免费获得每个游戏卡带将是一个梦想成真。
我知道这个问题有点老,但我想为这个讨论添加一些内容。这里大多数答案都集中在模拟器解释它们模拟的系统的机器指令方面。
然而,有一个非常著名的例外叫作 "UltraHLE" (WIKIpedia文章)。UltraHLE 是有史以来最著名的模拟器之一,在很多人认为不可能的情况下,在家用电脑上模拟商业任天堂64游戏时表现良好。事实上,当 UltraHLE 被创建时,任天堂仍在为 Nintendo 64 制作新游戏!
第一次,我看到了关于模拟器的文章出现在印刷杂志上,而以前我只在网上看到过它们被讨论。
UltraHLE 的概念是通过模拟 C 库调用而不是机器级别的调用来实现不可能的任务。
有值得一看的内容是Imran Nazar在JavaScript中尝试编写Gameboy模拟器。
我自己创建了80年代BBC微型计算机的仿真器(在Google中搜索VBeeb),这里有几个需要知道的事情。
实际上,你通常会考虑模拟的速度和精度。这是因为目标系统上的软件可能比源系统上的原始硬件运行得更慢。这可能会限制编程语言、编译器和目标系统的选择等问题。
此外,你必须确定你准备模拟什么,例如并非需要模拟微处理器中晶体管的电压状态,但很可能需要模拟微处理器的寄存器集合的状态。
一般来说,模拟的细节越小,对原系统的仿真就越精确。
最后,旧系统的信息可能不完整或根本不存在。因此,获取原始设备至关重要,或者至少解开其他人编写的良好仿真器!
是的,您必须手动解释整个二进制机器代码混乱的内容。而且大多数时候,您还需要模拟一些在目标机器上没有相应硬件的奇特硬件。
简单的方法是逐个解释指令。这种方法效果很好,但速度很慢。一种更快的方法是重新编译 - 将源机器代码转换为目标机器代码。这更加复杂,因为大多数指令不会一一映射。相反,您将不得不制定涉及额外代码的精心解决方案。但最终它的速度要快得多。大多数现代仿真器都是这样做的。
... --- ...
- 这三个莫尔斯码代表了三个字母S、O、S。”因为 ...
是代表字母“S”的一种编码。不行吗? - Vilx-当您开发一个模拟器时,您需要解释系统正在运行的处理器汇编语言(Z80、8080、PS CPU等)。
您还需要模拟系统拥有的所有外围设备(视频输出,控制器)。
您应该首先为像经典的Game Boy(使用Z80处理器,我没有搞错吧)或C64这样的简单系统编写模拟器。
模拟器的创建非常困难,因为需要模拟许多黑科技(即不寻常的效果)、时序问题等。
关于这一点,请参见http://queue.acm.org/detail.cfm?id=1755886。
这也将向您展示为什么模拟1MHz CPU需要多GHz的CPU。