avatar
Lars Diget

Making a ZX Spectrum Game - Part 6 - Running the Game on actual Hardware

Dec 15, 2020 13:01 · 679 words · 4 minute read

At this point, the game is playable in the emulator with graphics, animation, collision detection, and score keeping. The next step is to answer the obvious question: will it also run on an actual ZX Spectrum?

This has always been the entire point of this project; it is one thing to get something working in an emulator, but it feels very different when the code runs on the machine it was made for.

Loading the Game on Real Hardware

To get the game onto a real ZX Spectrum, I use a TXDuino tape emulator. It emulates cassette loading from digital audio files, which makes it a very practical way to move a TAP file from a modern computer to original hardware without having to rely on old tapes or a full physical cassette workflow.

Here is the game loading and running on the real machine:

Seeing the game load and run on the actual hardware is one of the most satisfying parts of the whole project. The emulator is useful while developing, but this is the point where the project starts to feel real.

Adding a Proper Loading Screen

If I am going to load the game like a real Spectrum game, I also want to give it a proper loading screen.

That is one of those details that is not strictly necessary, but it adds a lot to the experience. A loading screen makes the project feel less like a prototype and more like a tiny game that could plausibly have existed in the 80s.

The loading screen is handled by a small BASIC loader program:

10 CLEAR 24575
20 BORDER 0
30 LOAD ""SCREEN$
40 POKE 23739,111
50 LOAD ""CODE
60 RANDOMIZE USR 32768

There are a few important things happening here:

  • CLEAR 24575 reserves memory below the machine code program.
  • LOAD ""SCREEN$ loads a full screen image into the Spectrum display memory.
  • POKE 23739,111 tweaks the machine state after the screen load so the transition into the rest of the loader works correctly.
  • LOAD ""CODE loads the compiled game binary.
  • RANDOMIZE USR 32768 jumps to the start address of the game and runs it.

In other words, the loading screen is not generated by code at runtime. It is loaded as a prebuilt Spectrum screen before the actual game code starts.

So rather than drawing the splash screen line by line in the game itself, the artwork is treated as an asset and loaded up front as part of the boot sequence.

Here is the loading screen in action:

Packaging the Game

The repository contains both the loader and the compiled game source. The rough loading flow is:

  1. load the BASIC loader
  2. load the splash screen as SCREEN$
  3. load the compiled game code
  4. jump into the game at address 32768

That is a very classic 8-bit setup, and probably my favorite part of the whole thing. Even a very small game feels much more complete once it has a loader, a title image, and a proper boot sequence.

Wrapping Up

This series is a simple experiment: can I make a tiny game for the ZX Spectrum and document the process along the way?

The answer is yes.

Along the way, I touch a lot of the things that make the ZX Spectrum fun to work with: Sinclair BASIC, cross-compilation, user-defined graphics, sprites, animation, collision detection, and finally getting the result onto actual hardware.

The game itself is still small and simple, but that was never really the point. The point is to explore the machine, learn something, and make something tangible.

And there is something uniquely satisfying about seeing code written on a modern computer come to life on a machine that is more than 40 years old.

If nothing else, this project is a reminder of why old hardware is still so compelling: the limitations are obvious, the feedback is immediate, and even tiny results feel earned.

To me this “the” reason to make things for old 8-bit hardware.