Book review: ZX Spectrum BASIC

sinclairspectrum-preI just rediscovered my first computer, a Sinclair ZX Spectrum (good picture) which I bought back in 1983 or 1984 (I have no trace of the exact date, unfortunately). The machine was a perfect machine to learn programming on in my opinion, consisting of little more than a Z80 processor with memory, bit-mapped display (with a famously odd-ball addressing scheme and color handling) and ultra-simple sound output and input. Most of my friends in the end bought Commodore C64 machines, which had more powerful graphics and sound hardware, but a processor that was much less fun to program.

The Spectrum came with a built-in BASIC interpreter that are up the bottom 16kB of the 64kB addressing space. The BASIC was actually fairly powerful and easy-to-use, and included a very fun programming textbook. I just reread that textbook, and it is quite strikingly well-written and manages to cover both basic computer-science-style programming and deep close-to-the-machine and real-time programming in a compact 150 pages. There is no credit to a particular author in the book I have (Swedish translation by a group of people at Ord & Form here in Uppsala), but an online scan credits Steven Vickers.

Overall, the book does a very good job of explaining both the Sinclair BASIC interpreter, as well as some general programming concepts. And how the machine works deep down. Here are some highlights.

Explaining Functions

The way that functions are explained made me laugh out loud (quoting the original English according to the online resource I found):

Consider the sausage machine. You put a lump of meat in at one end, turn a handle, and out comes a sausage at the other end. A lump of pork gives a pork sausage, a lump of fish gives a fish sausage, and a load of beef a beef sausage.

Functions are practically indistinguishable from sausage machines but there is a difference: they work on numbers and strings instead of meat. You supply one value (called the argument), mince it up by doing some calculations on it, and eventually get another value, the result.

This is a very good analogy to introduce functions, in a fairly gender-neutral way and assuming no mathematical background on part of the user. I wonder if I ever cared to define any functions… as I recall it, GOSUB was as far as I got in sophistication before leaving BASIC and starting writing everything in Z80 assembler.

Reading a Changing Counter

Later on in the book, a suggestion is made to get a better time counter. Essentially, by reading a 24-bit value incrementing at 50 Hz, using three separate PEEK commands:

(65536*PEEK 23674+256*PEEK 23673+PEEK 23672)/50

This code does subject you to the issue of reading during an update and counter wrap from one byte to the next. This complication is cheerfully noted after a complete program using this feature as a by-the-way-the-code-is-correct by a small loop. There are many such small gems in the book, essential tricks and caveats that still apply to programming close to the hardware and doing real-time programming.

We have No Clock

The ZX Spectrum, as most computers of its day, did not have a real-time clock on board. Instead, you had to time things using the 50Hz screen refresh interrupt (which is what the code in previous section reads) or by just adjusting your code to wait appropriately. One example program is supposed to show a clock updating every second. However, getting to a second is a bit tricky when there is no firm time-base to work on. The suggesting instead is this:

This clock will run down after about 55.5 hours because of line 60, but you can easily make it run longer. Note how the timing is controlled by line 210. You might expect PAUSE 50 to make it tick one a second, but the computing takes a bit of time as well and has to be allowed for. This is best done by trial and error, timing the computer clock against a real one, and adjusting line 210 until they agree. (You can’t do this very accurately; an adjustment of one frame in one second is 2% or half an hour in a day.)

So what we have here is a classic “how long must I wait to get a steady pace of execution for my periodic code?” issue familiar to anyone using an RTOS and trying to determine how long to sleep a process for until the next periodic interval starts. Once again, illustrated in ten lines of BASIC and a few lines of text.

Repeatability and Randomness

In Chapter 11, randomness using the built-in random function is introduced. This was a 16-bit periodic pseudo-random system where you could set the random seed to put start the random generation at any particular point in a 100% repeatable manner. Indeed, the book introduces the concept of doing this in order to ensure repeatable execution of a program relying on randomness. This sounds familiar from my previous post on simulation determinism:

If you had a program with RND in it and it also had some mistakes that you had not found, then it would help to use RANDOMIZE like this so that the program behaved the same way each time you ran it.

Delving into Details

The BASIC manual does not try to hide how the BASIC interpreter works internally, rather on the contrary, including a list of all system variables so that they can be POKEd and changed if need be. It also explains the data layout of all variable types (the Spectrum BASIC used 32-bit integers, impressive for an 8-bit machine, and 40-bit floating point numbers).

The only useful information for me in the way I used the machine as a pure assembly-language target was the memory layout of the screen. Which is bizarre to say the least. It had a separate black-and-white bitmap and color overlay for every 8×8 character. And each scan line was NOT consecutive with the previous in memory, but rather offset by 256 bytes. I think the idea was to make it easy to insert a single character into the bitmap by just incrementing the high byte of the address by one for each pixel line.

To make that work, the screen was divided into three pieces of 8 character lines/2048 bytes each (8 character lines of 8 pixel lines each, each with 32×8 bits of data).  The sprite drawing routines that would work with that to plot a 16×16 sprite in any screen position was amazing code, to say the least. I independently invented unrolled loops to make this run fast. And misused the POP instruction to pull in data to draw (it took 11 cycles, rather than 12 as a more usual register-indirect load would do) — provided that you turned off interrupts or data corruption would ensue.

These were fun programming times. It shaped my programming habits for a decade, culminating in an infamous 68000 assembler hack in my first undergrad year at Uppsala, with some 50 pages of very tight and complicated assembly language making use of most features of the 68k instruction set… poor TA.

Final Notes

On it goes like that. The chapters are short but very much to the point, and a large number of fairly subtle concepts are introduced. The Spectrum was a good school for a budding programmer, with no compiler, no safety net, but also no way to break the machine in a way that a reboot would not cure.

I actually recommend seeking out the aforementioned online repository for the Spectrum programming book, it is almost still in shape to be used as an introduction to real-time and embedded programming.

I am currently trying to figure out what is a good ZX Spectrum emulator to relive these old times if I can find time. The hardware unit I have depends on an analog tape drive to load software… and I gave up analog sound back in 1993. As if the magnetic tapes which have been in storage for 20 years have any chance of containing useful data anyway.

6 thoughts on “Book review: ZX Spectrum BASIC”

  1. On Windows, Spectaculator (http://www.spectaculator.com/) is your best choice, easily worth paying up a few dollars for. (And I should know – I wrote the Speccylator emulator for the Amiga, back in the early 90:s.)

    And don’t despair about your old tapes! Borrow a good tape deck (someone you know probably has one) and start converting to .tap files, preserving every single bit. I dug up my original tapes from the basement only a year or so ago, and managed to salvage almost everything on them. (For games, you can just download most of them directly from World of Spectrum; again, .tap is the preferred form if it is available.)

    Finally, you should definitely read “The Complete Spectrum ROM Disassembly” (PDF and cover scans at http://www.worldofspectrum.org/infoseekid.cgi?id=2000076). It’s a gem!

  2. My favourite program example from that book was probably Pangolins (“Krokofant”, if you had the Swedish translation), in Appendix D. When I was 14, it seemed like magic. It would be many years before I saw another program that used a dynamic tree structure, and then it was certainly not in Basic.

  3. Now we are just waiting for full-system simulation of the Spectrum in Simics 😉

    I used a Commodore 128 as a kid, but only did some very naive BASIC games. Assembly would have been magic to me then! Anyway, I’ve heard from other people that the Spectrum BASIC was a lot more capable and usable than the Commodore ditto, so perhaps it was a better machine for programmers.

  4. Yes, the BASIC of the Spectrum actually impresses me now when I look at it again, 25 years later, with a lot of computing and programming experience. It looks like they made a strong effort to make a seriously usable programming tool, including some pretty smart handling of data and variables (arbitrary sublist indexing of strings, in 1982!, only recovered that ability with Python recently — it was lost in Pascal, C, C++).

  5. I always liked the elegant syntax for substring access: if e.g., a$=”hello”, then the expression a$(2) yields “e”, a$(2 TO 4) yields “ell”, a$(TO 3) yields “hel”, and a$(3 TO) yields “llo”. Couldn’t be simpler. And what’s more, it worked with assignment as well: a$(2 TO 4)=”arr” would make a$=”harro”, while a$(2 TO)=”alo” would make a$=”halo”. (If the substituted string was shorter than the range, it was padded with spaces: e.g., a$(2 TO 4)=”er” would yield “her o” rather than “hero”.)

    And there were also multidimensional arrays, pretty good maths functions, and built-in functions for drawing lines, circles, and circle segments (though very slowly).

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.