# nes-contra-us **Repository Path**: days2020/nes-contra-us ## Basic Information - **Project Name**: nes-contra-us - **Description**: nes-contra-us - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-08-30 - **Last Updated**: 2023-08-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 概述 - 这个仓库包含一个带有注释反汇编的魂斗罗美版NESROM,并包含将汇编代码重新装配成游戏的脚本. - 另外附赠了额外的文档,流程图,脚本和工具用来进一步研究魂斗罗这个游戏 - 特别感谢`Trax`,基于他的翻译项目[Revenge of the Red Falcon](https://www.romhacking.net/hacks/2701/),才会有这个项目的产生 ``` |-- docs - 附赠文档 | |-- attachments - 其他文档中的图片视频 | |-- diagrams - 游戏流程图 | |-- lua_scripts - 模拟器(mesen/fceux)的lua脚本 | |-- sprite_library - 提取的精灵图 |-- src - 游戏源代码 | |-- assets - 压缩图片数据和音频编码 |-- assets.txt - 资源列表,baserom.nes中偏移位置和长度 |-- build.bat - win的cmd编译脚本 |-- build.ps1 - win的powershell的编译脚本 |-- build.sh - linux/mac的编译脚本 |-- contra.cfg - cc65配置 |-- README.md |-- set_bytes.vbs - 从baserom.nes中提取数据的脚本 ``` # 构建流程 ## 前置素材 * 仓库中并没有包含编译生成游戏所需要的的数据(图片数据和音频数据).需要存在一个美国NES版本的魂斗罗`contra`名为`baserom.nes`用来提取需要的素材,rom的md5编码`7BDAD8B4A7A56A634C9649D20BD3011B`. * 下载cc65汇编和链接软件[cc65编译套件](https://cc65.github.io/). 安装并添加bin目录到系统环境. ## 说明 * 仓库包含3个构建脚本.只需要执行对应脚本即可. ``` .\build.ps1 <-- Windows .\build.bat <-- Windows (no PowerShell) ./build.sh <-- Unix ``` * `build.ps1` - PowerShell script recommended for building on Windows machines. Some users have reported needing to run the script as admin to access the `baserom.nes`, although I haven't experienced this. Additionally, on older versions of PowerShell, you may need to adjust the execution policy with the command `Set-ExecutionPolicy`. * `build.bat` - bat script that can be used on windows machines without PowerShell, but requires VBScript support. * `build.sh` - bash script to be used in unix environments, or on Windows environments with bash support (Git bash, WSL, etc.) ## 文档 - 附加文档包含了代码中有趣功能的解释.下面是一些比较重要的文档 * `docs/Aim Documentation.md` -敌人动画机制 * `docs/Bugs.md` - 反汇编重现的bugs * `docs/Contra Control Flow.md` - 游戏关卡和流程详情. * `docs/Enemy Glossary.md` - 敌人类型 * `docs/Enemy Routines.md` - 敌人关卡配置和随机生成. * `docs/Graphics Documentation.md` - 图形相关分析documentation on pattern tables, nametables, palettes, palette cycling, super-tiles, background collision, and compression. * `docs/Sound Documentation.md` - 音频引擎的分析. - 所有提取出的精灵素材`docs/sprite_library/README.md` ### 起步 - `src`目录下包含根据内存bank切分的. 魂斗罗卡带的Mapper是 [UxROM](https://www.nesdev.org/wiki/UxROM). 这个游戏包含8个16kb的bank,总共128kb. - Banks 0到在内存`$8000-$bfff`切换,Bank7是常驻内存`$c000-$ffff`. - 同一时间只有2个Banks存在于内存中,是理解游戏的观点点. - 和大多数游戏引擎一样游戏从`bank7.asm`开始, - 包含3个NES中断,并且常驻内存. - 建议从`docs/Contra Control Flow.md`开始阅读. 该文件包含了游戏整体循环流程. * `bank0.asm` - used exclusively for enemy routines. Enemy routines are the logic controlling enemy behaviors and settings: AI, movements, attack patterns, health, etc. Almost every enemy is coded in bank 0, but some enemy routines, usually those who appear in more than one level, are in `bank7.asm`. * `bank1.asm` - responsible for audio and sprites. The audio code takes up about 3/4 of the bank. The remaining 1/4 of the bank is for sprite data and code to draw sprites. * `bank2.asm` - starts with RLE-encoded level data (graphic super tiles for the level screens). It then contains compressed tile data and alternate tile data and occasional attribute table data. Then, bank 2 contains logic for setting the players' sprite based on player state. Next, bank 2 contains the level headers, which define specifics about each level. Bank 2 then has the data that specifies which enemies are on which screen and their attributes. Bank 2 also contains the soldier enemy generation code. * `bank3.asm` - starts with the data that specifies which pattern table tiles comprises super-tiles along with the color palettes. This bank also has the routines to manage the end of levels. * `bank4.asm` - mostly contains compressed graphic data. The rest of bank 4 is the code for the ending scene animation and the ending credits, including the ending credits text data. * `bank5.asm` - mostly contains compressed graphic data. The rest of bank 5 is the code and lookup tables for automated input for the 3 demo (attract) levels. * `bank6.asm` - contains compressed graphics data, data for short text sequences like level names and menu options. Bank 6 also contains the code for the players' weapons and bullets. * `bank7.asm` - the core of the game's programming. Reset, NMI, and IRQ vectors are in this bank and is the entry point to the game. Bank 7 contains the code for drawing of nametables and sprites, bank switching, routines for the intro sequence, controller input, score calculation, graphics decompression routines, palette codes, collision detection, pointer table for enemy routines, shared enemy logic, score table, enemy attributes, and bullet angles and speeds, and the NES undocumented footer, among other things. ### Annotations While reviewing the assembly, I used a notation to categorize unexpected, or interesting observations. You can search the code for these annotations. * `!(BUG?)` - a possible bug * `!(HUH)` - unexpected code or logic used * `!(WHY?)` - unsure of why the code is the way it is * `!(UNUSED)` - unused code or data that is never executed nor read * `!(OBS)` - observation or note # Project History I first became interested in this project after watching the [Summoning Salt](https://www.youtube.com/channel/UCtUbO6rBht0daVIOGML3c8w) video [The History of Contra World Records](https://www.youtube.com/watch?v=GgOE64kgjjo). In the video starting at 35m 19s, there was a section where a speedrunner named `dk28` died in the middle of level 1, and was advanced to level 2 for their next life. The video explains that there still isn't a known explanation as to why this happened. This got me interested in the assembly and thus this project began. Spoilers, I have not found the cause of the level skip bug. It is still unknown whether the bug is from some bug in the code, or whether it was a hardware glitch. The _Contra_ (US) NES ROM was disassembled using a NES disassembly tool. This provided a starting point for code investigation. The disassembler incorrectly marked many lines of code as data and this had to be manually corrected. At this point, there was an .asm file for each ROM bank in _Contra_. Build scripts were then created for both windows console (.bat), and powershell (.ps1). These scripts are equivalent and use ca65 to assemble the .asm files and cl65 to link the .o files into a single ROM file. Creating these build scripts required defining the memory addresses and bank layouts in the `contra.cfg` file. At this point, I had a repository that could be built that matched the NES rom byte for byte. Then, I found and was able to incorporate the comments from Trax's IDA Pro disassembly. This was incredibly helpful, but more work had to be done as Trax's disassembly couldn't be used directly for reassembly. For instance, it had a label for every line and all jump and branch statements were hard-coded memory address offsets and not label references. I then worked on updating all branch and jump offsets to point to label addresses. This helped ensure that the code was more readable. At this point, I also started updating data blocks that included memory offsets to use label offsets. The goal here was twofold: * make the code more readable and similar to what the original developers would have written * allow rom hacking without breaking the entire build due to breaking hard-coded memory offsets When all of this was done, the project could assemble and be byte-for-byte exactly as the _Contra_ (US) ROM. However, this was just the prerequisite to documenting the codebase. Every label had to be given an appropriate name, and each line of assembly had to be documented. # Build Details The build scripts accomplish the following tasks: * extracts necessary data from `baserom.nes` into `src/assets` * assemble each bank .asm file into a .o file * assemble constants.asm and ines_header into .o files * link all output .o files into a single .nes rom file The build scripts all utilize [cc65 compiler suite](https://cc65.github.io/) to assemble and link the 6502 assembly files. The asset data is pulled from `baserom.nes` as specified in `assets.txt`. Each line in `assets.txt` specifies the file name of the asset, its offset into `baserom.nes`, and its length. ## 1. Assembly Each .asm file is assembled into a .o object file. This section outlines what is happening as part of that process. ### Import Export Validation During assembly, if any symbol is undefined and not explicitly defined in an `.import` directive, an error will be generated. ## 2. Linking Linking is the concept of combining the various .o object files into a single .nes rom file. This is done by the cl65 linker. Its job is to replace labels with actual CPU memory addresses where the labels will exist when loaded. These are then stored in the resulting contra.nes rom file. This is aided by the linker configuration file contra.cfg. This file specifies the layout of the .net rom file. Without this file, or with a misconfigured file, the linker would not generate an identical .nes file. There are two parts to the contra.cfg file: MEMORY layout and SEGMENTS layout. ### Contra.cfg MEMORY Layout This section tells the linker where in memory each bank will exist. The linker needs this to know to replace a label with the correct address. For example, the opcodes that get generated for `jsr zero_out_nametables` depend on where in memory the label `zero_out_nametables` will exist. This is what the configuration file memory section specifies. ### Contra.cfg SEGMENTS Layout This section specifies defines in which order the .o files should appear in the resulting .nes rom file. # References * Trax's [Disassembly of _Contra (US)_](https://www.bwass.org/romhack/contra/) * Trax's [documentation on romhacking.net](https://www.romhacking.net/documents/713/) * [Tomorrow Corporation's Retro Game Internal Series on Contra](http://tomorrowcorporation.com/posts/retro-game-internals) * [Overview of NES Rendering by Austin Morlan](https://austinmorlan.com/posts/nes_rendering_overview/) * [Rom Detective article on Contra](http://www.romdetectives.com/Wiki/index.php?title=Contra_(NES))