It’s quite the rabbit hole. There are all sorts of exciting projects to distract me from investigating programming tools for the ZX Spectrum. I’m interested in tools I can use from the command-line in Linux primarily. Tools that can be Dockerised.
Table of Contents
Tape file target
There was a question to the JSSpeccy3 repository issues board asking about bas2tap like functionality to run basic programs. The response from the JSSpeccy3 author was that external tools should be used to create a tape file and provided to the emulator that way. After some further consideration, it seems that tape files are a good target for any Spectrum programs to be run, either in an emulator or on the old ZX Spectrum 48K machine itself.
Loading tape files to the old machine
The old machine audio inputs require the volume to be higher than my iPhone could emit. However, I have an Android phone for testing, and I recommend ZX Tape Player. Yet, I’m using a stereo cable, and I haven’t tried this tip on changing the tape audio signal from mono to stereo, but using the Android app is easy and convenient.
ZX Spectrum emulators
I’m currently using Windows 10 as my main OS, with WSL2 running Ubuntu 20.04 LTS also capable of running an X Server using X410. So this selection of emulators is for Windows, though elsewhere on this page, I’m using Ubuntu on the command line.
ZX Spectrum emulators for Windows:
Fuse is the fastest emulator to start up and is the one I have set up for file associations. In addition, Fuse is cross-platform and is available for a wide variety of operating systems.
Programming options
Sinclair BASIC
Sinclair BASIC is the most straightforward programming language on the ZX Spectrum. It’s not what I’m most interested in, but I’ll start with this as it is the easiest to get started with.
Compile the bas2tap
command:
wget https://raw.githubusercontent.com/speccyorg/bas2tap/master/bas2tap.c
gcc -Wall -O2 bas2tap.c -o bas2tap -lm ; strip bas2tap
Create a simple basic script to convert to a tape file:
10 PRINT "Hello, world!"
20 GO TO 10
Convert the basic script to a tape file:
bas2tap hello.bas -a -shello
The additional command options are to start the program automatically (otherwise, you have to enter RUN to start the program once loaded) and add “hello” as the program name.
Output is:
BAS2TAP v2.6 by Martijn van der Heide of ThunderWare Research Center
Creating output file hello.tap
Done! Listing contains 2 lines.
Launching the hello.tap
file with Fuse produces the following:
C and assembly with Z88DK
I’ve been really interested in Z88DK as it combines C and assembly language programming for the ZX Spectrum, among other targets. Moreover, the source of some excellent example games is available, such as zx-spectrum-snake and z88dk_breakout.
Build Z88DK
I found it a little challenging to get set up with Z88DK initially, so here are the steps that I have followed and then a Dockerfile that can be used.
sudo apt update
sudo apt install -y \
build-essential \
git \
subversion \
curl \
libxml2-dev \
bison \
flex \
libboost-all-dev \
texinfo \
zlib1g-dev
cd # wherever you want to clone the z88dk repository
git clone --depth 1 --branch v2.1 --recursive https://github.com/z88dk/z88dk.git
cd z88dk/
export Z88DK_PATH="$(pwd)"
export SDCC_PATH="/tmp/sdcc"
export BUILD_SDCC=1
export BUILD_SDCC_HTTP=1
./build.sh
rm -fR ${SDCC_PATH}
If the build does fail, you may need to clear the temporary files using the command rm -r -f /tmp/sdcc
before trying again.
Test the Z88DK commands built above
Here are some working examples to test the Z88DK commands we built above.
First, we need to set the following environment variables for the tools on the shell path:
export PATH="${Z88DK_PATH}/bin:${PATH}"
export ZCCCFG="${Z88DK_PATH}/lib/config/"
Build initial Z88DK tutorial examples
Extracts based on The ZX Spectrum Programmer’s Z88DK Getting Started Guide, which is an excellent set of tutorials to get started with Z88DK!
Hello World
The simplest example to get started:
cd # wherever you like
vi hello.c # or use another editor of choice
#include <arch/zx.h>
#include <stdio.h>
int main()
{
zx_cls(PAPER_WHITE);
puts("Hello, world!");
return 0;
}
A single command to build the tape file:
zcc +zx -vn -create-app -clib=sdcc_iy -startup=0 hello.c -o hello
Launching the hello.tap
file with Fuse produces the following:
Drawing Lines on Screen
cd # wherever you like
vi line.c # or use another editor of choice
#include <arch/zx.h>
#include <input.h>
#include <stdlib.h>
void plot(unsigned char x, unsigned char y)
{
*zx_pxy2saddr(x,y) |= zx_px2bitmask(x);
}
void line(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1)
{
unsigned char dx = abs(x1-x0);
unsigned char dy = abs(y1-y0);
signed char sx = x0<x1 ? 1 : -1;
signed char sy = y0<y1 ? 1 : -1;
int err = (dx>dy ? dx : -dy)/2;
int e2;
while (1)
{
plot(x0,y0);
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
int main(void)
{
unsigned char i;
zx_cls(PAPER_WHITE);
for( i=0; i<15; i++ )
{
line(rand()%256, rand()%192, rand()%256, rand()%192);
}
return 0;
}
The compile line is the same as for the last example:
zcc +zx -vn -startup=31 -clib=sdcc_iy line.c -o line -create-app
Launching the line.tap
file with Fuse produces the following:
Build zx-spectrum-snake
Clone and build the game:
cd # wherever you want to clone the z88dk_sp1_breakout repository
git clone https://github.com/dcrespo3d/zx-spectrum-snake.git
cd zx-spectrum-snake/
mkdir build
zcc +zx -vn -create-app -lndos -lm -I./zxlib snake.c -o build/snake.bin
Launching the build/snake.tap
file with Fuse produces the following:
This is a fun game. However, it has no sound.
Build z88dk_breakout
Clone and build the game:
cd # wherever you want to clone the z88dk_sp1_breakout repository
git clone https://github.com/antoniocmateus/z88dk_sp1_breakout.git
cd z88dk_sp1_breakout/
zcc +zx -v -startup=31 -DWFRAMES=3 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 --fsigned-char "@zproject.lst" -pragma-include:zpragma.inc -o build/z88dk-breakout -m
bas2tap -a10 -sz88break src/loader.bas build/loader.tap
mv build/z88dk-breakout.map build/z88dk-breakout_CODE.map
z88dk-appmake +zx -b build/z88dk-breakout_CODE.bin -o build/game.tap --blockname z88dk-breakout --org 25124 --noloader
cat build/loader.tap gfx/loading.tap build/game.tap > build/z88dk-breakout.tap
This example is a bit more complicated, with a loader and multiple commands to make.
Launching the build/z88dk-breakout.tap
file with Fuse produces the following:
This is a fun game. I used to play Arkanoid on the ZX Spectrum back in the day. This version of the game has basic sound – but it’s open-source and could be a fun project to work on.
Dockerfile
This is more of a recreation of the environment that I run on my desktop with Ubuntu, except using the Debian base image because it did build quicker at the time of writing.
# To create the image:
# $ docker build -t z88dk .
# To run the container:
# $ docker run -v ${PWD}:/src/ -it z88dk <command>
FROM debian:buster
ENV Z88DK_PATH="/opt/z88dk" \
SDCC_PATH="/tmp/sdcc" \
PATH="${Z88DK_PATH}/bin:${PATH}" \
ZCCCFG="${Z88DK_PATH}/lib/config/"
RUN apt update && apt install -y \
build-essential \
git \
subversion \
curl \
libxml2-dev \
bison \
flex \
libboost-all-dev \
texinfo \
zlib1g-dev
RUN git clone --depth 1 --branch v2.1 --recursive https://github.com/z88dk/z88dk.git ${Z88DK_PATH} \
&& cd ${Z88DK_PATH} \
&& export BUILD_SDCC=1 \
&& export BUILD_SDCC_HTTP=1 \
&& ./build.sh \
&& rm -fR ${SDCC_PATH}
WORKDIR /src/
This container image can compile programs, but note that this version runs as root, which is not ideal. Initial testing of using a non-root user didn’t work.
Z80 Assembler
I suspect that programming the ZX Spectrum in Z80 Assembler will probably be the most fun & engaging. I am interested in learning more about programming a primitive computer like the ZX Spectrum to appreciate the limited options available and the style of programming that this necessitates. I’m curious to know more about this machine in detail while reading the book The ZX Spectrum Ula: How to Design a Microcomputer.
ZXSpin Z80 Assembler
The YouTube playlist ZX Spectrum Z80 programming looks like an excellent dive into ZX Spectrum assembly language programming using the Z80 Assembler embedded in ZXSpin. However, that emulator is no longer maintained, and I read some forum posts noting problems with the assembler. However, it could be fun.
Unfortunately, it’s just for Windows.
Zeus
The Zeus Z80 Assembler looks like another great alternative, at least for Windows. There is a command-line version of the assembler, but it is a Windows executable.
Pasmo
The Pasmo multiplatform Z80 cross-assembler is probably the most interesting one from my point of view due to being able to run it on Linux, and more importantly, Docker.
Clone and build:
cd # wherever you want to clone the pasmo repository
git clone --branch 0.5.3 https://github.com/compilersoftware/pasmo.git
cd pasmo/
./configure
make
Add the pasmo
command to the shell path:
export PATH=$(pwd):$PATH
Copy the example scripts out into a new folder:
mkdir ~/zx-asm
cp *.asm ~/zx-asm
Build the hellospec.asm
script:
cd ~/zx-asm/
pasmo --tapbas hellospec.asm hellospec.tap
Launching the hellospec.tap
file with Fuse produces the following:
So, that’s a start!