1

我打算写一个nes模拟器。但首先,要了解仿真的工作原理,我将编写一个 Chip-8 仿真器。

模拟器快完成了。我在游戏中有一些错误,但很快就会修复。我的问题 1 是将仿真器与 Chip-8 的时钟速度同步。在我经常阅读的互联网上,一般时钟速度应该是〜540Hz。芯片的定时器应以 60Hz 的频率计时。

为了使我的模拟器与 Chip-8 同步,我编写了以下逻辑:

private void GameTick()
{
    Stopwatch watch = new Stopwatch();
    var instructionCount = 0;
    _gameIsRunning = true;

    while (_gameIsRunning)
    {
        watch.Restart();

        EmulateCycle();

        //Updates the internal timer at a 60hz frequenz
        //540hz (game tick) divided by 9 equals 60hz (timer tick)
        instructionCount++;
        if(instructionCount == 9)
        {
            UpdateSoundAndDelay();
            instructionCount = 0;
        }

        if (_readyToDraw)
        {
            DrawGraphics();
            _readyToDraw = false;
        }

        SetKeys();

        //Pause the game to get a virtual clock speed of ca. 540mhz
        var elapsedMicroseconds = watch.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));    
        while(elapsedMicroseconds < 1852)
        {
            elapsedMicroseconds = watch.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
        }     
    }
}

有关更多详细信息,请查看我的仓库:https ://github.com/Marcel-Hoffmann/Chip-8-Emulator

如您所见,对于每个 cpu 周期,我将等待 1852 微秒。结果将是每秒约 540 个周期,等于 540Hz。但我对这个逻辑不是很满意。

有人有更好的想法,如何同步时钟速度?

4

1 回答 1

2

这是典型的方法,并且有许多缺点 - 最值得注意的是,不必要的 CPU 使用和潜在的调度问题(您的应用程序将被视为 100% CPU 野兽,因此其他应用程序可能会在您负载之前获得它们的线程量)。

更好的方法是使用睡眠来代替 - 但是,默认情况下,系统计时器的频率远不及适应小于 2 毫秒的等待的频率。因此,如果您想使用睡眠,则需要更改系统计时器。这在较旧的 Windows 上有点棘手(它是系统范围的设置,对其他应用程序和一般 CPU 使用率有显着影响),但即使在这种情况下,它也比“忙循环”要好——只要你恢复系统之后的设置。在 Windows 8(在某种程度上,7 和 Vista)上,计时器是异步的,不再需要繁忙的循环,因此更容易获得更高的计时器分辨率。

.NET 不公开系统计时器 API,因此您需要使用 P/Invokes(timeBeginPeriod以及timeEndPeriod旧式 API)。如果这不可用,您可以随时退回到繁忙的循环:)

于 2016-05-27T12:06:40.927 回答