안녕하세요?
두번째 글로 인사드립니다. 스팀잇에서 자주 다뤄지는 주제와는 많이 동떨어져 있지만, 그래도 꾸준히 튜토리얼을 이어나가려 합니다. 나중에라도 필요한 분들에게 좋은 자료로 사용되어졌으면 좋겠어요 ^^&
패미컴 (or NES) 게임 한글화 튜토리얼 #01
오늘의 튜토리얼에서는 롬의 확장방법을 본격적으로 알아보겠습니다.
패미컴롬의 확장을 위해서 먼저 iNES 헤더를 이해하는 것이 선행되어야 합니다. 이 이후의 글에서 16진수의 값에는 (h)를 10진수의 값에는 (d) 를 붙여 구분하겠습니다.
iNES 헤더는 10(h) Byte의 데이타 Set 으로 롬에 관한 정보를 담고있습니다. 패미컴 카트리지 (=우리가 후후불어 사용하던 팩)에는 PRG ROM and/or CHR ROM + Mapper 가 있을 뿐 iNES 헤더는 포함되어있지 않습니다. 즉, 이 10(h) Byte의 iNES 헤더는 *.nes 파일에만 존재하는 테이타로 현재는 규격화 되어 nes 파일의 가장 앞부분에 포팅되어있습니다.
*.nes File = 10(h) Byte iNES 헤더 + PRG ROM + (CHR ROM, 맵퍼에 따라 생략가능)
위와 같이 nes 확장자를 가지는 롬파일들이 같은 규격을 사용하기 때문에 NES 에뮬레이터들은 iNES 헤더의 정보를 이용하여 다양한 맵퍼를 사용하는 롬들을 실기와 비슷하게 구동할 수 있는 것이죠. 에뮬레이터 마다 지원하는 맵퍼가 다르므로 몇몇 게임들은 특정 에뮬레이터에서만 실행되기도 합니다만, 요즘은 에뮬레이터마다 비슷한 게임 구동률을 보입니다...언제적 패미컴입니까.. ㅎㅎㅎ
예제로 삼은 "스위트 홈"의 첫 10(h) Byte (=iNES 헤더) 를 살펴보면 다음과 같습니다.
00000(h): 4E 45 53 1A *10 *00 12 00 00 00 00 00 00 00 00
왼쪽부터 차례로 0번 Byte ~ 15번 Byte라 하며 디테일한 iNES 헤더 정보는 이곳 링크에서 확인하실 수 있습니다. 다만, 폰트확장에서 필요한 부분은 보통은 4번 Byte와 5번 Byte로 각각은 다음의 의미를 가집니다,
위의 헤더정보를 분석해보면, 스위트홈은 10(h)개의 16 KB PRG ROM, 즉 16(d) x 16 KB = 256 KB 의 PRG ROM을 가지며 0개의 8KB CHR ROM(=CHR ROM 이 없다는 것은 이 게임이 CHR RAM을 사용한다는 것을 의미)을 가집니다. "스위트홈.NES" 롬파일의 용량이 256KB가량 나오는 이유가 이것 때문이죠.
iNES 헤더의 5번 Byte에서 알 수 있듯이, 스위트홈의 경우 CHR ROM을 사용하지 않고 CHR RAM을 사용합니다. 따라서 스위트홈 롬파일을 512KB로 확장 하고자 하려면 10(h)개의 16 KB PRG ROM이 더 필요하게 되는 것이죠.
즉, 다음과 같이 iNES 헤더의 4번 Byte를 20(h)으로 교체해 주는 것이 롬 확장의 첫 과정이 됩니다. 여기까지 완료하면 에뮬레이터는 "아... 이 롬은 32(d)개의 16KB PRG ROM 을 가지고 있구나..." 고 생각하고 처리하게 되는것이죠.
00000(h): 4E 45 53 1A *20 00 12 00 00 00 00 00 00 00 00
위의 과정을 완료하고 에뮬레이터를 통해서 롬을 실행시키면 각종 에러를 뿜으면서 멈춰버립니다. 에뮬레이터는 32(d)개의 16KB PRG ROM을 가지고 있을거라고 생각하지만 실제로 롬은 16(d)개의 PRG ROM을 가지고 있기 때문입니다. 따라서 HEX에디터를 통해서 더미데이타 (=FF)를 40000(h)개 만큼 추가시켜 주어야합니다. 즉 256KB 만큼의 FF 더미데이타를 추가시켜 주는 것이죠. 이 과정을 자동으로 수행하는 프로그램은 이글의 마지막 부분에 다뤄질 예정입니다.
40000(h) = 262144(d) bytes = 256 KB (1024 bytes = 1KB)
2.3.1 NES CPU 메모리 맵
이 부분을 이해하려면 NES 하드웨어의 CPU 메모리 맵을 전반적으로 이해하고 있어야 합니다.
Fig 1 - NES CPU 메모리 맵
위의 그림에서 알 수 있듯이 NES CPU는 $0000~$7FFF 까지의 RAM/Register 영역과 $8000~$FFFF까지의 ROM 영역으로 이루어져 있습니다. 여기서 ROM 영역은 PRG ROM 혹은 CHR ROM으로 이루어져 있으며 각각 16KB (총 32KB)의 테이타가 두 부분 ($8000~$BFFF, $C000~$FFFF) 으로 나뉘어서 CPU에 로드됩니다.
스위트 홈 nes 롬은 256KB (= $3FFFF)의 데이타를 가지고 있는데 NES CPU는 그 중 32KB의 데이타만 한번에 로드하고 엑세스 할 수 있는것이죠. 여기서 16KB 데이타 뭉치를 뱅크(Bank)라고 합니다.
맵퍼의 역할은 적재적소에 롬 내부의 데이타를 CPU메모리로 로드하는 것입니다. 이러한 데이타 수정 코드(=뱅크교환 루틴)는 주로 $C000~$FFFF (Upper Bank)부분에 존재하기 때문에 이 부분은 게임이 로드된 이후 뱅크교환 없이 계속 CPU에 상주하게 됩니다.
즉 Upper Bank에 게임 구동에 필요한 필수 코드(메인 루틴, NMI, etc.) 들을 넣어두고, Lower Bank 만 필요에 따라 교환하면서 게임이 진행되는 것이죠.
2.3.2 SUROM (512KB) 구동 방식
앞선 챕터에서 NES 하드웨어는 256KB의 롬을 구동 할 때 그 중 16KB는 Upper Bank 에 고정하고 나머지 16KB를 상황에 따라 번갈아 가면서 Lower Bank 에 로드함으로써 게임을 구동한다고 배웠습니다. 그럼 우리가 롬을 512KB로 확장을 하면 같은 방식으로 구동될까요?
아.닙.니.다 - 이 고전 게임기의 성능을 과대평가 하면 안되요!
이 경우에 NES 하드웨어는 512KB의 롬을 두개의 256KB 롬이 합쳐진 상태로 인식합니다. 즉 두개의 개별적인 256KB의 게임들이 한 카트리지에 있는 것으로 인식하지요. 따라서 1번 256KB가 구동되고 있을 때 2번 256KB에 있는 데이타는 접근이 안됩니다 (데이타뱅크 교환이 안됩니다). 먼저 1번 256KB를 2번 256KB로 바꾼 후에야 비로소 2번 256KB에 있는 데이타에 접근 할 수 있는 것이죠.
앞서서 각종 필수 프로그램코드가 들어있는 16KB의 데이타는 Upper Bank 에 고정된다고 했으니까, 1번 256KB (00~0F번 뱅크)를 2번 256KB (10~1F번 뱅크)로 바꾸는 코드도 마지막 뱅크에 저장되어 있겠죠. 게임을 부팅하면 1번 256KB가 처음으로 로드가 되므로 Upper Bank 에 고정되는 마지막 뱅크는 0F번 뱅크입니다 (1번 256KB는 00~0F번 16KB 뱅크로 구성). 즉 0F번 뱅크에는 각종 프로그램 코드가 담겨져 있는 것이죠. 여기서 2번 256KB (2번 256KB는 10~1F번 16KB 뱅크로 구성)로 변경하는 프로그램을 수행하면 이제 마지막 뱅크가 1F 되는데 여기에는 아직 아무 정보가 안담겨있죠.
게임이 멈춥니다.
이런 이유로 마지막 뱅크 (0F) 를 (1F)로 복사하는 과정이 필요한 것이죠. 즉, $3C000~$3FFFF까지의 데이타를 더미를 추가해 확장된 롬의 $7C000~$7FFFF 부분으로 복사하시면 됩니다.
2.4.1 ROM Expander Pro.txt 파일 작성 방법
그렇습니다. 이 과정을 자동으로 수행할 수 있는 프로그램이 있지요. 이곳 에서 다운로드 받으실 수 있습니다. 이 프로그램의 사용방법은 프로그램 내부에 자세하게 나와있습니다만, 간단히 설명하면,
앞서 설명된 모든 과정을 한번에 완료하는 텍스트파일의 예제를 첨부하면서 설명을 마무리 하겠습니다. 생각보다 구조가 복잡해서 프로그램 내부의 설명서를 자세히 읽어보셔야 할 것 같네요.
Fig.2 - Rom expander 예제
아무튼 여기까지 해서 롬의 확장을 마쳤네요. 오늘은 설명이 너무 길었습니다. 일단 업로드 하고 몇번 수정을 거쳐야 다른분들이 읽고 적용하시기가 쉬워질 듯 싶네요.
조만간, 3편으로 찾아뵙겠습니다.