Post

Exploring Animal Crossing's NES/FDS Emulation

Introduction

The standard NES emulator present within Animal Crossing is actually one of Nintendo’s most accurate emulators, proving to be more accurate to original hardware than their own NES Classic Edition and Nintendo Switch’s emulators. This emulator is typically called in-game when a player interacts with certain NES furniture items in-game. These items load one specific game only and have their corresponding game rendered on top of the NES. However, in 2018, James Chambers discovered that the emulator is also called when interacting with a special bare NES item. This item actually calls the GameCube’s memory card and searches for NES ROM files to load on the emulator.

This page aims to be a more complete public release of various notes I had about the emulator present within Animal Crossing.

Filesystem

Animal Crossing's Filesystem Animal Crossing’s (GAFE01) Filesystem

The most important files for Animal Crossing’s NES emulator lie inside famicom.arc. This is an archive format that can be extracted using a .arc extractor. Once extracted, the ROMs that the game loads via furniture items are present in /game/01/. These games are as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
01_nes_cluclu3.bin.szs
02_usa_balloon.nes.szs
03_nes_donkey1_3.bin.szs
04_usa_jr_math.nes.szs
05_pinball_1.nes.szs
06_nes_tennis3.bin.szs
07_usa_golf.nes.szs
08_punch_wh.nes.szs
09_usa_baseball_1.nes.szs
10_cluclu_1.qd.szs
11_usa_donkey3.nes.szs 
12_donkeyjr_1.nes.szs
13_soccer.nes.szs
14_exbike.nes.szs
15_usa_wario.nes.szs
16_usa_icecl.nes.szs
17_nes_mario1_2.bin.szs
18_smario_0.nes.szs
19_usa_zelda1_1.nes.szs

.szs is a file extension used by Nintendo in many of their games, typically referring to files compressed using the Yaz0 encoding. .szs is only a file extension, however, and not a file format.

It is worthy to note that all games here are standard North American .nes or .bin ROMs with the sole exception of 10_cluclu_1.qd.szs which is a .qd ROM. This is actually a ROM for the Famicom Disk System, which was a Japanese-exclusive peripheral for the Famicom. Games for this peripheral usually come as .fds files, but Nintendo is notorious for using .qd instead. This game specifically is an updated version of Clu Clu Land, localized as “Clu Clu Land D” (for “Disk”). Since the Famicom Disk System is a peripheral not included on the base NES, it requires a special BIOS to be loaded in order to play. This BIOS is present in Animal Crossing as noise.bin.szs and gets loaded specifically to play Clu Clu Land D.

Calling The Emulator

As mentioned in the introduction, there are two ways to access Animal Crossing’s emulator in-game. One of them is through the standard furniture items with the games on top, and the other is through the “blank” NES item. Despite these two different methods, the emulator is the exact same, it’s just called in different ways.

Game-Specific Furniture Items

Game-Specific NES

For the game-specific NES items, the function aMR_FamicomEmuCommonMove is called when the player interacts with one. This function checks a register value (r6) that corresponds to each of the 19 games listed above. When this register is non-zero, it simply starts the emulator through the function aMR_RequestStartEmu and loads the corresponding game.

The “Blank” NES

"Blank" NES

The “blank” NES item works similarly to the game-specific ones, but is a lot more complex after the initial call. As you might expect, interacting with this item calls the function aMR_FamicomEmuCommonMove with an r6 register value of zero since it does not correspond to one specific game. This sparks a series of complicated calls and functions to scan the GameCube’s memory card for ROM files.

Loading ROM Files on the Memory Card

When you interact with the “blank” NES, the game eventually scans the memory card through the function AMR_GetCardFamicomCount which tracks if there are any ROMs present in memory. If this function returns non-zero, the game will call famicom_get_disksystem_titles and memcard_game_list, which will mount the memory card. This function specifically looks for data with the strings "GAFE01", which is Animal Crossing’s internal name, and the prefix "DobutsunomoriP_F_". These strings must be present and act as a sort of “header” for the game ROM to be recognized by Animal Crossing. If these titles are correct, their titles will appear in the game’s UI when interacting with the NES item. Animal Crossing’s base code is actually fully capable of handling multiple ROMs and even has proper menuing and error messaging. Upon selecting a title, the game will call famicom_rom_load and begin the ROM loading process.

Structuring the Save File

While the game does scan for the memory card for ROMs, it is a highly specialized process designed specifically for Animal Crossing. First, since the games need to be stored on the GameCube memory card, they must be stored in a .gci save file. Cuyler has created a wonderful program, complete with a GUI executable, to automatically structure this save file for you based off a ROM input. You can find his ACNESCreator program here. This save file structure is detailed below.

The heading data of the save file must contain the following:

  • The ASCII text GAFE01 which is Animal Crossing’s internal game name at the start of the file.
  • The ASCII text DobutsunomoriP_F_. This is ideally appended with four characters describing the game on the save. So, a ROM of Super Mario Bros 3. could contain the text DobutsunomoriP_F_SMB3. This naming convention is leftover from the Japanese version of the game, どうぶつの森.
  • The ASCII text Animal Crossing starting at offset 0x00000040.
  • The ASCII text NES Game:/n followed by the game name. The game name cannot be more than 16 ASCII characters.
  • A specific checksum detailed in the next section.
  • Certain NES tags detailed in NES Tags section.

Example Example of a correct save file header

Checksum

There are several checksums, but the most important and the one required for the card to run is handled by the function calcSum.

When a save file is found and a ROM is loaded, this function gets called and serves as an algorithm that sums up all the bytes in the memory card data and checks the lower eight bits of the result. This check must return zero to pass. Thus, in order to pass this check, all the bytes in the save must be summed and added to an additional value that causes the lower eight bytes of this sum to be zero. Once this is done, including this value as a checksum byte at the end of the file suffices to pass the checksum.

The Python code below, sampled by James Chambers, performs this checksum calculation for you.

1
2
3
4
5
6
7
checksum = 0
for byte_val in new_data_tmp:
    checksum += byte_val
    checksum = checksum % (2**32)  # keep it 32 bit

checkbyte = (256 - (checksum % 256)) % 256
new_data_tmp[-1] = checkbyte

NES Tags

The most complex system for structuring this save file is handling specific ASCII NES tags that need to be present for Animal Crossing’s emulator to load the games. There are a whopping 24 valid tags that can be included in the save, and Cuyler has a detailed post on all of them here.

These tags must be present in the save file and mark metadata about the ROM. They are handled by the functions nesinfo_tag_process1, nesinfo_tag_process2, and nesinfo_tag_process3. The most important and common tags are detailed below.

TagMeaningDescription
TAGTagMarks the start of reading tag metadata
GIDGame IDA custom ID for the game, can be anything
GNMGame NameName of the game, maximum of 16 characters
GNOGame NumberSets the ROM’s game number, used in game-specific NES items for high scores
OFSOffsetSets write offset for other tags
BBRBattery BackupUsed for storing save data for NES ROMs
QDSQuick Disk SaveUsed for storing save data for Famicom Disk System ROMS
ENDEndMarks the end of reading tag metadata

Example Example of correct save file tag structure

Saving

If the NES ROM attempting to be loaded supports saving, there must be a header flag present with the value of 0xEA. If the game does not support saving, you only need the lower bit of this flag, and it can be set as 0xEA &= 1. To name this save file in the GameCube BIOS, include the string NES Save Data before the actual ROM in the save file.

ROMs

After all the previous data is set correctly, the actual ROM file can be appended to the actual save file. The emulator in Animal Crossing capable of reading .nes, .bin, and .qd (Disk System) ROMs. It is also capable of reading Yaz0 compressed ROMs if you wish to save on memory space. These ROMs are typically appended with .szs and this is the format for the default 19 ROMs.

Famicom Disk System ROMs are a special case, since they must be in their Quick Disk (.qd) format and contain the tag QDS. This is because the emulator needs to load a special BIOS to play Famicom Disk System games and this tag instructs the emulator to do so.

Animal Crossing is capable of handling multiple ROM save files with proper menuing, so one could theoretically include as many ROMs as their memory card can store.

Official Debugging Logs

The developers left a lot of debugging console logs in the game files which execute often when dealing with NES / FDS items in the game. These are flagged as OSREPORT and can be viewed in Dolphin Emulator’s log viewer. Note these are written in Japanese by default, but can be easily translated.

Loading ROM:

MessageTranslation
ファミコンセーブデータを読み込みます“Loading Famicom (NES) save data”
メモリーカードが、スロットに挿入されているかどうかを調べます。“Checking if a memory card is inserted.”
メモリーカードをマウントする“Mounting the memory card”
メモリーカードはマウント状態になった“Memory card mounted
ファイルのオープン [DobutsunomoriP_F_SAVE]“Opening file [DobutsunomoriP_F_SAVE]
ファイル読む“Reading file
ファイル閉じる“Closing file
読み込み成功!!“File read successfully!!
ヘッダIDは正しいです“Header ID is correct”
ヘッダチェックサムは正しいです“Header checksum is correct”
バージョンとヘッダサイズが合致しました“Version and header size match”
個人ID&データチェックサム[0-3]は正しいです“Individual ID & data checksum [0-3] is correct

Loading Highscore Data:

MessageTranslation
WRAMのハイスコアが初期値になっていません オフセット“There is no high score present at WRAM’s initial offset”
WRAMのハイスコアが初期値になりました“The high score has been set to the default value in WRAM”

Saving:

MessageTranslation
メモリーカードが、スロットに挿入されているかどうかを調べます。“Checking if a memory card is inserted.”
メモリーカードをマウントする“Mounting the memory card”
メモリーカードはマウント状態になった“Memory card mounted
ファイルの内容を取り込む(セーブの必要性チェック)“Saving file contents (checking need to save)”
セーブする必要が無いので正常終了“No need to save; exiting normally”

Official NES ROM Tag Data

Each of the 19 NES titles have their own NES tags included that describe their metadata. These tags can be useful insight on how Nintendo wrote their own ROMs and how to replicate their process for the purpose of creating custom NES / FDS games. These are documented on a separate page here.

This post is licensed under CC BY 4.0 by the author.