- -- --- Mr. Fusion by bananaboy

A bare metal demonstration for the Leapster Explorer presented at Syntax 2025
in the Wild Demo category, taking 6th place.

All code, graphics, and music by bananaboy.

:: Quick Start

To run the demo on your Leapster Explorer:

   1. Plug your device into your PC with a USB cable.
   2. Boot your device into recovery mode by holding down the left and right
      shoulder buttons and the ? button, and turn on the power. You should
      see a picture of the Leapster Explorer and a PC connected by a cable.
   3. Ensure that Python is in your path.
   4. Run `upload.bat` in this package as administrator.
   5. The demo should start!

Note: this will NOT overwrite anything in your Leapster! This simply loads
the demo into RAM and executes it from there.

If you run into any troubles feel free to contact me (see the end of this
document).

:: Hardware

The Leapster Explorer is a kids handheld console toy with an ARM9-based CPU
running at 393 Mhz, with 64 MB SDRAM, a simple audio output device, and a
320x240 screen. There is no FPU. There is also OpenGL ES 1.1 level 3D
acceleration, but Mr. Fusion doesn't use this; it only uses a framebuffer.

The Leapster Explorer runs Linux, but I didn't think it was particularly
interesting to just build an elf for Linux, so instead I wrote a bare metal
demo.

:: Running

If you have a Leapster Explorer and wish to run this demo, you can boot your
device into recovery mode and use the included batch file `upload.bat` to
transfer the demo to the device and launch it.

In recovery mode, the device expects to receive a Linux kernel, but we can
send it whatever binary we want. It will load the binary into RAM and jump
to it, as though it is starting a Linux kernel.

When in recovery mode the device appears to a connected PC as a USB mass
storage device, and waits for SCSI commands to send it data. We can automate
this using the `sg3_utils` package and some simple Python and batch scripting
to find the attached device and upload our code.

This zip includes the required executables and scripts (except for Python).

:: Software

The recovery mode boot loader does the bare minimum to initialise the device.
When it jumps to our entry point, we are running bare metal, so we have to do
everything - there is no elf loader, the MMU hasn't been configured, and most
of the hardware that we want to use hasn't been initialised.

We first need to do some housekeeping. When we start executing we are still
running in the ARM IRQ processor mode with whatever stack the boot loader set
up. But ideally we would be running in supervisor mode with our own stack
memory configured, and our own interrupt handlers.

The first thing we do is set up a new stack under our control for each of the
processor modes, and leave the processor in supervisor mode.

Because the boot loader runs from ROM, the initial interrupt vector table is
unmodifiable so we can't just patch in our own interrupt handlers. But the
ARM9 has an MMU and the ability to relocate the interrupt vector table to
0xFFFF0000. So we can enable the MMU, map some physical pages to 0xFFFF0000,
and then set up our interrupt vector table in there. We also enable the I- and
D-caches. Then we jump to main.

Now we can do what we like! Because we're running bare metal, we have no
executable loader that started us, and I also build without any runtime
library which means we have to zero the bss section ourselves. We have to also
be careful to not use any constructs that require relocations, since they will
never be patched (because no loader!). So when compiling we can enable
position-independent code with `-fPIC` which will tell the compiler to use
PC-relative addressing where possible.

In a future iteration of the code base I plan on writing a loader that handles
this and allows me to have relocatable code.

:: Contact

For any further questions about the tech and hacking the Leapster Explorer,
feel free to contact me at sam@humbug.net or ping me on Discord on the LFHacks
server.

EOF
