https://github.com/nevesnunes/ghidra-plays-mario Skip to content Toggle navigation Sign up * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code Explore + All features + Documentation + GitHub Skills + Blog * Solutions For + Enterprise + Teams + Startups + Education By Solution + CI/CD & Automation + DevOps + DevSecOps Resources + Customer Stories + White papers, Ebooks, Webinars + Partners * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} nevesnunes / ghidra-plays-mario Public * Notifications * Fork 0 * Star 39 Playing NES ROMs with Ghidra's PCode Emulator License MIT, MIT licenses found Licenses found MIT LICENSE MIT LICENSE.smolnes 39 stars 0 forks Activity Star Notifications * Code * Issues 0 * Pull requests 0 * Actions * Projects 0 * Security * Insights More * Code * Issues * Pull requests * Actions * Projects * Security * Insights nevesnunes/ghidra-plays-mario This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. master Switch branches/tags [ ] Branches Tags Could not load branches Nothing to show {{ refName }} default View all branches Could not load tags Nothing to show {{ refName }} default View all tags Name already in use A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch? Cancel Create 1 branch 0 tags Code * Local * Codespaces * Clone HTTPS GitHub CLI [https://github.com/n] Use Git or checkout with SVN using the web URL. [gh repo clone nevesn] Work fast with our official CLI. Learn more about the CLI. * Open with GitHub Desktop * Download ZIP Sign In Required Please sign in to use Codespaces. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching Xcode If nothing happens, download Xcode and try again. Launching Visual Studio Code Your codespace will open once ready. There was a problem preparing your codespace, please try again. Latest commit @nevesnunes nevesnunes Add slaspec build step to setup ... 356f206 Sep 9, 2023 Add slaspec build step to setup 356f206 Git stats * 4 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time flamegraphs Initial profiling September 9, 2023 11:44 ghidra_scripts Initial profiling September 9, 2023 11:44 imgs Initial commit September 3, 2023 22:19 inputs Initial commit September 3, 2023 22:19 .gitignore Initial commit September 3, 2023 22:19 LICENSE Add license September 4, 2023 21:24 LICENSE.smolnes Add license September 4, 2023 21:24 Makefile Initial commit September 3, 2023 22:19 README.md Add slaspec build step to setup September 9, 2023 17:48 smolnes_emuclt.c Initial profiling September 9, 2023 11:44 smolnes_standalone.c Initial commit September 3, 2023 22:19 View code Can Ghidra play Super Mario Bros? What? Why? Setup Takeaways Profiling Acknowledgements README.md Can Ghidra play Super Mario Bros? The answer is: [DEL:very slowly:DEL] YES! [smb] I've recorded keyboard inputs that can be replayed to complete the first level. It finishes at in-game time 316, but wall-clock time is 32 minutes. Transitions and starting the second level adds another 15 minutes. Demo (speedup 50x): demo.mp4 What? I took an existing minimal emulator, removed all CPU logic, and replaced it with a socket-based protocol for delegating CPU execution to Ghidra's PCode emulator (server). Everything else is still handled by the modified emulator (client), such as keyboard input and PPU logic. Why? Processor module validation! Sure, Ghidra has pcodetest for this purpose, but it's hard to tell how much coverage it provides. Apparently, not enough! Just getting the Super Mario Bros title screen to render required fixing bugs in 3 instructions. Even more were fixed while appeasing nestest.nes. Before (some tests fail, until a crash after jumping to an invalid instruction): [nestest1] After (all tests pass): [nestest2] Setup Tested with Ghidra 10.3.2, on Debian GNU/Linux 12. To reproduce the first level run: 1. Copy Ghidra/Processors/6502/data/languages/*.slaspec from my fork to your Ghidra installation, then run ant -f build.xml under data / to build the updated .sla files; 2. Install GhidraNes (tested with commit ef27b8d); 3. Load a Super Mario Bros (World) ROM (sha1 ea343f4e445a9050d4b4fbac2c77d0693b1d0922), and make sure it's focused in the listing (a.k.a. disassembly) window (in case you have other files open); 4. Copy ./ghidra_scripts/NesEmu.java to your project's ghidra_scripts directory; 5. Copy ./inputs/smb.w11full.inputs to /tmp/smb.inputs; 6. On Ghidra's Window > Script Manager, run NesEmu.java (starts the server); 7. Run make && ./smolnes_emuclt $ROM, (starts the client, $ROM is the full path to the same ROM being disassembled in Ghidra); 8. Sit back and enjoy an ~1 FPS demo; Of course, you can remove /tmp/smb.inputs and play yourself. Takeaways * As seen in the demo, Ghidra is constantly re-analyzing functions, caused by frantic clearing and disassembling of instructions. Not much room to improve here, since only disassembled instructions can be executed. * I've run into some desync when recording inputs in the standalone emulator vs replaying them in Ghidra's emulator. This means that inputs likely end up being set at different instruction lines. Expect diffs in e.g. how many VBlank interrupts happen when comparing both CPU emulators' trace logs... Still, it wasn't bad enough to break the demo, please let me know if that's not the case for you. * Currently, the protocol is very hardcoded for NES implementation details, and would benefit from a proper TLV encoding to handle variable address / data sizes. Profiling Some flamegraphs were captured with async-profiler: ./asprof -e itimer -d 30 -o flamegraph -f /tmp/out.html $GHIDRA_PID Surprisingly, stepping through instructions only takes about 15% of CPU time. About 50% is socket I/O (even after some quick optimizations like reusing the same buffer for payloads and buffering socket writes): [smb_buffer] Acknowledgements * deobfuscated.c from smolnes is under LICENSE.smolnes, and was modified into files smolnes_emuclt.c and smolnes_standalone.c; * Remaining files are under LICENSE; About Playing NES ROMs with Ghidra's PCode Emulator Resources Readme License MIT, MIT licenses found Licenses found MIT LICENSE MIT LICENSE.smolnes Activity Stars 39 stars Watchers 3 watching Forks 0 forks Report repository Releases No releases published Packages 0 No packages published Languages * HTML 86.3% * C 8.4% * Java 5.2% * Makefile 0.1% Footer (c) 2023 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact GitHub * Pricing * API * Training * Blog * About You can't perform that action at this time.