Last week’s article saw us preparing sprite graphics for display on the ZX Spectrum’s display screen. This week we’ll actually do the rendering, and kick off the shooting gallery project properly:
It also turns out that the shooting gallery project doesn’t quite exercise all the things we’d need from a sprite renderer, so the main program this week will be a simple test program that just moves a graphic between, and off, all four corners of the screen.
Put simply: the ZX Spectrum does not have any sprite graphics capability, but this did not stop the game developers of its time, it does not stop the developers targeting it today, and by the end of this article, it is not going to stop us.
My personal Rosetta Stone for spritework for awhile has been a simple shooting gallery program. We’ll be using its particular needs to guide our engine, and making note of the places where that leaves gaps.
It’s also going to be a quite large project. This week turns out to be almost entirely design and prep work, though that’s still going to involve writing a good chunk of code.
Working on these Spectrum projects has meant more practice with Z80 assembly along with everything else, and while I do think I’m basically at parity between Z80 and 6502 now in terms of my skills, the grind of actually doing things with it to get practical experience is still very necessary. Implementing the line-drawing algorithm required me to stretch my skills in new directions and put in some real work on both program design, instruction-level micro-optimizations, and in seeing just how far I could push my preferred assembler.
This was great, as practice: I had to really sit down and grind through what options are all available and when and how I could best use each option. I had to consider multiple ways of phrasing everything. I did in fact come up with some real uses for multiple idioms that were new to me in my own code. I could find that all of this still stayed basically consonant with my big CPU comparison last month.
I still have no proper illustration for the act of studying and hand-optimizing assembly code, so once again, enjoy the main menu screen of EXApunks (Zachtronics, 2018).
But then, the punchline: in practice, as opposed to as practice, none of those idioms ended up being worthwhile for the actual line-drawing function. After using them to write the function in the first place and then testing them out, I started tuning performance and every single one got removed.
That’s a quirk of this function, though. Wrestling with the alternatives here lays out the space neatly, and even though there’s no final work to show, there’s still going to be some value in showing my work.
Last time, we worked through the many and varied abilities the ZX Spectrum system ROM offers us when we treat the screen as being a text-based terminal. However, as we noted back then, the Spectrum does not in fact have a text mode, and instead provides only a bitmap screen that its system ROM sometimes wraps in a character-oriented API. That API is quite powerful, but we also have direct access to the bitmap memory. Today, we will discuss that memory and how to work with it.
The other relevant fact about the ZX Spectrum is that this bitmap mode is all we have. The platform got many finely-animated games over the years, so we will also cover some techniques for sprite-like behavior without actual sprites.
Before moving on to commanding the ZX Spectrum’s graphics hardware more directly, it’s time to settle some scores.
One of the things I particularly liked about the ZX Spectrum’s BASIC is that it provides pretty powerful commands that let you directly work with everything the system has to offer, and it lets you do it quite easily. The closest we got to having to do an end run around BASIC here was POKEing in the graphics for the umbrella—and even that was just using it to fill a buffer that BASIC itself gave us. Commodore 64 BASIC, rather infamously, offers basically no direct support for its own hardware. Everything is done via memory-mapped I/O with POKE and PEEK, directly. Furthermore, in an unpleasant number of cases, it’s really necessary to supplement the BASIC program with some machine language support programs to keep everything running at an acceptable speed.
So I got to thinking. What does it take to match this simple display from the TI-99/4A, and later the MSX and ZX Spectrum, on the C64? Obviously it can do it. But what does it take to do it in 100% BASIC, and how idiomatic can we make it?
Now that we’ve taken a look at the kind of control that the Spectrum’s BASIC gives us over the hardware, it’s time to dip down into machine language and see what is offered to us there. There’s quite a bit more to cover in this realm, and I expect it’s going to end up spread out over quite a few posts.
It is also quite a bit more fraught than on many other platforms, because Sinclair only paid minimal attention to exposing a consistent and structured firmware interface. Commodore’s 8-bits, from the original PET through to the C128, all had backwards-compatible jump tables at the end of their “KERNAL” ROMs which meant that quite a lot of machine language code could function identically even when doing things like file processing and disk access. MSX was not a single computer at all, but an industry standard that manufacturers wrote to, and a major part of that was a well-defined jump table up near the interrupt vectors. The IBM PC’s BIOS served a similar role, though less voluntarily.
The Spectrum, however, has only a handful of defined entry points and as a result developers tended to directly call deep within the system ROM itself in order to get the results they wanted. The Timex Sinclair 2068 had an incompatible ROM and as a result almost no Spectrum software ran on it—it seems like this was understood to have been a major contributor to its failure in the US Market. I’m a bit skeptical of this, because that meteoric US crash was shared by the MSX, the Commodore 16, and the Coleco Adam, all of which were plausible direct competitors to the TS2068. However, given that the 128 was released after the 2068’s failure, and that the 128 kept the relevant parts of its ROM very carefully compatible with the 48K version, I suspect that Sinclair nevertheless learned an important lesson here.
For the purposes of this series I will be taking the 48K Spectrum as the target platform, but also making sure that the techniques I describe also work on the 16K and 128K machines. There were a vast number of Spectrum clones and successors, of varying fidelity; if I encounter something interesting regarding them along the way I’ll bring it up, but it will all be purely sidebar territory.
For our first foray, I’m going to look at the facilities we have to command to get a display like the 100%-BASIC “Manic Mechanic” game I showed off last week:
In this first post, we’ll start by looking at basic system organization: how machine language programs exist on the system, how they are loaded and run, and how they coexist with BASIC and the BIOS. Then we’ll dig into the facilities for text-based displays on the system, including the “user-defined graphics” facility that Manic Mechanic itself relies on. We’ll wrap up by looking at keyboard and joystick input, which turns out to be quite close to what we had to do in BASIC.
Last month (just a couple days before my Exidy Sorcerer article) the ZX Spectrum celebrated its 44th birthday. I have written shockingly little about the system given that it still remains the first system I go to when prototyping Z80 code. I wrote up a platform guide for it last year and mentioned it in passing while I was trying out various Z80 development tools, but beyond that it’s been almost ten years since it’s gotten any dedicated articles. Even those were pretty perfunctory; I was mostly interested in the challenge of writing a machine code program that could run unchanged on the Spectrum 16K and the wildly incompatible TS2068.
So let’s have some fun, with a belated birthday bash. Today I’ll do a tour, in BASIC, through the capabilities of the core 16K and 48K Spectrums, and then take a quick look at what the 128 offers us as a casual user. Then, over the next couple weeks, I’ll dig down into how to take advantage of these capabilities in machine code as well. This will be in the vein of the tour I did back in the day for its predecessor, the ZX81, and more recently my exploration of the TI-99/4A and MSX.
A few years ago, I needed to save some cartridge space in a SNES project, and I did so by compressing that data with the LZ4 compression algorithm from 2012. I found that working within the constraints of the SNES allowed me to take some convenient shortcuts during decompression and I have since found those constraints and shortcuts to be widely relevant on the 8- and 16-bit platforms my hobby programming often involves. I accumulated two more implementations (for Motorola’s 6809 and 68000 processors) as I worked on projects for the Tandy Color Computer and the Sega Genesis.
Now, as a consequence of my recent experiences with the Sorcerer, I found myself with four new implementations, for the Z80, two CPUs related to it (the Intel 8080 and 8086), and the 6502. As I mentioned at the time, the Z80 implementation in particular was very straightforward, and it informed the other three pretty directly.
My article about this for the 68000 was kind of desultory—it’s pretty clear on rereading it that the only thing I found interesting about it was the way the 16-bit code ended up bearing more in common with the 8-bit 6809 code than the 16-bit 65816 code. I expect this article to be my last hurrah on the subject, so I’d also like to give it more respect and more scope. I’ll start with my potted summary of how LZ4 works and what variations I made to it, but then also look at why LZ4 is so friendly to the Z80, especially as it compares to the 8080 and 6502. After that, I’ll use the LZ4 implementation as a worked example of last week’s article comparing all these CPUs by showing how the Z80 implementation can be easily transformed into the 8080 and x86 implementations, and some of the very different implementation decisions the 6502 version must make.
Fair warning: This article is very long and very dry compared to my usual fare. If you want to see the same function implemented in four different assembly languages, this is the good stuff and go on and have fun. If not, maybe come back next week when I expect to be goofing around with high level languages again.
Last week’s adventures with the Exidy Sorcerer led me to write a Z80 version of the LZ4 decompressor I’d previously used on the SNES, the CoCo, and the Genesis. At this point, this has become generic enough that I took my previous implementations and broke them out into their own little library directory so I could use them in other projects. The SNES implementation turned out to be too tightly tied to the project it was in to be made generic, but the other three were just fine.
However, while I was looking at those implementations, I rapidly found that I had not three implementations, but six; the Z80 implementation inspired versions for the earlier Intel 8080 and the later Intel 8086, and I felt the lack of a dedicated 6502 version and wrote a decompressor there as well.
My original plan was to present all four new implementations side by side as a way of highlighting the similarities and differences between the various CPUs, with maybe a little historical scene-setting at the start to map out the relationships between all the various chips. This got entirely out of hand so I’ve split it in two; this week’s article is just about comparing the CPUs in their context, and next week I’ll dig into the implementations as a worked example of why these differences matter.
The idea of what it means to be a personal computer has evolved over the years. The usual story is that Back In The Day you turned the computer on and were immediately in BASIC, while nowadays you boot into some kind of graphical operating system and choose what application to run from there.
There’s a few problems with this. “Nowadays” starts clear back in 1984 with the Apple Macintosh, while “back in the day” was only a handful of computers like the Commodore and Sinclair machines. Apple’s 8-bits expected a boot disk and needed a special command code to enter BASIC, while the Atari and PCjr needed cartridges installed. PCs proper, along with the TRS-80, would boot into a command-line DOS that you could then enter BASIC from in a single command. If we allow those two, then “back in the day” extends through 1995, as the pre-Windows-95 DOS machines of that era were still a single command away from entering the (now much fancier, IDE-adjacent) QuickBASIC environment. Finally, there’s a clear era before this where computers are primarily electronics projects built from kits. That era has a fuzzy border with our C64-and-Apple-II era, too; the earliest Sinclair machines are contemporaneous with the VIC-20 and were sold as kit computers as well.
The kit computer era is interesting because it has a clear, iconic standout in the early 70s, much the same way that the Apple/PET/TRS trio stood out in the late 1970s: the Altair 8800. The two key features of the Altair were an 8080 processor and a very useful and expandable peripheral system. The 8080, thanks in part to the Altair’s popularity, got a large library of software, and the later systems based on the Zilog Z80 (which was fully backwards-compatible at the binary level) could make full use of all of it. Meanwhile, the Altair’s peripheral system became a de facto industry standard for expansion boards as the S-100 bus. A decade later, the IBM PC AT would inspire a new Industry Standard Architecture that they would literally name that.
So let us shift focus, then, to the year 1978, a year that’s in the middle of all of this. The home computer revolution has kicked off in earnest, with the PET, Apple II, and TRS-80 all already well-established. S-100 is still an industry standard, and kit computers, while niche, are still commonplace. We even have a vision of the future, as the Xerox Alto, the machine that inspired the Macintosh, also exists and has for some time. Into this space, the arcade game company Exidy released a home computer of its own: the Exidy Sorcerer. As an arcade company, we might expect the Sorcerer to be a video game powerhouse, prefiguring the Atari 400 and 800 that their competitor would release the next year. What we actually get, though, is something quite different:
The Sorcerer is an S-100-based computer with a Z80 CPU, fully pre-assembled, and with a cartridge system that let you boot into BASIC and a programmable text system similar to the TI-99/4’s graphics mode. Unlike those systems, though, it had a remarkable 64×30 monochrome display, so even its text-mode graphics could look quite detailed, as we can see in the game Galaxians: