每条指令6502周期计时

6502 cycle timing per instruction

我正在用 C 编写我的第一个 NES 模拟器。目标是使其易于理解和循环准确(尽管不一定必须是代码高效的),以便正常玩游戏 'hardware' 速度。在深入研究 6502 的技术参考时,这些指令似乎消耗了不止一个 CPU 周期 - 并且根据给定条件(例如分支)也有不同的周期。我的计划是创建读写函数,并使用 switch.

通过寻址模式对操作码进行分组

问题是:当我有一个多周期指令时,例如 BRK,我是否需要模拟每个周期中到底发生了什么:

#Method 1

cycle - action

1 - read BRK opcode
2 - read padding byte (ignored)
3 - store high byte of PC
4 - store low byte of PC
5 - store status flags with B flag set
6 - low byte of target address
7 - high byte of target address

...或者我可以只在一个 'cycle'(一个 switch case)中执行所有必需的操作,而在剩余的周期中什么都不做吗?

#Method 2

1 - read BRK opcode,
read padding byte (ignored),
store high byte of PC,
store low byte of PC,
store status flags with B flag set,
low byte of target address,
high byte of target address
2 - do nothing
3 - do nothing
4 - do nothing
5 - do nothing
6 - do nothing
7 - do nothing

既然这两种方法都消耗了想要的7个周期,那么两者就没有区别了吗? (准确度)

我个人认为方法 1 是可行的解决方案,但是我想不出一个合适、简单的方法来实现它...(请帮忙!)

你'need'会吗?这取决于软件。想象一个最简单的例子:

STA (), Y

... 碰巧碰到了硬件寄存器。如果您至少没有按照正确的周期进行写入,那么您就引入了时序缺陷。您正在写入的寄存器将在错误的时间写入。如果它是调色板寄存器之类的东西,而程序员是 运行 光栅效果怎么办?然后你刚刚移动到颜色发生变化的地方。您已经更改了图形输出。

在实践中,聪明的程序员会做比这更聪明的事情——例如人们可能会使用读取-修改-写入操作以精确的周期读取硬件值,修改它,然后在其他精确的周期将其写回。

所以我的答案是:

  1. 大多数软件都没有编写成 (1) 和 (2) 之间的差异会产生任何影响;但是
  2. 肯定是有的,因为作者很聪明;和
  3. 有些肯定是,只是因为作者进行了实验,直到他们发现了一个很酷的效果,而不管他们是否认识到原因;和
  4. 无论如何,当您发现某些东西在您的模拟器上无法正常工作时,您想花多少时间来考虑潜在原因的所有排列组合?每一个你能考虑的因素都少了一个考虑因素。

大多数模拟器曾经使用您的方法 (2)。通常发生的情况是他们使用 90% 的软件。然后有一些情况不起作用,模拟器作者在这里放一个特例,那里放一个特例。这些通常最终会导致交互效果不佳,并且仿真器在其余生中一直在支持 95% 的可用软件的不同组合之间摇摆不定,直到有人编写出更好的软件。

那么就用方法(1)吧。它会导致一些原本会被破坏的软件不会被破坏。它还会教给您更多知识,并且肯定会消除特殊情况的任何潜在动机,从而使您的代码更清晰。它会稍微慢一些,但我认为您的计算机可能可以处理它。

其他提示:6502只有几种寻址方式,寻址方式完全决定了时序。 This document 是您需要知道的完美时机的一切。如果你想要完美的清洁,你的开关table可以选择一个寻址模式和一个中央操作,然后退出,你可以在寻址模式上分支以执行主要操作。

如果您要使用原始 readwrite 方法,这在 6502 上很智能,因为每个周期都是读取或写入,所以这几乎是您需要的全部比如说,只要注意方法签名。例如,6502 有一个 SYNC 引脚,它允许观察者区分普通读取和操作码读取。检查 NES 是否将其公开给盒式磁带,因为它经常用于将其公开以进行隐式分页的系统,并且 NES 的主要识别特征是有数百种分页方案。

编辑:次要更新:

  • 说 6502 总是读或写实际上并不完全正确;它还有一个 RDY 输入。如果 RDY 输入有效且 6502 打算读取,它将暂停,同时保持预期的读取地址。在实践中很少使用,因为它不足以完成常见任务,例如允许其他人占用内存——无论 RDY 输入如何,6502 都会写入,它实际上是为了帮助单步执行——而且似乎不包括在 NES cartridge pinout,你不需要为那台机器实现它。
  • 根据相同的引出线,同步信号似乎也没有暴露给该系统上的磁带。