Donkey Kong Country 2와 Open Bus

13 hours ago 4

  • Donkey Kong Country 2의 회전하는 배럴 버그는 ZSNES 에뮬레이터에서 발생함
  • ZSNES는 open bus 동작을 제대로 에뮬레이션하지 않아, 배럴이 영구적으로 회전하는 문제 발생함
  • 실제 하드웨어와 달리 ZSNES에서 잘못된 메모리 접근 시 0이 항상 반환되어 버그 유발함
  • 올바른 동작에서는 배럴이 정확한 방향(8방향)에서 회전을 멈추는 로직
  • 이 문제는 코딩상의 사소한 실수(즉, 즉시 주소 지정 대신 절대 주소 지정 사용)에서 비롯된 것으로 추정됨

Donkey Kong Country 2와 ZSNES 에뮬레이터의 배럴 버그

Donkey Kong Country 2는 ZSNES라는 오래된 SNES 에뮬레이터에서 일부 스테이지의 회전하는 배럴(통)이 제대로 작동하지 않는 유명한 버그가 있음

배럴에 들어가면, 원래는 방향키 좌/우를 누르고 있는 동안만 배럴이 회전해야 하지만, ZSNES에서는 좌/우를 짧게 눌러도 배럴이 계속 그 방향으로 영원히 회전하게 됨

이 버그로 인해, 특히 나중 스테이지에서 가시밭이나 장애물 위에 나타나는 회전 배럴 구간이 개발자가 의도한 것보다 훨씬 어렵게 변함

이 문제는 과거 ZSNES 포럼에서 어느 정도 문서화되어 있었으나, 현재 포럼이 사라져 관련 자료를 찾기 어려움

버그의 원인 - Open Bus Emulation

이 버그의 근본 원인은 ZSNES가 open bus 동작을 에뮬레이션하지 않는 데 있음

  • open bus는 SNES와 같은 구형 플랫폼에서 무효 메모리 주소 읽기 시 발생하는 동작임
  • 실제 하드웨어에서는 마지막에 버스에 올린 값이 반환됨
  • SNES의 주요 CPU는 65C816(65816)임
  • 65816은 16비트 버전 6502이며, 24비트 주소 버스를 가지고, 메모리 뱅킹 방식을 사용함

DKC2의 회전 배럴 코드에서, 유효하지 않은 주소(Bank $B3의 $2000, $2001) 접근 시, 하드웨어에서는 open bus로 0x2020 값이 반환됨

ZSNES에서는 이 기능이 없기 때문에 항상 0이 반환되어 버그가 발생함

게임 코드의 동작 방식

회전 배럴과 관련된 게임 루틴은 다음과 같은 동작흐름을 가짐

  • 현재 배럴의 방향과 회전량(속도)을 합산하여 임시 변수에 저장함
  • XOR 연산으로 방향의 변화를 측정하고, 그 결과를 open bus에서 읽은 값과 AND 연산함
  • 그 AND 결과가 0이면 회전을 계속, 0이 아니면 멈추고, 방향을 8방향 중 하나로 반올림하여 정렬함

실제 하드웨어에서는 open bus 값이 0x2020이지만, 만약 0이 반환되면 회전이 무한히 계속됨

이 로직은 원래 AND 연산이 즉시값(address #$2000) 와 해야 하는데, 실수로 절대주소(address $2000) 를 사용했다는 점이 추정됨

하지만 하드웨어의 open bus 특성상, 실제로는 두 방식 모두 정상 동작함

해결 및 결론

Snes9x 같은 다른 SNES 에뮬레이터는 이 버그를 하드코딩 방식으로 픽스했으며, ZSNES는 개발 중단으로 패치되지 않음

해당 루틴에서 AND 명령어의 오퍼코드를 0x2D에서 0x29(AND #$2000)로 바꿀 경우, open bus 동작 없이도 회전 배럴이 정상 작동

이 문제는 실제 하드웨어나 최신 에뮬레이터에서는 발생하지 않음

결국, 이 버그는 open bus 에뮬레이션 미지원코딩 실수가 만나 발생한 예시임


추가 배경: 65816 구조와 SNES 메모리 맵

65816 CPU는 24비트 주소 버스를 가지고 있으나, 주로 8비트 뱅크와 16비트 오프셋 조합을 사용함

  • 프로그램 카운터(PC)는 16비트, 프로그램 뱅크 레지스터(PBR, K)로 전체 주소 구성
  • 데이터 뱅크(DBR, B)는 데이터 연산용 뱅크 선택에 사용됨
  • 하드웨어 스택과 direct page는 항상 $00뱅크에 존재함

SNES 메모리 맵도 65816을 기반으로 설계되어 주소를 8비트 뱅크+16비트 오프셋으로 생각하는 것이 더 효율적임

마무리

이 사례는 레거시 하드웨어의 특성(open bus 등)이 에뮬레이션에서 기대하지 않은 버그로 이어질 수 있음을 보여줌

개발자는 즉시 주소 지정을 사용해야 했지만, 우연히 절대주소도 정상 동작했던 사례임

현대에서는 open bus 동작까지 에뮬레이션하는 것이 구형 소프트웨어의 정확한 재현에 매우 중요함을 시사함

Read Entire Article