Overview
The Pokémon Red/Blue disassembly includes several custom C tools in thetools/ directory that handle specialized tasks during the build process. These tools are automatically compiled when you build the ROM.
Building the Tools
Tools are built automatically during ROM compilation, but you can build them separately:tools/Makefile:
Tools are built with optimization level O3 and strict C11 compliance. They depend on
common.h for shared utilities.Tool Overview
Four main tools are provided:gfx
Advanced graphics processing and tile manipulation
pkmncompress
Pokémon sprite compression and decompression
scan_includes
Assembly dependency scanning and tree building
make_patch
Virtual Console patch generation
gfx
Source:tools/gfx.c
Purpose: Post-processes Game Boy graphics files after rgbgfx conversion, providing advanced tile manipulation features that rgbgfx doesn’t support.
Usage
Options
--trim-whitespace
--trim-whitespace
Removes trailing blank (all-zero) tiles from the end of a graphic.Use case: Reduce file size by removing unused tiles at the end.Example:
--remove-whitespace
--remove-whitespace
Removes all blank tiles from anywhere in the graphic.Use case: Compact graphics by eliminating all empty tiles.Note: Changes tile indices, so use with caution.
--interleave
--interleave
Interleaves tiles in a 2D pattern for certain graphics formats.Requires:
--png option to determine image dimensions.Use case: Convert row-major tiles to Game Boy’s interleaved format.Example:--remove-duplicates
--remove-duplicates
Removes duplicate tiles, keeping only the first occurrence.Use case: Reduce ROM size by deduplicating tiles.Example:
--keep-whitespace
--keep-whitespace
When used with
--remove-duplicates, preserves blank tiles even if duplicated.Use case: Maintain empty tiles for proper spacing.--remove-xflip
--remove-xflip
Removes tiles that are horizontal flips of earlier tiles.Use case: Reduce size for graphics where hardware flipping will be used.
--remove-yflip
--remove-yflip
Removes tiles that are vertical flips of earlier tiles.Use case: Reduce size for graphics where hardware flipping will be used.
--preserve indexes
--preserve indexes
Comma-separated list of tile indices to preserve from removal.Use case: Keep specific tiles even if they would otherwise be removed.Example:
-d, --depth depth
-d, --depth depth
Bits per pixel (default: 2).Values: 1 or 2Use case: Process 1bpp graphics.
-p, --png filename.png
-p, --png filename.png
Source PNG file for dimension information.Required for:
--interleave option-o, --out outfile
-o, --out outfile
Write processed output to specified file.Note: Without this, no output is written.
Examples
How It Works
- Tile Processing: Operates on 8×8 pixel tiles (16 bytes for 2bpp, 8 bytes for 1bpp)
- Whitespace Detection: Identifies tiles where all bytes are 0x00
- Duplicate Detection: Compares tiles byte-by-byte
- Flip Detection: Uses a lookup table to detect flipped tiles efficiently
- Preservation: Maintains specified tile indices regardless of other operations
pkmncompress
Source:tools/pkmncompress.c
Purpose: Compresses and decompresses Pokémon sprites using the game’s custom compression algorithm.
Usage
Options
-u, --uncompress- Decompress instead of compress-h, --help- Show help message
Compression Algorithm
The tool implements the custom Pokémon sprite compression used in Gen 1:Separate Bit Planes
Splits 2bpp data into two separate 1bpp planes:
- Plane 0: Lower bit of each pixel
- Plane 1: Upper bit of each pixel
Apply Gray Coding
Converts each 4-bit nybble using Gray code to reduce bit transitions.This improves RLE compression efficiency.
RLE Encoding
Run-length encodes each plane:
- Alternates between data packets and zero runs
- Uses variable-length encoding for run lengths
- Encodes data as 2-bit groups
Try All Modes
Tests three compression modes:
- Mode 0: Both planes independent
- Mode 1: Plane 1 XORed with plane 0, plane 1 not Gray-coded
- Mode 2: Plane 1 XORed with plane 0, both Gray-coded
Format
Compressed format:- Header byte:
(width << 4) | heightin tiles - Mode and order bits
- RLE-encoded bit groups for both planes
- Maximum size: 15×15 tiles (limited by header format)
- Input must be square (equal width and height)
Pokémon sprites in Gen 1 are typically 7×7, 6×6, or 5×5 tiles. The compression achieves roughly 50-60% size reduction.
Examples
scan_includes
Source:tools/scan_includes.c
Purpose: Recursively scans assembly files for INCLUDE and INCBIN directives to build a complete dependency tree.
Usage
Options
-s, --strict- Exit with error if included files don’t exist-h, --help- Show help message
How It Works
Find Directives
Identifies
INCLUDE and INCBIN directives (case-insensitive).Validates they appear as complete tokens, not within other words.Recursive Scan
For INCLUDE directives, recursively scans the included file.INCBIN files are listed but not scanned (binary data).
Integration with Makefile
The Makefile uses scan_includes to auto-generate dependencies:Example Output
The tool builds a complete transitive closure of all dependencies, ensuring no included file is missed.
make_patch
Source:tools/make_patch.c
Purpose: Generates Virtual Console (3DS) patch files by comparing original and modified ROMs.
Usage
Arguments
- values.sym - Symbol file from the VC build
- patched.gbc - Modified ROM (e.g.,
pokered_vc.gbc) - original.gbc - Original ROM (e.g.,
pokered.gbc) - vc.patch.template - Template file with patch directives
- vc.patch - Output patch file
Options
--ignore addr:size- Ignore differences at specific address ranges
How It Works
Parse Symbols
Reads the
.sym file to map label names to ROM offsets.Handles bank:address format and local labels.Process Template
Reads the template file and interprets special directives:
{patch}- Insert ROM bytes from patch location{hex SYMBOL}- Insert symbol address as hex{db VALUE}- Insert byte value{dws ...}- Insert word values[Label@Symbol]- Mark patch location
Extract Differences
Compares patched ROM and original ROM byte-by-byte.Extracts changed bytes at addresses marked in template.
Generate Patch
Outputs a completed patch file with:
- Literal ROM data from changed regions
- Computed addresses and values
- Proper formatting for the VC patcher
Template Commands
{patch} / {PATCH}
{patch} / {PATCH}
Extracts bytes from the current patch location.Format:
{patch} for lowercase hex, {PATCH} for uppercaseExample:{patch OFFSET SIZE}
{patch OFFSET SIZE}
Extracts bytes at an offset from the patch location.Example:
{hex SYMBOL}
{hex SYMBOL}
Inserts the address of a symbol as hexadecimal.Example:
{db VALUE}
{db VALUE}
Inserts a single byte value.Example:
{dws VALUE...}
{dws VALUE...}
Inserts one or more word (16-bit) values in little-endian.Example:
[Label@Symbol]
[Label@Symbol]
Marks a patch location and sets the current context.Example:The
@Symbol part must match a .VC_* symbol in the assembly.Virtual Console Patches
The Makefile generates VC patches:Virtual Console releases include various fixes and enhancements. The patch format allows Nintendo’s VC emulator to apply modifications to the original ROM.
Common Tool Workflow
Here’s how the tools work together during a build:Troubleshooting
Tools fail to compile
Tools fail to compile
Problem: Compilation errors when running
make tools.Solution:- Ensure gcc or clang is installed
- Check that you have C11 support
- Verify
common.hexists in the tools directory
gfx tool removes wrong tiles
gfx tool removes wrong tiles
Problem: Important tiles are removed by processing.Solution:
- Use
--preserveto protect specific tile indices - Check that tile indices are calculated correctly
- Try different option combinations
pkmncompress fails on non-square images
pkmncompress fails on non-square images
Problem: Error about image not being square.Solution:
- Pokémon sprites must be square (NxN tiles)
- Maximum size is 15×15 tiles
- Ensure input is in 2bpp format
scan_includes misses dependencies
scan_includes misses dependencies
Problem: Files not rebuilding when includes change.Solution:
- Check INCLUDE directives use proper quotes
- Verify paths are correct
- Try
make cleanthenmaketo rebuild all
make_patch reports unpatched differences
make_patch reports unpatched differences
Problem: Warning about ROM differences not in patch.Solution:
- Add new patches to the template file
- Use
--ignorefor intentional differences - Verify symbols exist in the .sym file
Extending the Tools
All tools are open source and can be modified:- Edit the source - Modify
.cfiles intools/ - Add new options - Extend the argument parsing
- Test thoroughly - Verify with existing graphics/ROMs
- Rebuild - Run
make toolsto recompile