GAMES2025

biplup-run

An endless runner on hardware with no operating system. 16.8 MHz, and everything you get you have to ask for.

legally distinct

C · libtonc · Meson · arm-none-eabi-gcc

VIEW ON GITHUB  →

WHAT IT IS

A Pokemon themed endless runner for Game Boy Advance. An ARM7TDMI at 16.8 MHz with no operating system, so anything the game does, somebody has to write.

MY PART

  • Project setup, and the Meson cross-compilation toolchain
  • The unit test framework, and the tests that run in it
  • Physics, collision and the high score. This is the part where I was learning

THE TOOLCHAIN

Cross-compiling C into a real GBA ROM with Meson, arm-none-eabi-gcc and ninja, set up to build from Windows, macOS or Linux. libtonc underneath for direct hardware access, which keeps full control without giving up every convenience.

the game in the emulator

A Pokemon themed endless runner for the Game Boy Advance, running in an emulator. The flashing kit worked. The cartridge we got was the wrong one.

TESTS ON A GAME BOY

Meson does not cross-compile tests well, or at least it did not then. Running a test means running it on the target, and the target is a Game Boy. So the framework had to exist before any of the tests could.

A Game Boy has nowhere to print to. No terminal, no stdout, nothing watching. So the tests are their own ROM, and the results get drawn on the screen.

snprintf(test_buffer, sizeof(test_buffer),
         "system_utils.c:\n\n%d%d%d\n\ntext.c:\n\n%d%d%d%d\n\n..."
         SYSTEM_UTILS_TESTS, TEXT_TESTS, INPUT_TESTS,
         OBJECT_UTILS_TESTS, KINEMATICS_TESTS);

while (true) {
  tte_set_pos(5, 7);
  tte_write(test_buffer);
}
#define INPUT_TESTS \
  test_pregame_reset_score(), test_pregame_reset_frame(), \
      test_pregame_to_game(), test_jump_state(), ...

one digit per test, read off the screen

The test ROM output on screen: source file names, each followed by a row of ones
the test ROM

Every test returns 1 or 0. A macro expands a whole file worth of tests into a comma separated list, so each one lands as a single digit on screen and you read the results off the screen.

WHERE IT LANDED

Four of us over about five weeks, for Software Systems. A lot of it was pair programmed, sat at one machine, which is why the commit history reads the way it does.