From Spectrum hardware wiki
Jump to: navigation, search

Starting out

What kind of machine do you have?

  • If you have a 48K, Spectrum+, 128K with heatsink or grey +2, make sure the jumper J3 is removed (the jumper closest to the JTAG and edge connector).
  • If you have a +3 or black +2, J3 must be installed.

128K machines must use USR 0 mode for BASIC support, this is started automatically. At the moment, the BASIC extensions aren't compatible with the 128K editor. (You do have access to all the 128's memory in USR 0 mode, and 128K games will run).


The default configuration is to use DHCP to get IP settings. If you don't have a DHCP server or want to use a static address, type the following command:


You can also use the NMI to get to the configuration menu (briefly short S1 with something metallic, or install a switch).

Configuring the file system

You'll need a fileserver (the tnfsd, an installer for this is work in progress). There is a public fileserver which you can use at To mount a filesystem, use the %mount command. For example:

%mount 0,""

It's quite likely you'll want to do this automatically. You can set the automounter up with this command:


This menu will appear:

Error creating thumbnail: File missing

Press "A" to add a new filesystem, for example, to use "tnfs://" as your default filesystem:

  • Press "A", set a filesystem
  • Press "0" and Enter to select filesystem #0
  • Type tnfs://
  • Press D to save the changes.

When the Spectrum is reset, the server "" will be mounted.

If there are problems mounting a fileserver (for example, the fileserver isn't running) you can press BREAK while the Spectrum is trying to mount it to abort the operation.

Brief guide to the BASIC commands

Navigating a filesystem


%mount <fsnum>,"<url>" - Mount a filesystem. Examples:

%mount 0,""
%mount 0,""
%mount 1,"tnfs://"
%mount 3,"tnfs://"

The URL works just like you would expect. If there were a filesystem for a DivIDE, the command may be something like %mount 0,"ide://0 (or something very similar).


%umount <fsnum> - Disconnect from a filesystem. Example:

%umount 0


%cat "<fsp>" - Show the contents of a directory. Examples:

%cat "foobar"
%cat "0:/foo/bar/baz"

The path functions like a Unix path, the separator between the directories that make up the path is a "/". As expected, "." means the current directory, ".." means the directory above.


%cd "<fsp>" - Change directory. Examples:

%cd "/"
%cd "games"
%cd "/programs/basic"
%cd ".."


%fs <fsnum> - Change filesystem. Example:

%fs 1

The default filesystem is 0.

Reading and saving files


%load "<fsp>" [CODE address] - Load a file. Examples:

%load "manic"
%load "image" CODE 16384
%load "/foo/bar/baz.zx"
%load ""

The command %load "" will load the BASIC program "boot.zx". (If you've selected the Autoboot option in the %fsconfig menu, the Spectrum will try to load "0:/boot.zx" when it is reset).


%save "<fsp>" [CODE address,size] - Save a file. Examples:

%save "program"
%save "image" CODE 16384,6912
%save "program" LINE 1


%aload "<fsp>" CODE address - Load abitrary data. Example:

%aload "machinecode" CODE 32768

The difference with %load and %aload is that %aload effectively loads a "headerless" file. The "normal files" are formatted as a TAP archive, that's to say they have the same headers that are found in a file saved to tape, they contain the address where the data should be loaded and the kind of file - for example, "Program" or "Bytes". The %aload command can load any file. Because of this you always have to put the load address where the data must be loaded because there's no header to specify this information.

Therefore %aload is essential when you want to load a file that you've created on a PC (for example, with a cross assembler) that wasn't saved formatted as a TAP file.


%tapein "<fsp>" - Load a .TAP archive. Example:

%tapein "jsw.tap"

Effectively, %tapein is to emulate a tape. You always need to LOAD "" (or similar) after %tapein to actually run the "virtual tape".


%loadsnap "<fsp>" - Load a .SNA snapshot. Example:

%loadsnap "matchday.sna"

This command works with both 48K and 128K snapshots.

Opening and closing files

There is a set of commands that are used with ZX BASIC streams. They work with files, directories and network sockets. Here is an example and a short explanation.

 10 %open #4,"file","r"
 20 %oneof 100
 30 INPUT #4,a$
 40 PRINT a$
 50 GO TO 30
100 %close #4

This program opens the file named "file" and reads the contents, putting them on the screen. The first line:

10 %open #4,"file","r"

opens the file called "file" for reading. Line 20 is to catch the end-of-file condition. What it says is that when an EOF is encountered, jump to line 100. Lines 30, 40 and 50 are standard ZX BASIC commands to read the stream and put the results on the screen. Finally we arrive at line 100, where we close the file. (It is very important that this is done!)

Opeining and closing sockets

It's very easy to do similar things with a network connection. For example:

 10 %connect #4,"",80
 20 %oneof 100
 30 PRINT #4;"GET HTTP/1.0"
 40 PRINT #4
 50 INPUT #4;a$
 60 PRINT a$
 70 GO TO 50
100 %close #4

With code very similar to the first example, we can connect to another machine over the network using a TCP socket. The sintax of %connect is:

%connect #<stream>,"address",port

Here is a very simple example of a server written in BASIC:

10%listen #4,2000
20%accept #5,4
30 INPUT #5;a$
40 PRINT #5;"You sent me: ";a$
60%close #5
70%close #4

You can try this out from a PC using "telnet":

telnet <ip-address-of-spectrum> 2000

For example:

serendipity:~ winston$ telnet 2000
Connected to
Escape character is '^]'.
You sent me: hello
Connection closed by foreign host.

An example a little more complex: a server that can handle up to 3 connections at the same time on port 2000:

  1 DIM c(4)
 10%listen #4,2000
 20%control #5
 30 PRINT #5;"p"
 40 PRINT "Waiting..."
 45 INPUT #5;a;a$
 50 IF a<>0 THEN GO TO 200
 60 LET a$=INKEY$
 70 IF a$="x" THEN GO TO 700
 80 GO TO 45
200 IF a=4 THEN GO TO 400
210 IF a$="disconn" THEN GO TO 600
220 INPUT #a;c$
230 PRINT "Strm ";a;": ";c$
240 IF c$="rnd" THEN PRINT #a;RND: GO TO 40
250 IF c$="foo" THEN PRINT a;"Foo bar baz": GO TO 40
260 IF c$="quit" THEN PRINT #a;"Adios":GO TO 600
300 PRINT #a;"I didn't understand that"
310 GO TO 40
400 FOR i=1 TO 4
410 IF c(i)=0 THEN LET chan=i+5: GO TO 500
420 NEXT i
430 PRINT "Out of streams"
440 STOP
500 PRINT "Accepted connection on stream ";chan
510%accept #chan,4
520 LET c(i)=1
530 GO TO 40
600 PRINT "Closing #";a
605%close #a
610 LET c(a-5)=0
620 GO TO 40
700 PRINT "The program has finished"
710%close #5
715 PRINT "Closing socket"
720%close #4
730 PRINT "Closing connections"
740 FOR i=1 TO 4
750 IF c(i)=1 THEN %close #i+5
760 NEXT i

To try it out from a PC, using "telnet <ip-of-spectrum> 2000". You can type "rnd", "quit" or "foo".

Notable parts of the program:

10 %listen #4,"2000"

When this line executes, the Spectrum begins to listen on port 2000 (tcp). We need to do something else, too: when a connection arrives we must accept it. We use the %accept command for this. However, %accept will block waiting for a connection (in other words, execution of the program stops while waiting). To be able to continue without waiting, there is a control channel that allows us to look at the state of a socket. It's opened like this:

20 %control #5

Now stream #5 is the control channel. We can write and read this stream like this:

30 PRINT #5;"p"
50 INPUT #5;a;a$

Line 30 says to the control channel "tell me if there's data waiting on any socket" (this includes a socket that's in the listening state). In line 50, two things arrive: the stream number on which data is ready, and some information about the data. (Data being ready may mean a connection to be accepted, the remote end closing, or just some characters to read). If the stream is #4, we know know that it must be a new connection that needs to be accepted, because stream 4 is the listening socket. If the variable a contains 0, no sockets have data waiting.

510 %accept #chan,4

In this line we finally accept the new connection. The %accept command accepts the connection and creates a new stream for data to be read/written to this connection. The syntax of %accept is:

%accept #stream,listening-stream

Stream 4 is the listening stream in this case. The variable #chan is the number of the new stream we want to open.

Machine code

If you want to write programs in C, there is a guide with examples. Sockets are used in the same way as they are in Unix or Windows - if you already know how to write networked programs for modern operating systems you'll have no problems. If you've never used the BSD socket library, there are tutorials.

The guide is here