我正在模拟 6502 处理器,我快完成了(现在处于测试阶段),我正在使用 nesdev 站点的一些 NES 测试,它告诉我中断标志和未使用的第 5 个标志都是最初应该设置为 1(即禁用中断),但为什么呢?我可以理解未使用的标志部分,因为它......嗯......未使用,但我不理解中断标志。我试过在谷歌上搜索,一些网站确认它应该设置为 1,但没有人解释这背后的原因。为什么中断应该从程序开始就被阻止?
2 回答
上电时,状态寄存器中的“未使用”位通过 CPU 的内部电路硬连线为逻辑“1”。它只能是“1”,因为它不受任何内部标志或寄存器控制,而是由与“高”信号线的物理连接确定。
状态寄存器中的“I”标志由 CPU 复位逻辑初始化为“1”,当然可以由“SEI”和“CLI”程序指令以及 CPU 本身修改(例如在 IRQ 期间加工)。默认状态为“1”(因此设置中断禁用标志)的原因是主机系统可以执行启动/重置代码,而无需考虑和安排 IRQ 断言的服务。
许多 6502 主机系统依赖于一些用于 IRQ 和 NMI 断言的外部触发源——通常这将是一个 VIA 或 CIA 配套芯片,由 MOS Technology 专门设计为具有可配置定时器和其他事件响应器的接口适配器,可与 6502 无缝协作响应预定的硬件条件引发中断。这些配套芯片本身需要一些程序驱动的配置,以便将它们设置为已知状态,以便开始监视硬件事件并相应地引发中断。
由于这些芯片可能被硬件初始化为潜在的不确定状态,6502 不希望立即开始服务来自它们的中断,因为这些中断可能完全是虚假的。通过将“I”标志默认设置为“on”,CPU 开始执行其 RESET 程序,因为知道软件可以初始化主机系统的其余部分——包括 VIA 和 CIA 等支持芯片——而不会发生虚假 IRQ在整个系统处于可以处理的状态之前。例如,考虑一个场景,ROM 中的 CPU IRQ 向量指向 RAM 中的间接向量,该间接向量由 RESET 代码初始化为 IRQ 服务例程地址。如果在 RESET 代码初始化 RAM 向量之前发生 IRQ,它几乎肯定会指向一个随机地址(可能但不保证是 0000 美元),并且完全有可能发生系统崩溃。使用默认设置的“I”标志,IRQ 不会发生,直到程序发出“CLI”,这将在 RAM 向量地址已正确初始化以指向有效的 IRQ 服务例程之后。
如果您研究 6502 RESET 代码的常见示例,您将看到用于设置主机环境(包括用于 IRQ 生成的支持芯片定时器寄存器)的一套系统初始化例程的重复主题,然后是“CLI”指令代码所做的最后一件事。大多数环境往往本质上是 IRQ 驱动的,以精确的间隔(例如,每个视频帧一次)做家务和服务例程,因此 RESET 代码以“CLI”结尾,表示初始化(包括 IRQ 生成设置)已完成且 IRQ可以开始维修了。
现在,说了这么多,在 RESET 处理期间的任何时候,如何阻止 NMI 被断言,嗯?CPU 将努力挂起 RESET 程序并跳过 NMI ROM 向量 - 'I' 标志没有效果(正如你所期望的 - NMI 是不可屏蔽的,不能被忽略)。因此,具有讽刺意味的是,尽管“I”标志默认为“1”以保护 RESET 代码免受虚假或过早的 IRQ 的影响,但仍然存在并且始终存在无法阻止虚假 NMI 的可能性,因此可能产生相同的如果向量指向 RAM(直接或间接),则会出现问题。
程序员的任务是找到一种方法来管理这些不合时宜的 NMI,这样即使它们发生了也不会产生任何影响,或者至少不会干扰 RESET 处理。因此,可以说,如果软件必须满足这种情况,那么对 IRQ 做同样的事情并没有太多的努力——这意味着可以从 CPU 初始化电路中删除默认的“I”标志为“1”,或者,NMI 应该被硬连线以在 RESET 期间被忽略。但是,当然,它们不会在所有情况下都是不可屏蔽的,并且您需要在状态寄存器中设置一个特殊的“RESET”标志,您可以清除它来告诉 CPU RESET 处理已完成并且现在可以进行 NMI正常服务。但我离题了。;)
通常一台机器需要在安全地接收中断之前设置它的全局状态。如果最初启用了中断,那么您将永远不会知道在您的中断例程中已初始化什么以及未初始化什么。
所以它是关于允许在事件开始之前强加一个已知状态。
特别是在 NES 上,它可能几乎没有什么区别——内置硬件会生成不可屏蔽的中断,并且在被告知开始之前不会这样做。大多数带有标准中断生成硬件的磁带也需要提前被告知开始生成中断,而不仅仅是在通电时这样做。
但是,此 6502 行为对于该部件是通用的。他们可能试图避免的一个示例问题可能是具有两秒启动时间的系统和产生中断的键盘。中断例程可能会缓冲击键。但是,如果它在系统设置之前尝试这样做,那么它最终可能会将字节写入内存中的随机位置。