如果你已经阅读了我的另一个问题,你就会知道我本周末花了6502 CPU模拟器作为编程练习.
CPU模拟器大部分是完整的,并且从我的有限测试看起来相当准确,但它运行速度非常快,我想把它降低到机器的实际时钟速度.
我目前的测试循环是这样的:
// Just loop infinitely. while (1 == 1) { CPU.ClockCyclesBeforeNext--; if (CPU.ClockCyclesBeforeNext <= 0) { // Find out how many clock cycles this instruction will take CPU.ClockCyclesBeforeNext = CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].CpuCycles; // Run the instruction CPU.ExecuteInstruction(CPU.Memory[CPU.PC]); // Debugging Info CPU.DumpDebug(); Console.WriteLine(CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength); // Move to next instruction CPU.PC += 1 + CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength; } }
如您所知,每个操作码需要一段特定的时间才能完成,所以在我倒计时CPU周期时,我不会运行下一条指令.这提供了操作码之间的适当时序,它只是整个事情快速运行.
目标CPU的速度是1.79mhz,但是我想要时钟问题的任何解决方案,即使我增加了复杂性,也要保持1.79mhz的速度,所以我不需要调整它.
有任何想法吗?
我多年前写了一个Z80仿真器,为了循环准确执行,我将时钟速率分成许多小块,核心执行了很多个时钟周期.在我的情况下,我把它绑定到我正在模拟的游戏系统的帧速率.每个操作码都知道执行了多少个周期,并且核心将继续运行操作码,直到执行了指定的周期数.我有一个外部运行循环,它将运行cpu核心,并运行模拟系统的其他部分,然后休眠直到下一次迭代的开始时间.
编辑:添加运行循环的示例.
int execute_run_loop( int cycles ) { int n = 0; while( n < cycles ) { /* Returns number of cycles executed */ n += execute_next_opcode(); } return n; }
希望这可以帮助.
查看原始的quicktime文档以获取灵感.
它是很久以前写的,当时显示的视频只是以足够高的速度交换静止帧,但苹果公司认为他们需要一个完整的时间管理框架.该设计最初看起来过度设计,但它让它们处理各种不同的速度要求并使它们保持紧密同步.
你很幸运,6502具有确定性的时间行为,每个指令所用的确切时间都有详细记录; 但它并不是一成不变的.一些指令需要2个周期,其他3.就像QuickTime中的帧一样,视频没有"每秒帧数"参数,每个帧都表示它想要在屏幕上显示多长时间.
由于现代CPU是如此不确定,并且多任务操作系统甚至可以冻结几毫秒(虚拟内存!),如果您落后于计划,或者如果您可以休息几微秒,则应该保留一个选项卡.
正如jfk所说,最常用的方法是将CPU速度与(模拟)视频输出的垂直刷新联系起来。
选择每个视频帧要运行的周期数。这通常是特定于机器的,但是您可以通过以下方式进行计算:
cycles = clock speed in Hz / required frames-per-second
然后,您也要入睡,直到点击视频更新为止,这时您将开始接下来的n个CPU仿真周期。
如果您要特别模拟某些东西,则只需查找fps速率和处理器速度即可大致正确。
编辑:如果您没有任何外部时序要求,那么仿真器尽可能快地运行是正常的。有时这是理想的效果,有时不是:)