PicoDMG Devlog

Not just another Game Boy Emulator

View on GitHub

Rust RP2350 Version: Technical Postmortem

Description

This document summarizes what happened during the attempt to move the project from the YouMakeTech RP2040 C/Pico-SDK version of the emulator to the Altaflux Rust-based RP2350 version, what was tried technically, what worked, what did not, and why that path was abandoned.

This is not a language-level judgment against Rust. The problem was practical: the Rust RP2350 version did not converge to a usable emulator fast enough, and the working C codebase later proved to be a better foundation for the actual hardware goals.

Initial decision

The original plan was:

The assumption was reasonable:

Early bring-up work

The first phase was not about emulator accuracy. It was basic hardware bring-up and board adaptation.

Main goals in that phase:

Console and observability problems

One of the early frictions was that debugging visibility was weak.

Symptoms seen during this stage:

This matters because it slowed every other debugging step. Before display or emulator issues could be trusted, the board needed a known-good way to show status.

Observed sequence:

  1. UART was tried first and did not provide reliable output.
  2. Dedicated LED smoke testing proved the board itself was alive.
  3. USB CDC became the only way for runtime diagnostics.

This was not the final reason for abandoning the Rust branch, but it increased debugging cost significantly.

Display bring-up: the biggest practical problem

The largest technical problem on the Rust RP2350 path was the TFT/display path.

What was observed

Multiple repeated failure patterns appeared:

These symptoms came up across several tests with both small and larger SPI TFTs.

What was tried

What the results looked like

The branch produced several characteristic states:

Those numbers are critical because they explain the final decision.

The problem was not only “the panel is white”. The problem was that even when the display path could be made to show something, the emulator was still far from usable.

Performance measurements

Very bad early state:

FPS: 0.09 | frames=3 elapsed_ms=32651
FPS: 0.09 | frames=3 elapsed_ms=32787 | last_frame_ms=32708

Still unusable after improvement:

FPS: 7.59 | frames=8 elapsed_ms=1054 | last_frame_ms=131

With some changes disabled / isolated:

FPS: 18.11 | frames=19 elapsed_ms=1049 | last_frame_ms=55
FPS: 17.96 | frames=18 elapsed_ms=1002 | last_frame_ms=56

Best case during atomic rollback-style testing:

FPS: 29.82 | frames=30 elapsed_ms=1006 | last_frame_ms=30

Known-working hardware SPI path, but still far too slow:

FPS: 10.07 | frames=11 elapsed_ms=1092 | last_frame_ms=98

Technical interpretation

These numbers exposed two facts:

  1. The bottleneck was not one simple configuration error.
  1. Even the best observed runtime behavior was not close to acceptable gameplay.

Main debugging strategy that was used

I drove the testing in a disciplined way after the initial chaos:

It revealed an important technical conclusion:

Why I abandoned the Rust path

I did not abandon the Rust RP2350 version because of ideology. I give up because It was unusable.

Practical reasons

  1. The old RP2040 C firmware was performing much better out of the box.
  2. The Rust RP2350 branch required heavy bring-up work before it even reached comparable integration quality.
  3. The Rust RP2350 branch remained too slow for acceptable gameplay.
  4. Display behavior remained unreliable during much of the investigation.
  5. Every additional fix had a high validation cost because basic hardware feedback was already expensive.

Technical reason in one sentence

The Rust RP2350 emulator was abandoned because it never converged to both:

at the same time.