Convert arrays with hardcoded pointer addresses to use ROM_START/ROM_END symbols. This automates the process of adding USE_ASSET declarations, updating array initialization, and configuring YAML segments.
When working with data arrays that contain hardcoded ROM pointer addresses (like gCourseDataAssets or gSpriteAssets), you need to:
USE_ASSET declarations for each unique addressROM_START/ROM_END symbolssnowboardkids2.yaml to add named segments with proper end markersThis skill automates that entire process.
Use this skill when you see arrays with hardcoded pointer addresses like:
Asset_56910 gCourseDataAssets[] = {
{ (void *)0x00224420, (void *)0x00226BA0, 0x000024A8 },
{ (void *)0x0023CB80, (void *)0x00240520, 0x00003468 },
// ...
};
These should be converted to:
Asset_56910 gCourseDataAssets[] = {
{ (void *)&_224420_ROM_START, (void *)&_224420_ROM_END, 0x000024A8 },
{ (void *)&_23CB80_ROM_START, (void *)&_23CB80_ROM_END, 0x00003468 },
// ...
};
Look for arrays of type Asset_56910 or similar asset structures in src/data/course_data.c or other data files.
For each array entry, extract:
In include/assets.h, add USE_ASSET declarations for each unique start address:
USE_ASSET(_224420);
USE_ASSET(_23CB80);
USE_ASSET(_24D6C0);
// ... etc, sorted numerically
Convert the array entries from:
{ (void *)0x00224420, (void *)0x00226BA0, 0x000024A8 }
To:
{ (void *)&_224420_ROM_START, (void *)&_224420_ROM_END, 0x000024A8 }
The pattern is:
0x and 00 prefixes from addresses(void *)0xADDRESS with (void *)&_ADDRESS_ROM_START or _ROM_ENDFor each asset segment:
Find the location - Search for the address in the YAML:
grep -n "0x224420\|0x226BA0" snowboardkids2.yaml
Add or convert segments - If you see:
[0x224420, bin] alone → Convert to named segment:
- name: _224420
type: bin
vram: 0
start: 0x224420
Named segment without end marker → Add end marker:
- name: _224420
type: bin
vram: 0
start: 0x224420
- [0x226BA0, bin] # This marks where _224420 ENDS
Maintain proper ordering - Ensure segments are in ascending address order:
Example structure:
- name: _224420
type: bin
vram: 0
start: 0x224420
- [0x226BA0, bin] # End marker for _224420, also marks start of next
- name: _23CB80
type: bin
vram: 0
start: 0x23CB80
- [0x240520, bin] # End marker for _23CB80
Build and verify:
./tools/build-and-verify.sh
Watch for errors:
data_diff.py --find-first-mismatch to find the problematic symbolWhy: Multiple array entries may reference the same asset (duplicates share data).
If multiple array entries use the same start/end addresses (common for duplicate assets), only declare the asset once:
// Both entries 15 and 16 use the same addresses
{ (void *)&_34A2C0_ROM_START, (void *)&_34A2C0_ROM_END, 0x00000438 },
{ (void *)&_34A2C0_ROM_START, (void *)&_34A2C0_ROM_END, 0x00000438 },
When you see [0x226BA0, bin] in the YAML:
Add a named segment BEFORE it:
- name: _224420
type: bin
vram: 0
start: 0x224420
- [0x226BA0, bin] # End of _224420
Convert the marker to a named segment with its own end marker:
- name: _226BA0
type: bin
vram: 0
start: 0x226BA0
- [0x228400, bin] # End of _226BA0
WRONG: End marker followed by named segment at same address:
- name: _226BA0
type: bin
vram: 0
start: 0x226BA0
- [0x228400, bin] # REDUNDANT! _228400 starts at same address
- name: _228400
type: bin
vram: 0
start: 0x228400
CORRECT: Named segment serves as boundary:
- name: _226BA0
type: bin
vram: 0
start: 0x226BA0
- name: _228400 # Ends _226BA0, starts at 0x228400
type: bin
vram: 0
start: 0x228400
When explicit end markers ARE needed:
# Check if asset exists
grep "_224420:" snowboardkids2.yaml
# Find all uses of an address
grep -r "0x00224420" src/
# Validate segment order
python3 -m splat split snowboardkids2.yaml
# Build and verify
./tools/build-and-verify.sh
# Check data mismatches
python3 tools/data-differ/data_diff.py gSpriteAssets
# Find first mismatching data symbol
python3 tools/data-differ/data_diff.py --find-first-mismatch
Error: Segment 228400 has zero size.
Cause: Having both an end marker [0xADDRESS, bin] AND a named segment starting at the same address creates a zero-size segment.
# WRONG - Creates zero-size segment:
- [0x228400, bin] # End marker for _226BA0
- name: _228400 # Named segment at SAME address
type: bin
vram: 0
start: 0x228400
Fix: Remove the redundant end marker when a named segment exists at that address:
# CORRECT - Named segment serves as boundary:
- name: _228400
type: bin
vram: 0
start: 0x228400
Why: A named segment automatically marks the end of the previous segment. The previous segment (_226BA0 in this case) ends where _228400 starts.
Key principle: Named segments automatically end where the next segment starts.
- name: _226BA0
type: bin
vram: 0
start: 0x226BA0
# Automatically ends at 0x228400 (where _228400 starts)
- name: _228400
type: bin
vram: 0
start: 0x228400
# Automatically ends at 0x23CB80 (where _23CB80 starts)
- name: _23CB80
type: bin
vram: 0
start: 0x23CB80
When to use explicit end markers:
# Example with explicit end marker:
- name: _34A2C0
type: bin
vram: 0
start: 0x34A2C0
- [0x34A750, bin] # Explicit end marker - _34A2C0 ends here
- name: _34CB50 # Gap from 0x34A750 to 0x34CB50
type: bin
vram: 0
start: 0x34CB50
When debugging zero-size segment errors, use this Python script to find all redundant end markers:
import re
with open('snowboardkids2.yaml', 'r') as f:
lines = f.readlines()
for i in range(len(lines) - 1):
end_match = re.match(r'\s*-\s*\[0x([0-9A-Fa-f]+),\s*bin\]', lines[i])
if end_match:
end_addr = end_match.group(1).upper()
for j in range(i+1, min(i+5, len(lines))):
name_match = re.match(r'\s*-\s*name:\s*_' + end_addr + r'\b', lines[j])
if name_match:
print(f"Line {i+1}: [0x{end_addr}, bin] followed by name: _{end_addr} at line {j+1}")
break
[0xEND_ADDRESS, bin]include/assets.hBefore adding a named segment to the YAML, verify the address is actually used with ROM_START/ROM_END symbols:
# Check if address is used with ROM symbols
grep -r "_228400_ROM" src/ include/
If the address is only used as a hardcoded pointer (e.g., { (void *)0x00228400, ... }), you typically don't need a named segment. An end marker is sufficient:
# If _228400 is only used as hardcoded pointer:
- [0x228400, bin] # Just marks end of previous segment
# If _228400 is used with ROM symbols:
- name: _228400 # Needed for USE_ASSET(_228400)
type: bin
vram: 0
start: 0x228400
Exception: You may need a named segment even if not currently using ROM symbols, if you plan to convert the code later.
If the build fails with checksum mismatch:
Find the first mismatching symbol:
python3 tools/data-differ/data_diff.py --find-first-mismatch
Examine the byte differences to understand which addresses are wrong
Check the YAML segments around those addresses:
grep -n "0xADDRESS" snowboardkids2.yaml
Verify:
Original array:
Asset_56910 gSpriteAssets[] = {
{ (void *)0x00226BA0, (void *)0x00228400, 0x00002208 },
{ (void *)0x00240520, (void *)0x002415B0, 0x00001BA8 },
// ... 14 more entries
};
After conversion:
Asset_56910 gSpriteAssets[] = {
{ (void *)&_226BA0_ROM_START, (void *)&_226BA0_ROM_END, 0x00002208 },
{ (void *)&_240520_ROM_START, (void *)&_240520_ROM_END, 0x00001BA8 },
// ... 14 more entries
};
With YAML segments:
- name: _226BA0
type: bin
vram: 0
start: 0x226BA0
- [0x228400, bin]
- name: _240520
type: bin
vram: 0
start: 0x240520
- [0x2415B0, bin]