Hacker News 中文摘要

RSS订阅

Donkey Kong Country 2 and Open Bus

文章摘要

《大金刚国度2》在旧版SNES模拟器ZSNES中存在一个广为人知的bug,导致某些关卡中的旋转木桶无法正常工作。玩家无法通过方向键控制木桶的旋转,而是使其无限旋转,增加了游戏难度。该bug由ZSNES未正确模拟“开放总线”行为引起,尽管在其他模拟器中已修复,但ZSNES项目已长期停更,此bug始终未得到解决。

文章总结

文章主要讨论了在旧版SNES模拟器ZSNES中,《Donkey Kong Country 2》游戏中的一个已知bug,即某些关卡中的旋转桶无法正常工作。以下是文章的主要内容总结:

1. Bug描述

  • 在ZSNES模拟器中,玩家进入旋转桶后,本应通过按左右方向键控制桶的旋转,但在ZSNES中,按下方向键后桶会一直旋转,直到按下相反方向键才会反向旋转。
  • 这个bug使得相关关卡的难度大大增加,因为后续关卡中的旋转桶通常出现在尖刺等危险区域上方。

2. Bug原因

  • 该bug是由于ZSNES没有正确模拟“开放总线行为”(open bus behavior)导致的。开放总线行为是指当CPU读取无效内存地址时,通常会返回数据总线上最后的值。
  • 在《Donkey Kong Country 2》中,游戏代码会从无效地址$2000读取数据,正常情况下应返回0x2020,但在ZSNES中,由于没有模拟开放总线行为,导致读取的值不正确,从而引发桶的无限旋转。

3. 代码分析

  • 文章详细分析了游戏代码中处理旋转桶逻辑的部分。代码通过读取$2000地址的值,并结合当前桶的旋转方向和速度来决定是否停止旋转。
  • 在正常情况下,读取$2000地址会返回0x2020,这个值用于判断桶是否到达某个特定方向。如果读取的值不正确,逻辑判断会失效,导致桶无法停止旋转。

4. 修复方法

  • 文章指出,这个bug可能是由于代码中的拼写错误导致的。原本应该是使用立即寻址模式(and #$2000),但实际使用了绝对寻址模式(and $2000)。
  • 通过将ROM中的操作码从0x2D(绝对寻址)改为0x29(立即寻址),可以修复这个bug,即使在没有模拟开放总线行为的模拟器中也能正常工作。

5. 历史背景

  • 这个bug在ZSNES中从未修复,而ZSNES项目自2007年以来已经停止更新。相比之下,另一个SNES模拟器Snes9x在20年前就修复了类似的bug。
  • 文章作者出于学术兴趣,深入研究了这个问题,并最终确认了bug的根本原因。

6. 结论

  • 尽管这个bug在ZSNES中仍然存在,但几乎所有其他SNES模拟器都已经正确处理了开放总线行为,因此玩家在其他模拟器上不会遇到这个问题。
  • 文章的研究主要是为了满足作者的好奇心,但也为理解SNES硬件和模拟器开发提供了有价值的见解。

总结来说,文章详细探讨了《Donkey Kong Country 2》在ZSNES模拟器中的一个旋转桶bug,分析了其根本原因,并提出了修复方法,同时回顾了相关的历史背景和技术细节。

评论总结

  1. 对代码解释的欣赏

    • 评论1:作者喜欢这种结合汇编代码和文字解释的方式,认为它帮助理解代码,并享受发现经典软件中未被注意的漏洞的故事。
      "Love stuff like this, I feel like I’m only ever 60% following the assembly code, so the prose explanation alongside really helps."
    • 评论7:作者非常喜欢这类内容,认为这是他在HN上最喜欢的部分。
      "I love this sort of content! My favorite things I find on HN :D"
  2. 6502汇编编程中的常见错误

    • 评论2:作者作为6502汇编程序员,经常遇到忘记在立即值前加#的问题,导致意外的内存访问,这种情况有时会偶然工作。
      "I have wasted many hours of my life tracking down the same issue in my code (forgetting to put an # in front of an immediate value)."
    • 评论5:作者提到6502汇编中常见的错误是使用内存地址而不是立即值,并指出Rare公司的开发者也曾犯过同样的错误。
      "It’s a very common and easy mistake to make, and i believe Chuck Peddle himself deeply regretted the #$1234 syntax for immediate values."
  3. 经典游戏的持久魅力

    • 评论3:作者认为《大金刚国度2》在30年后仍然表现出色,图形、音效、关卡设计和控制都非常出色。
      "For a 30-year-old video game, it’s remarkable how well DK Country 2 holds up today."
    • 评论10:作者提到《大金刚国度1》使用SGI预渲染3D图形是当时的前沿技术,而《Vector Man》在Genesis上也做了类似的事情。
      "DKC 1 with the SGI prerendered 3d graphics was cutting edge stuff."
  4. 模拟器中的潜在问题

    • 评论4:作者在模拟器中玩游戏时,常常怀疑是否遇到了模拟器的bug,或者游戏本身设计得很难。
      "Whenever I’m playing a game via emulation and I get stuck, I do end up wondering if it’s a bug in the emulator."
    • 评论9:作者在开发RetroArch的RunAhead功能时,遇到了SNES《Puyo Puyo》的PPU开放总线问题,导致状态加载后值不匹配。
      "CPU execution trace logs didn’t match because a value read out of PPU Open Bus didn’t match after loading state."
  5. 开放总线(Open Bus)的解释与影响

    • 评论6:作者最初以为“Open Bus”是某种总线协议,后来意识到它指的是总线未连接任何设备的情况,并指出使用立即寻址模式可以加快代码执行速度。
      "It’s pretty funny that the omission of the immediate mode (#) went unnoticed until the obsolete emulator didn’t behave in the same way as the real hardware."
    • 评论8:作者详细解释了开放总线的物理原理,指出它是未驱动总线时的电容效应,并提到一些游戏和速通策略依赖开放总线行为。
      "Open bus quite literally means that the data bus lines are an open circuit -- the CPU has placed an unmapped or write-only address on the address bus."
  6. 其他编程中的类似问题

    • 评论12:作者在编程Parallax Propeller芯片时,经常忘记在跳转指令中使用#,导致跳转到错误的内存地址,这种错误有时会偶然工作。
      "I always forget to write JMP #address (which jumps to the specified memory location) and write JMP address instead."