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.
Hello, World
The first-generation Spectrum computers basically presented themselves as the ZX81 but more, and a veteran of the earlier Sinclair computers will be at home immediately:

The K prompt means the same thing it did on the ZX81; it means we are in “keyword” mode and a single keypress will give us one of BASIC’s commands. P will give us PRINT, J will give us LOAD, and many others. Here, too, we are the ZX81 but More. Here is Fuse’s keyboard reference, which replicates what was printed on the system’s own keys:

We have more options per key than we did on the ZX81, too, though some old friends return:
- Keyword mode, which will deliver the white word on the bottom of the key. Numbers are entered normally so we can enter line numbers in this mode if we wish.
- Letter mode is the mode we’re usually in when typing, and when we’re in it the keys represent the letter or number that is the printed boldly upon it. CAPS SHIFT gives us upper-case on letters, and on the top row it gets us the thing described by the white text above the key. (CAPS SHIFT 5-8 are the cursor-movement keys.) SYMBOL SHIFT gives us the red text character on the right side of the key. This means that CAPS SHIFT works like normal SHIFT on other systems, except for the top row. Exclamation point is SYMBOL SHIFT 1, for instance, while CAPS SHIFT 1 (“Edit”) erases the line you’ve typed so far and calls up the most recently accessed BASIC line in your program to edit it. This certainly didn’t trip me up a thousand times while I was preparing this article.
- Caps mode is toggled with CAPS SHIFT 2, and it leaves all the letters in uppercase for free when we’re in letter mode.
- Extended mode replaces the “Function” mode on the ZX81. We enter it by pressing CAPS and SYMBOL shift together, then releasing them. This gives us the green keyword printed above the key. If we hold either shift key while so doing, we get the red-text keyword underneath it instead. The top row, again, is different; it has only the red-text keyword and will provide it even when unshifted.
- Graphics mode is toggled with CAPS SHIFT 9. When in this mode the numbers 1-8 become the semigraphics characters depicted on their keys. Inverse text mode (CAPS SHIFT 3) will give the other 8 required to have the full set of 2×2 semigraphics. While in this mode, the letters A through U look like they’re always capital letters, and V-Z don’t work at all. There is more going on here than it seems; we’ll get to that in a bit.
When doing ordinary BASIC things, Spectrum BASIC is very similar to ZX81 BASIC. Here’s a Spectrum version of the temperature conversion program I wrote for the ZX81 nine years ago:
This just barely fits onto the Spectrum’s 32×24 screen.

The little caret by the last line works the same way as on the ZX81; it represents the “current line” that will be called up if we hit EDIT. I left the variables in lowercase this time too, but I often find that distracting and will keep everything in all-caps in the text. Identifiers are case-insensitive anyway.
One sort of unusual thing about Sinclair machines that I didn’t mention in my older articles is that there’s a sharp split between output in the upper portion of the screen and text entry in the lower two lines (the “status window”). We see that even with INPUT commands:

The Invisible Upgrade
The Spectrum and ZX81 both run a Z80A at similar speeds; 3.25MHz on the ZX81 and 3.5 on the Spectrum, both of which roughly match the MSX and ColecoVision. However, the Spectrum’s responsiveness is much, much faster than the ZX81’s when we work our way through these programs. This is far beyond what we’d expect from a 7% overclocking.
It turns out that this is the consequence of the Spectrum having actual proper video hardware. The ZX81 intimately involves the Z80 CPU when rendering the main display, so assuming the display is on (what its BASIC refers to as SLOW mode), we only get to run our code during VBLANK. The effect, as calculated by Martin Korth, is that a ZX81 is effectively only running at 800 kiloHertz, with the 60Hz T/S 1000 dropping to a bit over 500! The Spectrum, on the other hand, basically gets to run its CPU all the time and thus gets its full 3.5MHz.
Fancy Text
While you can do more than text in Sinclair BASIC, you can also do much more with text in it. Manic Mechanic was a type-in program from the November 1985 issue of Sinclair User and it is not at all atypical of what folks would do with it:

There’s a lot of moving parts here, so I’ll break them into categories:
Color Control
The color controls on the Spectrum are extremely respectable, especially given that it was always intended as a “budget” system. The screen is divided into a 32×24 grid of character cells, each of which has its own attribute byte. These each have independently controllable foreground and background colors, selectable from a set of 8. (This is a simple RGB bit combination; 1 is blue, 2 is red, and 4 is green, with the remaining colors being the combinations of those.) each cell also has a high-intensity bit that makes both the background and foreground colors brighter, and a “flash” bit that flips the foreground and background colors in the cell 4 times per second or so.
All of these, along with a few other display options, are available via BASIC commands:
- The background and foreground colors are controlled via the somewhat whimsically named
PAPERandINKcommands. These accept values 0-7 as arguments to select the colors as listed above. - There are also some special modes;
PAPER 8orINK 8is a sort of “overstrike” mode where future printing does not alter the colors currently on screen, andINK 9selects black or white ink depending on whichever gives better contrast with the paper. BORDERsets the border color as well as the background of the lower input window. When you’re doing input, the firmware appears to keep things inINK 9mode, so settingBORDER 0will turn the ink white in your input area even asPAPER 0will cheerfully leave your main screen output invisibly black-on-black.BRIGHTandFLASHmay be set to 1 or 0 to turn them off and on.INVERSE, too may be set to 1 or 0, but it leaves the ink and paper colors intact; instead it reverses ink and paper in the character data on its way to the screen.OVERis another option that mutates the character data in-flight; we’ll touch on that later, but it works the same way as these other commands so I’m listing it here.
We can also read data off the screen; ATTR (y,x) gives the attribute byte for screen location (y,x) (with 0,0 at the top of the screen), and SCREEN$ (y,x) does the same to read the character off the screen, when it can. (As we’ll see in a bit, SCREEN$ can be tricked, but ATTR is very reliable.)
User-Defined Graphics
Remember how the letters A through U would appear in all uppercase when we were in Graphics mode? Those aren’t actually the same letters as the ones we use in the upper-case mode. They’re placeholders for a region in RAM that lets us redefine the actual graphic for each of those characters, for use in our own designs. Even in BASIC, we have to do this via direct memory access with POKE; we don’t have an equivalent of TI BASIC’s CALL CHAR here. We do, however, have a function to tell us where we need to do our poking; USR "A" returns the address of graphic A’s definition, USR "B" does the same for B, and so on.
I relied on the machine code equivalent of this in my Spectrum Lights-Out program to be able to redefine characters even on systems that store the characters in different places. The 16K Spectrum turns out to disagree with other models on just where this is.
Inline Controls
PRINT AT (y,x) works to relocate the cursor, much like TI Extended BASIC’s DISPLAY AT or GW-BASIC’s standalone LOCATE command. Uniquely to Sinclair BASICs, you can do this at any point in a PRINT statement: a command like PRINT AT 10,5;"+++";AT 11,5;"+ +";AT 12,5;"+++" will draw a little box.
The Spectrum enhances this further by letting you use any of the color control commands above in a similar way. That makes it pretty easy to chain things together to produce some very nice text displays. Here’s a very slight variant of the nameplate banner program I produced in the TI-99/4A tour:

Creating it is a bit easier than on the TI, even, since colors now belong to places on the screen instead of to individual characters and so we may lay out our display’s color scheme directly:
10 INK 9: PAPER 4: BORDER 4: CLS
20 FOR I=0 TO 31: READ N: POKE USR "A"+I,N: NEXT I
30 DATA 3,15,31,63,127,127,255,255
40 DATA 192,240,248,248,240,224,192,128
50 DATA 255,254,124,120,48,0,0,0
60 DATA 128,192,96,48,24,8,56,0
70 PRINT AT 10,2; PAPER 0;" "
75 REM the ABCD below are actually Graphics characters
80 PRINT AT 11,2; PAPER 0; INK 1; BRIGHT 1;" AB"; INK 7; " BUMBERSHOOT SOFTWARE "
90 PRINT AT 12,2; PAPER 0; INK 1; BRIGHT 1;" C"; BRIGHT 0; INK 6;"D"; INK 7; BRIGHT 1;"Showing off the Spectrum "
100 PRINT AT 13,2; PAPER 0;" "
110 PAUSE 0
120 PAPER 7: BORDER 7: CLS
In fact, we can be even more direct than this, if we want. When we use CAPS SHIFT with the number keys to change colors or text modes, these are turned into text control codes that end up embedded in our strings. This, in principle, should make it much easier to produce complicated text displays in single PRINT statements, much like we did for the Commodore 8-bits. I added some extra work with graphics characters and INVERSE to put some corners on the nameplate:

However, unlike the the Commodore 8-bits, the text control codes get interpreted immediately by the interpreter instead of having a special “quote mode” that freezes them conveniently in amber. This ruins our listing:

Overall I think you’re better off with the interstitial INK and PAPER commands.
Full Graphics
We’ve been neglecting the OVER command. That’s because it works very differently from everything else we’ve seen. Notionally, it produces an “overstrike” effect on the letters that are already in place. The example given in the manual is that we could produce vowels with umlauts with a line like PRINT "uo"; OVER 1; AT 0,0;"""""". Leaving aside the extreme awkwardness of printing out multiple double-quotes in a row—Sinclair BASIC uses pairs of double-quotes to print out a single pair of them—the result doesn’t look anything like umlauts, either:

Studying the results more closely reveals what’s going on; when in OVER mode, the ink in the character being printed is used to toggle the pixels that are already present on the screen. That’s mighty strange behavior for a text display, and there’s a good reason for that: this isn’t a text display. The Spectrum doesn’t have a text display. Everything is bitmapped graphics, all the time. When working in BASIC—and, often enough, even in machine language—it feels like we’re working in a text mode, but digging into the details invariably reveals that we’re bumping into the restrictions set by the color cells.
(This is also, incidentally, how SCREEN$ can be tricked; drawing over a character with OVER or bitmap graphics causes the system to stop recognizing it.)
BASIC gives us pretty good control over the bitmap display at a pixel level. PLOT x,y draws a point at (x,y). DRAW dx,dy draws a straight line with the displacement given, starting at wherever the last PLOT or DRAW ended. CIRCLE x,y,r draws a circle with the specified radius and center point. All of these respect INK, PAPER, BRIGHT, FLASH, OVER, and INVERSE, though all but the last two are applied at the color-cell level, which gets very unfortunate very quickly:

INVERSE and OVER are more sensible; when drawing with INVERSE 1, drawing commands use the paper color instead of ink, and when OVER 1 is set the pixels “drawn” are toggled instead. This tracks broadly what we saw at the character level before.
We’ve had a lot of practice on the TI-99/4A and MSX when it comes to avoiding attribute clash, and with a little care we can get a display comparable to the one we made on the MSX:

The source is meaningfully different this time, though, and not only because DRAW is relative. Much like on the ZX81, screen coordinate (0,0) is on the lower left of the screen and the positive Y direction is towards the top. Furthermore, the lower text area where commands go isn’t part of it, so the display is only 175 pixels tall instead of the 192 we’d otherwise expect:
10 BORDER 1: PAPER 1: INK 9: CLS
20 PLOT 0,0: DRAW 255,0: DRAW 0,175: DRAW -255,0: DRAW 0,-175
30 FOR A=-85 TO 85 STEP 10
40 PLOT 0,88: DRAW 255,A
50 PLOT 255,88: DRAW -255,A
60 NEXT A
70 FOR A=-125 TO 125 STEP 10
80 PLOT 128,0: DRAW A,175
90 PLOT 128,175: DRAW A,-175
100 NEXT A
110 INK 6: PRINT AT 4,3;" "
120 PRINT AT 5,3;" ALL SPECTRUM DISPLAYS "
130 PRINT AT 6,3;" ARE BITMAPPED, ALLOWING "
140 PRINT AT 7,3;" FOR SEAMLESS INTEGRATION "
150 PRINT AT 8,3;" OF TEXT AND GRAPHICS. "
160 PRINT AT 9,3;" "
170 INK 5: PLOT 24,143: DRAW 207,0: DRAW 0,-47: DRAW -207,0: DRAW 0,47
180 DRAW 1,-1: DRAW 205,0: DRAW 0,-45: DRAW -205,0: DRAW 0,45
190 INK 9
There’s a few bonus capabilities the DRAW command provides, as well, which I didn’t have an excuse to use here. Much like with PRINT, color modifiers can be stacked into the command, semi-colon separated, before the actual coordinates to draw to, and these modifiers will be reset after the command finishes. Unlike PRINT, however, the coordinates themselves may not be stacked so I found very little use for this myself. The DRAW command can also produce arcs as well as straight lines; when invoked as DRAW dx,dy,a, it will draw a fragment of a circle through a radians of arc. PLOT 100,100: DRAW 50,50,PI gives you a neat semicircle.
Sound
The sound capabilities of the 16K and 48K Spectrums are pretty minimal—all it has is a simple 1-bit speaker that consumes the entire CPU to play a tone, much like the early Apple II systems. Unlike the Apple II, though, BASIC makes it very easy to command. The key instruction is BEEP, which takes two arguments: a duration in seconds and a pitch number that is the number of semitones above or below middle C we wish the note to be. A secondary but helpful instruction is PAUSE, which takes a duration in frames and which may be used for rests. (PAUSE 0 pauses forever, or at least until the user presses a key. I used that in the banner programs above.) Here’s a simple program that plays the shave-and-a-haircut jingle.
Keyboard and Joystick Input
Simple keyboard input matches many other BASICs. There is an INKEY$ function that returns the key currently being pressed, or the empty string if no key is being pressed. We used that in the temperature-conversion program up top.
However, we also have the ability to read the keyboard matrix directly. Sinclair BASIC directly exposes the I/O bus to the programmer with its IN and OUT commands, themselves analogous to PEEK and POKE for the main memory. As discussed in my dissection of Quadrun, the keyboard is divided into 8 half-rows each of which gets a 16-bit port attached to it that we may feed to BASIC’s IN command. Based on these and the key assignments, it’s not tough to check for proper key chords and do the kind of keyboard input that action games need. Korth’s documentation gives the layouts for various models.
We can do better, though, because we also have the opportunity to read any other ports this way. There were several different protocols for joysticks on the Spectrum over the years, and all of them are BASIC-friendly. Korth’s documentation again provides a list. It also provides a set of recommendations for controls to support in the modern era, and this list looks accurate to me:
- It should support the Kempston joystick protocol. This can be read with
IN 31, and the 1, 2, 4, 8, and 16 bits in the reply correspond to Right, Left, Down, Up, and Fire. The bits are 1 if the direction is pressed and 0 if not. The 32, 64, and 128 bits are unspecified and should not be relied upon to have any particular value. (This isn’t idle; a bug very like this was what broke Quadrun on 48K Spectrums.) - It should support the “Sinclair 2” joystick protocol, which was built-in on the Spectrum +2 and +3. Port 1 reads from port 61438 and the 1, 2, 4, 8, and 16 bits correspond to Fire, Up, Down, Right, and Left. The bits are 0 when pressed and 1 when released; the opposite of Kempston. Other bits must be ignored.
- It should support being controlled by the cursor keys, since that’s going to be the most comfortable way to control it from an emulator. This also reads from 61438 and uses 0 to mean a button is pressed, but the 1 and 2 bits are not used and the 4, 8, and 16 become Right, Up, and Down. Left is available on the 16 bit of port 63486. Fire has a few options but a good one is the 1 bit at port 49150 (the ENTER key).
- It should support the traditional keyboard controls, even though to my eyes they are the completely insane Q/A/O/P/SPACE for up/down/left/right/fire. Q,A,P, and SPACE are the 1 bit in ports 64510, 65022, 57342, and 32766 respectively, while O is the 2 bit in port 57342.
The joystick or cursor key options should not be checked unless the user has asked for them. The Kempston protocol in particular will have unpredictable results if there isn’t a joystick plugged in, and the cursor and Sinclair options interpret port 61438 in conflicting ways.
I differ with Korth on a handful of points regarding the cursor key controls. He suggests that the program should actually check for the cursor keys by confirming that the SHIFT key is being pressed alongside 5678. My experience with both FUSE and EightyOne is that emulators are a little bit unreliable about getting the SHIFT key press into the system in time, especially when there are keychords. I also sharply differ with his suggestion to use SPACE as the fire button to match the keyboard controls; SHIFT-SPACE is the BREAK combination and it will be entered any time the player fires while moving. That’s a complication you don’t want.
Upgrading to the 128
The 128K Spectrum was released a few years after the 48K, after some varyingly successful forays into foreign markets. The hardware changes from the 48K are pretty minor; there’s 80KB more memory, of course, but also a proper sound chip to supplement the 1-bit beeper. We’ve seen that chip before: it’s the AY-3-8910 that was in the Atari ST and the MSX. BASIC sees some changes too, which let us take advantage of both of these, but they are not the first thing we’ll notice when powering it on.

There’s a real boot menu now!
- Tape Loader effectively drops into BASIC for the duration of a single
LOAD ""command. Programs saved with theLINEargument will auto-run from that line number, so this usually serves to make cassette-based programs fully self-booting. - 128 BASIC gets us into the new system’s BASIC, as we’d expect. It’s about 99% compatible with the 48K’s BASIC.
- Calculator is just what it sounds like; a simple calculator app. It doesn’t do anything that a bunch of
PRINTstatements would. - 48 BASIC drops us into a very accurate recreation of the 48K’s BASIC environment, much like the Commodore 128’s
GO 64command. It’s more like 99.99% compatible; you can break this mode, but you have to try very hard to do so. - Tape Tester was designed to calibrate your tape recorder’s volume for more reliable loading and saving. This went away in later models that incorporated a tape deck directly into the console.
128 BASIC is the star of the show here, and selecting it and loading a program into it makes it immediately clear why:

We have a full-screen editor now! We also no longer have input modes, and can just type commands in and have them get tokenized like other systems instead of juggling four different shift states! It can even load and save BASIC programs compatibly with BASIC programs on the 48K Spectrum, as long as we’re using a compatible subset. Glorious.
Keeping to a compatible subset isn’t difficult, but going through the incompatible parts is a good summary of what’s new and changed:
- 128 BASIC has two new keywords:
SPECTRUM, which transfers you into 48K Spectrum mode without clearing the BASIC program from memory, andPLAY, which controls the new sound chip. - Those new keywords take up token space, so the 128 has two fewer user-defined characters; you only get A-S in 128 BASIC compared to 48K’s A-U.
- You can no longer directly type color or graphic control codes into strings; you have to use the inline
INKandPAPERandINVERSEcommands and so on. This is no great loss, and loading a 48K Spectrum program that has these doesn’t technically break at runtime; you just can’t edit it in 128 BASIC. - The additional RAM in the system is available to BASIC as a RAM disk. By adding an exclamation point to cassette commands (e.g.,
SAVE! "TestProg") it is instead saved to RAM for the session. Going to 48K mode does not destroy it, per se, but it also renders it permanently inaccessible.
In practice, PLAY is the only new command, and almost the entirety of the 128’s extended documentation is about this one command. It’s a music macro system tuned to the AY-3 and it’s very different from the one Microsoft BASICs use. I’ll just defer to the actual documentation for full details, and warp up this section with a command to play our shave-and-a-haircut jingle with some half-hearted counterpoint: PLAY "O4T150N5F3CC5$DC&EF","O4T150N3C&&&b&f&5&Ca" will play both parts simultaneously.
Leaving BASIC Behind
This little tour has been mainly of the parts of BASIC that showcase fundamental user interactions with the system, or that let us play with the special features of the computer as a whole. It has not particularly grappled with the distinct features of Sinclair BASIC itself, which is markedly different from the Microsoft-descended BASICs, BBC BASIC, or Atari BASIC. For these, you can really do no better than the official documentation at the time, which has authorized HTML conversions hosted at World of Spectrum; one for BASIC as a whole and one for the 128 Extensions.
Starting next week, we’ll move away from BASIC and start putting the system its paces with pure machine code. The gap here is smaller than usual; the Spectrum may have been a relatively low-powered budget system but Sinclair BASIC gets you remarkably close to its full power right out of the gate.
We’ve got a few things left up our sleeves, at least. Never fear.