{"id":13514215,"url":"https://github.com/henrikpersson/potatis","last_synced_at":"2026-01-18T14:25:36.696Z","repository":{"id":66503756,"uuid":"542230665","full_name":"henrikpersson/potatis","owner":"henrikpersson","description":"🥔 MOS-6502 and NES emulator in Rust (SDL/WebAssembly/Android/Embedded/Cloud)","archived":false,"fork":false,"pushed_at":"2024-11-26T12:28:49.000Z","size":21062,"stargazers_count":660,"open_issues_count":0,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-31T03:32:01.455Z","etag":null,"topics":["embedded-hal","emulator","jni","jni-android","mos-6502","nes","pico","rust","rust-embedded","wasm","webassembly"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/henrikpersson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-27T18:23:29.000Z","updated_at":"2025-03-20T04:40:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"d8b86fe5-6b44-4563-8093-ab37a138ff68","html_url":"https://github.com/henrikpersson/potatis","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/henrikpersson/potatis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikpersson%2Fpotatis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikpersson%2Fpotatis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikpersson%2Fpotatis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikpersson%2Fpotatis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/henrikpersson","download_url":"https://codeload.github.com/henrikpersson/potatis/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikpersson%2Fpotatis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28537561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T13:04:05.990Z","status":"ssl_error","status_checked_at":"2026-01-18T13:01:44.092Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embedded-hal","emulator","jni","jni-android","mos-6502","nes","pico","rust","rust-embedded","wasm","webassembly"],"created_at":"2024-08-01T05:00:49.934Z","updated_at":"2026-01-18T14:25:36.678Z","avatar_url":"https://github.com/henrikpersson.png","language":"Rust","funding_links":[],"categories":["Rust","Home Game Console Emulators","Entertainment and Games"],"sub_categories":["Nintendo","COVID-19"],"readme":"# 🥔 Potatis\n\u003cimg width=\"400\" alt=\"smb\" src=\"screenshots/smb.png\"\u003e\u003cimg width=\"400\" alt=\"smb3\" src=\"screenshots/smb3.png\"\u003e\n\u003cimg width=\"400\" alt=\"bb\" src=\"screenshots/bb.png\"\u003e\u003cimg width=\"400\" alt=\"dr\" src=\"screenshots/dr.png\"\u003e\n\n- `/mos6502` - Generic CPU emulator. Passes all tests, including illegal ops. (No BCD mode).\n- `/nes` - A very incomplete NES emulator.\n- `/nes-sdl` - Native target using SDL.\n- `/nes-wasm` - Browser target using WASM.\n- `/nes-cloud` - NES-as-a-service. Clientless cloud gaming with netcat and terminal rendering.\n- `/nes-embedded` - Embedded target for RP-2040 (Raspberry Pi Pico).\n- `/nes-android` - Android target using JNI.\n\n## /mos6502\n\n```rust\nlet load_base = 0x2000;\nlet mem = Memory::load(\u0026program[..], load_base);\nlet cpu = Cpu::new(mem);\nlet mut machine = Mos6502::new(cpu);\n\nloop {\n  machine.tick()\n  println!(\"{}\", machine); // Prints nestest-like output\n}\n```\n\n### Debugging\n\n```rust\nlet mut debugger = machine.debugger();\ndebugger.verbose(true); // Trace, dumps disassembled instructions to stdout\ndebugger.add_breakpoint(Breakpoint::Address(0x0666));\ndebugger.add_breakpoint(Breakpoint::Opcode(\"RTI\"));\ndebugger.watch_memory_range(0x6004..=0x6104, |mem| {\n  // Invoked when memory in range changes\n});\n```\n\n## /nes\n\nSupported mappers:\n- NROM (mapper 0)\n- MMC1 (mapper 1)\n- UxROM (mapper 2)\n- CNROM (mapper 3)\n- MMC3 (mapper 4)\n\n```rust\nimpl nes::HostPlatform for MyHost {\n  fn render(\u0026mut self, frame: \u0026RenderFrame) {\n    // frame.pixels() == 256 * 240 * 3 RGB array\n  }\n\n  fn poll_events(\u0026mut self, joypad: \u0026mut Joypad) {\n    // pump events and forward to joypad\n  }\n}\n\n\nlet cart = Cartridge::blow_dust(\"path/to/rom.nes\")?;\nlet mut nes = Nes::insert(cart, MyHost::new());\n\nloop {\n  nes.tick();\n  println!(\"{:?}\", nes); // Complete nestest formatted output\n}\n```\n\n## /nes-sdl\n\n`cargo run --release path/to/rom.nes`\n\n`cargo run -- --help` for options\n\n## /nes-wasm\n\n1. `cd nes-wasm`\n2. `wasm-pack build --release --target web`\n3. `npm install`\n4. `npm run dev`\n\nTry it here: https://henrikpersson.github.io/nes/index.html\n\n## /nes-cloud\n\nCloud gaming is the [next big thing](http://stadia.google.com). Obviously, Potatis needs to support it as well. No client needed,\nonly a terminal and netcat.\n\n### Usage\n```\nstty -icanon \u0026\u0026 nc play-nes.org 4444\n```\n\n_`stty -icanon` disables input buffering for your terminal, sending input directly to netcat. You can also connect without it but then you'd have to press \u003ckbd\u003eENTER\u003c/kbd\u003e after each key press._\n\n### Bring your own ROM\n```\nstty -icanon \u0026\u0026 cat zelda.nes - | nc play-nes.org 4444\n```\n\n### Rendering\n\n- [Sixel](https://en.wikipedia.org/wiki/Sixel) (port 6666) is recommended if your terminal supports it. iTerm2 does.\n- Unicode color (port 5555) works by using the unicode character ▀ \"Upper half block\", `U+2580` to draw the screen. Since the lower part of the character is transparent, [ANSI color codes](https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit) can be used to simultaneously draw two horizontal lines by setting the block's foreground and background color. Unfortunately the resulting frame is still too large to fit in a normal terminal window, so when using this mode **you have to decrease your terminal's font size a lot**.\n- ASCII (port 7777). No color, no unicode, just ASCII by calculating luminance for each RGB pixel. Same here, **you have to decrease your terminal's font size a lot** to see the whole picture.\n\n## /nes-embedded\nIt also runs on a RP-Pico with only 264kB available RAM! Without any optimizations it started out at ~0.5 FPS. But after some overclocking, and offloading the display rendering to the second CPU core, it now runs at a steady 5 FPS.\n\nTotal heap usage, single-core: 135kB\n\u003cbr\u003e\nTotal heap usage, multi-core: 243kB (2x frame buffers)\n\n\u003cimg width=\"600\" alt=\"smb\" src=\"screenshots/pico.jpg\"\u003e\n\n\n_The second Pico on the picture is wired up as a SWD debugger/flasher. The display is a [ST7789 by Adafruit](https://www.adafruit.com/product/4311)_.\n\u003cbr\u003e\n\n```\ncd nes-embedded\nROM=/path/to/rom.nes cargo run --release\n```\n\nIf you don't have a debug-probe setup, change the runner in `.cargo/config` to use a normal `elf2uf2`.\n\n## /nes-android\n\n1. Download Android NDK and `rustup target add [target]`\n2. Configure your target(s) in `~/.cargo/config` with the linker(s) provided by the Android NDK\n```\n[target.aarch64-linux-android]\nlinker = \"$NDK_PATH/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android33-clang\"\n\n[target.armv7-linux-androideabi]\nlinker = \"$NDK_PATH/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi30-clang\"\n\n[target.x86_64-linux-android]\nlinker = \"$NDK_PATH/toolchains/llvm/prebuilt/darwin-x86_64/bin/x86_64-linux-android30-clang\"\n```\n3. `cd nes-android \u0026\u0026 ./install.sh release`\n\n_Note: install.sh only targets arm64-v8a (aarch64-linux-android)._\n\n# Test\n\nRun all unit and integration tests (for all crates):\n\n`cargo test`\n\n# TODO\n\n- More mappers\n- APU\n\n# Key mappings\n\nUp, left, down, right: \u003ckbd\u003eWASD\u003c/kbd\u003e\nB: \u003ckbd\u003eK\u003c/kbd\u003e\nA: \u003ckbd\u003eL\u003c/kbd\u003e\nSelect: \u003ckbd\u003eSPACE\u003c/kbd\u003e\nStart: \u003ckbd\u003eENTER\u003c/kbd\u003e\nReset: \u003ckbd\u003eR\u003c/kbd\u003e\n\n\n# Thanks\n- nesdev.org\n- https://www.masswerk.at/6502/6502_instruction_set.html\n- https://github.com/amb5l/6502_65C02_functional_tests\n- http://www.baltissen.org/newhtm/ttl6502.htm (TTL6502.bin test)\n- https://www.nesdev.com/neshdr20.txt\n- https://github.com/christopherpow/nes-test-roms\n- http://nesdev.org/loopyppu.zip\n- https://www.youtube.com/watch?v=-THeUXqR3zY\n- https://archive.nes.science/nesdev-forums/f2/t664.xhtml\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenrikpersson%2Fpotatis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhenrikpersson%2Fpotatis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenrikpersson%2Fpotatis/lists"}