Hardware Sprites on the ZX Spectrum Next in C
Learning to program is an endurance game full of random side quests, dead ends and frustration. Rather than learning “how to do X”, which is specific, it’s much more useful learning “how to figure out how to do anything at all”.
Go look on StackOverflow at all the questions that come down to “I don’t understand what I’m trying to do in the first place, can you write my code for me?”. Here’s how to not be one of those people.
The Spectrum Next comes with its own sprite drawing tool. It’s quite simple, but works and saves its data in the exact format the Next wants. No fussing with conversion tools or trying to figure out how to make a Photoshop 24 bit PNG fit into an 8 bit machine.
Sprites on the screen
The manual contains a wonderfully detailed section on how to do sprites, using BASIC. Also, the Specnext website contains some technical information about what sections of memory to poke at in the Next to do the same.
Programming embedded systems
If you’ve never done embedded programming before, this is how hardware (mostly) works. There are special areas of “memory” called registers, or ports (depending on the terminology) which could be in RAM, or could be in pieces of hardware physically attached to the CPU’s bus. Writing data to those areas of memory controls the hardware directly.
The Next calls these registers, there’s several related to controlling the sprite hardware. Writing bytes into those registers will select a specific hardware sprite, and then set up the screen location, which image to draw, and so on.
People have done this before, learn from them
So how do we turn that into C code then? Well, fortunately, someone has done this for us, which saves a lot of effort. Are we here to learn deeply about the Next’s registers, or are we trying to draw some sprites on the screen? Today is sprite day. Some other day can be “understanding the innards” day. You can’t understand everything at once.
Before expending any effort figuring out what this code did, I needed to check whether the code even works. For all I knew, it could have been based on an old API, never worked in the first place, or not done what I wanted.
What they did, didn’t work for me… why?
I ran it in CSPect and was greeted with a sprite happily bouncing around the screen. Success! working code I can take apart. Even includes some sprite data for testing. Onwards with learning how to do the thing!
Except it didn’t work on the real hardware. I spent quite a long time - many hours - trying to find out what was wrong. At this point I didn’t know enough about what I was doing to understand why things weren’t working. I knew the general concept and theory of “put values in registers, things appear on screen” but that was it.
This was me learning the practical application of that theory.
Not giving up
This is the point most people give up. The trick is to not give up; knowing something is not the same as knowing how to use something. Also, just because you can’t do something now, doesn’t mean you won’t be able to do it later. Programming is an exercise in attention to detail, there will be one small thing wrong. Possibly that small thing is you failing to understand a concept at the moment.
Success is in the details
In this case it was a compiler switch and I discovered it by accident. The sprite demo was written before Next hardware was available, using an emulator, so naturally it worked in an emulator. Compiling the code produced a SNA file, which is a snapshot of the machine’s RAM (I think…) and is one of the formats the Next understands. However, my sketchy understanding is that a SNA file is a regular ZX Spectrum snapshot, not a Spectrum Next one.
They are called NEX files, and there’s a different compiler switch to make those. Changing the compiler to create a NEX file produced a file that worked in the emulator and also worked on the real hardware.
Recognising what success looks like
How did I figure out this tiny problem, buried inside a Makefile, on a line of code that wasn’t even visible on the screen because the line was too long?
Experience of dealing with this crap. I expected the problem to be obscure, non-obvious and yet incredibly reasonable once found. Problems like this always are. Again, this is learning the practical application of theory - Knowing what you want to do is not the same as actually doing it.
Fill your brain with relevant input
All the time I was trying to fix the problem, I found examples of other people’s Next programs, and they always showed the compiler switches. Everyone seems to use different ones, and a lot of the switches are strange and don’t make a lot of sense just by looking at them. There’s even two different C compilers, and two different C libraries to pick from, and about five different states the machine could be in.
The trick is to let all this detail wash over you, and pick out the recurring patterns, or look at things that stand out. I noticed the vast majority of Spectrum Next programs I was running on the hardware had a .nex extension, not .sna .
And in the Makefile was a line saying
-subtype=sna. Changing it to
-subtype=nex fixed it all.
So there we go, sprites. Lovely. Next time, let’s learn all about the perils of relying on documentation where none exists and make the sprites move around under my control using the joystick and the mouse.