jonathanpeppers/dotnes/nes-rom-debug
Claude Code and agent skill by jonathanpeppers/dotnes
- community
Checking that the SKILL.md file is still in the repository.
Disassemble and debug NES ROM files (.nes) produced by the dotnes transpiler. Use this skill whenever the user wants to disassemble a .nes ROM, inspect 6502 machine code, compare two NES ROMs side-by-side, debug transpiler output, investigate byte differences between a cc65 reference ROM and a dotnes ROM, or understand what 6502 instructions the transpiler emitted. Also use when the user mentions disasm, disassembly, PRG ROM, ROM bytes, NES addresses, or wants to look at the hex/binary output of a build. Even if the user just says something like "the ROM looks wrong" or "what did the transpiler emit", this skill applies.
Install
npx vskill@latest install jonathanpeppers/dotnes/nes-rom-debugSKILL.md
NES ROM Debug
Tools and knowledge for disassembling NES ROMs and debugging dotnes transpiler output.
Available Scripts
disasm.py — 6502 Disassembler
Disassembles the PRG ROM section of an iNES (.nes) file into human-readable 6502 assembly.
- `file.nes` — Path to the NES ROM file
- `start_hex` — (Optional) Start NES address in hex, default
8000 - `end_hex` — (Optional) End NES address in hex, default end of PRG
Examples:
Note:.nesfiles are build outputs — rundotnet buildin the sample directory first.
Output format:
Each line shows: $ADDR: HEX_BYTES MNEMONIC OPERAND
compare_rom.py — Side-by-Side ROM Comparison
Compares two NES ROMs with byte-level and instruction-level analysis. Use this to verify dotnes output against a cc65 reference ROM.
Output includes:
- File sizes
- Total byte differences (header / PRG / CHR breakdown)
- Contiguous diff groups with NES addresses
- Side-by-side disassembly of the largest diff region with match/mismatch markers
- Instruction mismatch count (ignoring absolute addresses, since the two compilers may place subroutines at different offsets)
ildump.cs — IL Opcode Dumper
Dumps the .NET IL opcodes from a compiled DLL — useful for understanding what IL the transpiler will process.
NES ROM Format (iNES)
Understanding the binary layout helps interpret disassembly output:
Key NES addresses:
$8000-$85AD— neslib runtime and built-in subroutines (palette, PPU, NMI handler, stack ops)$85AE+—main()and user code (exact layout varies per sample)$FFFA— NMI vector (2 bytes, little-endian)$FFFC— RESET vector (2 bytes, little-endian — entry point)$FFFE— IRQ vector (2 bytes, little-endian)
File offset → NES address: nes_addr = 0x8000 + (file_offset - 16) NES address → file offset: file_offset = (nes_addr - 0x8000) + 16
Common Debugging Workflows
"The ROM doesn't match the reference"
- Run
compare_rom.pyto identify where bytes differ - Use
disasm.pyon both ROMs targeting the diff region to see the instructions - Check if differences are just address relocations (compare_rom normalizes these) or actual logic differences
"What did the transpiler emit for my code?"
- Build the sample:
cd samples/hello && dotnet build - Dump the IL to see what C# compiled to:
dotnet run scripts/ildump.cs -- samples/hello/bin/Debug/net10.0/hello.dll - Disassemble the ROM to see the 6502 output:
python scripts/disasm.py samples/hello/bin/Debug/net10.0/hello.nes 8500
"Where is main() in the ROM?"
The RESET vector at $FFFC points to the startup code, which eventually jumps to main. To find it:
"Comparing test output against verified snapshot"
When TranspilerTests.Write fails, the test produces a .received.bin alongside the .verified.bin. Compare them:
6502 Quick Reference
The most common instructions you'll see in dotnes output:
| Opcode | Mnemonic | Meaning | |
|---|---|---|---|
A9 | LDA #imm | Load accumulator with immediate value | |
A5 | LDA zpg | Load accumulator from zero page | |
AD | LDA abs | Load accumulator from absolute address | |
85 | STA zpg | Store accumulator to zero page | |
8D | STA abs | Store accumulator to absolute address | |
20 | JSR abs | Jump to subroutine | |
60 | RTS | Return from subroutine | |
4C | JMP abs | Jump to address | |
D0 | BNE rel | Branch if not equal (Z=0) | |
F0 | BEQ rel | Branch if equal (Z=1) | |
C9 | CMP #imm | Compare accumulator with immediate | |
E6 | INC zpg | Increment zero page location | |
C6 | DEC zpg | Decrement zero page location |
Zero page addresses used by dotnes:
$17— TEMP$22-$23— sp (cc65 software stack pointer)$0325+— Local variables
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryChecking.github/skills/nes-rom-debug/SKILL.md
Popularity
- Repository stars
- 673
- Repository forks
- 24
- 7-day trend score
- 33
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/jonathanpeppers/dotnes/nes-rom-debug)