Yes — as of July 2026, a MicroPython port runs on original Super Nintendo hardware via a homebrew flash cartridge. The port sits inside the 128 KB WRAM budget, uses the 65816 CPU to interpret a stripped-down bytecode, and boots from any modern SNES flashcart. It is not fast, and it is not pretty, but it works — the same interpreter that runs on a Raspberry Pi Pico is now targeting a 1990 console.
In brief — 2026-07-20 · A new port brings the MicroPython interpreter to the SNES, running on original hardware via flash cart.
What happened
The port was released this week on GitHub by a solo developer who spent about a year building it. It runs on the SNES's Ricoh 5A22 CPU (a 65816 variant clocked at 3.58 MHz), uses the console's 128 KB Work RAM as the entire Python heap, and outputs to the standard PPU as a monochrome text-mode display. Coverage from Adafruit's blog picked it up as one of the more entertaining low-level ports of 2026, and the upstream MicroPython project has linked to it from the ports directory.
The port implements a subset of MicroPython 1.22:
- Integers (64-bit), strings (ASCII only), lists, tuples, dicts, functions
import,for/while/if, exception handling- No floats (the 65816 has no FPU; float support would cost too much cycles)
- No garbage collector — objects are freed only when their reference count hits zero
- No standard library beyond
sys,time, and a customsnesmodule for PPU access
The snes module is the interesting part. It exposes snes.putchar(x, y, c) for text, snes.readpad(n) for controller input, and a set of primitives for drawing sprites to the PPU. Anything more ambitious — sound, mode-7 backgrounds, DMA — is out of scope for this release.
Why it matters
The port is the strongest signal yet that "modern high-level language on vintage hardware" is now a solved category, not an aspiration. It joins earlier ports of Lua, JavaScript, and Rust to older consoles, and it does the hardest one — MicroPython on a 3.58 MHz CPU with 128 KB of RAM — without hacking the ABI.
The tinkering path is the useful takeaway for readers. To build, flash, and run one of these things on real hardware you need:
- A modern SBC as the development host. The Raspberry Pi 4 Model B 8GB is the reference host in the port's README. 8 GB is overkill for cross-compilation but the port depends on the
cc65toolchain, which links faster with more RAM available. A Pi 4 also handles the flash-cart's USB programming utility without any driver drama. - A cheap secondary Pi for headless flashing. A Raspberry Pi Zero W starter kit leaves your main machine free while the flashing loop runs. It's the kind of task where you'd rather dedicate a $30 board than tie up your desk.
- CompactFlash for source archives. Transcend CF133 4GB CompactFlash reads directly on vintage PC hardware and on modern USB adapters. If you're mixing this SNES port with a retro-PC workflow (say, developing ROMs on a period-correct DOS box), CF is the intermediate that lets both sides read.
- A USB adapter for reading CF and IDE. Unitek SATA/IDE to USB 3.0 reads CF cards through a CF-to-IDE adapter and reads original SNES cart save chips through the same USB bus. It's a boring $25 utility that turns "I have to physically walk cartridges between machines" into a Python script.
Total tinkering-box cost: about $150 for the pair of Pis, the CF card, and the USB adapter. That is far less than the flashcart itself.
Common pitfalls when you try this yourself
- Assuming your flashcart has enough SRAM. Many cheap SNES flashcarts ship with 32 KB or less of battery-backed SRAM. The MicroPython port is 128 KB and needs a cart with at least 256 KB of ROM space to store the interpreter, plus a matching WRAM allocation strategy. Check your flashcart's spec sheet before you burn the binary.
- Skipping the region-lock step. Original SNES consoles are region-locked in silicon. If you flash a build compiled for NTSC and your console is PAL, the port boots to a black screen. Compile with the right
SNES_REGIONenv var for your console. - Forgetting the SPC-700 sound chip. The port doesn't touch it. If you power on a program that hangs on
snes.putcharfor a while, you may hear the SPC-700 humming from a previous cart's stale state. This is normal and does not indicate a crash. - Debugging on emulator only. Emulators like snes9x and bsnes-plus do not perfectly emulate DMA timing. Programs that "work in emulator" can still lock the real console. Test on real hardware once per iteration.
Real-world numbers — what a 3.58 MHz CPU actually does
Approximate MicroPython benchmarks on the port, from the developer's README:
| Operation | Timing |
|---|---|
Empty for i in range(100): | ~85 ms |
| String concat, 20 chars × 10 iterations | ~350 ms |
putchar full 32x28 text screen | ~1.1 s |
Read all 4 controllers with snes.readpad | ~4 ms |
import sys; sys.info() | ~230 ms |
For reference, the same benchmarks on the MicroPython website's Raspberry Pi Pico reference run 500-2000× faster. The SNES port is not for real-time work — it's for teaching, hobby experiments, and the perverse pleasure of running print("Hello World") on hardware old enough to vote.
How the interpreter fits in 128 KB
The SNES's memory map splits into a 128 KB Work RAM region and up to 4 MB of ROM address space accessible via bank-switching. Fitting MicroPython inside this budget required aggressive rework:
- Bytecode compilation moved off-console. The full MicroPython source parser is ~40 KB alone; that alone would eat one-third of WRAM. The port pre-compiles Python source on the development host and ships only the bytecode dispatch loop and the runtime library to the SNES.
- String storage lives in ROM. All string literals from your program are placed in the flashcart's ROM bank and referenced by pointer. The interpreter's WRAM only stores mutable string objects.
- The 16-bit ABI kept. The 65816 has a 16-bit native word. The port keeps object headers 16-bit wherever possible and only widens to 24-bit pointers when addressing ROM banks past $80.
- No garbage collector. A generational GC would need a nursery region and mark bits per object, neither of which fit. The port uses reference counting with a manual
del()primitive for breaking cycles.
The end result: a runtime image around 55 KB in ROM, using roughly 60-70 KB of WRAM at steady state for a small program. That leaves ~40 KB for user data before you feel the memory pressure — enough for the small text-adventure or menu-driven scripts the port targets.
Comparison to other retro-console language ports
The MicroPython-on-SNES port is the latest entry in a growing category. Rough table of the current ports directory across the retro scene:
| Language | Target console | Real hardware? | Speed vs modern reference |
|---|---|---|---|
| MicroPython | SNES (65816, 3.58 MHz) | Yes, via flashcart | ~1000× slower than Pi Pico |
| Lua | NES (6502, 1.79 MHz) | Yes | ~5000× slower than Pi Pico |
| JavaScript (mJS) | Sega Genesis (68k, 7.6 MHz) | Yes | ~500× slower than Node.js |
| Rust (no_std) | GB Color (Z80, 8 MHz) | Yes | ~1× (Rust compiles to native) |
| Python (full CPython) | any retro console | No | N/A |
Rust's straight compile-to-native gives it a genuine speed advantage over the interpreted ports, but the tradeoff is compile-time debug. The interpreted ports (MicroPython, Lua, mJS) are all in the same slow-but-interactive tier — you accept 100-1000× slowdown for the ability to iterate without a full compile step.
The development loop
The workflow is:
- Write your
.pyfile on the Pi 4 host. - Cross-compile via the port's
snes-mpytool, which pre-compiles bytecode into a payload the SNES interpreter can load without a runtime parser (there is no space for the parser in WRAM). - Concatenate the interpreter + your bytecode into a
.smcROM image using the port'slink.py. - Flash to the cart over USB.
- Boot the console; the interpreter runs your program from the flash cart's ROM address space.
Iteration time is 40-90 seconds per cycle, dominated by the USB flashing step. You can shorten it by keeping the interpreter binary on the cart and only re-flashing the bytecode section — the port's link.py --bytecode-only mode does exactly this.
Why port a scripting language to a 1990 console at all?
The utility questions ("why not just write C?") miss the point. Scripting on the SNES is not a productivity choice — it's a teaching tool and a hobby demonstration. A student who wants to understand how a virtual machine works learns more from watching MicroPython's bytecode dispatch loop crawl through a 3.58 MHz CPU than from reading a textbook. The visible slowness is the pedagogy.
There is also a small-but-real community of retro-homebrew developers who want the rapid iteration of a REPL-like workflow (edit → flash → run in 60 seconds) without giving up real hardware. The port sits exactly at that intersection. It is not the fastest way to write an SNES game; it is the shortest path from "I want to try something on real hardware" to "the console shows my code running."
Case studies — what people are already doing with the port
Community projects that showed up on the port's GitHub within the first week of release, described in the README:
- Menu-driven text adventures. A ~2000-line MicroPython program with 40+ rooms, saved state, and controller-based menu navigation. Runs comfortably in the 60-70 KB WRAM steady-state budget.
- A visual metronome. Uses
snes.putcharto flash a numeric BPM display on the screen with sub-frame timing accuracy via manual VBLANK sync. Demonstrates that even a 1000× slowdown is enough for real-time visual feedback if the workload is tiny. - A "hello world" from a homebrew cart at a retro-computing meetup. The port's most-shared demo — a MicroPython script that prints a greeting, waits for controller input, and exits. Under 30 lines total. Runs on an unmodified 1990 SNES.
- A teaching aid for a university OS course. One professor is using the port to demonstrate memory-constrained interpreters. Students see the WRAM usage climb in real time as they add features; the ceiling forces them to think about object layout in a way modern hardware never does.
These are exactly the workloads the port was built for: small, interactive, pedagogical. None of them try to be a real game. All of them run on real hardware without modification.
When NOT to try this
- You want to make a real SNES game. Use
cc65or PVSnesLib — the MicroPython port cannot output more than text and small sprites. - You want performance. The port is 500-2000× slower than a Pi Pico. Anything CPU-bound falls off a cliff.
- You want to distribute what you build on cartridge. The port's license and the flashcart hardware are separate concerns; check both before you sell anything.
The source
The port's source code lives on GitHub under the developer's account (linked from the Adafruit blog coverage). The upstream MicroPython project has added it to the ports directory. The Raspberry Pi 4 Model B page is the canonical reference for the recommended host SBC.
Bottom line
You can now run MicroPython on a 1990 Super Nintendo, on the real hardware, from a flash cart. It is slow. It is deliberate. And it is exactly the kind of hobby project that the modern SBC + vintage-console pipeline has made trivially easy — a Raspberry Pi 4 Model B 8GB handles cross-compilation, a Pi Zero W starter kit handles the flashing loop, Transcend CF133 CompactFlash shuttles data with vintage machines, and a Unitek SATA/IDE-to-USB adapter reads both CF and old IDE hard drives into the same USB port. Total tinker-bench cost: about $150 for everything except the SNES itself.
If you have a working SNES and a flashcart, the barrier to trying this is one weekend of setup and about 40 seconds per iteration. That's a lower cost of entry than any comparable "write real code for real vintage hardware" workflow has ever been.
Related guides
- Build a Retro Emulation Cabinet Brain on a Pi 4 8GB
- Jellyfin on Raspberry Pi 4 8GB — Transcode Limits
- CompactFlash Imaging for Retro PCs — CF133 + IDE Workflow
Citations and sources
- Adafruit Blog — coverage of the MicroPython-on-SNES port
- MicroPython — official project page and ports directory
- Raspberry Pi — Model B 4 product page
This piece is editorial synthesis based on publicly available information. No independent first-party benchmarking is reported.
