关于模拟CPU时的循环计数精度的问题

时间:2011-08-19 14:21:12

标签: emulation z80 cpu-cycles

我计划在未来几个月内创建一个Sega Master System模拟器,作为Java中的一个爱好项目(我知道它不是最好的语言,但我发现它很舒服,并且作为一个Windows和Linux的频繁用户我认为跨平台应用程序会很棒)。我的问题是关于循环计数;

我查看了另一个Z80模拟器的源代码,以及其他模拟器,特别​​是执行循环引起了我的兴趣 - 当它被调用时,一个int作为参数传递(让我们说1000作为一个参数)例)。现在我得到每个操作码执行不同的循环次数,并且当执行这些循环时,循环次数从总体数字减少。一旦剩余的周期数<= 0,执行循环结束。

我的问题是,这些仿真器中的许多都没有考虑到最后一条要执行的指令可以将周期数推到负值的事实 - 这意味着在执行循环之间,最终可能会说,执行1002个循环而不是1000.这是重要的吗?一些仿真器通过补偿下一个执行循环来解决这个问题,有些则不能 - 哪种方法最好?请允许我说明一下我的问题,因为我并不擅长将自己放在一边:

public void execute(int numOfCycles) 
{ //this is an execution loop method, called with 1000.
   while (numOfCycles > 0)
   {
      instruction = readInstruction();
      switch (instruction)
      {
         case 0x40: dowhatever, then decrement numOfCycles by 5;
         break; 
         //lets say for arguments sake this case is executed when numOfCycles is 3.
      }
}

在这个特定的循环示例结束后,numOfCycles将为-2。这只会是一个小小的不准确,但在人们的经历中总体上是否重要?我很欣赏任何人对这一点的见解。我计划在每帧之后中断CPU,因为这似乎合适,所以1000个周期很低我知道,这只是一个例子。

非常感谢, 菲尔

3 个答案:

答案 0 :(得分:5)

  1. 大多数处理CPU时钟抽搐的模拟器/模拟器

    这对游戏等很好......所以你有一些计时器或者什么都可以运行CPU的模拟,直到CPU模拟计时器的持续时间。然后它会一直睡到下一个定时器间隔。这很容易模拟。您可以通过您询问的方法减少计时错误。但正如这里所说的游戏通常是不必要的。

    这种方法有一个显着的缺点,那就是你的代码只是实时的一小部分。如果定时器间隔(定时粒度)足够大,即使在游戏中也是如此。例如,您在仿真睡眠时及时点击键盘键,然后未检测到。 (键有时候不起作用)。您可以通过使用较小的时序粒度来解决这个问题,但这在某些平台上非常困难。在这种情况下,定时误差可以更多&#34;可见&#34;在软件中生成声音(至少对那些能听到它并且对我这样的事情没有聋的人来说是这样的。)

  2. 如果您需要更复杂的内容

    例如,如果您想将真实硬件连接到您的仿真/模拟,那么您需要模拟/模拟BUS&#39。系统的浮动总线争用之类的东西很难添加到#1 (这是可行的但是很痛苦)。< / p>

    如果将时间和仿真移植到机器周期,事情变得更加容易,突然之间出现争用或硬件中断等问题,浮动BUS正在解决自己的问题几乎靠自己。我将我的ZXSpectrum Z80仿真器移植到这种时序并看到了光。很多事情都很明显(比如Z80操作码文档中的错误,时间等)。此外,争用变得非常简单(只需几行代码而不是几乎每个指令类型条目的可怕解码表)。硬件模拟也很容易我用这种方式添加了像FDC控制器AY芯片仿真到Z80的东西(没有黑客它真正运行在他们的原始代码上......甚至软盘格式:))所以没有更多的TAPE加载hacks而不是工作对于像TURBO这样的自定义加载器

    为了完成这项工作,我创建了 Z80 的仿真/模拟,其方式是对每条指令使用微码。因为我经常纠正 Z80 指令集中的错误(因为没有单一的100%正确的文档,我知道即使其中一些人声称他们没有bug并且完整)我带来了如何处理它而不用痛苦地重新编程模拟器。

    每条指令由表中的条目表示,其中包含有关时序,操作数,功能的信息......整个指令集是所有指令的所有这些条目的表。然后我为我的指令集形成一个MySQL数据库。并为我找到的每个指令集形成类似的表。然后痛苦地比较所有选择/修复错误和正确的错误。结果将导出到单个文本文件,该文件在仿真启动时加载。这听起来很可怕但实际上它简化了很多事情甚至加速了仿真,因为指令解码现在只是访问指针。可在此处找到指令集数据文件示例What's the proper implementation for hardware emulation

  3. 几年前我也发表了关于这方面的论文(遗憾的是,机构认为会议不再存在,所以服务器在那些旧报纸上表现不错,幸运的是我仍然得到了副本)所以这里描述了问题的图像:

    CPU Scheduling

    • a)Full throtlle 没有原始速度同步
    • b)#1 导致硬件同步问题存在较大差距
    • c)#2 需要以非常小的粒度进行大量睡眠(可能会出现问题且速度慢下来)但是指令的执行非常接近实时...
    • 红线是主机CPU处理速度(显然上面的内容需要花费更多时间,因此应该在下一条指令之前剪切并插入但是很难正确绘制)
    • Magenta line是仿真/模拟CPU处理速度
    • 交替green/blue颜色代表下一条指令
    • 两个轴都是时间

答案 1 :(得分:2)

最近关于Arstechnica的一篇关于控制台模拟的文章是一篇非常有趣的文章,也链接到很多模拟器,可能会有很好的研究:

Accuracy takes power: one man's 3GHz quest to build a perfect SNES emulator

相关的一点是作者提到的,我倾向于同意,即使时间偏差为+/- 20%,大多数游戏似乎都能正常运行。您提到的问题看起来可能永远不会引入超过一小部分时间错误,这可能是在玩最终游戏时难以察觉的。作者可能认为不值得处理。

答案 2 :(得分:0)

我想这取决于你希望你的模拟器有多准确。我不认为它必须那么准确。想想仿真x86平台,有很多处理器变体,每个都有不同的执行延迟和发布率。