Releases: rh1tech/frank-snes
Release list
Version 1.11
- Fixed black-screen-with-audio on Cybernator (USA) and Assault Suits Valken; HDMI palette is now pushed when the game raises brightness instead of at end-of-frame
- Fixed long ROM filenames like "Assault Suits Valken (Japan) [T-En by Aeon Genesis v1.1].sfc" not launching from the carousel
- Added a third MOUSE PORT value "OFF" to hide the SNES mouse from games that lock up when one is detected (e.g. King Arthur & The Knights of Justice); PS/2 and USB mice still work in menus
- Suppressed the once-per-second mouse-pipeline heartbeat log when no mouse is attached
Version 1.10
- Added USB XInput (Xbox 360) gamepad support alongside existing HID pads
- Added per-device USB gamepad button maps keyed on VID/PID, regenerated from captures in
gamepads/ - Added first-connect menu A/B calibration wizard for unknown USB pads; learned bits are saved to
snes/gamepads/gamepad_VVVV_PPPP.txton SD and reused on later boots - Added a
hid_ripHID descriptor fallback parser so arcade sticks, composites, and cheap clones the stock TinyUSB parser trips on now enumerate their buttons - Auto-detect NES vs SNES pad type per port; NES pads map A and B correctly, SNES pads get A/B/X/Y/L/R without manual configuration
- Changed gamepad settings hotkey from Select+Start to Select+Start+A; bare Select+Start now toggles the ROM carousel / file browser
- Tab on a PS/2 or USB keyboard also toggles the carousel / file browser
- File browser: A opens directories and launches ROMs; Start is reserved for combos
- Settings launched from the ROM selector shows "BACK TO ROMS" instead of "BACK"
- Added Settings → Button Mapping → Clean USB Cache to wipe learned USB pad layouts and re-arm the wizard
- Replaced SNES Mouse on/off toggle with Mouse Port: Gamepad 1/2; entry is hidden when no mouse is connected, and emulation engages automatically whenever a PS/2 or USB mouse is detected
- Show a visible NO SD CARD DETECTED screen at boot when the SD card is missing instead of a silent LED-blink loop
- release.sh: added -t/--test flag for preview builds that skip version.txt rewrite and postfix output with _test
- release.sh: strip leading zeros from version.txt so minor=09 is no longer parsed as octal
Version 1.09
- Fix PS/2 mouse init on USB_HID=1 release builds (BAT succeeded but
SET_SAMPLE_RATEreturned0xFC). Workaround: skip IntelliMouse magic knock, NVIC-mask host-to-device frames, 50 ms inter-byte gap, wait for bus idle before SIO→PIO handoff. - Fix HDMI resync glitch when a PS/2 mouse is plugged in on M2 boards. PS/2 bit-bang on GPIO 0/1 was perturbing HDMI TMDS pairs on GPIO 12–19. PS/2 keyboard and mouse now init before
graphics_init(). - Bump mouse init retry loop from 3 attempts to 10, with 500 ms between attempts. Bail out immediately if no device responds to RESET.
- Restore full mouse init path on USB_HID=0 builds (IntelliMouse probe, sample rate 200, resolution 3, scaling 1:1). USB_HID=1 keeps the skip-magic-knock workaround.
- Log now distinguishes
Mouse: No device on bus, giving upfromMouse: Init FAILEDafter 10 retries.
Version 1.08
Focus: PS/2 mouse support now works with a much wider range of devices, including cheap and older mice that previously failed to initialize.
Fixes
- Handle the device's
0xFE(RESEND) reply. A single corrupt host-to-device byte no longer fails the whole init; the driver retries the byte as the spec requires. - Handle the device's
0xFC(ERROR) reply the same way. The spec says0xFCis BAT-only, but many real-world mice send it post-BAT as a soft "please resend". The driver now treats it as a retry request instead of a fatal error. - Wait for the bus to be idle (CLK and DATA both high) before every host-to-device transmit. Slower mice that hold the lines a little longer no longer cause a request-to-send collision.
- Add a 50 ms settling delay after BAT completes, plus a drain of any stragglers in the PIO RX FIFO, before the first configuration byte. Mice that were still finishing internal init no longer get commands thrown at them too early.
- Flush the RX FIFO before every command. A leftover response from a previously failed command can no longer be misread as the answer to the current one.
- Replace the old 4-try / 5 ms retry loop with 2 tries at 30 ms. The faster loop was flooding some mice into a locked state that even a fresh reset couldn't recover from.
- Add a communication-inhibit bus recovery step between init attempts: CLK held low for 20 ms, both lines released for 30 ms, then the PIO state machine is restarted. Retry attempts now start from a clean bus instead of a wedged one.
- Fall back gracefully when the IntelliMouse magic knock fails. Previously the driver gave up; now it continues in plain 3-button mode.
Diagnostics
- Command timeouts log
timed out waiting for ACKinstead of0xFFFFFFFF.
Assets
frank-snes_m1_1_08.uf2— firmware for M1 board variantfrank-snes_m2_1_08.uf2— firmware for M2 board variantmetadata.zip— sdcard ROM metadata bundle
Version 1.07
SNES mouse support
- Added SNES mouse support. PS/2 and USB mice both work as a SNES mouse on controller port 2. Enables Cannon Fodder, Mario Paint, Lemmings, and other mouse titles.
- Replaced the PS/2 keyboard driver with a unified PS/2 driver that handles keyboard and mouse on separate PIO instances. Keyboard moved to PIO2; mouse lives on PIO1 next to audio, matching the proven frank-wolf layout.
- Fixed the snes9x 0x4017 serial read path. The original port truncated to 16 bits; mice need the full 32-bit packet, so dx/dy bytes now reach the game instead of being read as 1s.
- Added a
SNES MOUSEtoggle on the main Settings page, directly underButton Mapping. Default is on. Saved to/snes/settings.ini. - USB mouse fixes ported from frank-wolf: accept short HID reports via a zero-padded copy, detect mouse via
HID_USAGE_DESKTOP_MOUSEin the descriptor forprotocol=NONEdevices, route generic reports through the descriptor dispatcher so generic-HID mice are not swallowed by the gamepad path. - Axes normalized for the on-board mouse orientation. Raw
dymaps to screen-x; rawdxmaps to screen+y. Same transform applied to USB and PS/2 so both feel identical. - Free-running mouse accumulator. The pointer no longer clamps at
[0..255, 0..223], so motion after reaching a screen edge still registers (fixes "can't move left after hitting the left edge").
SuperFX / DOOM fixes
- Fixed the cold-boot regression from 1.05 where DOOM (and other SuperFX games needing a 6 MB ROM buffer) rendered a single garbage scanline on first launch and only worked after a selector round-trip. Root cause: the 57 KB sub-screen transparency buffer was allocated inside the permanent PSRAM arena after
psram_mark_session, which pushedS9xInitGFX's 22 KBLocalStateallocation past the ceiling and silently returnedNULL.GFX.OBJLinesthen stayedNULLand the PPU dereferenced it from frame one. The buffer is now parked at a fixed offset inside the 512 KB scratch region, which is outside the session lifecycle, so it survives across ROM launches and never competes with ROM data.S9xInitGFX's return value is now checked and fatal-logged. - Fixed SuperFX rendering for DOOM and other non-Star-Fox SuperFX titles. Three bugs were conspiring: VRAM/RAM/SRAM/FillRAM were
malloc'd instead ofcalloc'd, so DOOM's tilemap referenced never-DMA'd tile indexes and rendered PSRAM garbage as a red/blue houndstooth over the viewport.FxEmulatewas hard-capped to 350/700 cycles per HBlank (a Star Fox-specific hack); DOOM needs the GSU to run toSTOPwithin the frame, so this is nowFxEmulate(~0)matching snes9x2005.NO_WINDOW_CLIPPINGskippedComputeClipWindowsentirely, which SuperFX games rely on to mask the 3D viewport borders — the optimization is now conditional on!Settings.SuperFX. GSU opcode handlers also moved to.time_criticalSRAM.
Performance
- Moved the hot emulation code out of XIP-cached flash into
.time_criticalSRAM sections. XIP cache misses during opcode dispatch were the dominant overhead. Tagged: all 478 65816 opcode handlers and the five 256-entry dispatch tables incpuops.c, the SPC700APUExecuteswitch (called every HBlank),S9xGet/SetPPUandS9xGet/SetCPU(hit on every$21xx/$42xx/$43xxaccess),S9xDoDMA,S9xSetAPUDSP,S9xMixSamplesMono,S9xUpdateScreen, andS9xDoHBlankProcessing. - Moved the 96 KB SPC700 echo buffer from static
.bssto PSRAM viasnes_malloc, freeing SRAM for the hot sections above. Echo is read/written at most once per sample and only when enabled, so PSRAM latency is not measurable. - DOOM gameplay measurements: emulation throughput 27.6 → 30.3 fps, skip-frame 28.0 → 26.0 ms, render-frame 60.2 → 55.2 ms.
Dev / build
- Dev-build USB CDC wait: block until the host terminal opens the port, then pause 3 seconds before the first
LOG(...). Full boot log now lands in the console. build.shacceptsUSB_HID_ENABLEDas an environment override (USB_HID_ENABLED=ON ./build.sh M2).
Downloads
frank-snes_m1_1_07.uf2— M1 board variantfrank-snes_m2_1_07.uf2— M2 board variantmetadata.zip— SD-card metadata bundle (drop into/of your SD card)
Version 1.06
A small but targeted release. Two fixes on top of 1.05, one visible, one you only hit if you'd been poking at the video settings.
What's new
HUD chrome reappears in games that use OBJ palette 7
Several SNES titles store their HUD colors in the top slice of CGRAM — OBJ palette 7, which lives at indices 240–255. Our HDMI driver reserves indices 251–254 for sync-control codes, and when the framebuffer contains one of those values the assembly scanline copy substitutes it with the nearest visible color from the rest of the palette.
That substitution table was only computed once, before the game had uploaded its real palette, and never refreshed. So the first time a game wrote silver/white chrome colors to CGRAM 252/253/254, those pixels showed up on screen as sync-black instead.
Addams Family Values surfaced this first — the skull life counter and its silver frame looked like an empty black pill. The fix is small: the substitute table now updates incrementally on every palette write. Cost is O(4) in the common case, a full rescan only when one of the reserved targets itself moves. All of it stays on Core 0, so the HDMI VBlank ISR is untouched.
As a bonus while I was in there, the fast-mode per-scanline sprite cap went from 16 back up to 32 (SNES hardware max). Some HUDs assemble their chrome from a lot of small sprites and the cap was silently dropping the late ones.
Warning at boot when video settings could hide game content
If you've been debugging something and left BG1 off, or turned transparency off to check what it was doing, it's easy to forget. The next day you fire up a game and wonder why it looks broken.
After the welcome screen, you now get a yellow warning page listing every game-affecting video setting you have turned off — BG1–4, sprites, transparency, HDMA — with a nudge to open the settings menu (Start+Select in-game) if that wasn't intentional. The screen is skipped entirely when everything is at defaults, so you'll only see it when it's telling you something useful. CRT overscan is excluded because it doesn't affect game content.
Press any button or wait eight seconds to continue.
Firmware
frank-snes_m1_1_06.uf2— Board variant M1frank-snes_m2_1_06.uf2— Board variant M2metadata.zip— SNES cover art and game info for the ROM selector (copy to your SD card, same as before)
Version 1.05
This release is focused on the UX around the ROM selector and a handful of in-game hotkeys. The emulator core is unchanged; if a game ran on 1.04 it runs on 1.05.
What's new
File browser
There's a second way to pick a ROM now. From the carousel press Select+Start and you land in a directory listing rooted at /snes, with .. for up-navigation, a size column, and folders sorted before files. Only .smc, .sfc, and .fig files are shown.
- Up/Down wraps (top ⇄ bottom)
- Left/Right pages by 20 entries
- Scrollbar when the list overflows
- Auto-repeat on held D-pad
- Your current directory and last-launched filename are saved, so a cold boot returns you exactly where you left off
B / ESC / F12 or another Select+Start returns to the carousel.
No-ROMs flow
When /snes is missing or empty, 1.04 sat at a blank loading screen. Now you see an explanatory screen telling you what to copy, then it drops you into the file browser so you can load a ROM from anywhere on the SD card.
Search
Select+A in the carousel or file browser opens a search dialog. Gamepad users can pick letters from an on-screen keyboard. If you have a PS/2 or USB keyboard plugged in, just type — the query updates live and shows the top five matches by title. Picking a result takes you straight back to the carousel at that ROM.
Settings behaviour
- Settings no longer opens from the ROM selector. Start+Select on the carousel now opens the file browser instead. Settings are only available while a ROM is running.
- New RESTART GAME entry at the bottom of the in-game Settings menu — same effect as hitting the Reset button on a real SNES: the ROM stays loaded, state is cleared, the title screen comes back.
- The Settings menu now shows a scrollbar when the list overflows.
New video option
- CRT OVERSCAN toggle in Video Settings. Blanks the edge columns of the frame to hide scroll artifacts that appear at the left/right edges in games using per-tile offset scrolling (Axelay and other Mode 5/6 titles). In 1.04 this blanking was applied unconditionally; it's a switch now.
New in-game hotkeys
- F11 → back to ROM selector. Skips the menu entirely.
- Ctrl+Alt+Del → soft-reset the current ROM, same effect as the Restart Game menu entry. Edge-triggered so one press fires exactly one reset.
Both work on PS/2 and USB keyboards.
ROM selector quality of life
- ROMs are sorted alphabetically (case-insensitive) after the scan.
- CRC indexing and metadata loading now show a progress bar instead of a blank screen.
- Held buttons no longer leak between screens — you won't auto-select a ROM just because you were still holding A when the selector appeared.
Firmware
frank-snes_m1_1_05.uf2— Board variant M1frank-snes_m2_1_05.uf2— Board variant M2
SD card metadata
metadata.zip contains cover art and game info indexed by CRC32. Extract the metadata/ directory into /snes/ on your SD card. The selector shows filenames when metadata is missing, so this is optional.
Version 1.04
Changes
- Fix scroll edge artifacts (CRT overscan simulation for offset-per-tile modes)
- Implement SuperFX (GSU) chip emulation - work in progress
- Fix version display (1.03 was showing as 1.3)
Firmware
frank-snes_m1_1_04.uf2— Board variant M1frank-snes_m2_1_04.uf2— Board variant M2
Version 1.03
What's New
- Button mapping settings: New Settings > Button Mapping submenu for remapping A/B/X/Y/L/R/Start/Select per input device (keyboard, NES/SNES gamepad, USB gamepad)
- Scan-based mapping: press A to scan, then press any button on the target device to assign it
- Mappings saved to settings.ini and take effect in-game immediately
- D-pad remains fixed (not remappable)
Version 1.02
Fix crash on games using SNES hi-res modes (Mode 5/6)
Games that use SNES hi-res rendering (512px wide) — such as Axelay — would crash shortly after switching to Mode 5 or Mode 6. The 512px rendering overflowed the 256px framebuffer, corrupting emulator state.
Fix: Hi-res modes now render at half horizontal resolution (256px), preventing the buffer overflow. Visual quality in hi-res scenes is slightly reduced but gameplay works correctly.