我见过一些模拟器声称他们执行,即使他们这样做,他们的源代码显示他们不直接解析每 1 和 0 来确定指令。
我的问题是,如果模拟器必须模拟真实 CPU 的确切操作码,是否不需要解析游戏的正确二进制操作码格式以合法(或根本不需要)模拟 CPU?
例如,在游戏文件中我存储了一条指令,一个字节,标记如下:
0000 1111
Run Code Online (Sandbox Code Playgroud)
我的程序必须验证这条指令确实意味着(例如“向 A 寄存器加一”),但它是否不需要检查文本文件中的每个 0 和 1 以确保这一点?
然后仿真器将解析整个字节,但整个字节同样是 8 位,波动的模式会改变操作输出。
例如,0000 1111 可能意味着将 A 添加到 A,但 0000 1110 可能意味着将 A 与 A 相加。
如果您正在阅读模拟器的源代码,但它没有阅读二进制(可执行)文件的某些位,并且仍在忠实地执行代码,那么可能会出现三种结果:
为另一个平台和/或 CPU(例如,wine)执行代码的模拟器在不同阶段执行操作。有些阶段是模拟器工作绝对需要的;其他阶段是可选的,代表性能优化的可能性。
必需:“解析”可执行代码(机器代码、MSIL、Java 字节码等)解析包括:
要求:将解析出的代码(通常是某种抽象数据模型、状态机、抽象语法树或类似的东西)“翻译”成高级命令(例如 C 或 Java 中的语句)或低级命令命令(例如 x86 处理器的 CPU 指令)。高级命令往往更优化。例如,如果您分析一长串 CPU 指令的代码流并在较高级别确定它要求的是从磁盘播放某个 MP3 文件,您可以跳过整个指令级仿真,而只使用您的本机平台的 MP3 解码器(可能针对您的处理器进行了优化)来播放相同的 MP3 文件。另一方面,如果您要尽可能按字面意思“跟踪”仿真程序的执行,这会更慢且不太理想,因为您将放弃通过本机执行指令而受益的大部分优化。
可选:“优化”和分析大量仿真程序代码或整个程序的代码流,以确定完整的执行顺序,并构建一个非常详细和复杂的模型,说明您的仿真器将如何进行仿真与本机平台的设施的行为。Wine 在一定程度上做到了这一点,但它所翻译的代码是 x86 到 x86 的这一事实有所帮助(这意味着在这两种情况下,CPU 是相同的指令集,所以你所要做的就是连接 Windows代码到基于 UNIX 的外部环境,并让它“本地”运行)。
在考虑模拟器的性能时,请考虑在以下情况下,如果您正在观看某人烤蛋糕的视频(带音频),您需要为自己写下多少张纸的说明:
如果您以前从未动过手或锻炼过身体的任何肌肉;(提示:您需要数千张纸来记录手部运动、手眼协调、角度、速度、位置、抓握、握持器皿、揉捏等基本技术的详细步骤。)
如果您有基本的运动控制能力(您可以自己走路和吃饭),但您以前从未准备过任何食物;(提示:您需要数十张纸来记录各个步骤,并且可能需要大量练习才能掌握诸如揉捏和拿着不熟悉的器皿之类的技巧,但您可以用更少的时间记录下来时间比前一种情况)
如果您以前从未烤过蛋糕,但之前已经做过一些食物准备工作;(提示:您需要几张纸,但不要超过 10 张;您已经熟悉测量成分、搅拌等。)
如果你以前烤过很多次蛋糕,并且非常熟悉这个过程,但你不知道如何烤这种特殊品种/口味的蛋糕(提示:你可能需要半张纸来记下基本的成分和它在烤箱中需要的时间,就是这样)。
基本上,在“模拟器能力”的这些不断提高的水平上,模拟器可以“本地”做更多更高级别的事情(使用它已经知道的例程和过程),并且必须做更少的“跟踪”(使用它是的例程和过程)从字面上遵循模拟程序)。
用计算机术语来做这个类比,你可以想象一个仿真器模拟运行被仿真程序的实际硬件,并忠实地“跟踪”该硬件的行为,甚至可能下至硬件(电路)级别;与将程序分析到如此复杂程度的模拟器相比,这将非常慢,以至于它可以理解何时尝试播放声音文件,并且可以“本机”播放该声音文件而无需跟踪模拟程序的指令所以。
最后一件事:跟踪速度很慢,主要是因为您必须使用大量内存来“复制”您正在模拟的事物的非常详细、复杂的组件,而不仅仅是在主机 CPU 上执行指令,您必须执行指令哪个执行指令(参见间接级别?),这会导致效率低下。如果你全神贯注地模拟计算机系统的物理硬件以及程序,那么你将模拟 CPU、主板、声卡等,这些反过来又会“跟踪”程序的执行情况,就像你的程序一样。模拟器“跟踪”CPU 的执行,并且有这么多级别的跟踪,整个过程将非常缓慢和繁琐。
这是一个详细的示例,其中仿真器不需要读取输入程序的每个位/字节来模拟它。
假设我们知道一个用 C 或 C++ 编写的 API(细节不重要)用于模拟软件环境,该 API 有一个函数void playSound(string fileName)。假设我们知道这个函数的语义是打开磁盘上的文件,读取它的内容,找出文件的编码(MP3?WAV?别的什么?),然后在扬声器上播放它普通/预期采样率和音高。如果我们从本机代码中读取一组指令,上面写着“进入 playSound 例程开始播放声音/home/hello/foo.mp3”,我们可以在那里停止读取程序代码,并使用我们自己的(优化!)本机打开该声音文件并播放它的例程。我们是否需要在指令级别上遵循仿真处理器?不,我们真的不知道,如果我们相信我们知道 API 的作用的话。
当然,通过读取一堆指令并“推断”一个高级执行计划,如上面的示例所示,您可能会冒着可能无法精确模拟在原始硬件上运行的原始程序的行为的风险。例如,原始硬件可能有硬件限制,只能同时播放 8 个声音文件。那么,如果您的新电脑可以同时播放 128 个声音文件就好了,并且您正在playSound高水平地模拟例程,那么有什么能阻止您一次播放 8 个以上的声音文件呢?这可能会导致...在程序的模拟版本中出现奇怪的行为(无论好坏)。这些情况可以通过仔细测试来解决,或者可以通过非常了解原始执行环境来解决。
例如,DOSBox 有一个特性,可以让你故意限制模拟的 DOS 程序的执行速度,因为如果让它们全速运行,某些 DOS 程序会运行不正确;它们实际上取决于 CPU 时钟频率以预期速度执行的时间。这种有意限制执行环境的“特性”可用于在执行的忠实度(即,使仿真程序正常工作)和执行效率(即,构建程序的表示)之间提供良好的折衷。足够高,可以通过最少的跟踪有效地模拟)。
| 归档时间: |
|
| 查看次数: |
643 次 |
| 最近记录: |