Sinclair ZX Spectrum +3 Manual



Sinclair ZX Spectrum +3
128K Integrated Home Computer/Disk System

Following on from the outstanding success of the established ZX range of computers: the original Spectrum, the Spectrum +, the Spectrum 128 and the new generation Spectrum +2, we now proudly present the ZX Spectrum +3, a machine that combines the very best features of the previous Sinclair models with the added convenience of a fast access floppy disk drive.

The whole is a truly complete computer/disk system which allies established Sinclair technology with AMSTRAD's expertise in integration and engineering reliability and flair for producing a 'no nonsense' all-in-one package.

Software compatibility

The +3 may be used with software written for the earlier models in the ZX Spectrum range. This means that a vast quantity of software of software already exists for the +3. There are literally thousands of titles available covering every conceivable application: games utilities, music, scientific, educational and many many more.


The +3 uses a computer language called BASIC (Beginners' All-purpose Symbolic Instruction Code). BASIC is by far the commonest language for home computers, and +3 BASIC has been designed to be particularly easy to learn and use.

How to read this book

In order to get the best out of your +3, it is vital that you read all the relevant information provided in this manual. If you skip various sections, it is likely that you will come to a grinding halt later on!

Therefore, you should adopt the following reading programme...

Chapter 1 - This chapter shows you how to connect up your +3 system. Note especially the safety warnings regarding the wiring-up of the mains plug.

Chapter 2 - This chapter describes the switching on of the +3 and shows you how to tune in your TV to display the computer's signal. You are then shown how to select an option from the 'opening menu' - and if you don't know how to do that, you'll not be able to use the +3 at all! If, however, you do know how to tune-in your TV and select menu options (perhaps by having previously used a Spectrum 128 or a +2), then you may skip this chapter.

Chapter 3 - This chapter shows you how to load commercially available disk software. If you never intend to use such software, then you may skip this chapter.

Chapter 4 - This chapter shows you how to load commercially available pre-recorded tape software. If you never intend to use such software, then you may skip this chapter.

Chapter 5 - This chapter covers the use of the +3's built-in disk drive (known as drive A:). You may skip this chapter only if you never intend to use the disk drive during BASIC programming (perhaps having purchased the +3 solely to load and run commercially available software (eg. games)). Note that if you have connected an additional disk drive (B:) to the +3, then throughout the manual you should take any general references to 'the disk drive' as meaning both drives (A: and B:).

Chapter 6 - This chapter introduces you to +3 BASIC. It particular, it describes the editor and certain aspects of BASIC programming that differ from those of other computers. Therefore, even if you are an experienced BASIC programmer on another computer, you should still read chapter 6. Note that you'll require a blank CF-2 floppy disk as you work through this chapter. If, however, you never intend to program in BASIC and have purchased the +3 solely to load and run commercially available software (eg. games), then you may skip this chapter.

Chapter 7 - This is the one chapter that you may freely skip. It describes the 48 BASIC mode (in which the +3 operates exactly like the 'old-style' Spectrum - even in the editing and programming aspects). This mode is not recommended as anything other than a history lesson for the curious, or for loading old (Spectrum 48 only) tape software. You should certainly not use this mode for BASIC programming; indeed you cannot access many of the advanced features of the +3 (including disk drive, extra memory, RS232/MIDI/AUX interfaces or RAMdisk) from 48 BASIC. Notwithstanding the above, we have provided the relevant information in this chapter for your reference.

Chapter 8 - This chapter forms the very heart of the manual. It is a complete guide to BASIC programming on the +3. If you have programmed in BASIC before, then you may wish to use this chapter merely as a reference guide, searching the main index to find the information you need from one of the subsections. If, on the other hand, you are new to BASIC, you may wish to work through the chapter, one subsection at a time, developing your programming skills as you go. Once you are able to type in and run a program, and have grasped a few of the fundamentals of BASIC, then you may feel confident about skipping ahead to later subsections. If, however, you never intend to program in BASIC and have purchased the +3 solely to load and run commercially available software (eg. games), then you may skip this chapter.

Chapter 9 - This chapter shows you how to use the +3 as a calculator only. You may skip this chapter if you wish.

Chapter 10 - This chapter illustrates how add-ons (peripherals) are connected to the +3. Peripherals include such devices as a cassette unit, a printer, an additional disk drive, a joystick, etc. So if you're thinking of linking up any device at all to the +3, check this chapter to make sure that you've got the right connections. If, on the other hand, you intend to use just the standard +3 set up (ie. computer and TV only), then you may skip this chapter.

Neither the whole nor any part of the information contained herein, nor the product described in this manual, may be adapted or reproduced in any material form except with the prior written approval of AMSTRAD Plc. ('AMSTRAD').

The product described in this manual, and products for use with it are subject to continuous development and improvement. All information of a technical nature and particulars of the product and its use (including the information and particulars in this manual) are given by AMSTRAD in good faith.

All maintenance and service on the product must be carried out by Sinclair authorised dealers. AMSTRAD cannot accept any liability whatsoever for any loss or damage caused by service or maintenance by unauthorised personnel. This guide is intended only to assist the reader in the use of the product, and therefore, AMSTRAD shall not be liable for any loss or damage whatsoever arising from the use of any information or particulars in, or any error or omission in, this guide or any incorrect use of the product.

We ask that all users take care to submit their user registration/guarantee cards.

All correspondence relating to the product or to this manual should be addressed to:

Sinclair Computers Division
Brentwood House
169 Kings Road
Essex CM14 4EF

First Published 1987

Written by Ivor Spital
Contributions by Cliff Lawson and Rupert Goodwins
Produced by Des Rackliff

Extracts from the book 'ZX Spectrum BASIC programming' written by Steven Vickers and Robin Bradbeer

Published by AMSTRAD

+3DOS written by Locomotive Software Ltd.

CP/M is the trademark of Digital Research Inc.
LocoScript is the trademark of Locomotive Software Ltd.
Acknowledgements to Centronics and Epson Corps.

The following are registered trademarks of AMSTRAD Plc.:
Sinclair ZX Spectrum, +2, +3, +3DOS
AMSTRAD, AMSDOS, PCW8256, PCW8512, CPC464, CPC664, CPC6128
DMP2000, DMP3000, DMP3160, DMP4000, FD-1
AMSOFT, CF-2, PL-1, DL-2

Unauthorised use of the above trademarks, or of the word AMSTRAD, is strictly forbidden.


You must read this...

(Don't worry if you are a little baffled by some of the technical jargon in this section, the importance of these warnings will becomes clearer as you work through this manual.)

  1. Always connect the mains lead of the power supply unit (PSU) to a 3-pin plug following the instructions given in chapter 1.
  2. Do not attempt to connect the PSU to any mains supply other than 220-240V AC 50Hz.
  3. After you have finished using the +3, always disconnect the PSU from the mains supply socket.
  4. There are no user serviceable parts inside the equipment - DO NOT ATTEMPT TO GAIN ACCESS INSIDE THE PSU - THERE ARE HIGH VOLTAGES INSIDE. Refer all servicing to qualified service personnel.
  5. Do not block or cover the ventilation slots in the equipment.
  6. Do not use or store the equipment in excessively hot, cold, damp, or dusty areas.
  7. Never plug in (or unplug) any device from any of the rear sockets while the +3 is switched on - doing so will probably damage both the +3 and the device.
  8. Never switch the +3 on or off while a disk is inserted in the disk drive. Doing so may corrupt your disk, losing valuable programs or data.
  9. After you have switched off your TV (or VDU monitor), do not immediately disconnect the +3 - wait a few seconds or so.
  10. Do not switch off the +3 (or switch on or off any peripheral device connected to the +3) while there is a program or data in the memory that you wish to keep - doing so may make the +3 'crash', losing the program or data.
  11. Always keep the disk drive and disks away from magnetic fields. For maximum data reliability, do not position the disk drive close to your TV or monitor, or close to any source of electrical interference.
  12. If you have connected an additional disk drive to the +3, keep the ribbon cable (to the additional drive) away from mains leads.
  13. Whenever possible, make back-up (duplicate) copies of disks which contain valuable programs. Otherwise, should you accidentally lose or corrupt the disk, replacing may prove very expensive.
  14. Never touch the floppy disk surface itself inside its protective casing.
  15. Do not eject a disk while it is being read from or written to.
  16. Always remember that formatting a disk will erase its previous contents.

Chapter 1
Open the box

Subjects covered...


Inside the carton, you'll find the following...

The Spectrum +3 computer
The power supply unit (PSU)
The aerial lead
This manual (together with your user registration/guarantee card)

USER INSTRUCTIONS This manual Aerial lead PSU Spectrum +3 computer User registration/guarantee card GUARANTEE CARD

Fitting a mains plug

The power supply unit for the Spectrum +3 operates from a 220-240 Volt AC 50Hz mains supply.

Fit a proper mains plug to the mains lead of the power supply unit. If a 13 Amp (BS1363) plug is used, a 3 Amp fuse must be fitted. The 13 Amp fuse supplied in a new plug must NOT be used. If any other type of plug is used, a 5 Amp fuse must be fitted either in the plug or at the distribution board.

IMPORTANT - The wires in this mains lead are coloured in accordance with the following code...

As the colours of the wires in the mains lead of this apparatus may not correspond with the coloured markings identifying the terminals in your plug, proceed as follows...

The wire which is coloured BLUE must be connected to the terminal which is marked with the letter N or coloured black.

The wire which is coloured BROWN must be connected to the terminal which is marked with the letter L or coloured red.

Disconnect the mains plug from the supply socket when not in use.

Do not attempt to remove any screws, nor open the casing of the power supply unit. Always obey the warning on the rating label of the power supply unit.


Setting up

We will now set up the standard +3 system. All you need (other than the items you unpacked) is a standard TV set (UHF). You can use a colour or black-and-white TV, but of course, with the latter you will not be able to enjoy the full colour capabilities of your +3.

Note that if you wish to attach one or more add-ons, or peripherals, (eg. printer, joystick, cassette deck, second disk drive, monitor, audio amplifier, MIDI device, modem or other serial/expansion device) to your +3 system, you should turn to chapter 10 (Peripherals for your +3).

Place the +3 computer on a suitable flat surface, ready to be connected to your TV. Next, remove any plug which is already connected to the aerial socket at the back of the TV. Using the aerial lead provided with your +3, insert he larger plug into the TV's aerial socket, and insert the smaller plug into the socket marked TV at the back of the +3.

Finally, insert the 6-pin DIN plug coming from the power supply unit into the socket marked PSU at the back of the +3.

The +3 system is now ready to be switched on.

Aerial lead PSU TV set Spectrum +3 computer PSU TV
The standard +3 system set-up.

Chapter 2
Operating your +3

Subjects covered...

Switching on

Connect the mains plug of the power supply unit to the mains supply socket, and switch on the socket-switch (if necessary). The power indicator lamp on the top panel of the +3 should illuminate.

Now switch on your TV. On the screen you will probably see either a faint TV picture or just random 'white noise' and hear a loud 'hissing' sound from the TV's speaker. Adjust the TV's volume control until the sound is at a comfortable listening level. The next thing to do is set up the +3 ready for tuning-in.

Preparing to tune-in your TV

The +3 is capable of generating its own test signal, enabling you to tune-in the TV accurately. The test signal consists of sixteen vertical colour bars (overprinted with text characters) which appear on the TV screen, and a repeating tone which is reproduced through the TV's speaker. (If you are using a black-and-white TV, then the colour bars appear as varying shades of grey.) You will see and hear the test signal when you have completed the tuning-in of your TV (described ahead).

Switch on the test signal by holding down the BREAK key (at the top right of the keyboard) and while it is held down, press and release the RESET button (at the left hand side of the +3). Keep the BREAK key held down for a few seconds longer, then release it. The test signal will now be generated by the +3, and you should proceed to tune-in your TV as now described.

Push-button TV channel selectors

If your TV doesn't have push-button channel selectors, then skip to the section ahead entitled 'Manual tuning'.

If your TV does have push-button channel selectors, then press one of them to select a spare channel (ie. one not normally used for receiving TV or video programmes). Note that if your TV is equipped with an AFC (or AFT) switch, then this should be set to the off position.

Using the tuning control that corresponds to the selected channel, tune-in to the test signal (shown on the previous page). Make sure that both picture and sound are tuned-in for the best possible results.

When you are satisfied with the tuning, then you may (if your TV is so equipped) set the AFC (or AFT) switch to the on position.

Finally, adjust the TV's brightness, contrast and colour controls for the clearest display of the text characters within the colour bars.

Now that you have tuned-in one of the TV's push-button channel selectors specifically for the +3, you may thereafter select that particular channel whenever you wish to use the +3 with your TV.

You may now skip to the section ahead entitled Using the +3.

Manual tuning

If your TV isn't equipped with push-button channel selectors, then you will have to use the TV's manual tuning knob to tune-in to your +3.

Having connected and switched on the +3 and TV, switch on the +3's test signal as described in the previous section entitled Preparing to tune-in your TV.

Tune-in the TV's manual tuning knob until the test signal is received. Make sure that both picture and sound are tuned-in for the best possible results.

Each time that you wish to set up and use the +3 with your TV, you should follow the above manual tuning procedure.

You may now skip to the section ahead entitled 'Using the +3'.

Having problems?

If you have tuned in your TV satisfactorily, you may now skip to the section ahead entitled Using the +3.

If, however, you are unable to tune-in your TV, the following check list may help you to ascertain where the problem lies, and what remedial action you can take.

  1. Problem...

The power indicator lamp (on the top panel of the +3) is not illuminated.


  1. Problem...

The power indicator lamp is illuminated, but no signal whatsoever can be tuned-in on the TV.


  1. Problem...

Only a poor signal from the computer can be tuned-in on the TV.


  1. Problem...

A signal from the computer is being tuned-in, but it's not the test signal described above.


  1. Problem...

The test signal colour bars appear, but no sound (repeating tone) is audible from the TV's speaker.


  1. Problem...

The test signal sound (repeating tone) can be head, but no colour bars can be seen on the TV.


  1. Problem...

The test signal colour bars and sound are tuned-in, but none of the text characters can be read.


If you cannot identify the cause of your problem, try carrying out the entire procedure (from the beginning of this chapter) again. If the problem still persists, contact your Sinclair dealer.

Using the +3

The +3 system should now be fully set up, with the test signal colour bars on the screen, and the repeating tone coming from the TV's speaker.

We will now switch off the test signal and start using the +3. Press and release the RESET button (at the left hand side of the +3). The test signal will disappear from the screen, and in its place will be the opening menu.

The opening menu

Note that the opening menu initially indicates which drives are available for use: drive A: is the built-in disk drive (at the front of the computer) and drive M: is the +3's internal RAMdisk (more about this in chapter 8 part 20). If you have connected an external disk drive to the +3, then you will see drive B: also indicated on the menu. The opening menu will appear whenever you first plug in and switch on the +3, or whenever you press and release the RESET button.

As its name suggests, the menu offers you a selection of options. You can choose from one of the four options which appear within the central box on the screen. These are:

How to choose an option

Notice that the menu option Loader appears to be highlighted by a 'bar'. This means that the Loader option is ready to be selected - (the selection hasn't been confirmed yet). For the purpose of this example, let's assume that you don't want to select Loader, but that instead you want to select +3 BASIC. This means that you need to move the highlight bar to the option +3 BASIC. To do this, use the cursor keys (shown below) until the highlight bar moves to the desired position.

When the highlight bar is on +3 BASIC, confirm this choice by pressing the ENTER key.

The computer then switches to the +3 BASIC mode. You will see a black horizontal bar (containing the words +3 BASIC) towards the bottom of the screen, and a flashing blue and white blob (called the cursor) at the top left-hand corner.

Don't worry if you know nothing about BASIC - we're not going to do any programming just yet - we'll simply return to the opening menu again. To do this, we use a different menu - this one's called the edit menu. Call up the edit menu by pressing the EDIT key.

Again, using the cursor keys and ENTER, select the option Exit to return to the opening menu.

You may now select whichever opening menu option you require. Depending upon your selection, refer to the following chapters for further information...

IMPORTANT - Whenever you have finished using the +3, always disconnect the power supply unit from the mains supply socket (having first removed any disk from the disk drive).

Chapter 3
How to load disk software

Subjects covered...

This chapter describes the loading of commercially available disk software.

(For a description of the loading, saving, formatting, etc., procedures that you would use during BASIC programming, see chapter 6 and chapter 8 part 20.)

Disks for the +3

The +3 uses 3 inch compact floppy disks. We strongly recommend that for reliable data-to-disk transfer, you use AMSOFT CF-2 floppy disks. Disks made by other leading manufacturers, however, may also be used.

Each side of a disk may be used independently. A disk should be inserted with its label facing outward from the drive, and with the side that you wish to use face up...

Loading disk software

To load Spectrum +3, Spectrum +2 and Spectrum 128 software (a game, an utility program, etc.) from disk, carry out the following instructions.

  1. Set up and switch on the +3 so that the opening menu appears on the screen...

  1. Insert your software disk into the disk drive.

  2. Press the ENTER key to select the option Loader from the opening menu. (If you don't know about selecting menu options, refer back to chapter 2.)

The software will start to load from disk. On the disk drive, you will see the read/write indicator lamp start to flash on and off (indicating that the disk is being read from). After a few seconds, the screen display will change and the software will be loaded, ready to use.

When you have finished using the software and wish to use the +3 for something else, press and release the RESET button (at the left-hand side of the +3). Always remember that whenever the RESET button is pressed, everything in the computer's memory (RAM) is cleared. You should therefore always make sure that you have completely finished with any program in the +3's memory, before you press the button.

If you are going to switch off the +3 completely, remember to remove any disk from the disk drive first.

Abandoning loading

If you wish to abandon a loading operation, simply press and release the RESET button. The +3 will return to the opening menu.

Chapter 4
How to load tape software

Subjects covered...

This chapter describes the loading of commercially available pre-recorded tape software.

(For a description of the loading, saving, formatting, etc., procedures that you would use during BASIC programming, see chapter 6 and chapter 8 part 20.)

Using tape instead of disk

So far, you have seen how to load software from disk. To use tape, first set up the +3 system so that your cassette unit is connected to the TAPE/SOUND socket at the back of the +3 (details of connections to this socket will be found in chapter 10).

Spectrum +3, Spectrum +2 and Spectrum 128 software

To load Spectrum +3, Spectrum +2 and Spectrum 128 software (a game, an utility program, etc.) from tape, carry out the following instructions...

  1. Set up and switch on the system so that the opening menu appears on the screen...

  1. Make sure that no disk in inserted in the drive.

  2. Press the ENTER key to select the option Loader from the opening menu. (If you don't know about selecting menu options, refer back to chapter 2.)

Now skip to the section ahead entitled 'Loading from tape'.

Note that when you select the Loader option from the opening menu, the +3 knows that you wish to load from tape (instead of disk) by automatically detecting the absence of a disk in the disk drive. If a disk is inserted, the tape will be ignored.

Spectrum 48 software

To load Spectrum 48 software (a game, an utility program, etc.) from tape, carry out the following instructions...

  1. Set up and switch on the system so that the opening menu appears on the screen...

  1. Select the option 48 BASIC from the opening menu. (If you don't know how to select a menu option, refer back to chapter 2.) The opening menu will disappear and the following message will be displayed at the bottom of the screen...

  1. Now press the J key once, followed by the " (double quote) key twice. The screen should look like this...

When you see this message, press ENTER.

Now skip to the section ahead entitled 'Loading from tape'.

(If the screen does not correspond to the above picture, then you may have selected the wrong menu option or pressed the wrong key. In this case, press and release the RESET button (at the left-hand side of the +3) and carry out steps 2 and 3 again.)

Loading from tape

  1. Insert the software tape into your cassette unit and make sure that it is rewound to the beginning.

  2. Play the cassette. As loading commences, the border colour will flash and appear striped, indicating that the program is being 'read' from the tape. If your TV's volume control is turned up, you will also hear a varying high-pitched tone. Again, this is an indication that the program is being read.

Most commercially available software cassettes take a few minutes to load. Initially, the program name may appear (toward the top left-hand corner of the screen) possibly followed by various other displays or messages (these will differ from program to program).

When the program has loaded, stop the cassette. The software is then ready to use.

When you have finished using the software and wish to use the +3 for something else, press and release the RESET button (at the left-hand side of the +3). Always remember that whenever the RESET button is pressed, everything in the computer's memory (RAM) is cleared. You should therefore always make sure that you have completely finished with any program in the +3's memory, before you press the button.

Abandoning loading

If, while loading software from tape, you wish to abandon the loading operation, then simply press and release the RESET button. The +3 will return to the opening menu.

NOTE - Holding the BREAK key down while loading Spectrum +3, Spectrum +2 or Spectrum 128 software will return the +3 to the opening menu; holding the key down while loading Spectrum 48 software will return the +3 to the 48 BASIC mode.

Chapter 5
The +3 disk drive

Subjects covered...

Disks and drives

The +3 uses 3 inch compact floppy disks. We strongly recommend that for reliable data-to-disk transfer, you use AMSOFT CF-2 floppy disks. Disks made by other leading manufacturers, however, may also be used.

If you have connected an additional disk drive to the +3, note that the main disk drive (within the +3) is called drive A: and the second (additional) disk drive is called drive B:.


Each side of a disk may be used independently. A disk should be inserted with its label facing outward from the drive, and with the side that you wish to use face up...

Write protection

In the left-hand corner of each side of a blank disk, you will see an arrow pointing to a small shuttered hole. This is called the write protect hole, and allows you to protect the contents of the disk from erasure or 'overwriting'...

Write protect hole

When the hole is closed, data can be 'written' onto the disk by the computer. When the hole is open, however, the disk will not allow data to be written onto it, thus enabling you to avoid the accidental erasure of valuable programs.

Various disk manufacturers employ differing mechanisms for opening and closing the write protect hole. The operation carried out on the AMSOFT CF-2 compact floppy disk is as follows.

To open the write protect hole, slide back the small shutter located at the left-hand corner of the disk, and the hole will be opened.

Write protect hole (OPEN) Shutter OPEN Shutter CLOSED

Once the hole is open, write protection is ON.

To close the write protect hole, simply slide the shutter to its closed position. Write protection is then OFF.

Other manufacturers' disks employ a small lever located in a slot at the left-hand corner...

Lever Write protect hole (CLOSED)
Write protection OFF

To open the write protect hole on this type of disk, slide the lever towards the middle of the disk (using the tip of a ball-point pen or similar object)...

Write protect hole (OPEN) Slide lever towards middle of disk
Write protection ON

Note that regardless of the method employed to open and close the write protect hole, opening the hole in all cases facilitates protection against overwriting.

When your disk is in

At the front of the disk drive, you will see a push button (for ejecting the disk), and a red lamp (called the read/write indicator lamp)...

Read/write indicator lamp Eject button

Read/write indicator lamp

This lamp indicates that data is being read from or written to the disk. Note, however, that if a second disk drive is connected, the read/write indicator lamp on drive B: will be constantly on (except when drive A: is reading or writing to disk).

Eject button

Pressing in the eject button allows you to remove your disk from the disk drive.

Do not press the eject button while the disk is being read from or written to.

Always eject your disk from the disk drive before switching the system off.

Chapter 6
Introducing +3 BASIC

Subjects covered...

The +3 has an advanced editor to create, modify and run BASIC programs. To enter the editor, select the option +3 BASIC from the opening menu, using the cursor keys and ENTER. (If you don't know how to select a menu option, refer back to chapter 2.)

The screen should now look like this...

There are three things to notice about this screen.

Firstly, there is a flashing blue and white blob in the top left-hand corner. This is called the cursor, and if you type any letters at the keyboard, then they will appear on the screen at the position of the cursor.

Secondly, there's a black bar towards the bottom of the screen. This is called the footer bar, and tells you which part of the +3's built-in software you're using. At the moment, it says +3 BASIC because that's the name of the editor.

The last item of note at the moment is the small screen. This fits between the footer bar and the bottom of the screen, and is currently blank. It only has room for two lines of text, and is most often used by the +3 when it detects an error and needs to print a report to say so. It does have other uses, however, and these will be described later.

Now press the EDIT key. You will notice two things happen - the cursor vanishes, and a new menu appears. This is called the edit menu...

The edit menu's options are selected in the same way as for the opening menu (by using the cursor keys and ENTER).

Taking the options in turn...

+3 BASIC - This option simply cancels the edit menu and restores the cursor. On the face of it - not very useful; however, if EDIT is pressed accidentally, then this option allows you to return to your program with no damage done.

Renumber - BASIC programs use line numbers to determine the order of the instructions to be carried out. You enter these numbers (which can be any whole-number from 1 to 9999) at the beginning of each program line you type in. Selecting the Renumber option causes the BASIC program's line numbers to start at line 10 and go up in steps of 10. BASIC commands which include references to line numbers (such as GO TO, GO SUB, LINE, RESTORE, RUN and LIST) also have these references renumbered accordingly.

If for any reason it's not possible to renumber, perhaps because there's no program in the +3, or because Renumber would generate line numbers greater than 9999, then the +3 makes a low-pitched bleep and the menu goes away.

A useful aid to this renumbering facility can be found in chapter 8 part 33.

Screen - This option moves the cursor into the smaller (bottom) part of the screen, and allows BASIC to be entered and edited there. This is most useful for working with graphics, as any editing in the bottom screen does not disturb the top screen. To switch back to the top screen (which you can do at any time whilst editing), select the edit menu option Screen again.

Print - If a printer is connected, this option will print-out a listing of the current program to it. When the listing has finished, the menu will go away and the cursor will come back. If for some reason the computer cannot print (eg. the printer is not connected or is off-line), then pressing the BREAK key twice will return you to the editor.

Exit - This option returns you to the opening menu - the +3 retains any program that you were working on in the memory. If you wish to go back to the program again, select the option +3 BASIC from the opening menu.

If you select the opening menu option 48 BASIC (or if you switch off or reset the +3), then any program in the memory will be lost. (You may, however, use the opening menu option Calculator without losing a program in the memory.)

Reset the computer and select +3 BASIC. Now type in the line below. As you type it in, the characters will appear on the screen (a character is a letter, number, space, etc.). Note that to type in the equals sign '=' you should hold down the SYMB SHIFT key, then press the L key once. Try typing in the line now...

10 for f=1 to 100 step 10

...then press ENTER. Providing you have spelt everything correctly, the +3 should have reprinted the line with the words FOR, TO and STEP in capital letters, like this...

10 FOR f=1 TO 100 STEP 10

The +3 should have also emitted a short high-pitched bleep, and moved the cursor to the start of the next line.

If the line remains in small letters and you hear a low-pitched bleep, then this indicates that you have typed in something wrong. Note also that the colour of the cursor changes to red when a mistake is detected, and you must correct the line before it will be accepted by the +3. To do this, use the cursor keys to move to the part of the line that you wish to correct, then type in any characters you wish to insert (or use the DELETE key to remove any characters you wish to get rid of). When you have finally corrected the line, press ENTER.

Now type in the line below...

(The colon : is obtained by SYMB SHIFT and Z, and the minus sign - is obtained by SYMB SHIFT and J.)

20 plot 0,0:draw f,175:plot 255,0:draw -f,175

...then press ENTER. On the screen you will see...

10 FOR f=1 TO 100 STEP 10
20 PLOT 0,0: DRAW f,175: PLOT
   255,0: DRAW -f,175

Don't worry about line 20 spilling over onto the next line of the screen - the computer will take care of this and align the text so that it is easier to read. Unlike a typewriter, there's no need for you to do anything when you approach the end of a screen line because the +3 detects this automatically and moves the cursor to the beginning of a new line.

The final line of this program to type in is...

30 next f

...again, press ENTER.

The numbers at the beginning of each line are called line numbers and are used to identify each line. The line you just typed in is line 30, and the cursor should be positioned just below it. As an exercise, we will now edit line 10 (to change the number 100 to 255). Press the cursor up key (four times) until the cursor has moved up to line 10. Now press the cursor right key until the cursor has moved to the right of 100. Press DELETE three times and you will see the 100 disappear. Now type in 255 and press ENTER. Line 10 of the program has now been edited...

10 FOR f=1 TO 255 STEP 10

The computer has opened up a new line in preparation for some new text. Type...


Press ENTER and watch what happens. Firstly, the footer bar and the program lines are cleared off the screen as the +3 BASIC editor prepares to hand over control to the program you've just typed in.

Then the program starts, draws a pattern, and stops with the report...

0 OK, 30:1

Don't worry about what this report means.

Press ENTER. The screen will clear and the footer bar will come back, as will the program listing. This takes about a second or so, during which time the +3 won't be taking input from the keyboard, so don't try and type anything while it's all happening.

You've just done most of the major operations necessary to program and use a computer! First, you've given the +3 a list of instructions. Instructions tell the +3 what to do (like the instruction 30 NEXT f). Instructions have a line number and are 'stored away' rather than used immediately you type them in. Then you gave the +3 the command run to execute the stored program.

Commands are just like instructions, only they don't have line numbers and the +3 carries them out immediately (as soon as ENTER is pressed). In general, any instruction can be used as a command, and vice versa - it all depends on the circumstances. Every instruction or command must have at least one keyword. Keywords make up the vocabulary of the computer, and many of them require parameters. In the command DRAW 40,200 for example, DRAW is the keyword, while 40 and 200 are the parameters (telling the computer exactly where to do the drawing). Everything the computer does in BASIC will follow these rules.

Now press EDIT and select the Screen option. The editor moves the program down into the bottom screen, and gets rid of the footer bar. You can only see line 10 of the program as the rest is 'hiding' off-screen (you can prove this by moving the cursor up and down).

Press ENTER then type...


Press ENTER again, and the program will run exactly the same as before. But this time, if you press ENTER afterwards, the screen doesn't clear, and you can move up and down the program listing (using the cursor keys) without disturbing the top screen. If you press EDIT to get the edit menu, you might think that this would mess up the top screen. However, the +3 remembers whatever's behind the edit menu and restores it when the menu is removed.

To prove that the editor really is working in the bottom screen, press ENTER and change line 10 to...

10 FOR f=1 TO 255 STEP 7 moving the cursor to the end of line 10 (just to the right of STEP 10), then pressing DELETE twice, and typing 7 (press ENTER).

Now type...

go to 10

(Press ENTER.) The keywords go to tell the +3 not to clear the screen before starting the program. The modified program draws a slightly different pattern on top of the old one. You may continue editing the program to add further patterns, if you wish.

A word of warning - while editing in the bottom screen, don't try to edit instructions which are more than two screen lines long. Otherwise, when the editor comes across an instruction which has its beginning or its end off-screen, it may become 'confused'. (The same is true of the top screen, but of course, this is unlikely to cause any problems as the screen is so much larger.)

One thing you may notice while you're typing away is that CAPS SHIFT and the number keys used together do strange things. CAPS SHIFT with 5, 6, 7 and 8 move the cursor about, CAPS SHIFT with 1 calls up the edit menu, CAPS SHIFT with 0 deletes a character, CAPS SHIFT and 2 is equivalent to CAPS LOCK, and finally CAPS SHIFT with 9 selects graphics mode. All of these functions are available using the dedicated keys on the +3, and so there is no reason why you should ever want to use the above CAPS SHIFT and number key alternatives.

Simple disk operations

You have seen how to place a program into the computer's memory by typing it in. This is all very well the first time you write a particular program, but what about if you switch off the computer and want to use the same program the next day? Surely you don't have to type it all in again from scratch - the answer, of course, is no - the disk drive section of the +3 allows you to save a program from the computer's memory onto a disk, and to load a program from a disk into the computer's memory. This means that you can type in a program, save it to disk, then happily switch off the +3 knowing that next time you switch it on, you'll be able to load that same program back into the memory.

The final part of this chapter, therefore, deals with these two very important operations (saving and loading). However, before you can do either of these, you will be shown how to prepare a brand new disk so that it is ready for saving programs onto. This preparation process is called formatting.

You will need to have a brand new blank disk to hand as you work through this chapter. Whatever you do - don't use a disk with any valuable software, games, etc. on it.

Disks and tapes

Even if you are familiar with saving and loading, it is worth pointing out two important points which must be remembered when dealing with disks.

Firstly, a brand new blank disk cannot be simply taken out of its wrapper and recorded onto (as is the case with a tape) - instead, each side of a disk must be formatted first. Note that the formatting process completely erases that side of the disk.

Secondly, it is important that disk files are correctly 'named'. Filenames on tape may vary greatly in length and may at times be omitted. Not so with disks - disk filenames must conform to very strict standards (and you will read about these shortly in the section ahead called 'Filenames'.

Formatting a disk

Formatting can be likened to building a series of shelves and pigeonholes on a disk prior to the storage of information on those shelves. In other words, formatting lays down an organised framework around which data can be put in or taken out.

The formatting divides the disk into 360 distinctly separate areas...

Missing image of a floppy disk structure

There are 40 concentric tracks from the outside of the disk (Track 0) to the inside (Track 39), and each track is divided into 9 sectors.

Each portion of track in a sector can store up to 512 bytes of data, hence the total available space on each side of a disk is 180 kilobytes (180K). Note that 7K of the 180K is reserved for the computer's own use, this leaves 173K per side for your programs.

We will now format a new blank disk, and save the program below...

10 FOR f=1 TO 255 STEP 7
20 PLOT 0,0: DRAW f,175: PLOT 255,0: DRAW -f,175
30 NEXT f

...which should still be in the memory from the previous exercise (check that the above program is currently in the memory by pressing ENTER then typing...


(Press ENTER again.) If the program isn't in the memory (or you have since switched off the +3), then switch it on, select +3 BASIC and type in the above program).

Insert side 1 of a new blank disk into the disk drive and type...

format "a:"

(Press ENTER.) The read/write indicator lamp on the disk drive will start to flash on and off. About 30 seconds later, you will see the report...

0 OK, 0:1

You have now formatted side 1 of the disk. Once you have done this, you should not need to format side 1 of that disk ever again.

(If you don't receive the above report (and some other message appears instead), check the section entitled 'Error reports' at the end of this chapter.)

Saving a program

Having formatted side 1, it is now ready for saving programs onto.

In order that each program file on a disk can be identified, you must give the program a filename when you save it. For example, as the program that you are about to save draws a patterned picture, save the program using the name 'pattern.pic', ie. type in...

save "pattern.pic"

(Press ENTER.) After a few seconds, you will see the report...

0 OK, 0:1

The program is now saved onto disk.

(If you don't receive the above report (and some other message appears instead), check the section entitled 'Error reports' at the end of this chapter.)


Note that a filename on disk consists of two parts (fields). The first field is obligatory and can contain up to 8 characters (letters and numbers may be used but no spaces and punctuation marks). In the above example filename, 'pattern' is the first field.

The second field is optional. You can use up to 3 characters (but again no spaces or punctuation). In the above example filename, 'pic' is the second field.

If you use two fields in a filename, they must be separated by a dot (eg. 'pattern.pic').

Disk catalog

A catalog of the disk (in alphabetical order) can be displayed by typing in...


(Press ENTER.) The filenames of all the programs on that side of the disk will be displayed, together with each file's length (to the nearest higher kilobyte). The amount of free space will also be indicated.


172K free

Loading a program

Imagine that you have switched off the +3 and later want to load the program you have just saved. Do this now by resetting the +3 (using the RESET button) and selecting the option +3 BASIC from the opening menu. Type in...

load "pattern.pic"

(Press ENTER.) After a few seconds, you will see the report...

0 OK, 0:1

The program is now loaded from disk. Press ENTER and you will see the program listing displayed.

(If you don't receive the above report (and some other message appears instead), check the next section entitled 'Error reports'.)

Once loaded, you may run the program by simply typing...


...and pressing ENTER, as before.

Error reports

If you don't correctly carry out the instructions in this section, you may receive various error reports. If so, identify the report (from those shown below), read the explanation given, and then take the necessary corrective action.

Drive not ready

The above report means that you have probably forgotten to insert a disk into the disk drive. If there is a disk inserted in the disk drive, then eject it, re-insert it and try again.

Disk is write protected

The above report means that you are trying to format, or save a program to, a disk which has its write protect hole open. Eject the disk, close its write protect hole, re-insert the disk and try again.

File not found

The above report means that you are trying to load a program which doesn't exist on that side of the disk. Eject the disk, make sure that the correct disk is inserted (the right way up) and try again. Take care to ensure that you accurately type in the filename to load.

Bad filename


Invalid filename

The above reports mean that you are trying to load or save a program using an illegal filename (or no filename at all). Read the section entitled 'Filenames' earlier in this chapter, and try again.

Disk is already formatted
A to abandon, other key continue

The above report means that you are trying to format a disk that has already been formatted. In general, a disk should need formatting only once (at the beginning of its life). In rare cases, a disk may become corrupted and there will be no alternative other than to format it again. However, unless this is the case, you should always type A (to abandon) when you see the above report.

NOTE - If you don't type A, then the formatting process will go ahead and completely erase that side of the disk (as soon as you press a key).

If you find that one particular disk (or side of a disk) keeps requiring formatting, then it is likely that the disk itself is damaged and you should avoid using it in future.

Some commands that fail produce reports that offer you the options...

- Retry, Ignore or Cancel?

If you receive the above options, then:

...typing R (after taking the necessary corrective action) makes the computer retry the command;

...typing I makes the computer ignore the reason that the command failed in the first place and continue regardlessly (typing I is therefore not recommended unless you know exactly what you're doing);

...typing C abandons the command (this may be followed by the appearance of another report).

Further information

Further information on disk operations (together with details of how to use the +3's RAMdisk and how to use an external cassette unit) can be found in chapter 8 part 20. A guide to +3DOS (the +3 Disk Operating System) will be found in chapter 8 part 27.

Chapter 7
Using 48 BASIC

Subjects covered...

The +3 has the ability to act exactly like a 48K Spectrum (or Spectrum +). This achieved by selecting the option 48 BASIC from the opening menu. In 48 BASIC mode, many of the enhanced features of the +3 (such as the disk drive, extra memory, full screen editor, multi-channel sound, RS232/MIDI/AUX interfaces and RAMdisk) cannot be used. The JOYSTICK 1 and JOYSTICK 2 sockets will still operate, however.

The 48 BASIC mode is included for compatibility reasons only - there is no advantage in using 48 BASIC (instead of +3 BASIC mode) to write programs, and it is not recommended. The following information is included for reference only, or for anybody who is used to the old 48K Spectrum and wants to use the machine immediately without having to learn about the +3 BASIC editor.

There are, in fact, two methods of entering the 48 BASIC mode: the first is by selecting the 48 BASIC option from the opening menu (if you don't know how to select a menu option, refer back to chapter 2).

When 48 BASIC starts up, you will see the following on the screen...

The second method allows you to enter the 48 BASIC mode while editing a +3 BASIC program. To do this (while in +3 BASIC mode), type...


...and press ENTER. The +3 will respond with an OK message [not on any +3 I've ever used...] and will have changed to 48 BASIC mode, retaining any program that you had in memory. Once in 48 BASIC mode, there is no way back to +3 BASIC mode apart from resetting the +3 (or switching off, then on again).

One major difference between 48 BASIC and +3 BASIC is in the entering and editing of programs. (Note also that in +3 BASIC the tokens SPECTRUM and PLAY have replaced the user defined graphics characters for the keys T and U under 48 BASIC (values 163 and 164).)

Once in 48 BASIC mode, the keyboard performs as follows:

All the BASIC commands, functions and operators are available directly from the keyboard rather than needing to be spelled out. In order to accommodate all these functions and commands, some keys have five or more distinct meanings, obtained partly by 'shifting' the keys (ie. pressing either CAPS SHIFT or SYMB SHIFT together with the required key); and partly by having the machine in different modes. The flashing cursor contains a letter (K, L, C, E or G) to indicate which mode you are operating in.

K (for Keywords) mode automatically replaces L (for Letters mode when the machine is expecting a command or program line (rather than input data), and from its position on the line the +3 knows that it should expect either a line number or a keyword. K mode occurs at the beginning of a line, or after a colon ':' (except in a string), or after the keyword THEN. Whenever the K cursor appears, the next key pressed will be interpreted as either a keyword or a line number, as follows...

The keyboard in K mode

L (for Letters) mode normally occurs at all times (other than K mode, described above). Whenever the L cursor appears, the next key pressed will be interpreted as per the legends on the key-tops themselves, ie....

The keyboard in L mode

In both K and L modes, pressing SYMB SHIFT together with a key will be interpreted as follows...

The keyboard using SYMB SHIFT in K or L mode

Using CAPS SHIFT in L mode simply converts small letters to capitals. In K mode, however, CAPS SHIFT does not affect the keywords.

C (for Capitals) mode is a variant of L mode whereby all letters appear as capitals. The CAPS LOCK key is used to change from L mode to C mode, and back again.

E (for Extended) mode is used to obtain further characters, mostly tokens. It is entered by pressing the EXTEND MODE key, and lasts for only one character (or key depression) thereafter. Whenever the E cursor appears, the next key pressed will be interpreted as follows...

The keyboard in E mode

Applying CAPS SHIFT while in E mode, the next key pressed will be interpreted as follows...

The keyboard using CAPS SHIFT in E mode

Applying SYMB SHIFT while in E mode, the next key pressed will be interpreted as follows...

The keyboard using SYMB SHIFT in E mode

G (for Graphics) mode occurs when GRAPH is pressed, and lasts until it is pressed again (or 9 is pressed on its own). A number key will give a mosaic graphics, and each of the letter keys (apart from V, W, X, Y and Z) will give a user-defined graphics which, until it is defined, will look identical to a capital letter. Whenever the G cursor appears, the next key pressed will be interpreted as follows...

The keyboard in G mode

Applying CAPS SHIFT while in G mode inverts the mosaic graphics (ie. the ink colour becomes the paper colour, and the paper becomes the ink colour). Hence, the next key pressed will be interpreted as follows...

The keyboard using CAPS SHIFT in G mode

General keyboard notes

If any key is held down for more than 2 or 3 seconds, it will start repeating. Keyboard input appears in the bottom half of the screen as it is typed, each character (single symbol or compound token) being inserted just before the cursor. The cursor can be moved left and right using the cursor control keys left and right (to the left of the space bar). The character to the left of the cursor can be removed using DELETE.

When ENTER is pressed, the line is either executed, entered into the program, or used as input data. If the line contains a syntax error, however, a flashing question mark ? appears next to the error.

As program lines are entered, a listing is displayed in the top half of the screen. The last line entered is called the current line and is indicated by the symbol > after the line number. Any line in the program may be selected as the current line (for editing purposes) by using the up and down cursor keys (to the right of the space bar). To then edit the select current line, press the EDIT key. (Editing takes place at the bottom of the screen.)

When a command is executed or a program is run, output is displayed in th top half of the screen and remains there until either ENTER or the cursor up or down key is pressed. At the bottom of the screen appears a report giving a code (digit or letter) referred to in part 29 of chapter 8. This report remains on the screen until a key is pressed and the +3 returns to K mode.

Chapter 8
The +3 BASIC programmer's guide

Part 1

Whether you read chapter 6 first, or came straight here, you should be aware that...

This guide to BASIC starts by repeating some of the information given in chapter 6 (Introducing +3 BASIC), but in greater detail. You may also find exercises at the end of some sections - don't ignore these, as many of them illustrate points that are hinted at in the text. Look through them, and do any that interest you or that seem to cover ground that you don't understand properly.

The Keyboard

The characters used on the +3 comprise not only single symbols (letters, digits, etc.) but also compound tokens (keywords, function names, etc.). Everything must be typed in full, and in most cases it doesn't matter whether capital letters (known as UPPER CASE) or small letters (lower case) are used. There are three sorts of keys on the keyboard: letter and number keys (called alphanumeric keys); symbol keys (punctuation marks); and control keys (things like CAPS SHIFT, DELETE and so on).

The most commonly used keys for BASIC are the alphanumeric keys. When a letter key is pressed, a lower case letter will appear on the screen with a flashing blue and white blob called the cursor. To get an upper case letter, the CAPS SHIFT key should be held down while the letter is typed.

If you wish to continuously type upper case letters, then pressing the CAPS LOCK key once will make all subsequent letters typed upper case. To return to lower case letters, simply press CAPS LOCK again.

To type the symbols which appear on the alphanumeric keys on the keyboard, ie....

! @ # $ % & ' ( ) _ < > ^ - + = : <pound sign> ? / *

...simply hold down the SYMB SHIFT key while the alphanumeric key with the required symbol on it is pressed (see the following diagram)...

Symbols available using SYMB SHIFT

Additionally, the symbols...

  [ ] © ~ | \ { }

...can be obtained by first pressing the EXTEND MODE key once, then holding down SYMB SHIFT while pressing the appropriate alphanumeric key (see the following diagram)...

Symbols available using SYMB SHIFT in EXTEND MODE

To enter graphics mode, the GRAPH key is pressed once. Mosaic graphics (see the following diagram) can then be produced by pressing the number keys (except 9 and 0). Pressing the letter keys (except T, U, V, W, X, Y and Z) produce user-defined graphics (if set up).

Mosaic graphics available using GRAPH

To obtain inverted mosaic graphics, press the above number keys while holding down CAPS SHIFT.

General keyboard notes

If any key is held down for more than 2 or 3 seconds, it will start repeating. As keys are pressed, a line will be built up on the screen. A line, by the way, means a line of BASIC, and may easily be several lines long on the screen. The cursor keys can be used to move about the line, and if the part of the line that the cursor is moved to is off screen, then the text on screen will scroll up or down to display it. Any characters typed will be inserted at the cursor, and pressing DELETE causes the character to the left of the cursor to be removed. As soon as ENTER is pressed or any attempt is made to move the cursor off the line, the +3 checks to see if the line makes sense. If it does, then there is a high-pitched bleep, and the line is either acted upon immediately or stored away as part of a program. If the line contains an error, then the +3 generates a low-pitched bleep and moves the cursor to the area where it thinks the error is (the colour of the cursor also changes to red to indicate the error). It is impossible to move off a line which contains an error the +3 will always move the cursor back.

The monitor screen

This has 24 lines (each being 32 characters long) and is divided into two parts. The larger (top) part of the screen is at most 22 lines and displays either a listing or program output. It is the one used most often for editing. When printing in the top part has reached its bottom limit, the contents scroll up by one line. If, however, scrolling would mean losing a line that you haven't yet had a chance to see, then the +3 stops with the message...


Pressing any key (except N, BREAK or the space bar) will let scrolling continue.

Pressing one of the keys N, BREAK or the space bar will make the program stop with the report...

D BREAK - CONT repeats

The smaller (bottom) part of the screen is used for editing short programs, entering input data, entering direct commands (where the main screen must not be used, eg. graphics programs), and also for displaying reports.

Program entry

If the program being entered gets bigger than the screen size, then the +3 attempts to display the area of most interest (usually the last line entered together with its surrounding lines). You may, however, specify a different area of the program to be displayed using the command...

    LIST xxx

...where xxx is a line number, telling the +3 to bring a specified area of the program into view.

When a command is executed or a program is run, output is displayed in the top part of the screen and remains there when the program finishes (until a key is pressed). If the program is being edited in the bottom part of the screen, then any output in the top screen will stay there until it is either overwritten, scrolled off, or a CLS command is issued. The bottom screen may display a report giving a code (digit or letter) referred to in part 29 of this chapter. This report remains in the bottom screen until a key is pressed.

While the +3 is running a BASIC program, the BREAK key is checked every so often. This happens at the end of a statement, during use of the cassette unit (if connected) or printer (if connected), or while music is being played. If the +3 finds that the BREAK key is pressed, then program execution stops and displays a report. The program may then be edited.

Part 2
Simple programming concepts

Subjects covered...

Type in the following first two lines of a program (which will eventually print the sum of two numbers). Don't forget to press ENTER after you type each line...

   20 print a
   10 let a=10

Note that the screen looks like this...

   10 LET a=10
   20 PRINT a

As we have already discussed - because these lines began with numbers, they were not obeyed immediately but were stored away as program lines. You will have also noticed here that the line numbers govern the order in which the program lines are to be executed, and as you can see on the screen, the +3 sorts all the lines into order whenever a new line is entered.

Note also that although we typed each line in lower case letters, the keywords (ie. PRINT and LET) were converted to upper case as soon the line was entered and accepted by the +3. From now on, we will show keywords to be typed in upper case letters; however, you may continue to type in lower case letters.

(By the way, if you don't know what a keyword is, you should have studied chapter 6 before reading this chapter.)

So far you have only entered one number, so type...

    15 LET b=15

...and press ENTER. Now you need to change line 20 to...

    20 PRINT a+b

You could type out the replacement line in full, but it is far easier to move the cursor (using the cursor keys) to just after the a, and then type...

+b (don't press ENTER yet)

Check that the line then reads...

    20 PRINT a+b

...then press ENTER. The cursor will move to the line below, and the screen should look like this...

    10 LET a=10
    15 LET b=15
    20 PRINT a+b

What you have done in this program is to have assigned the value 10 to the variable called a, and the value 15 to the variable called b. You have then instructed the computer to print the sum of these two values by simply adding the two variables.

Run this program by typing...


...and pressing ENTER. The sum of the two numbers will be displayed...


Run the program again and then afterwards, press ENTER and type...

    PRINT a,b

Now press ENTER again and notice how the values of the variables a and b are still in the +3's memory, even though the program has finished...

    10              15


If you enter a line by mistake, say...

    12 LET b=8

...and you wish to delete the line, then simply type...


..and press ENTER. Line 12 will vanish, and the cursor will reappear where line 12 used to be.

Now type...


...and press ENTER. The +3 will search for line 30, and since there isn't one, it will 'fall off' the end of the program. The cursor will be positioned just after the last line. If you enter any non-existent line number (such as 30), then the +3 will place the cursor where it thinks the line would have been if it really existed. This can be a useful way of moving about large programs, but beware - it can also be very dangerous because if the line really did exist before you entered the line number - it certainly wouldn't exist afterwards!

To list a program on the screen, type...


...and press ENTER. You may (particularly when working with more lengthy programs) wish to list from a certain point onwards. This can be achieved by typing an appropriate line number after the LIST command.


    LIST 15

...and press ENTER, to see this illustrated.

When we were developing the above program, note how we were able to insert line 15 between the other two lines - this would have been impossible if they had been numbered 1 and 2 instead of 10 and 20. It is always good practice, therefore, to leave gaps between line numbers.

(Note that line numbers must be entered as whole numbers between 1 and 9999.)

If, at some time, you find that you haven't left enough space between line numbers, then you may use the edit menu to renumber a program. To do this, press the EDIT key then select the Renumber option from the menu that appears; this sets the gap between each line number to 10. Try this out and see how the line numbers change.

We are now going to use the BASIC command NEW. This erases any existing programs and variables in the +3's memory. The command should be used whenever you are about to start afresh, so type...


...and press ENTER. From now on, we won't mention 'press ENTER' every time - we'll assume that you'll remember.

With the opening menu on the screen, start up BASIC by selecting the option +3 BASIC.

Now carefully type in this program, which converts Fahrenheit temperatures to Celsius (centigrade)...

    10 REM temperature conversion
    20 PRINT "deg F","deg C"
    30 PRINT
    40 INPUT "Enter deg F",f
    50 PRINT f,
    60 PRINT (f-32)*5/9
    70 GO TO 40

Although you can type in all of line 10 in lower case, only the REM will be converted to upper case on entry as it's the only keyword that the +3 recognises. Also, although the words GO TO will appear with a space between them, they may be typed in as one word (GOTO) if you prefer.

Now run the program. The instructions will start being carried out in the order determined by the line numbers. First of all, you'll see the headings deg F and deg C printed on the screen (as instructed by line 20), but what has line 10 done? It looks like the +3 has completely ignored it - in fact, it has! The REM in line 10 stands for remark, so line 10 is solely to remind you of what the program does. A REM command consists of REM followed by anything you like - the +3 will ignore everything after the REM, right up to the end of the line.

After line 20, the +3 carries out line 30 which simply prints a blank line. When the +3 gets to the INPUT command in line 40 it waits for you to type in a value for the variable f - you can tell this because at the bottom of the screen is a flashing cursor.

Type in a number (then press ENTER). The +3 displays the result and then waits for you to enter another number. This is because the instruction in line 70 says GO TO 40 - in other words, 'instead of running out of program and stopping, jump back to line 40 and continue running from there'.

So, enter another temperature, then another...

After a few more of there you might be wondering if the computer will ever get bored of this - it won't! Next time it asks for another number, hold down SYMB SHIFT and type A. The word STOP will appear, and when you press ENTER then +3 comes back with the report...

    H STOP in INPUT in line 40:1

...which tells you why it stopped, and where (in line 40). (The :1 after the line number in the report tells you that the 1st instruction in line 40 is being reported upon.)

If you wish to continue the program, type...


...and the +3 will ask you for another number.

When CONTINUE is used, the +3 remembers the line number in the last report that it sent you (as long as the report that it sent you (as long as the report was not 0 OK) and jumps back to that line, which in this case is line 40 (the INPUT command).

Stop the program again and replace line 70 by...

    70 GO TO 31

There will be no perceptible difference to the running of the program because if the line number in a GO TO command refers to a non-existent line, then the jump is to the next line after the given number. The same goes for RUN (in face, RUN on its own actually means RUN 0).

Keep entering numbers until the screen starts getting full. When it is full, the +3 will move the whole of the top half of the screen up one line to make room, losing the heading off the top - this is called scrolling.

When you are tired of entering numbers, stop the program as before and enter the editor by pressing ENTER.

Look at the PRINT statement in line 50. The , comma in this line is very important.

Commas are used to make the printing start either at the left-hand margin, or in the middle of the screen (depending upon which comes next). Thus in line 50, the comma causes the Celsius temperature to be printed in the middle of the line.

A semicolon ; on the other hand, is used to make the next number (or characters) be printed immediately after the preceding one(s).

Another punctuation mark you can use like this in PRINT commands is the apostrophe '. This makes whatever is printed next appear at the beginning of the next line on the screen. This also happens by default at the end of each PRINT command.

If you wish to inhibit this (so that whatever follows to be printed continues on the same line) you can put a comma or semicolon at the end of the PRINT statement. To see how this works, replace line 50 in turn by each of these...

    50 PRINT f,
    50 PRINT f;
    50 PRINT f

...and run the program each time to see the difference.

The line with the comma (you typed in originally) printed everything in two columns; the line with the semicolon crams everything together, and the line without either, prints each number on a new line (you could have also used PRINT f' to do this).

Always remember the difference between commas and semicolons in PRINT commands, and do not confuse them with : colons which are used as separators between commands on a single line, for example...

    PRINT f: GO TO 40

Now type in these extra lines...

    100 REM greeting program
    110 INPUT "Enter your name",n$
    120 PRINT "Hello ";n$;"!"
    130 GO TO 110

This is a separate program from the last one, but you may keep them both in the +3 at the same time. To run the new one, type...

    RUN 100

Because this program expects you to input a string (a character or group of characters) instead of a number, it prints out two string quotes '""' as a reminder. So type in a name and press ENTER.

Next time round, you will get two string quotes again, but you don't have to use them if you don't want to. Try this, for example: rub out the quotes by pressing cursor right, then DELETE twice, and type...


Since there are no string quotes, the +3 knows that it has to do some calculation - the calculation in this case is to find the value of the string variable called n$ (which is whatever name you happen to have typed in last time round). In this way, the INPUT statement acts like LET n$=n$, so the value of n$ is unchanged.

If you wish to stop the program, delete the quotes then hold down SYMB SHIFT and type A, then ENTER.

Now look back at that RUN 100 instruction which jumps to line 100 and runs the program from there. You may be asking, 'What's the difference between RUN 100 and GO TO 100 ?' Well, RUN 100 first of all clears all the variables and the screen, and after that works just like GO TO 100. On the other hand, GO TO 100 doesn't clear anything, and there may well be occasions where you wish to run a program without clearing any variables; here GO TO would be necessary and RUN could be disastrous, so it is better not to get into the habit of automatically typing RUN to start a program.

Another difference of course is that you may type RUN without a line number, and it starts off at the first line in the program; GO TO must always be followed by a line number.

Both this program and the 'temperature conversion' program stopped because you pressed SYMB SHIFT and typed A in the input line. Sometimes, you may write a program that you can't stop and that won't stop itself. Type...

    200 GO TO 200
    RUN 200

Although the screen is blank, the program is running - executing line 200 over and over again. This looks all set to go on forever unless you pull the plug out or reset the computer! However, these is a less drastic remedy - press the BREAK key. The program will stop with the report...

    L BREAK into program

At the end of every statement, the program looks to see if this key is pressed, and if it is, then the program stops. The BREAK key can also be used when you are in the middle of using a printer, a cassette unit, or various other add-ons that you can attach to the +3.

In these cases there is a different report...

    D BREAK - CONT repeats

The instruction CONTINUE in this case *and in most other cases too) repeats the statement where the program was stopped and carries straight on with the next statement (after allowing for any jumps to be made).

Run the 'name' program again and when it asks you for input, type...

n$ (after removing the quotes)

Because n$ is an undefined variable, you will get the error report...

    2 Variable not found

If you now type...

    LET n$="Fremsley"

(which produces the report 0 OK, 0:1), and then type...

    CONTINUE will find that you can use n$ as input data without any trouble.

In that case CONTINUE does a jump to the INPUT command in line 110. It disregards the report from the LET statement because that said OK and jumps to the command referred to in the previous report, ie. line 110. This feature can be extremely useful as it allows you to 'fix' a program that has stopped due to errors, and then CONTINUE from that point.

As we said before, the report L BREAK into program is special because after it, CONTINUE does not repeat the command where the program stopped.

You have now seen the statements, PRINT, LET, INPUT, RUN, LIST, GO TO, CONTINUE, NEW and REM, and they can all be used either as direct commands or in program lines - this is true of almost all commands in +3 BASIC, however, RUN, LIST, CONTINUE and NEW are not usually of much use in a program.


  1. Put a LIST statement in a program, so that when you run it, it lists itself afterwards.
  2. Write a program to input prices and print out the tax due (at 15 percent). Put in PRINT statements so that the +3 announces what it is going to do, and asks for the input price with extravagant politeness. Modify the program so that you can also input the tax rate (to allow for zero ratings or future changes).
  3. Write a program to print a running total of numbers you input (like an adding machine).
  4. What would CONTINUE and NEW do in a program? Can you think of any uses at all for this?

Part 3

Subjects covered...

All the programs we have seen so far have been pretty predictable - they went straight through the instructions, and then went back to the beginning again. This is not very useful, as in practice, we would want the +3 to make decisions and act accordingly. The instruction to do this in BASIC takes the form...

IF something is true (or not true) THEN do something

Let's look at an example of this. Use NEW to clear the previous program from the +3, select +3 BASIC, then type in and run this program. (This is clearly meant for two people to play!)...

    10 REM Guess the number
    20 INPUT "Enter a secret number",a: CLS
    30 INPUT "Guess the number",b
    40 IF b=a THEN PRINT "That is correct": STOP
    50 IF b<a THEN PRINT "That is too small, try again"
    60 IF b>a THEN PRINT "That is too big, try again"
    70 GO TO 30

Note that the CLS command (at the end of line 20) means 'clear the screen'. We have used it in this program to stop the other person seeing the secret number after it is entered.

You can see that the IF statement takes the form...

IF condition THEN xxx

...where 'xxx' stands for a command (or a sequence of commands separated by colons). The condition is something that is going to be worked out as either true or false - if it comes out as true then the statements in the rest of the line (after THEN) are executed; otherwise they are skipped over, and the program executes the next instruction.

The simplest conditions compare two numbers or two strings; they can test whether two numbers are equal or whether one is bigger than the other. They can also test whether two strings are equal, or whether one comes before the other in alphanumerical order. They use the symbols =, <, >, <=, >= and <> (these are known as relational operators).

(If you keep getting mixed up about the meanings of < and >, it may help you to remember that the thin end of the symbol points to the number which is supposed to be smaller.)

In the program we have just typed in, line 40 compares a and b. If they are equal, then the program is halted by the STOP command. The report at the bottom of the screen...

    9 STOP statement, 40:3

...shows that the 3rd statement (ie. the STOP command) in line 40 caused the program to halt.

Line 50 determines whether b is less than a, and line 60 whether b is greater than a. If one of these conditions is true then the appropriate comment is printer, and the program works its way down to line 70 which jumps back to line 30 and starts all over again.

Finally, note that in some versions of BASIC (not +3 BASIC) the IF statement can have the form...

IF condition THEN line number

This means the same as...

IF condition THEN GO TO line number +3 BASIC.


  1. Try this program...
        10 LET a=1
        20 LET b=1
        30 IF a>b THEN PRINT a;" is higher"
        40 IF a<b THEN PRINT b;" is higher"

Before you run it, try to work out what will be printed on the screen.

Part 4

Subjects covered...

Suppose you wish to input five numbers and add them together.

One way (don't type this in unless you are feeling dutiful) is as follows...

     10 LET total=0
     20 INPUT a
     30 LET total=total+a
     40 INPUT a
     50 LET total=total+a
     60 INPUT a
     70 LET total=total+a
     80 INPUT a
     90 LET total=total+a
    100 INPUT a
    110 LET total=total+a
    120 PRINT total

This method is not good programming practice. It may be just about controllable for five numbers, but you can imagine how tedious a program like this to add twenty numbers would be, and to add a hundred or more would be out of the question.

Much better is to set up a variable to count up to 5 and then stop the program, like this (which you should type in)...

    10 LET total=0
    20 LET count=1
    30 INPUT a
    40 REM count is number of times that a has been input so far
    50 LET total=total+a
    60 LET count=count+1
    70 IF count <= 5 THEN GO TO 30
    80 PRINT total

Notice how easy it would be to change line 70 so that this program adds ten numbers, or even a hundred.

This sort of thing is so useful that there are two special commands to make it easier - the FOR command and the NEXT command. They are always used together. Using these, the program you have just typed in does exactly the same as...

    10 LET total=0
    20 FOR c=1 TO 5
    30 INPUT a
    40 REM c is number of times that a has been input so far
    50 LET total=total+a
    60 NEXT c
    80 PRINT total

(To get this program from the previous one, you just have to edit lines 20, 40 and 60, then delete line 70.)

Note that we have changed count to c. This is because the control variable of a FOR...NEXT loop must have a single letter as its name.

The effect of this program is that c runs through the values 1 (the initial value), 2, 3, 4 and 5 (the limit), and each time, lines 30, 40 and 50 are executed. Then, when c has finished its five values, line 80 is executed.

At this point, attempt exercise 2 (which refers to the above program), at the end of this section.

An extra subtlety to the FOR...NEXT structure is that the control variable does not have to go up by 1 each time - you can change this 1 to anything you like by using a STEP part in the FOR command. The most general form of a FOR command is...

FOR control variable = initial value TO limit STEP step

...where the control variable is a single letter, and where the initial value, the limit and the step are all things that the +3 can calculate as numbers - like the actual numbers themselves, or sums, or the names of numeric variables. So, if you replace line 20 in the program by...

    20 FOR c=1 TO 5 STEP 3/2

...this will step the control variable by the amount 3/2 each time the FOR loop is executed. Note that we could have simply said STEP 1.5, or we could have assigned the step value to a variable, say s, and then said STEP s.

With the above modification, c will run through the values 1, 2.5 and 4. Notice that you don't have to restrict yourself to whole numbers, and also that the control value does not have to hit the limit exactly; it carries on looping as long as it is less than or equal to the limit.

At this point, attempt exercise 3 at the end of this section (which refers to the above program).

Step values can be negative instead of positive. Try this program which prints out the numbers from 1 to 10 in reverse order. (Remember, use the command NEW before typing in a new program.)

    10 FOR n=10 to 1 STEP -1
    20 PRINT n
    30 NEXT n

We said before that the program carries on looping as long as the control variable is less than or equal to the limit. If you consider what that would mean in this case, you'll see that it now doesn't hold true. Hence, the rule has to be modified to say that when the step is negative, the program carries on looping as long as the control variable is greater than or equal to the limit.

At this point, attempt exercises 4 and 5 at the end of this section (which refer to the above program).

You must be careful if you are running two FOR...NEXT loops together, one inside the other. Try this program, which prints out the numbers for a complete set of six dot dominoes.

    10 FOR m=0 TO 6                       |
    20 FOR n=0 TO m         |             |
    30 PRINT m;":";n;" ";   |- n loop     |- m loop
    40 NEXT n               |             |
    50 PRINT                              |
    60 NEXT m                             |

You can see that the n loop is entirely inside the m loop. This means that they are properly nested.

However, what must be avoided is having two FOR...NEXT loops that overlap without either being entirely inside the other, like this...

     5 REM this program is wrong
    10 FOR m=0 TO 6               |
    20 FOR n=0 TO m               |           |
    30 PRINT m;":";n;" ";         |- m loop   |- n loop
    40 NEXT m                     |           |
    50 PRINT                      |
    60 NEXT n                     |

Two FOR...NEXT loops must either be one inside the other, or completely separate.

Another thing to avoid is jumping into the middle of a FOR...NEXT loop from the outside. The control variable is only set up properly when its FOR statement is executed, and if you miss this out, then the NEXT statement will confuse the +3. You will probably get an error report saying NEXT without FOR or Variable not found.

There is nothing to stop you using a FOR...NEXT loop in a direct command. For example, try...

    FOR m=0 TO 10: PRINT m: NEXT m

You can sometimes use this as a (somewhat artificial) way of getting around the restriction that you cannot GO TO anywhere inside a command - because a command has no line number. For instance...


The step size of zero here makes the command repeat itself forever.

This sort of thing is not really recommended, because if an error crops up then you have lost the command and will have to type it in again; moreover, CONTINUE will not work.


  1. Make sure that you understand that a control variable not only has a name and a value (like an ordinary variable), but also a limit, a step, and a reference to the statement after the corresponding FOR statement. Ensure that when the FOR statement is executed all this information is available (using the initial value as the first value the variable takes), and also that this information is enough for the NEXT statement to know by how much to increase the value, whether to jump back, and if so where to jump back to.

  2. Run the third program in this section, then type...

    PRINT c

Why is the answer 6, and not 5?

(Answer: The NEXT command in line 60 is executed five times, each time 1 being added to c. On the last time, c becomes 6 so the NEXT command decides not to loop back but to carry on, c now being past its limit.)

  1. What happens if you put STEP 2 at the end of line 20 of the third program? Try STEP 10.

Now change the third program so that instead of automatically adding five numbers, it asks you to input the amount of numbers you wish to add. When you run this program, what happens if you input 0 (meaning that you don't wish to add any numbers)? Why would you expect this to cause problems for the +3, even though it is clear what you mean?

  1. In line 10 of the fourth program in this section, change 10 to 100 and run the program. It will print the numbers from 100 down to 79 on the screen, and then say scroll? at the bottom. This is to give you a chance to see the numbers that are about to be scrolled off the top. If you press N, BREAK or the space bar, the program will stop with the report D BREAK - CONT repeats. If you press any other key, then it will print another 22 lines and ask you again if you wish to scroll.

  2. Delete line 30 from the fourth program. When you run the new curtailed program, it will print the first number and stop with the message 0 OK. If you then type...

    NEXT n

...the program will go once round the loop, printing out the next number.

Part 5

Subjects covered...

Sometimes, different parts of the program will have rather similar jobs to do, and you will find yourself typing in the same lines two or more times; however, this is not necessary. Instead, you need only type in the lines once (in what's called a subroutine) and then call the subroutine into action whenever you need it in the program.

To do this, you use the statements GO SUB (go to subroutine) and RETURN. This takes the form...

    GO SUB xxx

...where 'xxx' is the line number of the first line in the subroutine. It is just like GO TO xxx except that the +3 remembers where the GO SUB statement was, so that it can come back again after carrying out the subroutine.

(In case you're interested, the +3 does this by remembering at which point in the program the GO SUB command was issued (in other words where it should continue from afterwards) and storing this return address on top of a pile called the GO SUB stack.)

When the command...

    RETURN met (at the end of the subroutine itself), the +3 takes the top return address off the GO SUB stack, and continues from the next statement.

As an example, let's look at the number guessing program again. Retype it as follows...

     10 REM "A rearranged guessing game"
     20 INPUT "Enter a secret number",a: CLS
     30 INPUT "Guess the number",b
     40 IF b=a THEN PRINT "Correct": STOP
     50 IF b<a THEN GO SUB 100
     60 IF b>a THEN GO SUB 100
     70 GO TO 30
    100 PRINT "Try again"
    110 RETURN

The GO TO 30 statement in line 70 (and the STOP statement in line 60 of the next program) are very important because otherwise the programs will run on into their subroutines and cause an error (7 RETURN without GO SUB) when the RETURN statement is reached.

The following program uses a subroutine (from line 100 to 150) which prints a 'times table' corresponding to the value of parameter n. The command GO SUB 100 may be issued from any point in the program to call the subroutine. When the RETURN command in line 150 of the subroutine is reached, control returns to the main program, which continues running from the statement after the GO SUB call. Like GO TO, GO SUB may be typed in as GOSUB.

     10 REM times tables for 2, 5, 10 and 11
     20 LET n=2: GO SUB 100
     30 LET n=5: GO SUB 100
     40 LET n=10: GO SUB 100
     50 LET n=11: GO SUB 100
     60 STOP
     70 REM end of main program, start of subroutine
    100 PRINT n;" times table"
    110 FOR t=1 TO 9
    120 PRINT t;" x ";n;" = ";t*b
    130 NEXT t
    140 PRINT
    150 RETURN

One subroutine can happily call another, or even itself (a subroutine that calls itself is known as recursive).

Part 6
Data in programs

Subjects covered...

In some of the previous programs we saw that information, or data, can be entered directly into the +3 using the INPUT statement. Sometimes this can be very tedious, especially if a lot of the data is repeated every time the program is run. You can save a lot of time by using the READ, DATA and RESTORE commands. For example:

    10 READ a,b,c
    20 PRINT a,b,c
    30 DATA 1,2,3

A READ statement consists of READ followed by a list of the names of variables, separated by commas. It works rather like an INPUT statement, except that instead of getting you to type in the values to give to the variables, the +3 looks up the values in the DATA statement.

Each DATA statement is a list of expressions - numeric or string expressions - separated by commas. You can put them anywhere you like in a program, because the +3 ignores them except when it is doing a READ. You must imagine the expressions from all the DATA statements in the program as being put together to form one long list of expressions - the DATA list. The first time the +3 goes to READ a value, it reads the first expression from the DATA list; the next time, it reads the second; and thus as it meets successive READ statements, it works its way through the DATA list. (If it tries to read past the end of the DATA list, then it reports an error.)

Note that it's a waste of time putting DATA statements in a direct command, because READ will not find them. DATA statements must go in a program.

Let's see how all this works in the program you've just typed in. Line 10 tells the +3 to read three pieces of data and assign them to the variable a, b and c. Line 20 then say PRINT these variables. The DATA statement in line 30 provides the values of a, b and c for line 10 to read.

The information in DATA can be part of a FOR...NEXT loop. Type in...

    10 DATA 2,4,6,8,10,12
    20 FOR n=1 TO 6
    30 READ d
    40 PRINT d
    50 NEXT n

Note from the above two programs that a DATA statement can appear anywhere - before or after the READ statement.

When the above program is run, the READ statement moves through the DATA list with each pass of the FOR...NEXT loop.

DATA statements may also contain string variables. For example...

    10 FOR a=1 TO 7
    20 READ n$
    30 PRINT n$
    40 DATA "Bob","Edith","Carole","Jacquie","Gavin","Charles","Holly"
    50 NEXT a

The +3 doesn't have to READ the DATA statements in order - it can be made to 'jump about' between DATA statements by using the RESTORE command. The form of the command is...


...where 'xxx' is the line number of the DATA statement to be READ from. If you use the command RESTORE on its own (without a line number) the +3 will jump to the first DATA statement in the program.

Type in and run the following program...

     10 DATA 1,2,3,4,5
     20 DATA 6,7,8,9
     30 GO SUB 110
     40 GO SUB 110
     50 GO SUB 110
     60 RESTORE 20
     70 GO SUB 110
     80 RESTORE
     90 GO SUB 110
    100 STOP
    110 READ a,b,c
    120 PRINT a'b'c
    130 PRINT
    140 RETURN

The command GO SUB 110 calls a subroutine which READs the next three items of DATA and the PRINTs them. Notice how the RESTORE command affects which items are read.

Delete line 60 and run this program again to see what happens.

Part 7

Subjects covered...

You have already seen some of the ways in which the +3 can calculate with numbers. It can perform the four arithmetic operations +, -, * and / (remember that * is used for multiplication, and / is used for division), and it can find the value of a variable, given its name.

The example...

    LET tax=sum*15/100

...illustrates that calculations can be combined. Such a combination, like sum*15/100, is called an expression - so an expression is just a short-hand way of telling the +3 to do several calculations, one after the other. In our example, the expression sum*15/100 means 'look up the value of the variable called sum, multiply it by 15, and divide by 100'.

In expressions containing *, /, +, -, multiplication and division are carried out first - they have a higher priority than addition and subtraction. Multiplication and division have the same priority as each other, which means that they are carried out in whichever order they appear in the expression (from left to right). The next operations to be carried out are addition and subtraction - these again have the same priority as each other and so, again, are carried out in order from left to right.

Hence in the expression 8-12/4+2*2, the first operation to be carried out is the division 12/4 which equals 3, so we can then represent the expression as 8-3+2*2.

The next operation to be carried out is the multiplication 2*2 which equals 4, so the expression then becomes 8-3+4.

Next to be carried out is the subtraction 8-3 which equals 5, so the expression becomes 5+4. Finally, the addition is carried out leaving the result 9.

Try this out for yourself. Type in...

    PRINT 8-12/4+2*2

A full list of the priorities of mathematical (and logical) operations will be found in part 31 of this chapter.

You may, however, change the priority of calculations within an expression by the use of brackets. Calculations within brackets are carried out first, so if in the above expression, you required the addition 4+2 to be carried out first, you would enclose it in brackets. To see this, type in...

    PRINT 8-12/(4+2)*2

...and the result this time is 4 instead of 9.

Expressions are useful because, whenever the +3 is expecting a number from you, you can give it an expression instead and it will work out the answer.

You can also add together strings (or string variables) in a single expression. For example...

    10 LET a$="large "
    20 LET b$="and puffy"
    30 LET c$=a$+b$
    40 PRINT c$

We really ought to tell you what you can and cannot use as the names of variables. As we have already said, the name of a string variable has to be a single letter followed by $, and the name of the control variable in a FOR...NEXT loop must be a single letter; however, the names of ordinary numeric variables are less restricted - they can use any letters or digits as long as the first one is a letter. You can put spaces in as well to make it easier to read, but they won't count as part of the name. Also, it doesn't make any difference to the name whether you type it in upper or lower case letters. There are some restrictions about variable names which are the same as commands, however. In general, if the variable contains a BASIC keyword in it (with spaces around it) then it won't be accepted.

Here are some examples of the names of variables that are allowed...

any old thing
this name is impractical because it is too long
mixed cases spaces

(Note that these last two names (mixed cases spaces and MixEdCAsEsSpAcES) are considered the same, and refer to the same variable.)

The following are not allowed as the names of variables...

Numerical expressions can be represented by a number and exponent. Try the following to prove the point...

    PRINT 2.34e0
    PRINT 2.34e1
    PRINT 2.34e2

...and so on up to...

    PRINT 2.34e15

PRINT gives only eight significant digits of a number. Try...

    PRINT 4294967295, 4294967295-429e7

This proves that the computer can hold the digits of 4294967295, even though it is not prepared to display them all at once.

The +3 uses floating point arithmetic, which means that it keeps separate the digits of a number (its mantissa) and the position of the point (the exponent). This is not always exact, even for whole numbers. Type...

    PRINT 1e10+1-1e10,1e10-1e10+1

Numbers are held to about nine and a half digits accuracy, so 1e10 is too big to be held exactly right. The inaccuracy (actually about 2) is more than 1, so the numbers 1e10 and 1e10+1 appear to the computer to be equal.

For an even more peculiar example, type...

    PRINT 5e9+1-5e9

Here the inaccuracy in 5e9 is only about 1, and the 1 to be added on in fact gets rounded up to 2. The numbers 5e9+1 and 5e9+2 appear to the computer to be equal. The largest integer (whole number) that can be held completely accurately is 4,294,967,294.

The string "" with no character at all is called the empty or null string. Remember that spaces are significant and an empty string is not the same as one containing nothing but spaces.


    PRINT "Did you read "The Times" yesterday?"

When you press ENTER you will get the flashing red cursor that shows there is a mistake somewhere in the line. When the +3 finds the double quotes at the beginning of the "The Times" it imagines that these mark the end of the string "Did you read ", and it then can't work out what The Times means.

There is a special device to get over this - whenever you wish to write a string quote symbol in the middle of a string, you must write it twice, like this...

    PRINT "Did you read ""The Times"" yesterday?"

As you can see from what is printed on the screen, each double quote is only really there once - you just have to type it twice to get it recognised.

Part 8

Subjects covered...

Given a string, a substring of it consists of some consecutive characters from it, taken in sequence. Thus "cut" is a substring of "cutlery", but "cute" and "cruelty" are not substrings.

There is a notation called slicing for describing substrings, and this can be applied to arbitrary string expressions. The general form is...

string expression (start TO finish) that, for instance...

"abcdef"(2 TO 5) equal to bcde.

If you omit the start, then 1 is assumed; if you omit the finish, then the length of the string is assumed. Thus...

"abcdef"( TO 5) is equal to abcde "abcdef"(2 TO ) is equal to bcdef "abcdef"( TO ) is equal to abcdef

You can also write this last one as "abcdef"().

A slightly different form misses out the TO and just has one number.

"abcdef"(3) is equal to "abcdef"(3 TO 3) is equal to c.

Although normally both start and finish must refer to existing parts of the string, this rule is overridden by another one: if the start is more than the finish, then the result is the empty string. So...

"abcdef"(5 TO 7) the error 3 Subscript wrong because the string only contains 6 characters and 7 is too many, but...

"abcdef"(8 TO 7)


"abcdef"(1 TO 0)

...are both equal to the empty string "" and are therefore permitted.

The start and finish must not be negative, or you get the error B integer out of range. This next program is a simple one illustrating some of these rules...

    10 LET a$="abcdef"
    20 FOR n=1 TO 6
    30 PRINT a$(n TO 6)
    40 NEXT n

Type NEW when this program has been run and enter the next program.

    10 LET a$="1234567890"
    20 FOR n=1 TO 10
    30 PRINT a$(n TO 10),a$((11-n) TO 10)
    40 NEXT n

For string variables, we can not only extract substrings, but also assign to them. For instance, type...

LET a$="Velvet Donkey"

...and then...

LET a$(8 TO 13)="Lips******"



Since the substring a$(8 TO 13) is only 6 characters long, only its first 6 characters (Lips**) are used; the remaining 4 characters (****) are discarded. This is a characteristic of assigning to substrings: the substring has to be exactly the same length afterwards as it was before. To make sure this happens, the string that is being assigned to it is cut off on the right if it is too long, or filled out with spaces if it is too short - this is called 'Procrustean assignment' after the inn-keeper Procrustes who used to make sure that his guests fitted their beds by either stretching them out on a rack or cutting their feet off!

Complicated string expressions will need brackets around them before they can be sliced. For example...

"abc"+"def"(1 TO 2) is equal to "abcde" ("abc"+def")(1 TO 2) is equal to "ab"


  1. Try writing a program to print the day of the week using string slicing. (Hint - Let the string be SunMonTuesWednesThursFriSatur.)

Part 9

Subjects covered...

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 lump of beef gives 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.

Meat in        ->    Sausage Machine    ->    Sausage out
Argument in    ->    Function           ->    Result out

Different arguments give different results, and if the argument is completely inappropriate the function will stop and give an error report.

Just as you can have different machines to make different products - one for sausages, another for combs, a third for dish cloths, and so on, different functions will do different calculations. Each will have its own name to distinguish it from the others.

You use a function in expressions by typing its name followed by the argument, and when the expression is evaluated the result of the function will be worked out.

As an example, there is a function called LEN, which works out the length of a string. Its argument is the string whose length you wish to find, and its result is the length, so that if you type...

PRINT LEN "Jammy Smears"

...the +3 will write the answer 12, ie. the number of characters (including spaces) in the string Jammy Smears.

If you mix functions and operations in a single expression, then the functions will be worked out before the operations. Again, however, you can circumvent this rule by using brackets. For instance, here are two expressions which differ only in the brackets, and yet calculations are performed in an entirely different order in each case (although, as it happens, the end results are the same).

LEN "Fred" + LEN "Bloggs"
4+LEN "Bloggs"


LEN ("Fred" + "Bloggs")
LEN ("FredBloggs")
LEN "FredBloggs"

Here are some more functions...

STR$ converts numbers into strings: its argument is a number, and its result is the string that would appear on the screen if the number were displayed by a PRINT statement. Note how its name ends in a $ sign to show that its result is a string. For example, you could say...

LET a$= STR$ 1e2

...which would have exactly the same effect as typing...

LET a$="100"

Or you could say...

PRINT LEN STR$ 100.0000

...and get the answer 3, because STR$ 100.0000 is equal to "100", the length of which is 3 characters.

VAL is like STR$ in reverse - it converts strings into numbers. For instance...

VAL "3.5" equal to the number 3.5.

VAL is the reverse of STR$ because if you take any number, apply STR$ to it, and then apply VAL to it, you get back the number you first thought of.

However, if you take a string, apply VAL to it, and then apply STR$ to it, you do not always get back to your original string.

VAL is an extremely powerful function, because the string which is its argument is not restricted to looking like a plain number - it can be any numeric expression. Thus, for instance...

VAL "2*3" equal to 6. Even...

VAL ("2"+"*3") equal to 6. There are two processes at work here. In the first, the argument of VAL is evaluated as a string - the string expression "2"+"*3" is evaluated to give the string "2*3". Then, the string has its double quotes stripped off, and what is left is evaluated as a number: so 2*3 is evaluated to give the number 6.

There is another function, rather similar to VAL, though probably less useful, called VAL$. Its argument is still a string, but its result is also a string. To see how this works, recall how VAL goes in two steps: first its argument is evaluated as a string, then the string quotes stripped off this, and whatever is left is evaluated as a number. With VAL$, the first step is the same, but after the string quotes have been stripped off in the second step, whatever is left is evaluated as another string. Thus...

VAL$ """Ursula""" is equal to Ursula

(Notice how the string quotes proliferate again.) Try...

LET a$="99"

...and print all of the following: VAL a$, VAL "a$", VAL """a$""", VAL$ a$, VAL$ "a$" and VAL$ """a$""". Some of these will work, and some of them won't - try to explain all the answers.

SGN is the sign function (sometimes called signum). It is the first function you have seen that has nothing to do with strings, because both its argument and its result are numbers. The result is +1 if the argument is positive, 0 if the argument is zero, and -1 if the argument is negative.

ABS is another function whose argument and result are both numbers. It convert the argument into a positive number (which is the result) by forgetting the sign, so that for instance...

ABS -3.2 equal to...

ABS 3.2

...which is simply equal to 3.2.

INT stands for integer part - an integer is a whole number, possibly negative. This function converts a fractional number into an integer by 'throwing away' the fractional part, so that for instance...

INT 3.9 equal to 3.

Be careful when you are applying it to negative numbers, because it always rounds down. Thus for instance...

INT -3.1 equal to -4.

SQR calculates the square root of a number, ie. the result that, when multiplied by itself, gives the argument, for instance...

SQR 4 equal to 2 because 2 x 2 is equal to 4.

SQR 0.25 equal to 0.5 because 0.5 x 0.5 is equal to 0.25.

SQR 2 equal to 1.4142316 (approx) because 1.4142316 x 1.4142316 is equal to 2 (almost).

If you multiply any number (even a negative number) by itself, the answer is always positive. This means that negative numbers do not have square roots, so if you apply SQR to a negative argument you get the error report A Invalid Argument.

You can also define functions of your own. Possible names for these are FN followed by a letter (if the result is a number) or FN followed by a letter followed by $ (if the result is a string). These function are much stricter about brackets - the argument must be enclosed in brackets.

You define a function by putting a DEF statement somewhere in the program. For instance, here is the definition of a function FN s whose result is the square of the argument...

10 DEF FN s(x)=x*x: REM the square of x

The s following the DEF FN is the name of the function. The x in brackets is a name by which you wish to refer to the argument of the function. You can use any single letter you like for this (or, if the argument is a string, a single letter followed by $).

After the = sign comes the actual definition of the function. This can be any expression, and it can also refer to the argument using the name you've given it (in this case, x) as though it were an ordinary variable.

When you have entered this line, you can invoke the function just like one of the +3's own functions, by typing its name, FN s, followed by the argument. Remember that when you have defined a function yourself, the argument must be enclosed in brackets. Try it out a few times...

PRINT FN s(3+4)
PRINT 1+ INT FN s ( LEN "chicken"/2+3)

Once you have put the corresponding DEF statement into the program, you can use your own functions in expressions just as freely as you can use the computer's.

INT always rounds down. To round to the nearest integer, add 0.5 first - you could write your own function to do this...

20 DEF FN r(x)= INT (x+0.5): REM gives x rounded to the nearest integer.

You will then get, for instance...

FN r(2.9) is equal to 3 FN r(2.4) is equal to 2 FN r(-2.9) is equal to -3 FN r(-2.4) is equal to -2

Compare these with the answers you will get when you use INT instead of FN r. Type in and run the following...

10 LET x=0: LET y=0: LET a=10
20 DEF FN p(x,y)=a+x*y
30 DEF FN q()=a+x*y
40 PRINT FN p(2,3), FN q()

There are a lot of subtle points in the program. Firstly, a function is not restricted to just one argument: it can have more, or even none at all - but you must still always keep the brackets.

Secondly, it doesn't matter whereabouts in the program you put the DEF statements. After the +3 has executed line 10, it simply skips over lines 20 and 30 to get to line 40. They do, however, have to be somewhere in the program - they can't be in a command.

Thirdly, x and y are both the names of variables in the program as a whole, and the names of arguments for the function FN p. FN p temporarily forgets about the variables called x and y, but since it has no argument called a, it still remembers the variable a. Thus when FN p(2,3) is being evaluated, a has the value 10 because it is the variable, 'x' has the value 2 because it is the first argument, and y has the value 3 because it is the second argument. The result is then, 10+2*3 which is equal to 16. When FN q() is being evaluated, on the other hand, there are no arguments, so a, x and y all still refer to the variables and so have the values 10, 0 and 0 respectively. The answer in this case is 10+0+0 which is equal to 10.

Now change line 20 to...

20 DEF FN p(x,y)= FN q()

This time, FN p(2,3) will have the value 10 because FN q will still go back to the variables x and y rather than using the arguments of FN p.

Some BASICs (not +3 BASIC) have functions called LEFT$, RIGHT$, MID$ and TL$.

LEFT$(a$,n) gives the substring of a$ consisting of the first n characters.

RIGHT$(a$,n) gives the substring of a$ consisting of the last n characters.

MID$(a$,n1,n2) gives the substring of a$ consisting of n2 characters, starting at the n1-th.

TL$(a$) gives the substring of a$ consisting of all its characters except the first.

You can write some user-defined functions to do the same...

10 DEF FN t$(a$)=a$(2 TO ): REM TL$
20 DEF FN l$(a$,n)=a$( TO n): REM LEFT$

Check that these work with strings of length 0 or 1. Note that our FN l$ has two arguments, one a number and the other a string. A function can have up to 26 numeric arguments (why 26?) and at the same time up to 26 string arguments.


Use the function FN s(x)=x*x to test SQR. You should find that...

FN s( SQR x)

...equals x if you substitute any positive number for x, and...

SQR FN s(x)

...equals ABS x whether x is positive or negative. (Why is the ABS there?)

Part 10
Mathematical functions

Subjects covered...

This section deals with the mathematics that the +3 can handle. Quite possibly you will never have to use any of this at all, so if you find it too heavy going, don't be afraid of skipping it. It covers the operation ^ (raising to a power), the functions EXP and LN, and the trigonometrical functions SIN, COS, TAN and their inverses ASN, ACS and ATN.

^ and EXP

You can raise one number to the power of another. This means 'multiply the first number by itself the second number of times'. This is normally shown by writing the second number just above and to the right of the first number; but obviously this would be difficult on a computer so we use the symbol ^ instead. For example, the powers of 2 are...

...and so on.

Thus, at its most elementary level, a^b means 'a multiplied by itself b times', but obviously this only makes sense if b is a positive whole number. To find a definition that works for other values of b, we consider the rule...

a^(b+c) equals a^b x a^c

(Notice that we give ^ a higher priority than multiplication and division so that when there are several operations in one expression, ^ is evaluated before * and /). You should not need much convincing that this works when b and c are both positive whole numbers, but if we decide that we want it to work even when they are not, then we find ourselves compelled to accept that...


a^(b x c) equals (a^b)^c

If you have never seen any of this before then don't try to remember it straight away, just remember that...

a^(-1) equals 1/a


a^(1/2) equals SQR a

...and maybe when you are familiar with these, the rest will begin to make sense.

Experiment with all this by trying this program...

10 INPUT a,b,c
20 PRINT a*(b+c),a^b*a^c
30 GO TO 10

Of course, if the rule we gave earlier is true, then each time round, the two numbers that the +3 prints out will be equal. (Note - because of the way the computer works out ^, the number on the left, a in this case, must never be negative.)

A rather typical example of what this function can be used for is that of compound interest. Suppose you keep some of your money in a building society and they give 15% interest per year. Then after one year you will have not just the 100% that you had anyway, but also the 15% interest that the building society has given you, making altogether 115% of what you had originally. To put it another way, you have multiplied your sum of money by 1.15, and this is true however much you had there in the first place. After another year, the same will have happened again, so that you will then have 1.15 x 1.15, or in other words, 1.15 ^ 2, or in other words, 1.3225 times your original sum of money. In general then, after y years, you will have 1.15 ^ y times what you started out with.

If you try the command...

FOR y=0 TO 100: PRINT y,10*1.15^y: NEXT y will see that even starting off from just £10, it all mounts up quite quickly, and what's more, it gets faster and faster as time goes on (though you might still find that it doesn't keep up with inflation).

This sort of behaviour, where after a fixed interval of time some quantity multiplies itself by a fixed proportion, is called exponential growth, and it is calculated by raising a fixed number to the power of the time.

Suppose you did this...

10 DEF FN a(x)=a^x

Here, a is more or less fixed, by LET statements - its value will correspond to the interest rate, which changes only every so often.

There is a certain value for a that makes the function FN a look especially pretty to the trained eye of a mathematician, and this value is called e. The +3 has a function called EXP defined by...

EXP x is equal to e^x

Unfortunately, e itself is not an especially pretty number; it is an infinite non-recurring decimal. You can see its first few decimal places by typing...


...because EXP 1 is equal to e^1 which is equal to e. Of course, this is just an approximation. You can never write down e exactly.


The inverse of an exponential function is a logarithmic function - the logarithm (to base a) of a number x is the power to which you'd have to raise a to get the number x, and this is written logax. Thus by definition, a^logax is equal to x; and it is also true that log (a^x) is equal to x.

You may well already know how to use base 10 logarithms for doing multiplications; these are called common logarithms. The +3 has a function LN which calculates logarithms to the base e; these are called natural logarithms. To calculate logarithms to any other base, you must first divide the natural logarithm by the natural logarithm of the base, ie. logax is equal to LN x/LN a.


Given any circle, you can find its perimeter (the distance around its edge - often called its circumference) by multiplying its diameter (width) by a number called π. π (pronounced pi) is the Greek equivalent of the English letter p, and it is used because it stands for perimeter.

Like e, π is an infinite non-recurring decimal - it starts off as 3.1415927. The word PI on the +3 is taken as standing for this number. Try...



These trigonometrical functions measure what happens when a point moves round a circle. Here is a circle of radius 1 ('1 what?' you may ask - it doesn't matter, as long as we keep to the same unit all the way through) and a point moving round it. The point started at the '3 o'clock' position, and then moved round in an anti-clockwise direction.

radius=1 distance moved around circle=a starting position x-axis y-axis

We have also drawn in two lines called axes through the centre of the circle. The one through 3 o'clock is called the x-axis, and the one through 12 o'clock is called the y-axis.

To specify where the point is, you say how far it has moved round the circle from its 3 o'clock starting position: let us call this distance a. We know that the circumference of the circle is 2π (because its radius is 1 and its diameter is thus 2), so when it has moved a quarter of the way round the circle, a is equal to π/2; when it has moved halfway round, a is equal to π; and when it has moved the whole way round, a is equal to 2π.

Given the curved distance round the edge - a, two other distances you might like to know are how far the point is the right of the y-axis, and how far it is above the x-axis. These are called, respectively, the cosine and sine of a. The functions COS and SIN on the +3 will calculate these.

a cosine of a=COS a sine of a =SIN a

Note that if the point goes to the left of the y0axis, then the cosine becomes negative, and if the point goes below the x-axis, the since becomes negative.

Another property is that once a has got up to 2π, the point is back where it started and the sine and cosine start taking the same values all over again, ie. SIN (a+2*PI) equals SIN a, and COS (a+2*PI) equals COS a.

The tangent of a is defined as being the sine divided by the cosine; the corresponding function on the +3 is called TAN.

Sometimes we need to work these functions out in reverse, finding the value of a that has given some cosine or tangent. The functions to do this are called arcsine (ASN on the +3), arccosine (ACS) and arctangent (ATN).

In the diagram of the point moving round the circle, look at the radius joining the centre to the point. You should be able to see that the distance we have called a (the distance that the point has moved round the edge of the circle) is a way of measuring the angle through which the radius has moved away from the x-axis. When a is equal to π/2, the angle is 90 degrees; when a is equal to π the angle is 180 degrees, and so on, round to when a is equal to 2π, and the angle is 360 degrees. You might just as well forget about degrees, and measure the angle in terms of a alone; we say then that we are measuring the angle in radians. Thus π/2 radians is equal to 90 degrees and so on.

You must always remember that on the +3, the functions SIN, COS, etc. use radians and not degrees. To convert degrees to radians, divide by 180 and multiply by π; to convert back from radians to degrees, you divide by π and multiply by 180.

Part 11
Random Numbers

Subjects covered...

This section deals with the keywords RND and RANDOMIZE.

In some ways RND is like a function - it does calculations and produces a result. It is unusual in that it does not need an argument.

Each time you use it, its result is a new random number between 0 and 1. (Sometimes it can take the value 0, but never 1.)


20 GO TO 10 see how the answer varies. Can you detect any pattern? You shouldn't be able to - 'random' means that there is no pattern.

Actually, RND is not truly random, because it follows a fixed sequence of 65536 numbers. However, these are so thoroughly jumbled up that there are at least no obvious patterns, and we say that RND is pseudo-random.

RND gives a random number between 0 and 1, but you can easily get random numbers in other ranges. For instance, 5*RND is between 0 and 5, and 1.3+0.7*RND is between 1.3 and 2. To get whole numbers, uses INT (remembering that INT always rounds down) as in 1+INT(RND*6), which we shall use in a program to simulate dice. RND*6 is in the range 0 to 6, but since it never actually reaches 6, INT(RND*6) is 0, 1, 2, 3, 4 or 5.

Here is the program...

10 REM dice throwing program
20 CLS
30 FOR n=1 TO 2
40 PRINT 1+ INT ( RND *6);" ";
50 NEXT n
60 INPUT a$: GO TO 20

Press ENTER each time you wish to 'throw' the dice.

The RANDOMIZE statement may be used to make RND start off at a definite place in its sequence of numbers, as you can see with this program...

20 FOR n=1 TO 5: PRINT RND ,: NEXT n
30 PRINT: GO TO 10

After each execution of RANDOMIZE 1, the RND sequence starts off again with 0.0022735596. You can use other numbers between 1 and 65535 in the RANDOMIZE statement to start the RND sequence off at different places.

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.

RANDOMIZE used on its own (or RANDOMIZE 0) have a different effect - they really do randomise RND - you can see this in the next program...


The sequence you get here is not very random, because RANDOMIZE uses the time since the +3 was switched on. As this has gone up by the same amount each time that RANDOMIZE is executed, the next RND does more or less the same. You would get better 'randomness' by replacing GO TO 10 by GO TO 20.

Here is a program to toss coins and count the numbers of heads and tails...

10 LET heads=0: LET tails=0
20 LET coin= INT ( RND *2)
30 IF coin=0 THEN LET heads=heads+1
40 IF coin=1 THEN LET tails=tails+1
50 PRINT heads;",";tails,
60 IF tails <> 0 THEN PRINT heads/tails;
70 PRINT: GO TO 20

The ratio of heads to tails should become approximately 1 if you go on long enough, because in the long run you expect approximately equal numbers of heads and tails.


  1. Choose a number between 1 and 872 and type...

    RANDOMIZE your number

Note that the next value of RND will be...

Try this out for yourself.

Part 12

Subjects covered...

Suppose that you have a list of numbers - for instance, the marks of ten people in a class. To store them in the +3 you could use the variables m1, m2, m3... and so on up to m10, but the program to set up these ten variables would be rather long and tedious to type in, ie....

 10 LET m1=75
 20 LET m2=44
 30 LET m3=90
 40 LET m4=38
 50 LET m5=55
 60 LET m6=64
 70 LET m7=70
 80 LET m8=12
 90 LET m9=75
100 LET m10=60

Instead, these is a mechanism, known as an array whereby you may specify a variable which (instead of containing a single value as variables normally do) may contain a number of separate elements, each of which may contain different values. Each element is referenced by an index number (the subscript) written in brackets after the variable name. For the above example, the array variable's name could be m - (the name of an array variable must be a single letter), and the ten variables would then be m(1), m(2), m(3)... and so on up to m(10).

The elements of an array are called subscripted variables, as opposed to the simple variables that you are already familiar with.

Before you can use an array, you must reserve some space for it in the +3's memory, and you do this by using the keyword DIM (for dimension). The statement...

DIM m(10)

...sets up an array called m whose dimensions are 10 (ie. there are 10 subscripted variables). The DIM statement initialises each element in the array to zero. It also deletes any array called m that existed previously - (however, it doesn't delete any simple variable called m. An array variable can coexist alongside a simple numerical variable of the same name because the array can always be distinguished by its subscript).

The array elements' subscripts may be represented by any numerical expression yielding a valid subscript number. This means that an array can be processed using a FOR...NEXT loop. Thus, instead of the above long-winded process, we can now set up the variables m(1)...m(10) using...

10 DIM m(10)
20 FOR n=1 TO 10
30 READ m(n)
40 NEXT n
50 DATA 75,44,90,38,55,64,70,12,75,60 READ in the elements' values from a DATA list, or...

10 DIM m(10)
20 FOR n=1 TO 10
30 INPUT m(n)
40 NEXT n INPUT the elements' values by hand.

Note that the DIM statement must come before any attempt to access the array in a program.

If you wish, you may examine the contents of the array using...

10 FOR n=1 TO 10
20 PRINT m(n)
30 NEXT n

...or individually using...

PRINT m(1)
PRINT m(2)
PRINT m(3)


You can also set up arrays with more than one dimension. In a two dimensional array you need two numbers to specify an element - rather like the line and column numbers that specify a character position on the screen. If you imagine the line and column number (two dimensional) as referring to a printed page, you could then, for example, have an extra dimension to represent the page numbers. Think of the elements of a three dimensional array v as being specified by v(page number,line number,column number).

For example, to set up a two-dimensional array c with dimensions 3 and 6, you use the DIM statement...

DIM c(3,6)

This then gives you 3x6=18 subscripted variables...

c(1,1), c(1,2)... to c(1,6) c(2,1), c(2,2)... to c(2,6) c(3,1), c(3,2)... to c(3,6)

The same principle works for any number of dimensions.

Although you can have a number and an array with the same name, you cannot have two arrays with the same name, even if they have a different number of dimensions.

There are also string arrays. The strings in an array differ from simple strings in that they are of fixed length and assignment to them is always Procrustean (ie. chopped off or padded with spaces).

The name of a string array is a single letter followed by $. Unlike numeric arrays, a string array and a string cannot have the same name.

Suppose then, that you want an array a$ of five strings. You must decide how long these strings are to be - let us suppose that 10 characters for each element is long enough. You then say...

DIM a$(5,10) (type this in)

This sets up a 5x10 array of characters, but you can also think of each row as being a string...

a$(1) equals a$(1,1) a$(1,2)... to a$(1,10) a$(2) equals a$(2,1) a$(2,2)... to a$(2,10) a$(3) equals a$(3,1) a$(3,2)... to a$(3,10) a$(4) equals a$(4,1) a$(4,2)... to a$(4,10) a$(5) equals a$(5,1) a$(5,2)... to a$(5,10)

If you give the same number of subscripts (two in this case) as there were dimensions in the DIM statement, then you get a single character, but if you miss the last one out, then you get a fixed length string. So, for instance, a$(2,7) is the 7th character in the string a$(2). Using the slicing notation, we could also write this as a$(2)(7). Now type...

LET a$(2)="1234567890"


PRINT a$(2), a$(2,7)

You get...

1234567890     7

For the last subscript (the one you can miss out), you can also have a slicer, so that for instance...

a$(2,4 TO 8) is equal to a$(2)(4 TO 8) is equal to "45678"

Remember - In a string array, all the strings have the same fixed length.

The DIM statement has an extra number (the last one) to specify this length. When you write down a subscripted variable for a string array, you can put in an extra number (a slicer) to correspond with the extra number in the DIM statement.

You can have string arrays with no extra dimensions. Type...

DIM a$(10)

...and you will find that a$ behaves just like a string variable, except that it always has length 10, and assignment to it is always Procrustean.


  1. Use READ and DATA statements to set up an array m$ of twelve strings in which m$(n) is the name of the nth month. (Hint - The DIM statement will be DIM m$(12,9). Test it by printing out all the values of m$(n) (use a loop).)

Part 13

Subjects covered...

We saw in part 3 of this chapter how an IF statement takes the form...

The conditions there were the relations =, <, >, <=, >= and <> which compare two numbers or two strings. You can also combine several of these, using the logical operations AND, OR and NOT.

One relation AND another relation is true whenever both relations are true, so that you could have a line like... which result gets printed only if a$ is equal to yes and x is greater than zero. The BASIC here is so close to English that it hardly seems worth spelling out the details. As in English, you can join lots of relations together with AND, and then the whole lot is true if all the individual relations are.

One relation OR another is true whenever at least one of the two relations is true. (Remember that it is still if both the relations are true - this is something that English doesn't always imply.)

The NOT relationship turns things upside down. The NOT relation is true whenever the relation is false, and false whenever it is true.

Logical expressions may use combinations of AND, OR and NOT, just as numerical expressions may use combinations of +, -, * and so on.

You can even put them in brackets if necessary. Logical operations have priorities in the same way as +, -, *, / and ↑ do. NOT has the highest priority, then AND, then OR.

NOT is really a function, with an argument and a result, but its priority is much lower than that of other functions. Therefore, its argument does not need brackets unless it contains AND or OR (or both). NOT a=b means the same as NOT (a=b) (and the same as a<>b of course).

<> is the negation of = in the sense that it is true only if = is false. In other words...

...and also...

Convince yourself that >= and <= are the negations of < and > respectively. Thus you can always get rid of NOT from in front of a relation by changing the relation.

Also... the same as...

...and... the same as...

Using this, you can work NOTs through brackets until eventually they are all applied to relations, and then you can get rid of them. Logically speaking, NOT is unnecessary, although you might still find that using it makes a program clearer.

The following section is quite complicated, and can easily be skipped by the faint by the faint-hearted!


...which you might expect to give a syntax error. In fact, as far as the computer is concerned, there is no such thing as a logical value - instead it uses ordinary numbers, subject to a few rules...

(i) =, <, >, <=, >= and <> all give the numeric results: 1 for true, and 0 for false. Thus, the PRINT command above printed 0 for 1=2, which is false, and 1 for 1<>2, which is true.

(ii) In the statement...

...the condition can be actually any numeric expression. If its value is 0, then it counts as false, and any other value (including the value of 1 that a true relation gives) counts as true. Thus the IF statement means exactly the same as...

(iii) AND, OR and NOT are also number-valued operations...

x AND y has the value

x OR y has the value

NOT x has the value

(Notice that 'true' means non-zero when we're checking a given value, but it means 1 when we're producing a new one.)

Now try this program...

10 INPUT a
20 INPUT b
30 PRINT (a AND a >= b)+(b AND a< b)
40 GO TO 10

Each time it prints the larger of the two numbers a and b.

Convince yourself that you can think of... meaning...

...and of... meaning...

An expression using AND or OR like this is called a conditional expression. An example using OR could be...

LET total=price less tax*(1.15 OR v$="zero rated")

Notice how AND tends to go with addition (because its default value is 0), and OR tends to go with multiplication (because its default value is 1).

You can also make string valued conditional expressions, but only using AND... it means x$ if y (else the empty string).

Try this program, which inputs two strings and puts them in alphabetical order.

10 INPUT "type in two strings"'a$,b$
20 IF a$>b$ THEN LET c$=a$: LET a$=b$: LET b$=c$
30 PRINT a$;" ";("<" AND a$<b$)+("=" AND a$=b$);" ";b$
40 GO TO 10

Part 14
The Character Set

Subjects covered...

The letters, digits, spaces, punctuation marks and so on that can appear in strings are called characters, and they make up the character set that the +3 uses. Most of these characters are single symbols, but there are some more, called tokens, that represent whole words, such as PRINT, STOP, <> and so on.

There are 256 characters, and each one has a code between 0 and 255 (there is a complete list of them in part 26 of this chapter). To convert between codes and characters, there are two functions, CODE and CHR$.

CODE is applied to a string, and gives the code of the first character in the string (or 0 if the string is empty).

CHR$ is applied to a number, and gives the single character string whose code is that number.

This program prints out the entire character set...

10 FOR a=32 TO 255: PRINT CHR$ a;: NEXT a

On the screen will appear the following...

The character set

As you can see, the character set consists of a space, 15 symbols and punctuation marks, the ten digits, seven more symbols, the capital letters, six more symbols, the lower case letters and five more symbols. These are all (except £ and ©) taken from a widely-used set of characters known as ASCII (American Standard Codes for Information Interchange). ASCII also assigns numeric codes to these characters, and these are the codes that the +3 uses.

The rest of the characters are not part of ASCII, but are dedicated to the ZX Spectrum range of computers. First amongst them are a space and 15 patterns of black and white blobs. These are called the graphics symbols and can be used for drawing pictures. You can enter these from the keyboard, using what's known as graphics mode. Pressing the GRAPH key switches on graphics mode, after which the keys 1, 2, 3, 4, 5, 6, 7 and 8 will produce the graphics symbols...

While in graphics mode, pressing CAPS SHIFT together with one of the keys 1 to 8 produces 'inverted' versions of the same symbols, ie. black becomes white and white becomes black...

The cursor keys won't work properly while all this is going on as the +3 interprets them as shifted number keys, and prints graphics characters accordingly.

Pressing the 9 key turns everything back to normal (as does pressing GRAPH again). The 0 key deletes the character to the left of the cursor.

Here are the sixteen graphics symbols...

Symbol Code Symbol Code
128 143
129 142
130 141
131 140
132 139
133 138
134 137
135 136

After the graphics symbols in the character set, you will see what appears to be another copy of the alphabet from A to S. These are characters that you can redefine yourself (though when the machine is first switched on they are set as letters) - they are called user-defined graphics. You can type these in from the keyboard by going into graphics mode, and then using the letter keys A to S.

To define a new character for yourself, follow this recipe, it defines a character to show π.

(i) Work out what the character looks like. Each character has an 8 x 8 grid of dots, each of which can appear to be on or off. You'd draw a diagram something like this (with blank squares representing the dots which are on)...

When a dot is on, the +3 prints the ink colour; when a dot if off, the +3 prints the paper colour. (The terms ink and paper are explained in part 16 of this chapter.)

We've left a one-square border around the edge because all the other letters also have one (except for lower case letters with tails, where the tail goes right down to the bottom).

(ii) Work out which user-defined graphic you wish to display π - let's say the one corresponding to P so that if you press P (after pressing GRAPH) you get π.

(iii) Store the new pattern. Each user-defined graphic has its pattern stored as eight numbers, one for each row. You can write each of these numbers in a program as BIN followed by eight 0's or 1's - 0 for paper, 1 for ink - so the eight numbers for our π character are...

(If you know about binary numbers, then it should help you to know that BIN is used to write a number in binary instead of the usual decimal.) Look at the pattern of binary numbers through half-closed eyes - you may even be able to see the π character!

These eight numbers are stored in eight locations (bytes) in memory. Each of these locations has an address. The address of the first byte (or group of eight digits) is USR "P" (we chose P in (ii) above). The address of the second byte is USR "P"+1, and so on up to the address USR "P"+7.

USR here is a function to convert a string argument into the address of the first byte in memory for the corresponding user-defined graphic. The string argument must be a single character which can be either the user-defined graphic itself or the corresponding letter (in upper or lower case). There is another use for USR, when its argument is a number, which will be dealt with later.

Even if you don't understand this, the following program will define the character for you...

 10 FOR n=0 TO 7
 20 READ row: POKE USR "P"+n, row
 30 NEXT n
 40 DATA BIN 00000000
 50 DATA BIN 00000000
 60 DATA BIN 00000010
 70 DATA BIN 00111100
 80 DATA BIN 01010100
 90 DATA BIN 00010100
100 DATA BIN 00010100
110 DATA BIN 00000000

The POKE statement stores a number directly in a memory location, bypassing the mechanisms normally used by the BASIC. The opposite of POKE is PEEK, and this allows us to look at the contents of a memory location although it does not actually alter the contents themselves. PEEK and POKE are described more fully in part 24 of this chapter.

After the user-defined graphics in the character set come the tokens.

You will have noticed that we have not printed out the first 32 characters (codes 0 to 31) - these are control characters. They don't produce anything printable, but instead are used to control the screen display or some other function of the +3.

(If you try to print control characters, the +3 displays ? to show that it doesn't understand them. Control characters are described more fully in part 28 of this chapter.)

The three control characters that the screen display uses are 6, 8 and 13 (these will now be explained). On the whole, CHR$ 8 is the only one you are likely to find useful.

CHR$ 6 prints spaces in exactly the same way as a comma does in a PRINT statement, for instance...

PRINT 1; CHR$ 6;2

...does the same as...


Obviously this is not a very clear way of using it. A more subtle way is to say...

LET a$="1"+ CHR$ 6+"2"

CHR$ 8 is 'backspace' - it moves the print position back one place. Try...

PRINT "1234"; CHR$ 8;"5"

...which prints out...


CHR$ 13 is 'newline' - it moves the print position to the beginning of the next line.

The screen display also uses control codes 16 to 23 - these are explained in parts 15 and 16 of this chapter (all the codes are listed in part 28).

Using the codes for the characters we can extend the concept of 'alphanumerical ordering' to cover strings containing any characters, not just letters. If instead of thinking in terms of the usual alphabet of 26 letters we use the extended alphabet of 256 characters, in the same order as their codes, then the principle is exactly the same. For instance, the following strings are in their 'Spectrum' ASCII alphabetical order. (Notice the rather odd feature that lower case letters come after all the capitals; so a comes after Z. Notice also that spaces are significant.)

"(Parenthetical remark)"
"129.95 inc. VAT"
"Elgar, the Regal Lager"

Here is the rule for finding out in which order two strings come. Start by comparing the first two characters. If they are different, then one of them has its code less than the other, and the string it comes from is the earlier (lesser) of the two strings. If they are the same, then go on to compare the next two characters. If in this process one of the strings runs out before the other, then that string is the earlier; otherwise they must be equal.

The relations =, <, >, <=, >= and <> are used for strings as well as for numbers: < means 'comes before' and > means 'comes after', so that...


...are both true.

<= and >= work in the same way as they do for numbers, so that...

"The same string" <= "The same string" true, but...

"The same string" < "The same string" false.

Experiment on all this using the program here, which inputs two strings and puts them in order.

10 INPUT "Type in two strings:",a$,b$
20 IF a$>b$ THEN LET c$=a$: LET a$=b$: LET b$=c$
30 PRINT a$;" ";
40 IF a$<b$ THEN PRINT "<";: GO TO 60
50 PRINT "=";
60 PRINT " ";b$
70 GO TO 10

Note (in the above program and also in the program at the end of part 13 how we have to introduce c$ in line 20 when we swap over a$ and b$. Can you see why simply using...

LET a$=b$: LET b$=a$

...would not have the desired effect?

The next program sets up user defined graphics for the following keys to display chess pieces...

Chess pieces...

5 LET b=BIN 01111100: LET c=BIN 00111000: LET d=BIN00010000
10 FOR n=1 TO 6: READ p$: REM 6 pieces
20 FOR f=0 TO 7: REM read pieces into 8 bytes
30 READ a: POKE USR p$+f, a
40 NEXT f
50 NEXT n
100 REM bishop
110 DATA "b", 0, d, BIN 00101000, BIN 01000100
120 DATA BIN 01101100, c, b, 0
130 REM king
140 DATA "k", 0, d, c, d
150 DATA c, BIN 01000100, c, 0
160 REM rook
170 DATA "r", 0, BIN 01010100, b, c
180 DATA c, b, b, 0
190 REM queen
200 DATA "q", 0, BIN 01010100, BIN 00101000, d
210 DATA BIN 01101100, b, b, 0
220 REM pawn
230 DATA "p", 0, 0, d, c
240 DATA c, d, b, 0
250 REM knight
260 DATA "n", 0, d, c, BIN 01111000
270 DATA BIN 00011000, c, b, 0

Note that in the above DATA statements, we have simply used 0 instead of BIN 00000000.

When you have run this program, you may look at the pieces by pressing GRAPH followed by any of the keys: B, K,R, Q, P or N.


  1. Imagine the space for one symbol divided up into four quarters like a Battenberg cake. Then if each quarter can be either black or white, there are 2^4 = 16 possibilities. Find them all in the character set.

  2. Run this program...

     10 INPUT c
     20 PRINT CHR$ c;
     30 GO TO 10

If you experiment with it, you'll find that CHR$ c is rounded to the nearest whole number; and if c is not in the range 0 to 255, then the program stops with the error report B integer out of range.

  1. Which of these is the lesser?


Part 15
More about PRINT and INPUT

Subjects covered...

You have already seen PRINT used quite a lot, so you will have a rough idea of how it is used. Expressions whose values are printed are called PRINT items. They may be separated by commas, semicolons or apostrophes, which are called PRINT separators. A PRINT item can also be nothing at all, which is a way of explaining what happens when you use PRINT on its own.

There are two more kinds of PRINT items, which are used to tell the +3 not what, but where to print. For example, the instruction...

10 PRINT AT 11,16;"*"

...prints an asterisk '*' in the centre of the screen. This is because...

AT line,column

...moves the PRINT position (the place where the next item is to be printed) to the line and column specified. Lines are numbered from 0 (at the top) to 21; columns are numbered from 0 (on the left) to 31.

SCREEN$ is the reverse function to PRINT AT, and will (within limits) 'read' the character which is located at a particular position on the screen. It uses line and column numbers in the same way as PRINT AT, but enclosed in brackets. For example, the instruction...

20 PRINT AT 0,0; SCREEN$ (11,16)

...will read the asterisk printed in the centre of the screen, then print it at location 0,0 (the top left-hand corner).

Characters from tokens are read normally (as single characters), and spaces are read as spaces. However, attempting to read user-defined characters, graphics characters, or lines drawn by PLOT, DRAW and CIRCLE, result in a null (empty) string being returned. The same applies if OVER has been used to create a composite character. (The keywords PLOT, DRAW, CIRCLE and OVER are described in parts 16 and 17 of this chapter.)

You cannot normally PRINT or PLOT on the bottom two lines { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Columns ⟶ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Pixel y coordinates ⟶ 0 7 8 15 16 23 24 31 32 39 40 47 48 55 56 63 64 71 72 79 80 87 88 95 96 103 104 111 112 119 120 127 128 135 136 143 144 151 152 159 160 167 168 175 Pixel x coordinates ⟶ 0 7 8 15 16 23 24 31 32 39 40 47 48 55 56 63 64 71 72 79 80 87 88 95 96 103 104 111 112 119 120 127 128 135 136 143 144 151 152 159 160 167 168 175 176 183 184 191 192 199 200 207 208 215 216 223 224 231 232 239 240 247 248 255 An example: this is the pixel (191, 159)

The function...

TAB column

...prints enough spaces to move the PRINT position to the column specified. It stays on the same line, or, if this would involve backspacing, moves to the next line. Note that the +3 reduces the column number 'modulo 32' (ie. it divides by 32 and takes the remainder) - so TAB 33 means the same as TAB 1.

As an example...

PRINT TAB 30;1; TAB 12;"Contents"; AT 3,1;"Chapter"; TAB 24;"Page" how you might want to print out the heading on the contents page (page 1) of a book.

Try running this...

10 FOR n=0 TO 20
20 PRINT TAB 8*n;n;
30 NEXT n

This shows what is meant by the TAB numbers being reduced modulo 32.

For a more elegant example, change the 8 in line 20 to a 6.

Note the following points...

(i) TABs and print items are best terminated with semicolons, as we have done above. You can use commas (or nothing, at the end of the statement), but this means that after having carefully set up the PRINT position, you immediately move it on again - not terribly useful!

(ii) You cannot print on the bottom two lines (22 and 23) on the screen because they are reserved for commands, INPUT data, reports, error messages and so on. References to 'the bottom line' usually mean line 21.

(iii) You can use AT to locate the PRINT position even where these is already something printed - the new print item will simply overwrite the old.

Another statement connected with PRINT is CLS. This clears the whole screen.

When printing reaches the bottom of the screen, it starts to scroll upwards rather like a typewriter. You can see this if you go into the small screen using the edit menu option Screen (described in chapter 6, and then type...

CLS: FOR n=1 TO 30: PRINT n: NEXT n

When it has printed a screen full, the +3 will stop with the message scroll? at the bottom of the screen. You can now inspect the first 22 numbers at your leisure. When you have finished with them, press Y (for yes) and the +3 will give you the next screen full of numbers. Actually, any key will make the +3 carry on except N (for no), the BREAK key or the space bar. These will make the +3 stop running the program with the report D BREAK - CONT repeats.

The INPUT statement can do much more than we have told you so far. You have already seen INPUT statements like...

INPUT "How old are you?", age which the +3 prints the caption How old are you? at the bottom of the screen, and then you have to type in your age. In fact though, an INPUT statement can be made up of items and separators in exactly the same way as a PRINT statement, so How old are you? and age are both INPUT items. INPUT items are generally the same as PRINT items, however, there are some very important differences.

First, an obvious extra INPUT item is the variable whose value you require to be typed in - age in our example above. The rule is that if an INPUT item begins with a letter, then it must be a variable whose value is to be input.

This would seem to mean that you can't print out the values of variables as part of a caption. However, you can get round this by putting brackets around the variable. Any expression that starts with a letter must be enclosed in brackets if it is to be printed as part of a caption.

Any kind of PRINT item that is not affected by these rules is also an INPUT item. Here is an example to illustrate what's going on...

LET my age = INT ( RND * 100): INPUT ("I am ";my age;".");" How old are you?", your age

my age is contained in brackets, so its value gets printed out. your age is not contained in brackets, so you have to type its value in.

Everything that an INPUT statement writes goes to the bottom part of the screen, which acts somewhat independently of the top part. In particular, lines are numbered relative to the top line of the bottom half, even if this has moved up the actual TV screen (which it does if you type lots of INPUT data). Whatever the small screen does during INPUT, however, it will always revert to being two lines in size when the program stops, and you start editing.

To see how AT works in INPUT statements, try this...

10 INPUT "This is line 1.", a$; AT 0,0;"This is line 0.",a$; AT 2,0;"This is line 2."; AT 1,0;"This is still line 1.",a$

Run the program (just press ENTER each time it stops). When This is line 2 is printed, the lower part of the screen moves up to make room for it; but the numbering moves up as well, so that the lines of text keep their same numbers.

Now try this...

10 FOR n=0 TO 19: PRINT AT n, 0;n;: NEXT n
20 INPUT AT 0, 0;a$; AT 1, 0;a$; AT 2, 0;a$; AT 3, 0;a$; AT 4,
    0;a$; AT 5, 0;a$;

As the lower part of the screen goes up and up, the upper part remains undisturbed until the lower part threatens to write on the same line as the PRINT position. Then the upper part starts scrolling up to avoid this.

Another refinement to the INPUT statement that we haven't seen yet is called LINE input and is a different way of inputting string variables. If you use LINE before the name of a string variable to be input, as in...


...then the +3 will not give you the string quotes that it normally does for a string variable (though it will pretend to itself that they are there). So if you type in...

bugs the INPUT data, a$ will be given the value bugs. Because the string quotes do not appear with the string, you cannot delete them and type in a different sort of string expression for the INPUT data. Remember that you cannot use LINE for numeric variables.

There's an interesting side effect to INPUT. Whilst typing into an INPUT request, the old Spectrum single-key entry system enjoys a brief moment of freedom before being locked away again when you press ENTER. Run this program if you're interested...

10 INPUT numbers
20 PRINT numbers
30 GO TO 10

Input a few numbers, and they'll be printed faithfully onto the screen. Now press EXTEND MODE followed by the M key. The word PI appears, and if you press ENTER, then 3.1415927 will appear as if by magic. However, if you type PI as two letters without the aid of EXTEND MODE then the +3 will stop with the report 2 Variable not found, 10:1.

There's no simple explanation for this behaviour, and it's best just to be aware that it can happen if you press some combinations of keys during INPUT. If for some reason you're keen to experiment, chapter 7 (Using 48 BASIC) will tell you which keys produce which effects.

The control characters CHR$ 22 and CHR$ 23 have effects rather like AT and TAB. Whenever the +3 is instructed to print one of them, the character must be followed by two more characters that do not have their usual effect, but that are treated instead as numbers (their codes) to specify the line and column (for AT) or the tab position (for TAB). You will almost always find it easier to use AT and TAB in the usual way rather than use control characters, however, they might be useful in some circumstances. The AT control character is CHR$ 22. The first character after it specified the line number and the second specifies the column number, so that...

PRINT CHR$ 22+ CHR$ 1+ CHR$ c;

...has exactly the same effect as...

PRINT AT 1, c;

This is so that even if CHR$ 1 or CHR$ c would normally have a different meaning (for instance if c=13); the CHR$ 22 before them overrides that.

The TAB control character is CHR$ 23 and the two characters after it combine to give a number between 0 and 65535, specifying the number you would have in a TAB item. The statement...

PRINT CHR$ 23+ CHR$ a+CHR$ b;

...has the same effect as...

PRINT TAB a+256*b;

You can use POKE to stop the computer asking if you wish to scroll? by typing...

POKE 23692,255

...every so often. After this it will scroll up 255 times before stopping with scroll?. As an example, try...

10 FOR n=0 TO 1000
20 PRINT n: POKE 23692,255
30 NEXT n

...and watch everything whizz off the screen!


  1. Try this program on some children, to test their multiplication tables...

      10 LET m$=""
      20 LET a= INT ( RND *12)+1: LET b = INT ( RND *12)+1
      30 INPUT (m$) ' ' "what is ";(a);" x ";(b);"?";c
     100 IF c=a*b THEN LET m$="Right.": GO TO 20
     110 LET m$="Wrong. Try again.": GO TO 30

If they are perceptive, they might manage to work out that they do not have to do the calculation themselves. For instance, if the +3 asks them to type the answer to 2 x 3, then all they have to do is type in 2*3 literally.

Part 16

Subjects covered...

Run this program...

 10 FOR m=0 TO 1: BRIGHT m
 20 FOR n=1 TO 10
 30 FOR c=0 TO 7
 40 PAPER c: PRINT "    ";: REM 4 coloured spaces
 50 NEXT c: NEXT n: NEXT m
 60 FOR m=0 TO 1: BRIGHT m: PAPER 7
 70 FOR c=0 TO 3
 80 INK c: PRINT c;"  ":
 90 NEXT c: PAPER 0
100 FOR c=4 TO 7
110 INK c: PRINT c;"  ";
120 NEXT c: NEXT m
130 PAPER 7: INK 0: BRIGHT 0

This shows the eight colours (including white and black) and the two levels of brightness that the +3 can produce on a colour TV. (If your TV is black-and-white, then you will see just various shades of grey.) A quicker way to achieve a similar result is to RESET the +3 whilst holding down BREAK - but that's a little drastic. Here is a list of which numbers produce which colours (for your reference)...

0 - black
1 - blue
2 - red
3 - magenta
4 - green
5 - cyan
6 - yellow
7 - white

On a black-and-white TV, these numbers are in order of brightness. To use these colours properly, you will need to understand a bit about how the picture is arranged.

The picture is divided up into 768 (24 lines of 32) positions (cells) where characters can be printed.

A typical character cell

Each character cell consists of an 8 x 8 grid (such as above). This should remind you of the user-defined graphics in part 14, where we had 0s for the white dots and 1s for the black dots.

The character has two colours associated with it: the ink, or foreground colour, which is the colour for the black dots in our square, and the paper, or background colour, which is used for the white dots. To start off with, every cell has black ink and white paper so writing appears as black on white.

The character also has a brightness (normal or extra bright), and something to say whether it flashes or not. Flashing is done by continuously swapping the ink and paper colours. All this information can be coded into numbers, so a character then has the following...

(i) An 8 x 8 grid of 0s and 1s to define the shape of the character, with 0 for paper and 1 for ink.

(ii) Ink and paper colours, each coded into a number between 0 and 7.

(iii) A brightness - 0 for normal, 1 for extra bright.

(iv) A flash number - 0 for steady, 1 for flashing.

Note that since the ink and paper colours cover a whole character cell, you cannot possibly have more than two colours in a given block of 64 dots. The same goes for the brightness and flash numbers - they refer to the whole character cell, not individual dots within the cell. The colour, brightness and flash number for a given character cell are called attributes.

When you print something on the screen, you change the dot pattern for that character cell. It is less obvious, but still true, that you also change the cell's attributes. To start off with you do not notice this because everything is printed with black ink on white paper (at normal brightness and no flashing); however, you can vary this with the INK, PAPER, BRIGHT and FLASH statements. Using the edit menu's Screen option, go to the bottom screen, and try...


...and then PRINT a few items on the screen - they will appear on cyan paper, because as they are printed, the paper colour for the cells they occupy are set to cyan (which has code 5).

The others work the same way, so you may use the settings...

...and any printing will set the corresponding attributes for all the character cells it subsequently uses.

Try some of these out. You should now be able to see how the program at the beginning of this section worked (remember that a space is a character that has its ink and paper the same colour).

There are some ore numbers you can use in these statements that have less direct effects.

8 can be used in all four statements, and means 'transparent' in the same sense that the old attribute shows through. Suppose, for instance, that you do...


No character position will ever have its paper colour set to 8 because there is no such colour; what happens is that when a position is printed on, its paper colour is left the same as it was before. However, INK 8, BRIGHT 8 and FLASH 8 work the same way as for the other attribute numbers.

9 can be used only with PAPER and INK, and means 'contrast'. The colour (ink or paper) that you use it with is made to contrast with the other by being made white if the other is a dark colour (black, blue, red or magenta), or being made black if the other is a light colour (green, cyan, yellow or white).

Try this by doing...

INK 9: FOR c=0 TO 7: PAPER c: PRINT c: NEXT c

A more impressive display of its power is to run the program at the beginning to make coloured stripes (again, making sure that you are in the lower screen when you type RUN), and then doing...

INK 9: PAPER 8: PRINT AT 0, 0;: FOR n=1 TO 1000: PRINT n;:NEXT n

The ink colour here is always made to contrast with the old paper colour for each character cell.

Colour TV relies on the fact that the human eye need see only three colours of light (red, green and blue) in various combinations and intensities in order to perceive all the colours of the spectrum. The +3 also displays its spectrum of colours by using mixtures of red, green and blue. For instance, yellow is made by mixing red with green - which is why the code, 6, is the sum of the codes for red and green.

To see how all eight colours fit together, imagine three rectangular spotlights, coloured red, green and blue shining at not quite the same place on a piece of white paper in the dark. Where they overlap you will see mixtures of colours, as shown by the following program (note that solid ink spaces are obtained by entering graphics mode (pressing GRAPH) then holding down CAPS SHIFT while pressing 8. To exit from graphics mode, press 9.)...

  10 BORDER 0: PAPER 0: INK 7: CLS
  20 FOR a=1 TO 6
  30 PRINT TAB 6; INK 1;"██████████████████": REM 18 ink squares
  40 NEXT a
  50 LET dataline=200
  60 GO SUB 1000
  70 LET dataline=210
  80 GO SUB 1000
  90 STOP
 200 DATA 2,3,7,5,4
 210 DATA 2,2,6,4,4
1000 FOR a=1 TO 6
1010 RESTORE dataline
1020 FOR b=1 TO 5
1030 READ c: PRINT INK c;"██████";: REM 6 ink squares
1040 NEXT b: PRINT: NEXT a

There is a function called ATTR that finds out what the attributes are at a given position on the screen. It is a fairly complicated function, so it has been relegated to the end of this section.

There are two more statements, INVERSE and OVER, which control not the attributes, but the dot pattern that is printed on the screen. They use the numbers 0 for off, and 1 for on. If you use INVERSE 1, then each character cell's dot pattern will be the inverse of its usual form, ie. paper dots will be replaced by ink dots and vice versa. Thus the character cell containing 'a' (shown previously) would be printed as follows...

If (as at switch on) we have black ink on white paper, then the 'a' will appear as white on black.

The statement...


...sets into action a particular sort of overprinting. Normally when something is written into a character position, it completely obliterates what was there before; however, using OVER 1, the new character is simply added on top of the old one. This can be particularly useful for writing composite characters, like an underlined letter, as in the following program. (Reset the computer and select +3 BASIC. Note that the underline character is obtained by pressing SYMB SHIFT together with 0.)...

10 OVER 1
20 PRINT "w"; CHR$ 8;"_";

(Notice we have used the control character CHR$ 8 (backspace) before overprinting the b with _.)

There is another way of using INK, PAPER and so on which you will probably find more useful than having them as statements. You can put them as items in a PRINT statement (followed by ;), and they then do exactly the same as they would have done if they had been used as statements on their own, except that their effect is only temporary, lasting as far as the end of the PRINT statement that contains them. Thus if you type...


...then only the x will be on yellow paper.

PAPER, INK, etc. when used as statements do not affect the colour in the bottom part of the screen (where INPUT data is typed in and reports are displayed). The bottom screen uses the colour of the border for its paper colour, code 9 (for contrast) for its ink colour, has flashing off, and everything at normal brightness. You can change the border colour to any of the eight normal colours (not 8 or 9) using the statement...

BORDER colour

When you type in INPUT data, it follows this rule of using contrasting ink on border coloured paper, but you can change the colour of the captions written by the +3 by using PAPER, INK, etc. items in the INPUT statement, just as you would in a PRINT statement. Their effect lasts either to the end of the statement, or until some INPUT data is typed in, whichever comes soonest. Try...

INPUT FLASH 1; INK 4;"Enter a number?";n

The +3 has a high regard for your sanity - no matter what combination of effects and colours you manage to produce from a BASIC program, the editor will always use black ink on white paper.

There is one more way of changing the colours by using control characters - rather like the control characters for AT and TAB in part 15.

These are each followed by one character that shows a colour by its code; so that (for instance)...

PRINT CHR$ 16+ CHR$ 9;"item"

...has the same effect as...

PRINT INK 9;"item"

On the whole, you would not bother to use these control characters because you might just as well use the statements PAPER, INK, etc. However, if you have some old 48K BASIC programs on cassette, you may find such control characters embedded in the listing. In general, the editor will actively ignore them, and remove them at the first opportunity. It is not possible to insert them into listings as with the old 48K Spectrum.

The ATTR function has the form...


Its two arguments are the line and column numbers that you would use in an AT item, and its result is a number that shows the colours and so on at the corresponding character position on the TV screen. You can use this as freely in expressions as you can any other function.

The number that is the result is the sum of four other numbers as follows...

For instance, if the character cell is flashing, normal brightness, yellow paper and blue ink, then the four numbers that we have to add together are 128, 0, 8x6=48 and 1, making 177 altogether. Test this with...

PRINT AT 0,0; FLASH 1; PAPER 6; INK 1;" "; ATTR (0,0)


  1. Try...
  PRINT "B"; CHR$ 8; OVER 1;"/";

Where the / has cut through the B, it has left a white dot. This is the way that overprinting works on the +3 - two papers or two inks give a paper, one of each gives an ink. This has the interesting property that if you overprint with the same thing twice you end up with what you had at the beginning. If you now type...

PRINT CHR$ 8; OVER 1;"/"

...why do you recover an unblemished B?

  1. Run this program...
  10 POKE 22528+ RND *704, RND *127
  20 GO TO 10

(Never mind how this program works.) The program is changing the colours of squares on the TV screen and the RND should ensure that this happens randomly. (The diagonal stripes that you eventually see are a manifestation of the hidden pattern in RND, ie. pseudo-random instead of truly random.)

Part 17

Subjects covered...

For all of this section, type in the example programs, commands and RUN in the small screen (use the edit menu's Screen option).

In this section we shall see how to draw pictures on the +3. The part of the screen you can see has 22 lines and 32 columns, making 22x32 =704 character positions. As you may remember from part 16, each of these character positions is made up of an 8 x 8 grid of dots which are called pixels (picture elements).

A pixel is specified by two numbers - its coordinates. The first, its x coordinate, says how far it is across from the extreme left-hand column. The second, its y coordinate, says how far it is up from the bottom. These coordinates are usually written as a pair in brackets, so (0,0) (255,0) (0,175) and (255,175) are the bottom left, bottom right, top left and top right corners of the screen.

If you have trouble memorising which coordinate is which, simply remember that x is a cross (x is across).

The statements...

PLOT x coordinate, y coordinate

..inks in the pixel with these coordinates, so this measles program...

10 PLOT INT ( RND *256), INT (RND *176): INPUT a$: GO TO 10

...plots a random point each time you press ENTER.

Here is a rather more interesting program. It plots a graph of the function SIN (a sine wave) for values between 0 and 2*π...

10 FOR n=0 TO 255
20 PLOT n, 88+80* SIN (n/128*PI )
30 NEXT n

This next program plots a graph of SQR (part of a parabola) between 0 and 4...

10 FOR n=0 TO 255
20 PLOT n, 80* SQR (n/64)
30 NEXT n

Notice that pixel coordinates are rather different from the line and column in an AT item. You may find that the diagram in part 15 of this chapter is useful when working out pixel coordinates and line and column numbers.

To help you with your pictures, the +3 will draw straight lines, circles and parts of circles for you, using DRAW and CIRCLE statements.

The statement DRAW (to draw a straight line) takes the form...

DRAW x, y

The starting place of the line is the pixel where the last PLOT, DRAW or CIRCLE statement left off (this is called the PLOT position - RUN, CLEAR, CLS and NEW reset it to the bottom left-hand corner, at 0,0); the finishing place of the line is x pixels to the right of that and y pixels up. The DRAW statement on its own determines the length and direction of the line, but not its starting point.

Experiment with a few PLOT and DRAW commands, for instance...

PLOT 0,100: DRAW 80,-35
PLOT 90,150: DRAW 80,-35

Notice that the numbers in a DRAW statement can be negative, but those in a PLOT statement can't.

You can also plot and draw in colour, although you have to bear in mind that colours always cover the whole of a character cell and cannot be specified for individual pixels. When a pixel is plotted, it is set to show the full ink colour, and the whole of the character cell containing it is given the current ink colour. This program demonstrates that point...

10 BORDER 0: PAPER 0: INK 7: CLS: REM black out screen
20 LET x1=0: LET y1=0: REM start of line
30 LET c=1: REM for ink colour, starting blue
40 LET x2= INT ( RND *256): LET y2= INT ( RND *176): REM
   random finish on line
50 DRAW INK c;x2-x1,y2-y1
60 LET x1=x2: LET y1=y2: REM next line starts where last
   one finished
70 LET c=c+1: IF c=8 THEN LET c=1: REM new colour
80 GO TO 40

The lines seem to get broader as the program goes on, and this is because a line changes the colours of all the inked-in pixels of all character cells that it passes through. Note that you can embed PAPER, INK, FLASH, BRIGHT, INVERSE and OVER items in a PLOT or DRAW statement just as you could with PRINT and INPUT. They go between the keyword and the coordinates, and are terminated by either semicolons or commas.

An extra frill with DRAW is that you can use it to draw part of circles instead of straight lines, by including an extra number to specify an angle to be turned through. The form is...

DRAW x,y,a

x and y are used to specify the finishing point of the line just as before, and a is the number of radians that it must turn through as it goes. If a is positive then it turns to the left, if a is negative then it turns to the right. Another way of seeing a is as showing the fraction of a complete circle that will be drawn, (a complete circle is 2*π radians) so if a equals π it will draw a semicircle, if a equals 0.5*π a quarter if a circle, and so on.

For instance, suppose a equals π. Then whatever values x and y take, a semicircle will be drawn. Try...

10 PLOT 100,100: DRAW 50,50, PI

...which will draw this...

Start at (100,100) Finish at (150,150)

The drawing starts off in a south-easterly direction, but by the time it stops, it is going north-west. In between, it has turned through 180 degrees, or π radians (the value of a).

Run the program several times, with PI replaced by various other expressions, eg. -PI, PI/2, 3*PI/2, PI/4, 1, 0, etc.

The last statement in this section is CIRCLE, which draws an entire circle. You specify the coordinates of the centre and the radius of the circle using...

CIRCLE x coordinate, y coordinate, radius

Just as with PLOT and DRAW, you can put various sorts of colour items in at the beginning of a CIRCLE statement.

The POINT function tells you whether a pixel is ink or paper colour. Its two arguments are the coordinates of the pixel (which must be enclosed in brackets) and its result is 0 if the pixel is paper colour, or 1 if its ink colour. Try...




...and investigate how INVERSE and OVER work inside PLOT statement. These two affect just the relevant pixel, and not the rest of the character cell. They are normally off (0) in a PLOT statement, so you only need to mention them to turn them on (1).

Here is a list if the possibilities for reference:

PLOT; - This is the usual form. It plots an ink dot, ie. sets the pixel to show the ink colour.

PLOT INVERSE 1; - This plots a dot of 'ink eradicator', ie. it sets the pixel to show the paper colour.

PLOT OVER 1; - This exchanges the pixel colour with whatever it was before, so if it was ink colour then it becomes paper colour, and vice versa.

PLOT INVERSE 1; OVER 1; - This leaves the pixel exactly as it was before, but note that it also changes the PLOT position, so you might use it simply to do that.

As another example of using OVER statement, fill the screen up with writing using black on white, and then type...

PLOT 0,0: DRAW OVER 1;255,175

This will draw a fairly decent line, even though it has gaps in it wherever it hits some writing. Now type in exactly the same command again. The line will vanish without leaving any trace whatsoever - this is the great advantage of OVER 1. If you had drawn the line using...

PLOT 0,0: DRAW 255,175

...and erased using...

PLOT 0,0: DRAW INVERSE 1;255,175

...then you would also have erased some of the writing.

Now try...

PLOT 0,0: DRAW OVER 1;250,175

...and try to 'undraw' it using...

DRAW OVER 1;-250,-175

This doesn't quite work because the pixels that the line uses on the way back are not quite the same as the ones that it used on the way there. You must therefore undraw a line in exactly the same direction as you drew it.

One way to get unusual colours is to speckle two normal ones together in a single square, using a user-defined graphic. Try this program...

1000 FOR n=0 TO 6 STEP 2
1010 POKE USR "a"+n, BIN 01010101: POKE USR "a"+n+1, BIN 10101010
1020 NEXT n
1030 REM now press GRAPH then A

...which gives the user-defined graphic corresponding to a chessboard pattern. If you print the character (press GRAPH then A) you will find that the character is reproduced in a combination of the current paper and ink colours.


  1. Experiment with PAPER, INK, FLASH and BRIGHT items in a PLOT statement. These are the parts that affect the whole of the character cell containing the pixel. Normally it is as though the PLOT statement had started off...

    PLOT PAPER 8; FLASH 8; BRIGHT 8; ...etc

...and only the ink colour of a character cell is altered when something is plotted there, but you can change this if you wish.

Be especially careful when using colours with INVERSE 1, because this sets the pixel to show the paper colour, and may change the ink colour, which might not be what you expect.

  1. If you have read part 10, see if you can work out how to draw circles using SIN and COS. Run this program...
 10 FOR n=0 TO 2* PI STEP PI /180
 20 PLOT 100+80* COS n, 87+80*SIN n
 30 NEXT n
 40 CIRCLE 150, 87, 80

You can see that the CIRCLE statement is much quicker, albeit less accurate.

  1. Try...

    CIRCLE 100,87,80: DRAW 50,50

You can see from this that the CIRCLE statement leaves the PLOT position at a rather indeterminate place - it is always somewhere about half way up the right-hand side of the circle. You will usually need to follow the CIRCLE statement with a PLOT statement before you do any more drawing.

Part 18

Subjects covered...

Quite often you will want to make the program take a specified length of time, and for this you will find the PAUSE statement useful.


...stops computing and displays the picture for n frames of the TV (there are 50 frames per second in Europe and 60 in USA). The value of n can be up to 65535, which gives you a pause of just under 22 minutes. If n=0 then it means 'pause indefinitely'.

A pause can always be cut short by pressing a key.

This program works the second hand of a clock...

 10 REM first we draw the clock face
 20 FOR n=1 TO 12
 30 PRINT AT 10-10* COS (n/6* PI ),16+10* SIN (n/6* PI );n
 40 NEXT n
 50 REM now we start the clock
 60 FOR t=0 TO 200000: REM t is the time in seconds
 70 LET a=t/30* PI: REM a is the angle of the second hand in radians
 80 LET sx=80* SIN a: LET sy=80* COS a
200 PLOT 128,88: DRAW OVER 1;sx,sy: REM draw second hand
210 PAUSE 42
220 PLOT 128,88: DRAW OVER 1;sx,sy: REM erase second hand
400 NEXT t

The 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 once per second, however, 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 +3 clock against a real one, and adjusting line 210 until they agree. You can't do this very accurately - an adjustment of one frame per second is equal to 2% (or half an hour in a day).

There is a much more accurate way of measuring time. This uses the contents of certain memory locations. The data stored is retrieved by using PEEK. Part 25 of this chapter explains what we're looking at in detail. Type in the expression...

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

This prints the number of seconds since the +3 was turned on (up to about 3 days and 21 hours, after which it goes back to 0).

Here is a revised clock program to make use of this...

 10 REM first we draw the clock face
 20 FOR n=1 TO 12
 30 PRINT AT 10-10* COS (n/6* PI ),16+10* SIN (n/6* PI );n
 40 NEXT n
 50 DEF FN t()= INT ((65536* PEEK 23674+256* PEEK 23673+ PEEK 23672)/50): REM number of seconds since start
100 REM now we start the clock
110 LET t1= FN t()
120 LET a=t1/30* PI: REM a is the angle of the second hand in radians
130 LET sx=72* SIN a: LET sy=72* COS a
140 PLOT 131,91: DRAW OVER 1;sx,sy: REM draw hand
200 LET t= FN t()
210 IF t<=t1 THEN GO TO 200: REM will wait until time for next hand
220 PLOT 131,91: DRAW OVER 1;sx,sy: REM rub out old hand
230 LET t1=t: GO TO 120

The internal clock that this method uses should be accurate to about 0.01% (approx 10 seconds per day) so long as the +3 is simply running the program. However, when you use the BEEP statement (described in part 19 of this chapter) or operate the disk drive or any peripheral attached to the +3 (eg. a printer or second disk drive), the internal clock stops temporarily, losing time.

The numbers PEEK 23674, PEEK 23673, and PEEK 23672 are held inside the +3 and used for counting in 50ths of a second. Each is between 0 and 255 and they gradually increase through all the numbers from 0 to 255; after 255 they drop straight back to 0.

The one that increases the most often is PEEK 23672 - every 1/50 second it increases by 1. When it is at 255, the next increase 'nudges' it to 0, and at the same time it increments PEEK 23673 up by 1. When (every 256/50 seconds) PEEK 23673 is nudged from 255 to 0, it in turn increments PEEK 23674 up by 1. This should be enough to explain why the expression above works.

Now, consider this carefully: suppose our three numbers are 0 (for PEEK 23674), 255 (for PEEK 23673) and 255 (for PEEK 23672). This means that it is about 21 minutes after switch on. Our expression ought to yield (65536x0+256x255+255)/50 which is equal to 1310.7.

But there is a hidden danger - the next time there is a 1/50 second count, the three numbers will change to 1, 0 and 0. Every so often, this will happen when you are half way through evaluating the expression - the +3 would evaluate PEEK 23674 as 0, but then change the other two to 0 before it can PEEK them. The answer would then be (65536x0+256x0+0)/50 which is equal to 0, which is obviously wrong.

A simple way of avoiding this problem is to evaluate the expression twice in succession and take the larger answer.

Now if you look carefully at the previous program, you can see that it does this implicitly.

Here is a trick to apply the rule. Define the functions...

10 DEF FN m(x,y)=(x+y+ ABS (x-y))/2: REM the larger of x and y
20 DEF FN u()=(65536* PEEK 23674+256* PEEK 23673+PEEK 23672)/50: REM time (may be wrong)
30 DEF FN t()= FN m( FN u(), FN u()): REM time (correct)

You can change the three counter numbers so that they give the real time instead of the time since the +3 was switched on. For instance, to set the time at 10.00am, you work out that this is 10 x 60 x 60 x 50 which is equal to 1800000 fiftieths of a second (and 1800000 is equal to 65536 x 27 + 256 x 119 + 64 x 1).

To set the three numbers to 27, 119 and 64, you type...

POKE 23674,27: POKE 23673,119: POKE 23672,64

In countries with mains frequencies of 60 Hz (cycles per second), these programs must replace 50 by 60 where appropriate.

The function INKEY$ (which has no argument) reads the keyboard. If you are pressing just one key, (or say, CAPS SHIFT and just one other key), then the result is the character which that key gives normally, otherwise the result is an empty string.

Try this program, which works like a typewriter.

10 IF INKEY$ <> "" THEN GO TO 10
20 IF INKEY$ ="" THEN GO TO 20
40 GO TO 10

Here line 10 waits for you to life your finger off the keyboard, and line 20 waits for you to press a new key.

Unlike INPUT, INKEY$ doesn't wait for you, so you don't have to press ENTER.


  1. What happens if you miss out line 10 in the 'typewriter' program?

  2. Another way of using INKEY$ is in conjunction with PAUSE, as in this alternative 'typewriter' program...

 10 PAUSE 0
 30 GO TO 10

To make this work, why is it essential that a pause should not finish if it finds you already pressing a key when it starts?

  1. Adapt the 'clock second hand' program so that it also shows minute and hour hands, re-drawing them every minute. If you're feeling ambitious, arrange so that every quarter of an hour, it puts on some kind of show - perhaps you could produce the 'Big Ben' chimes using PLAY (described in part 19 of this chapter).

Part 19

Subjects covered...

As you will have already noticed, the +3 can make a variety of noises. To get the best quality of sound, it's important to make sure that your TV is tuned-in properly (see chapter 2. If, instead of a TV, you are using a VDU monitor (which won't reproduce the +3's sound), note that a separate sound signal (which may be connected to an audio amplifier powering speaker(s) or headphones) is available from the TAPE/SOUND socket at the back of the +3. Headphones may not be plugged into the TAPE/SOUND socket directly.

Connections to the TAPE/SOUND socket are described in chapter 10.

To get the most out of the +3's musical ability, it helps to have a little knowledge about musical terms.

Note that in the examples that follow, it is important that you type in the string expressions exactly as shown in upper case and lower case letters, ie. the example "ga" should not be typed in as "Ga" "gA" or "GA".

Type in this command (don't worry what it means just yet)...

PLAY "ga"

Two notes were played - the second slightly higher than the first. The difference between the notes is called a tone. Now try...

PLAY "g$a"

Again there were two notes played - the first one was the same as the previous example, but there was less of a jump to the second. If you didn't hear the difference, then try the first example followed by the second again. The second example has half the difference between notes, and this is called a semitone.

When you're happy with semitones, try this...


This sort of difference is called a fifth, and occurs quite often in music of all kinds. With that example ringing in your ears, type...


Although (hopefully) you noticed that there was a much bigger difference that time than for the fifth, the two notes somehow sounded much more similar. This is called an octave, and is the point at which music starts to repeat itself. Don't worry about that unduly, just remember what an octave sounds like.

There are two ways of making music and sounds with the +3. The most elementary is the somewhat spartan BEEP command. This takes the form...

BEEP duration,pitch

...where the duration and pitch parameters represent numerical expressions. The duration is given in seconds, and the pitch is given in semitones above middle C (negative number for notes below middle C).

Here is a diagram to show the pitch values of all the notes in one octave on the piano for BEEP...

-3 -2 -1 0 C C♯ D♭ 1 2 D 3 D♯ E♭ 4 E 5 F 6 F♯ G♭ 7 G 8 G♯ A♭ 9 A 10 A♯ B♭ 11 B 12 C 13 14 15 16

Hence, to play the A above middle C for half a second, you would use...

BEEP 0.5,9

...and to play a scale (for example, C major) a complete (albeit short) program is needed...

10 FOR f=1 TO 8
20 READ note
30 BEEP 0.5,note
40 NEXT f
50 DATA 0,2,4,5,7,9,11,12

To get higher or lower notes, you have to add or subtract 12 for each octave that you go up or down.

BEEP exists mostly to provide compatibility with the older designs of Spectrum, though it can be useful for very short or rapid sound effects. For any new program you develop, the second way of producing sound is much to be preferred, and this is achieved using the PLAY command (if you worked through the simple examples earlier in this section, you'll remember that that's what you used).

PLAY is much more flexible than BEEP - it can play up to three voices in harmony with all manner of effects, and gives a much higher quality of sound. It's also much easier to use. For example, to play A above middle C for half a second, simply type in...

PLAY "a"

...and to play the C major scale (which needed a program to itself before), use...

PLAY "cdefgabC"

Notice that the last 'C' in the example above is in upper case. This tells the PLAY command to play it an octave higher than the lower case c. A scale, by the way, is the term used for a set of notes spanning an octave. The example above is called the C major scale because it's the set of notes between two C's. Why not? There are two main classes of scale, major and minor, and this is just musical shorthand for describing two different sets. Just for interest, the C minor scale sounds like this...

PLAY "cd$efg$a$bC"

Preceding a note by $ drops it by a semitone (flattens it), and preceding a note by # raises it by a semitone (sharpens it). The PLAY command spans 9 octaves, and can be told which one to use by having the upper case letter O followed by a number, in the list of notes it is given. Type in this little program...

10 LET o$="O5"
20 LET n$="DECcg"
30 LET a$=o$+n$
40 PLAY a$

There are a few new things in this program. Firstly, PLAY is just as happy with a string variable as with a string constant. In other words, providing that a$ has been set up beforehand, PLAY a$ works just as well as PLAY "O5DECcg". In fact, using variables in PLAY statements has certain distinct advantages, and we shall be doing this from now on.

Notice also that the string a$ has been 'built up' by combining the two smaller strings o$ and n$. While this doesn't make much difference at this sort of level, PLAY can cope with strings many thousands of notes long, and the only sensible way of creating and editing those strings from BASIC is to combine lots of smaller strings in this way.

Now run the above program. Edit line 10 so that "O5" becomes "O7", and run it again, or if you want to be a big spaceship make it "O2". If you don't specify an octave number for a particular string, then the +3 assumes that you want octave 5. Here follows a diagram of the notes and octave numbers which correspond to the standard even-tempered musical scale...

𝄞 𝄢 C D E F G A B C D E F G A B C D E F G A B C D E F G A B c d e f g a b C D E F G A B OCTAVE 3 c d e f g a b C D E F G A B OCTAVE 4 c d e f g a b C D E F G A B OCTAVE 5 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘 𝅘

There is a lot of overlap, so for example, "O3D" is the same as "O4d". This makes it easier to write tunes without having the change octave all the time. Some of the notes in the lowest octaves (0 and 1) aren't very accurate for technical reasons, and so the computer just makes a brave attempt at getting as close as possible.

PLAY can also handle many different lengths of note. Edit the program above so that line 10 is now...

10 LET o$="2"

...and run it. Then alter the setting of o$ between "1" and "9". The note length can be changed anywhere in a string by including a number between 1 and 9, and this is effective for all subsequent notes until a new number is encountered. Each of these nine note lengths has a specific musical name, and looks different when written down in musical notation. The following table shows which is which...

1 semi-quaver 𝅘𝅥𝅯
2 dotted semi-quaver 𝅘𝅥𝅯.
3 quaver 𝅘𝅥𝅮
4 dotted quaver 𝅘𝅥𝅮.
5 crotchet 𝅘𝅥
6 dotted crotchet 𝅘𝅥.
7 minim 𝅗𝅥
8 dotted minim 𝅗𝅥.
9 semi-breve 𝅝

PLAY can also cope with triplets, which are three notes played in the time for two. Unlike simple note lengths, the triplet number only applies for the three notes immediately following, and then the previous note length number resumes. The triplet numbers are as follows...

10 triplet semi-quaver
11 triplet quaver
12 triplet crochet

PLAY is quite happy about being told to 'shut up'! A timed period during which no notes play is called a rest, and "&" is used to signify this. The length of rest it produces is the same as the current note length. To demonstrate, edit lines 10 and 20 to...

10 LET o$="O4"
20 LET n$="DEC&cg"

Two notes played together without a break are called tied notes, which are signified in a PLAY command by an _ underline, so a crotchet c and a minim c tied together would be "5_7c". (The second value is then used as the note length for all subsequent notes, as before.)

There are occasions when ambiguity creeps in. Say that a piece of music needs octave 6 and a note length of 2, then...

10 LET o$="O62"

...seems a good bet - but no! The computer will find the O and try to read the number following it. When it finds 62, it will stop with the report n Out of range. In cases like this, there is a 'dummy note' called N that just serves to split things up, so line 10 should be...

10 LET o$="O6N2"

The volume can be set between 0 (minimum) and 15 (maximum) using "V" followed by a number. In practice, only 10 to 15 are likely to be useful, as 1 to 9 are too soft unless the +3 is being used with an amplifier. As previously mentioned, BEEP is louder than a single channel of PLAY, but if all three channels play a note at volume 15, then it should be at the same level as a note produced by BEEP.

Playing more than one channel at a time is very simple; you just separate lists of notes by commas. Try this new program...

10 LET a$="O4cCcCgGgG"
20 LET b$="O6CaCe$bd$bD"
30 PLAY a$,b$

In general, there is no difference between the three channels, and any string of notes can be put onto any channel. The overall speed of the music (the tempo) must be in the string assigned to channel A (the first string after PLAY), otherwise it will be ignored. To set tempo in beats (crotchets) per minute, use "T" followed by a number between 60 and 240. The standard value is 120, or two crotchets per second. Modify the program above to...

 5 LET t$="T120"
10 LET a$=t$+"O4cCcCgGgG"
20 LET b$="O6CaCe$bd$bD"
30 PLAY a$,b$

...and run it several times, changing line 5 for different tempos.

A common feature in music is the repetition of a group of notes. Any part of a string can be repeated by enclosing it in brackets, so if you change line 10 to...

10 LET a$=t$+"O4(cC)(gG)"

PLAY treats it just the same as the old line 10. If you include a closing bracket (with no matching opening bracket), then the string up to that point is repeated indefinitely. This is useful for rhythm effects and bass lines. To demonstrate, try this (you'll have to press BREAK to stop the sound)...

PLAY "O4N2cdefgfed)"


PLAY "O4N2cd(efgf)ed)"

IF you set up an infinitely repeating bass line, and then play a melody with it, then it would be nice if the bass line stops when the melody does. There is a device to do this - if PLAY comes across "H" (for halt) in any of the strings it is playing, then it stops all sounds immediately. Run the following program (again, you'll have to press BREAK to stop it)...

10 LET a$="cegbdfaC"
20 LET b$="O4cC)"
30 PLAY a$,b$

Now modify line 10 to...

10 LET a$="cegbdfaCH"

...and run it again.

So far we've only used notes which start and stop at one level of volume. The +3 can alter the volume of a note while it is playing, so it can start loud and die away like a piano, or rise and fall like a dog growling. To turn these effects on, use "W" (for waveform) followed by a number between 0 and 7, together with "U" for each channel you want to use the effect on. Any channel with a volume setting ("V") will not respond to "U". This table shows graphically how the volume changes for each setting...

0 single decay then off. 1 single attack then off. 2 single decay then hold. 3 single attack then hold. 4 repeated decay. 5 repeated attack. 6 repeated attack-decay. 7 repeated decay-attack.

This program plays the same note with each effect in turn, so you can compare them again the diagram above.

10 LET a$="UX1000W0C&W1C&W2C&W3C&W4C&W5C&W6C&W7C"
20 PLAY a$

The U turns on effects, and the W selects which waveform to use. There's also an "X1000". X sets how long the effect will last for (from 0 to 65535). If you don't include an X, then the +3 will choose the longest value. Waveforms that settle down (0 to 3 in the previous table) after the initial part, work best with X settings of about 1000, whereas repetitive effects (4-7) are more effective with short values like 300. Try varying the X setting in the previous program to get some idea of how each works.

The PLAY command isn't limited to pure musical notes. There are also three 'white noise' generators (white noise is a sound which is like an un-tuned FM radio or TV), and any of the three channels can play notes, white noise, or a mixture of both. To select a mix of noise and note, you may use "M" followed by a number between 1 and 63. You can work out which number to use from this table...

Tone channels Noise channels
Number 1 2 4 8 16 32

Write down the numbers corresponding to the effects you want, and then add them together. If you wanted A to be noise, B to be tone, and C to be both tone and noise, then add 8, 2, 4 and 32 to get 46 (the order of the channels is the order of the strings which follow the PLAY command). The best effects can be obtained with the A channel - don't be afraid to experiment.

By now, you'll be writing symphonies! However, it can be difficult to work out just which part of the music a particular section of string is responsible for. To alleviate this problem, your music string may include 'comments' enclosed between ! exclamation marks. For example...

1090 LET z$="CDcE3Ge4_6f! end of 75th bar !egeA"

The PLAY command will simply 'hop over' any comments in the string.

If you have an electronic musical instrument with MIDI, then the +3 can control it using PLAY. Up to 8 channels of music can be sent to synthesisers, drum machines or sequencers. The PLAY command is constructed exactly as described so far in this section, except that each string should include a "Y" followed by a number between 1 and 16. The number after the Y controls which channel the music data is assigned to. Up to eight strings can be used; the first three strings will still be played through the TV as before so you'll probably want to turn the TV sound down. You can also send MIDI programming codes via the PLAY command, using "Z" followed by the code number. Key velocities (loudness) are calculated and sent at 8 times the V setting (so "V6" will send 48 as a key velocity).

So, to send a little tune (in four-part harmony) to a four-voice synthesiser (after consulting your synth's handbook to find out how to allocate MIDI channels to different voices), you would use the PLAY command with four strings, each starting with Y followed by a number. This example program illustrates the PLAY command in some of its full glory...

10 LET a$="Y1T100O2(((1CCg$b))(($E$E$b$D))((FFC$E))((GGDF))))"
20 LET b$="Y2O5N&&&&C$bfG)"
30 LET c$="Y3O4((3C&)C&1CCDD(3$E&)$E&1$E$EEE(3F&)F&1FF$G$G(3G&)G&1GG$EC))"
40 LET d$="Y4N9&&&&&&&&(9EGF7b5CD))"
50 PLAY a$,b$,c$,d$

Summary table

Finally, here is a brief list of the parameters that can be used in the string of a PLAY command, together with the values they may have...

Specifies the pitch of the note within the current octave range.
$ Specifies that the note which follows must be flattened.
# Specifies that the note which follows must be sharpened.
O Specifies the octave number to be used (followed by 0 to 8).
1...12 Specifies the length of notes to be used.
& Specifies that a rest is to be played.
_ Specifies that a tied note is to be played.
N Separates two numbers.
V Specifies the volume to be used (followed by 0 to 15).
W Specifies the volume effect is to be used in a string.
U Specifies that the volume effect is to be used in a string.
X Specifies duration of volume effect (followed by 0 to 65535).
T Specifies tempo of music (followed by 60 to 240).
() Specifies that enclosed phrase must be repeated.
! ! Specifies that enclosed comment is to be skipped over.
H Specifies that the PLAY command must stop.
M Specifies the channel(s) to be used (followed by 1 to 63).
Y Specifies that MIDI channel is to be used (followed by 1 to 16).
Z Specifies MIDI programming code (followed by code number).

Part 20
File operations

Subjects covered...


The +3 has a built-in disk drive that can be used to save and load your own programs, and to load programs produced by other people. As it is also possible to connect a second disk drive to the +3, BASIC must have some way of identifying which disk drive is which. The built-in drive is known as drive A: (always followed by a colon because +3 BASIC knows that when you say A:, you mean 'disk drive A'). If the external drive is present, it is referred to as drive B:.

As the processor at the heart of the +3 can only converse with 64K of memory at a time, the extra RAM in the +3's 128K memory is used just like another drive. This is called the RAMdisk and is identified by the letter M: (for memory drive). All the commands (except FORMAT) that you can use on drives A: and B: can also be used on drive M:. Drive M: is much faster than the mechanical disk drives, but it is very important to remember that just like the contents of the program memory, the contents of drive M: are erased if you press the RESET button or switch off the +3. BASIC's NEW command, however, will leave any files stored on drive M: intact.

If you don't have a second disk drive connected to your +3, you can still use the machine as if drive B: were present. If you ask the machine to perform an operation on drive B: (you'll see how to do this later), a message will appear asking you to...

Please put the disk for B: into
the drive then press any key

...whereupon you should put the disk that you would have used in drive B: (if it had existed) into drive A: then press any key (for example ENTER). From then on, the machine will treat the built-in disk drive as if it really were drive B:. When the +3 next needs to perform some operation on the disk that was originally in the drive, it will ask you to...

Please put the disk for A: into
the drive then press any key

This technique will be particularly useful when using the COPY command (described later in this section).

Now that you know which drives are available and what they are called, let's see what they can be used for. Type in the short program (which displays coloured squares) that you first met at the end of part 16, ie...

10 POKE 22527+ RND *704, RND *127
20 GO TO 10

This is the program that you are going to save to disk.

As previously explained (in chapter 6, you cannot simply unwrap a brand new disk and hope to save programs onto it straight away; it must first be made ready to use with the aid of the FORMAT command. FORMAT will erase anything that was previously on the disk and set it up for +3 BASIC to use. Be careful, therefore, not to FORMAT any disk that has programs on it you might like to keep. To format your new disk, type in the following...


If you haven't already put your new disk into the drive, don't worry - the +3 will just come back with the error report Drive not ready.

In this case, put your new disk into drive A: and re-type the command.

By the way, while you are using the various disk commands you may occasionally see the report Drive A: not ready (possibly followed by - Retry, Ignore or Cancel ?). This invariably means that you have forgotten to put a disk into the drive.

Whenever a report appears that ends with - Retry, Ignore or Cancel ?, there are three options open to you.

The first is to take action to rectify the problem, for example, if the report was Drive not ready, then put a disk into the drive and type R (to retry). The disk system will then try to carry out the same operation again and hopefully this time it will succeed.

If you were half way through copying a large file and an error such as Missing address mark appeared, this would usually mean that the disk being read has been damaged in some way. Try R a few times and if the error persists, you indeed have a damaged disk. At this stage, you'll probably want to salvage any un-damaged data, so try typing I (to ignore). Although this tells the +3's disk system to ignore the error, there is no guarantee that all your data will be read intact - it's really just a last ditch operation when all else has failed.

Finally, if you have tried to perform an operation where an error occurs, you may realise that there is no point in trying to go on. In this case type C (to cancel) which tells the +3's disk system to abandon the current command. Having typed C, BASIC will report an error (usually very similar to the text of the previous report.

Back to out attempt to format a disk. If you have made a mistake and the disk you put into drive A: has already been formatted, the +3 will spot this and you will receive the report...

Disk is already formatted,
A to abandon, other key continue

This is a safety feature that will allow you to abandon the format before the process gets going, if, by some chance, you inserted the wrong disk. In this case, you should type A (to abandon) and nothing more will happen. If, however, you really do intend to reformat the disk and don't mind losing what's on it, then press any key apart from A (eg. press ENTER).

After about 30 seconds, the usual 0 OK report will appear. The disk is now usable and should not need to be formatted again. You can always reformat a disk if you wish to clear the disk of data completely, but remember that it is an irreversible process.

Disks can occasionally become spoilt (corrupted). This can happen if some dust or dirt comes into contact with the disk surface, if the disk is left too close to a magnetic field (such as that produced by a TV or a telephone), if the disk is ejected while it is being written to, or if the disk is left in the drive when the computer is switched on or off. A corrupted disk will cause errors during LOAD or SAVE, and should be reformatted before any more data is saved onto it.

If you want to recover files from a corrupted disk, you can try to copy them individually (using COPY) to a known 'good' disk. If one or more files prove uncopiable, then you have probably lost them for good. We recommend that you keep at least two copies of important files (on different disks) - one for day-to-day use, and one kept in a safe place just in case the unthinkable happens. Making regular copies of valuable data and programs is known as backing-up, and is an essential habit to get into. Backing-up can save you untold misery and tears. You can of course make back-ups onto tape, which may prove cheaper in the long run.

Unlike many computers, the FORMAT command is built-in and can be used like any other BASIC command. It doesn't affect the program you have in the computer, so you can save the little two-line program you typed in a moment ago.

Type in the following...

SAVE "squares"

The words SQUARES is just a name that you use to 'label' the program you are going to store on disk. To prevent confusion, everything stored on disk must be given a name. These names (called filenames) are a little different from those that you may use when storing programs on tape.


The range of characters that you are allowed to use for disk filenames is more limited than for tape filenames. The format of filenames used on +3 disks is the same as that used by an operating system known as CP/M (Control Program/Monitor) by Digital Research Inc. The fact that these formats are the same means that you can take a +3 disk and use it on other computers. Data can be transferred in this way between the +3 and a CP/M system, and this is most likely to be useful for people writing machine code programs or moving text from a +3 word processor to a CP/M program. (It is extremely unlikely that programs written in BASIC can be usefully converted from one machine to another using this method.)

Filenames can be as simple as the example above - SQUARES (or even simpler - S, for example). However a full CP/M-type filename can be made up of as many as four parts: user number, drive letter, name and type. Each of these parts is called a field (eg. the name field or the type field).

You needn't worry about what user number means; if you don't know already, then it's probably best to remain blissfully ignorant. However, for anyone who is interested: on CP/M machines with very large disk capacities (or hard disks) with perhaps more than one terminal connected, user numbers are used to partition files into subsections (known as user areas) so that there isn't just one huge directory with several thousand files. On the +3, however, disks cannot have more than 64 files, so the use of user areas is not really necessary. Nevertheless, user areas can be specified in filenames used in +3 disk commands. They take the form...

...where user number is in the range 0 to 15, and drive letter is A:, B: or M:. If you specify a user number, then you must also specify a drive letter. So, to save our example program in user area 5, we would use...

SAVE "5a:squares"

The problem with using user areas is that it's quite easy to forget which user area you saved a file to, and so finding it could take a while (as the CAT command can only catalog one user area at a time).

As just mentioned, the drive letter will normally be A:, B: or M:. notice that the letter must be followed by a colon (eg. 'a:squares'). If you don't specify a drive letter, then +3 BASIC will use the drive that was last used - this is known as the default drive. (When you first switch on the +3, the default drive is set to A:.) So typing...

SAVE "squares" just as if you had typed...

SAVE "a:squares"

There are special forms of SAVE and LOAD which can be used to change the default drive. When SAVE or LOAD is followed by a filename that contains nothing but a drive letter and a colon, the drive identified by the letter is then made the new default drive. So...

SAVE "m:"
SAVE "squares"

...will change the default drive to drive M: then save the program onto drive M:. (If the above command had been 'SAVE "m:squares"' the program would still have been saved to drive M: though the default drive would not have been changed.)

To switch the default back to drive A:, type...

SAVE "a:"

Note that SAVE and LOAD followed by just a drive letter (and colon) wildcard will do nothing other than change the default drive. They certainly won't save or load a program. You must use SAVE or LOAD followed by a real filename for this.

The name field of a filename is the only field that you have to specify when using SAVE, LOAD, etc. The name field can be from 1 to 8 characters long and may contain any of the following:

Upper and lower case letters are the same in filenames, so EXAMPLE and example would be identical.

A filename can end with an optional type field (which is just a further three characters) that you may wish to use in order to group together files of the same type. If a type field is specified, it must be preceded by a dot. (Unlike some other BASICs, +3 BASIC does not automatically allocate a type field to files if one is not specified.) You may find it useful to add your own type fields - a popular convention is to use the type fields .BAS to identify BASIC files and .BIN to identify CODE files (.BIN being short for binary). If you think this is a good idea, then the previous example program could be saved using...

SAVE "squares.bas"

The characters * and ? have a special meaning to +3 BASIC, and cannot be used in a filename for LOAD and SAVE. There are, however, file commands in which * and ? can be used, and these will be discussed later.

Here are some examples of valid filenames...


Here are some illegal filenames (and reasons why)...

Disk catalog

You may have spotted the fact that we have now saved the same program twice with two different names (SQUARES and SQUARES.BAS). It would be nice to be able to check what has been saved on a particular disk, and this is where the CAT command comes in. CAT displays a catalog of what you have stored on a disk.

Press ENTER then type in...


The +3 will take a quick look at the disk (the read/write indicator lamp will come on briefly), and will display a list of the disk's contents on the screen. The list is sorted into alphanumerical order and each file is followed by an indication of its size to the nearest number of kilobytes (rounded up). At the end of the list, the amount of free space on the disk is also displayed.

CAT (on its own) is the simplest form of the command. If you wanted to list all the files on a different drive (eg. drive M:), you would use...

CAT "m:"

When CAT is followed by a filename containing just a drive letter, ie. A:, B: or M: (including the colon), all the files on the nominated drive will be listed. CAT on its own gave a list of the files on drive A:, this is because A: is the current default drive. You will remember that LOAD or SAVE followed by a drive letter will make that drive the current default. So...

LOAD "m:"

...will also list all the files on drive M:. This isn't quite the same as 'CAT "m:"', because now the default drive has been left as M:. Change it back to A: before going further.

We will now save several copies of our simple example program using different names, so that you will be able to see what the various forms of the CAT command will produce. So far the disk should contains SQUARES and SQUARES.BAS. If either of these weren't listed with the above CAT command, add their name to the list below. Type the following...

SAVE "fred"
SAVE "fat"
SAVE "santa.bin"
SAVE "trepur.bak"
SAVE "cliff.cjl"
SAVE "sausages.bas"

Don't worry about cluttering up the disk with lots of copies of the same thing - you'll be shown how files can be erased later.


If a disk has a large number of files, it is often desirable to selectively list only those of interest. The +3 caters for this. If, for example, you wished to list only those files that ended in .BAS you would use:

CAT "*.bas"

The asterisk character * is what's known as a wildcard. When a filename, perhaps containing a wildcard, is specified, CAT will list only the files that match the 'specification' given. When the * wildcard is used (in either the name field or the type field) it means 'any character from here to the end of this field'. So, in the above command, we want CAT to display any files that have any characters in their name field and the letters 'BAS' in their type field. If there are no files on the disk that match the specification, the report No files found will be displayed (followed by the amount of free space). If you give a file specification of *.* (ie. CAT "*.*") or no specification at all, (ie. CAT) and the report No files found is displayed, then this means that the disk is empty. An empty disk in drive A: or B: will have a free space value of 173K (this value may be different for disks from other types of computer). An empty drive M: will usually have 58K free. If you catalog a disk containing a commercial program (such as a game), it might appear to have no files on it but very little space free. This is a protection measure taken by the software writers to prevent illicit copying, and shouldn't cause any concern.

If we use...

CAT "s*.bas"

...then all files that begin with the letter S and then have any characters whatsoever between the S and the end of the name field, followed by a type field of BAS, will be shown. Files with the names SQUARES.BAS, SAUSAGE.BAS, SUPER.BAS would all be listed, but SQUARES.BIN, TOAST.BAS and SQUARES would not.

The * wildcard can also be used in the type field of a filename (note, however, that you cannot use it in place of the user number or drive letter). If we wanted to list all files that had SQUARES as their name field and anything as their type field, we would use...

CAT "squares.*"

Similarly, if we wanted to list all the files that began with a letter S and had a type field that began with the letter B we would use...

CAT "s*.b*"

When we type CAT (on its own), we want to list all files on a disk. Therefore, CAT is just a shorthand way of saying...

CAT "*.*"

From the above you will notice that the * wildcard can only be used as the last character in a field, and it is used to mean 'I don't care what other characters are present between here and the end of this field'. Sometimes, however, you may want to specify a group of files but need to be a little more discerning. This is when you use the ? question mark wildcard (in either the name field or the type field). The ? wildcard means 'I don't mind what character happens to be in this specific position'.

Therefore, if we used the command...

CAT "?at"

...then the files listed would be all those that are three characters long, ending in AT, but we don't mind what character is in the first position. Thus files such as CAT, SAT, MAT and FAT would be listed, but CAR, CATTLE and AT would not. Unlike the * , ? wildcards can be used in place of any of the 8 characters of the name field and the 3 characters of the type field. There is no limit to the number of question marks you can use (other than the 8 and 3 limits of the filename field lengths).

Valid file specifications containing ? wildcards include...

If you have a printer connected to your +3, you may find it useful to print-out the files listed by CAT. You can do this by directing the output from CAT to stream 3 (streams are explained in part 22 of this chapter). The command to do this is...

CAT #3

If you only want some of the files printed-out, you can also include a file specification in exactly the same way as before. For example...

CAT #3,"a:*.bas"

(The above CAT #3 commands will not work unless a printer is connected to the +3 and is on line. To abandon, press BREAK.)

Any form of the CAT command may also end with the word EXP, for example, CAT "a:" EXP. The EXP is short for expanded, and as the name might suggest, gives you a little more information about the attributes of the files on a disk. Not only will the expanded catalog display system files but also it will indicate whether files are set to write protected mode, archive mode or system status (these terms are explained in the section ahead entitled 'File attributes').

(There is one other specialist use for the CAT command, and this will be dealt with in the section ahead entitled 'Tape catalog'.

Now that you have successfully saved a program to drive A:, you can happily switch off or reset the +3, or start a NEW program, knowing that you could always load in the saved program if you needed it. Remember - there is a difference between resetting the +3 and using the NEW command - if you reset, all the +3's memory (RAM) will be cleared. This includes any files you may have saved on drive M:. When you use NEW, however, any files on drive M: will remain intact. As we have saved the program on the disk in drive A:, you can go ahead and press the RESET button, then release it. The usual opening menu will be displayed. Select +3 BASIC then type the command...

LOAD "squares"

The LOAD command reads in a new program (and variables) from disk, and then deletes any program (and variables) previously in the memory. (If the program that you specified to load is not on the disk, then any program currently in the memory is not deleted.) Just like SAVE, the LOAD command must be given a filename whose name field is at least one character long. If you have been used to a tape machine in the past, then you may have used LOAD ""' to mean 'load the next program on the tape'. The concept of a 'next program' on disk does not exist, so if you don't specify a filename, the disk system won't know what to load and will report an error. If you can't remember what name you saved a file under, use CAT to check what's on the disk (this is why it's a good idea to save programs on disk using 'mnemonic' names (names that remind you what they contain) - eg. it is more obvious what sort of program a file named TENNIS.BAS contains compared to one simply named T).

There is a short cut for loading programs (such as games) that have been specially set up - you can select the Loader option from the opening menu. This option, when selected, attempts to load and run programs. First of all, it looks for a program called * on the disk. If this exists, then it will be loaded and run. The program has to be a machine code program saved in a particular fashion (as BASIC can't use * as a filename for SAVE), and is, therefore, only for use on commercial software or by those who understand machine code.

If * can't be found, the +3 will then look for a file called DISK. This can be a BASIC program that you've previously written and saved, so if the Loader option finds a program called DISK, it will load it and wait for the next operation.

At this point, pressing ENTER will just load the program again.

If you wish to run or edit the program after it has loaded, first press the cursor down key once, then ENTER. This selects the +3 BASIC option from the opening menu.

If there isn't a program called DISK on the disk (or if the +3 detects that there isn't a disk in the disk drive), then the computer will try to load a program from tape, displaying the message...

Insert tape and press PLAY
To cancel - press BREAK twice

This is the recommended method for loading Spectrum +3 (Spectrum +2 and Spectrum 128) software from tape (see chapter 4.

As previously mentioned, LOAD deletes the old program and variables in the +3 whenever it loads in the new ones from disk. However, there is another command - MERGE, which is similar to LOAD but it only deletes an old program line or variable if there is a new one with the same line number or name. Clear the program memory using the NEW command, then type in the 'dice' program from part 11 of this chapter and SAVE it onto disk, using...

SAVE "dice"

Use NEW to clear the program memory again, then enter and run the following program...

 1 PRINT 1
 2 PRINT 2
10 PRINT 10
20 LET x=20

Now type in...

MERGE "dice"

If you then LIST the program, you will see that lines 1 and 2 have survived, but lines 10 and 20 have been overwritten by those from the dice program. Note that the value of the variable x has also survived (try PRINT x).

You have now seen simple forms of five of the commands that work in conjunction with disk:

A variant on SAVE takes the form...

SAVE filename LINE number

A program which is saved using this command, is stored in such a way that when it is loaded, it automatically jumps to the line with the given number, then runs itself.

Use NEW to clear the program memory then type in the following...

10 PRINT "program running"
20 PLAY "cdefgabC"

Now save this program using the command...

SAVE "disk" LINE 10

Now reset the +3, and when the main menu appears, ensure that the disk (with the above program on it) is in the drive then press the ENTER key. This will select the Loader option which searches for a file on the disk called DISK. When it finds the simple example program you just saved, it will load it, and as it was saved using a LINE parameter, it will automatically start running (from line 10).

At this point, pressing ENTER will load and run the program again.

If you wish to edit the program after it has run, press the cursor down key once, then ENTER. This selects the +3 BASIC option from the opening menu.

Note that if you load a program called DISK which doesn't automatically run (using the Loader option from the opening menu), then you will have to select the +3 BASIC option (after the program has loaded) before you can run it or edit it.

So far, the only kinds of information we have stored on disk have been programs (together with their variables). There are also two other kinds of information, called arrays and bytes.

You can save arrays on disk using the keyword DATA in a SAVE statement...

...where filename is the name that the information will have on disk and works in exactly the same way as when you save a program.

The array name specified the array you want to save, so it is just a letter (or a letter followed by $). Remember to put the brackets () after the array name.

Be clear about the separate roles of filename and array name. If you say (for instance)...

SAVE "bloggs" DATA b ()

...then SAVE takes the array b() from the computer and stores it on disk under the name BLOGGS.

The command...

LOAD "bloggs" DATA b ()

...sees if it is possible to load the array (ie. if there is room for it in the computer), then if so, deletes any already existing array called b() and loads in the array BLOGGS from disk, calling it b() in the computer.

You cannot use MERGE with saved arrays.

You can save character (string) arrays in exactly the same way. However, note that when you load in a character array, it will delete not only any previous character array with the same name, but also any simple string variable with the same name.

When dealing with a large amount of data you may find it useful to use the SAVE...DATA option and the LOAD...DATA option to and from drive M:. Once saved on drive M: the space previously used by an array can be re-used. Using drive M: will mean that saving and loading are very fast.

Byte storage is used for pieces of information without any reference to what the information is used for - it could be a screen display, or perhaps some user-defined graphics, or just something you have made up for yourself. It is specified using the word CODE, as in...

SAVE "picture.bin" CODE 16384,6912

The unit of storage in memory is the byte (a number between 0 and 255), and each byte has an address (which is a number between 0 and 65535). The first number after CODE is the address of the first byte to be stored on disk; the second number is the amount of bytes to be stored. In our case, 16384 is the address of the first byte in the file (which contains the screen display), and 6912 is the amount of bytes in it, so we are saving an actual copy of the screen display onto disk. Try the above SAVE command. (You don't have to save the bytes using the name PICTURE.BIN - it's merely a convenient reminder of what's on the disk.)

To load it back, use...

LOAD "picture.bin" CODE

You can put parameters after CODE in the form...

LOAD filename CODE start,length

Here, the length parameter is used as a safety measure - when the computer attempts to load the bytes from disk, it will check the length and refuse to load the bytes if there are more than specified (thereby safeguarding against the extra bytes accidentally overwriting an area of memory that you wished to preserve). In such a case, the report Code length error is displayed. (Anyone using a cassette unit under 48 BASIC should note that the above error will display a different report: R Tape loading error.

If you leave out the length parameter, the +3 will read in the bytes however many there are.

The start parameter shows the address where the first byte is to be loaded back to - this can be different from the address it was saved from, though if they are the same, then you can leave out the start parameter in the LOAD statement.

CODE 16384,6912 is such a useful area of memory (the screen display) to save and load, that a special function (SCREEN$) has been provided to represent it, so you can type (for example)...

SAVE "picture.bin" SCREEN$


LOAD "picture.bin" SCREEN$

Automatic back-ups

If you have saved one or two things on a disk and then you save something with a filename that has already been used, what will happen? Well, each time you save a program, the disk system checks to see if the filename you specify has already been used. If it has, the existing copy on disk is given a new filename before the information you have asked to save is stored. The new name given to the existing file has the same name field but its type field will always be .BAK (short for backup).

If a .BAK version of the file already exists, then that will be lost in preference to the new .BAK file. This means that as you save successive versions of a program with the same name the previous copy will still be there in a file called filename .BAK. So, if you make a serious programming error and inadvertently save the program, you can delete the newest version and rename the .BAK file to the original filename. The next section shows you how to do this; but first, type...

SAVE "a:squares" save the program using the filename SQUARES yet again.

Deleting and renaming files

Files can be deleted from a disk using the ERASE command. This should be followed by a filename that specifies which file or files are to be deleted. Just like CAT, you can use the wildcards * and ? to identify a group of files, or you can specify the name in full if you only want to get rid of one particular file. If you specify a single filename, that file will immediately be erased from the disk - so take care. If you specify a group of files (by including * or ?), BASIC will ask you to confirm that you really mean to delete this group of files. Typing Y will make the deletion process continue, so if you have made a mistake, type N.

If, for example, you wanted to delete a file from drive M: called FRED.BAS, you would use...

ERASE "m:fred.bas"

If drive M: has already been set as the default drive, then you don't need to include the M: at the start of the filename. It doesn't hurt to include the drive letter anyway, and with as powerful a command as ERASE, you might feel safer if you do. To erase all the files on drive B: you would use...

ERASE "b:*.*"

Before doing this, BASIC will ask for confirmation...

Erase b:*.* ? (Y/N)

...and assuming that you really mean to wipe all the files from the disk in drive B:, you would then type Y.

If you ask to delete a single file (or a group of files using the wildcards * and ?) and there are no files on the disk that match the specification, then the report File not found will be displayed.

Note that ERASE followed by just a drive letter (eg. ERASE "m:") will erase all files on the specified drive without asking for confirmation. Be careful, therefore, not to enter this form of the command unless you really mean to delete everything! (The ERASE process will stop and report an error if a write protected disk or file is detected.)

The disk you have been using up to now has many copies of the simple SQUARES program (saved under different names) on it. This is a waste of space so you might as well erase those that aren't needed. What you want to do in effect is erase everything except SQUARES (though there is no simple way to do this). However, some of the different files have the same letters in common, so you may be able to use various forms of * and ? specifications to cur down the amount of typing. See if you can work out the fewest number of ERASE commands to erase all files other than SQUARES.

Once a file has been saved, it can be given a new names using the MOVE command. For example, if there is a file on drive M: called SQUARES that you would like to call BLOCKS, its name could be changed as follows (first we make sure there is a file called SQUARES on drive M:). Type...

SAVE "m:squares"
MOVE "m:squares" TO "m:blocks"
CAT "m:"

Imagine we have saved a file called FRED, and then after working on it and saving a new version with the same name, realised that we had made a terrible mistake and would like to recover the last version. This would be possible using the commands...

ERASE "fred"
MOVE "fred.bak" TO "fred"

Unlike ERASE, you cannot include the wildcards * or ? when renaming files.

MOVE will take into account the current default drive so the filename doesn't necessarily have to contain a drive letter. Note, however, that it is not possible to use MOVE to rename files between different drives. The command...

MOVE "a:fred" TO "b:eric"

...(for example) will fail with the error No rename between drives reported. Instead, you can use the COPY command (explained ahead) followed by ERASE to achieve the desired result.

File attributes

MOVE has another use besides renaming files. It can also be used to change the attributes of a file. Attributes are bits of information associated with a file that tell you (and the computer) a little more about it.

There are three attributes that can be changed. The most useful attribute is write protection. Once a file's write protection attribute has been set, it will not be possible to erase it (or save a file with the same name) until you remove the write protection. It behaves a little like the write protect hole on the disk, but works just on individual files. Unlike the write protect hole, however, it offers no protection against FORMAT, which erases everything on a disk, regardless of attributes. You can set a file's write protection attribute to on with a command such as...

MOVE "squares" to "+p"

The letter P is short for protection (against overwriting). If you now try to use the command...

ERASE "squares" will receive an error report saying File is read only.

To switch write protection off, use...

MOVE "squares" TO "-p"

...and you'll be able to erase the file as before.

In all the MOVE commands that change attributes, + means switch it on, and - means switch it off.

When you are using MOVE to change attributes, the filename can include the wildcards * and ?. So, to make all the files on drive M: write protected, you would use...

MOVE "m:*.*" to "+p"

As always, the drive letter can be omitted if it is the current default drive.

You can repeatedly switch attributes on or off without causing an error, so if you set write protect on a file that has already got write protection, it will just stay protected.

The second attribute that can be changed is known as the system status attribute. This is really provided just to be compatible with other CP/M based computers, however, if you do set a file's system attribute to on, then you will notice that the file no longer appears in the list of files when you use CAT. The system status attribute is identified by +S (or -S) in the MOVE command. If you use the expanded catalog, (ie. CAT EXP), all the files will then be listed including system status files (which are followed by the letters SYS). You may also notice that any files that are write protected are followed by the letters PROT. You can use the system attribute to remove files from a catalog if they would otherwise just clutter things up.

Bear in mind that you cannot have two files on the same disk with the same filename and different system status attributes; so if you try to create or copy a file onto a disk where a file of that already exists (but is hidden from CAT), then the previous file will be deleted.

The final attribute you can change is known as the archive attribute. In an expanded catalog it shows up as ARC, and is identified by +A (or -A) in the MOVE command. On the +3, the archive attribute is of no practical use and is only provided for file compatibility with CP/M based computers.

Here are some attribute-setting MOVE commands. See if you can predict what they will do...

MOVE "*.*" TO "+p"
MOVE "*.bas" TO "-s"
MOVE "s???.*" TO "+a"
MOVE "m:?.?" TO "-p"

If you try to use any letter other than A, S or P in setting or resetting attributes, or if the 'attribute string' is not two characters long, then you will receive the report Invalid attribute.

Quite often, a situation will arise when you would like to make a copy of one of your files, (to give to a friend perhaps, or to put it on drive M: so that it can be accessed quicker). The COPY command can be used to copy from one drive to another and even to make complete copies of disks. The very simplest form of the COPY command will look something like this...

COPY "a:fred" TO "m:"

This means, put a copy of the contents of the file called FRED (which is presently on drive A:) onto drive M:. As no destination name has been specified (after M:), the new file will also be called FRED.

The name before the word TO is known as the source filename, and the name after TO is the destination filename.

The command...

COPY "fred" TO "eric"

...will take the contents of a file called FRED on the default drive and copy it to a file called ERIC, also on the default drive. The files FRED and ERIC then contain the same information.

You cannot copy one file to another with the same name and on the same drive. Trying to do so will result in the error report File already exists (or possibly File already in use).

The source filename for copying from can include the wildcards * and ?, however, in this case the destination filename has to be just a drive letter. So, for example...

COPY "a:*.ovl" TO "m:"

...will work (assuming that there are some files on drive A: that match this specification), and transfers all files on A: with a .OVL type field onto drive M:. However, the command...

COPY "a:*.bas" TO "m:*.bin"

...will fail with the error report Destination cannot be wild.

The COPY command does not copy any attribute information associated with a file; you have to set any attributes you require on the new file after copying.

COPY will always list the files it is copying in two columns. This will allow you to check that any wildcard specification you use encompasses all the files that you were intending to copy.

After copying, a report will appear to let you know many files were copied. (If you were copying a group of files, this may be useful to check that you have indeed copied all the files you intended to.)

There is a special format of the COPY command as follows...

COPY "a:" TO "b:"

...which will perform a complete 'sector by sector' copy of the disk in drive A: to an already formatted disk in drive B:. Anything already stored on the disk in drive B: will be lost - so, if there are only a few files on the source disk to be copied, it may be quicker to use...

COPY "a:*.*" TO "b:"

Even if you have only one drive (A:), you can use the fact that the single mechanism can be used as if it were drive A: or drive B:. For example, suppose you have a single drive system and want to copy a couple of files (that both end in .BAS) from one disk to another. Put the source disk in the drive and type...

COPY "a:*.bas" to "b:"

Once the +3 has read part of the first file that ends in .BAS, it will ask you to...

Please put in the disk for B: into
the drive then press any key

Simply follow this instruction. After the +3 has written the information onto the 'drive B:' disk, it will ask you to...

Please put in the disk for A: into
the drive then press any key

This process of swapping between disks will go on until all files have been copied. Because the COPY command will try to use any free space on drive M:, it is a good idea to clear drive M: (if possible) before doing a lot of copying (as this can reduce the number of disk swaps needed).

As well as copying files between drives, COPY can also be used to copy files to the screen or to a printer (if connected). The command...

COPY "words.txt" TO SCREEN$

...will display the contents of a file on the default drive called WORDS.TXT. Any control characters (except carriage returns) will be filtered out. This command cannot really be used to look at BASIC program files as they contain various control codes. Its main use will be to inspect the contents of ASCII text files, such as those produced by a word processor.

The command...

COPY "words.txt" TO LPRINT similar to the above, but this time the contents of the file will be sent to the printer. In this case, however, control codes will be sent to the printer. If you have set the print output to be via the RS232 with tokens unexpanded (using FORMAT LPRINT "R";"U"), then this command can be used to 'export' files to other computers. Once again, this command cannot be used for BASIC programs - it is intended for sending ASCII text files only.

People writing machine code programs may find it easier to do so on a larger development machine. However, the files produced by this method will probably not be recognised by the +3, as BASIC expects to find a 128 byte header at the start of each file which contains information used by the LOAD command. However, once a binary file has been produced on a +3 formatted disk, it can have a header of the correct type put on it using a command such as...


This will produce a new file on the same drive, having the same name field but with a type field of .HED (short for headed). In the above example, a new file called GAME.HED will be created, and it will be written to the default drive (as no drive letter was specified).

Obviously this command will only be of use for machine code files. Headed files produced in this way will have the length part in their header set to the correct value and the type part set to be a CODE file. However, BASIC cannot know what address the file should be loaded to, so the load address should be specified when the LOAD...CODE command is used. For example, if the above program had been assembled to execute at 7000h (the 'h' denotes a hexadecimal number) or 28672 decimal, then the headed file could be loaded with the command...

LOAD "game.hed" CODE 28672

As SCREEN$ files are just another type of CODE file, this technique can be used to 'import' screens designed on another machine, though they obviously wouldn't make much sense unless they had been tailored to fit the +3's size and layout.

The RAMdisk

You may have been wondering what point there is in storing information in the RAMdisk (drive M:) as it will be lost once the +3 is switched off. Well, perhaps the most obvious use of drive M: is to store chunks of BASIC program (or routines) which can be merged (using MERGE M:filename) into a smaller program, in sequence. This makes it possible to write about 90K of BASIC program, and hold it in the +3 (though to do this, the program structure has to be well defined).

You can keep the various routines on a 3 inch disk and use COPY to put them into drive M: before you run the program. The benefit of doing this is that drive M: is much quicker to access than the mechanical drives (A: and B:). The mechanical drives, however, can hold much more data, so you might like to evolve a system using both disk and RAMdisk. Careful design and planning will repay itself many times over it terms of speed and performance.

One of the more interesting uses of the RAMdisk is in animation, where a series of pictures can be defined by a 'slow' BASIC program, stored in drive M:, then called back to the screen at high speed. The following program offers a taste of this. Doubtless you can do better...

 20 FOR f=1 TO 10
 30 CIRCLE f*20,150,f
 40 SAVE "m:ball"+ STR$ (f) CODE 16384,2048
 50 CLS
 60 NEXT f
 70 FOR f=1 TO 10
 80 LOAD "m:ball"+ STR$ (f) CODE
 90 NEXT f
100 BEEP 0.01, 0.01
110 FOR f=9 TO 2 STEP -1
120 LOAD "m:ball"+ STR$ (f) CODE
130 NEXT f
140 BEEP 0.01, 0.01
150 GO TO 70

Before running the program, always make sure that drive M: is empty. If it isn't, first type ERASE "m:*.*" (typing Y at the (Y/N) prompt), then RUN.

Note that in line 40 of this program, the two numbers following CODE are the address in memory of the start of the screen (16384) and the length of the top third of it (2048). By saving and loading only the top third, the overall speed is maintained.

Tape operations

(See chapter 10 (Peripherals for your +3) for details on how to connect a cassette unit to your +3.)

Much of what has been said in this section about the use of LOAD, SAVE and MERGE on disk will apply equally to tape (if you have connected a cassette unit to the +3). However, the commands FORMAT, COPY, MOVE, CAT and ERASE do not apply on tape (although there is a special form of CAT that can be used - described in the section ahead entitled 'Tape catalog').

As you will already know, when you first switch on the +3, the default drive for all file operations is set to drive A:. This means that if you use CAT, ERASE, LOAD, SAVE, etc. without specifying a drive letter, then +3 BASIC will perform the operation on drive A:. You will also know that the default disk can be changed using either...

LOAD "drive letter:"


SAVE "drive letter:"

...where drive letter is either A:, B: or M: (which must include the colon). In fact you can also use T: as a drive letter, but only in this one special form of the LOAD and SAVE command...

LOAD "t:"

After 'LOAD "t:"', all subsequent LOAD and MERGE operations are performed to tape (until changed back to disk by, for example, LOAD "a:"). Similarly, if you use...

SAVE "t:"

...then all future SAVE operations will be performed to tape (again, until changed back to disk by, for example, SAVE "a:". Unlike A:, B: or M:, when you use T: as the drive letter, it will change only future LOAD, SAVE and MERGE commands. The default drive used for MOVE, COPY, CAT and ERASE will stay the same as it was before (as these commands have no relevance to tape).

If all this sounds a little complicated, a few examples might help to make it a little clearer. Assuming you have just switched on (or reset) the +3, the default for all operations will be A:. So if you now type...

SAVE "m:"

...then the default drive for all subsequent operations will be set to drive M: (this is exactly the same as if the command LOAD "m:" had been used). Using the command...

LOAD "b:"

...will then set the default drive for all operations to drive B:. For this sort of thing, LOAD and SAVE operate in exactly the same way.

If we now use the command...

SAVE "t:"

...this will perform all future SAVE operations to tape, but all other commands will still default to drive B:. Using the command...

LOAD "t:"

...will also perform all future LOAD and MERGE operations to tape; however, the default drive for all disk-only commands will still be drive B:.

Finally, using the command...

SAVE "a:"

...will perform all future SAVE operations and all disk operations (except LOAD and MERGE) to drive A:. LOAD and MERGE will still be from tape, however.

Let's try to save our simple 'squares' program onto tape. Reset the +3 then type...

LOAD "squares"

This should load in the program that we saved earlier. If you press ENTER, the program will be listed as follows...

10 POKE 22527+ RND *704, RND *127
20 GO TO 10

This is the program that you are now going to save to tape. Any standard tape should work, although low noise tapes are preferable.

Type in the following...

SAVE "t:"
SAVE "squares"

This will save the program onto tape using the filename SQUARES. When saving files on tape, you are allowed up to ten characters in the name. Unlike disk, you can use any characters you like and the name can include spaces.

The +3 will display the message...

Press REC & PLAY, then any key.

We shall first go through a 'dry run' so that you can see what will happen when we actually do save the program later. This time, therefore, don't press REC and PLAY on your cassette unit - just press a key on the +3 (for example ENTER) and watch the border around the screen display. You will see patterns of coloured horizontal stripes as follows:

Five seconds of red and cyan stripes moving slowly upwards, followed by a very short burst of blue and yellow stripes.

A short pause.

Two seconds of the red and cyan stripes again, followed by another short burst of blue and yellow stripes.

While the stripes appear on the screen, you can also hear the 'sound' of the data through your TV's speaker.

Keep trying out the above SAVE command (without actually operating your cassette unit) until you can recognise these patterns. What's actually happening is that the information is being saved in two blocks and both blocks have a 'lead-in' (which corresponds to the red and cyan stripes) followed by the information itself (which corresponds to the blue and yellow stripes). The first block is a preliminary one containing the name and various other bits of information about the program, and the second is the program itself together with any variables present. The pause between them is just a gap. Now let's actually save the program onto tape:

  1. Wind the tape to an area that is either blank, or that you are prepared to overwrite.

  2. Type...

     SAVE "squares"
  3. Follow the instructions on the screen, ie....

     Press REC & PLAY, then any key.
  4. Watch the screen as before. When the +3 has finished (with the report 0 OK), stop the tape.

Whenever you save a program to tape, before clearing the saved program from the +3's memory, you should always make sure that the program was correctly saved. You can check the signal on the tape against the program in the memory using the VERIFY command (this command isn't used on disk, as disks are not prone to the same sorts of errors as tapes are):

  1. Rewind the tape to just before the point at which you saved the program.

  2. Type...

     VERIFY "squares"

Play the tape. The border will alternate between red and cyan until the +3 finds the program that you specified, then you will see the same pattern as you did when you saved the program. During the pause between the blocks, the message Program: squares will be displayed on the screen. (When the +3 is searching for something on tape, it displays the name of everything it comes across.) If, after the pattern has appeared, the +3 displays the report 0 OK, then your program is safely stored on tape and you can skip to the section ahead entitled 'Verified OK'. Otherwise, something has gone wrong - take the following steps to find out what.

If the program name has not been displayed, then either the program was not saved properly in the first place, or it was but was not 'read back' properly. You need to find out which. To see if it was saved properly, rewind the tape to just before the point at which you saved the program, then play it back while listening to the TV's speaker. The (red and cyan) lead-in should produce a clear, steady high pitched note, while the (blue and yellow) information part gives a much harsher screech.

If you do not hear these noises, then the program was probably not saved. Check that you were not trying to save the program onto the plastic leader at the beginning of the tape. When you have checked this, try saving again.

If you can hear the sounds as described, then SAVE was probably alright and your problem is with reading back.

It could be that you mistyped the program name when you saved it (in which case when the +3 finds the program it will display the mistyped name on the screen). On the other hand, perhaps you mistyped the program name when you verified it, in which case the +3 will ignore the correctly saved program and carry on looking for the wrong name, flashing red and cyan as it goes.

If there is a genuine mistake on the tape, then the +3 will display the report R Tape loading error which means in this case that it failed to verify the program. Note that a slight fault on the tape itself (which might be almost inaudible with music) can wreak havoc with a computer program. Try saving the program again, perhaps on a different part of the tape (or a different tape altogether).

Verified OK

Now let us suppose that you have saved the program and successfully verified it. Loading it back into the memory is just a matter of typing...

LOAD "squares"

(Since the program verified properly, you should have no problem loading it.)

LOAD deletes the old program (and variables) in the memory when it loads in the new one from tape.

Once a program has been loaded, the report 0 OK will appear. The program can then be run or edited.

As mentioned in chapter 4, it is possible to buy pre-recorded programs (software) on tape. They must be specially written for the ZX Spectrum range (ie. the Spectrum, the Spectrum +, the Spectrum 128, the Spectrum +2 or the Spectrum +3). Different makes and models of computer have different ways of storing programs, so they cannot use each other's tapes.

If your tape has more than one program stored on the same side, then each program will have a name. You can choose the program you wish to load using the LOAD command - for instance, if the one you want is called HELICOPTER, you could type...

LOAD "helicopter"

The command LOAD "" means 'load the first program that the +3 comes across on tape'. This can be very useful if you cannot remember the name that you saved the program under! (Remember that this only works on tape - normally you cannot specify a blank filename.)

When there is no disk in drive A: (or the disk contains no file called * or DISK), then the option Loader from the opening menu has the same action as LOAD "" from tape, and is much quicker to use - simply switch on (or reset) the +3 and press ENTER.

MERGE will operate in a similar way to that described for disk except, of course, that on tape you can use MERGE "" to mean 'merge the next file on tape'. Filenames in a MERGE command may conform to the less stringent limits for tape (ie. any combination of 10 characters including spaces).

If you have BASIC programs saved on tape (perhaps because you owned a previous Spectrum model), you will probably want to transfer them to disk to gain the advantage of faster loading. This should be relatively straightforward. Just use...

LOAD "t:"
SAVE "a:"

...then for each BASIC file on the tape, use...


...which will load the next file from the tape into the +3's program memory. Once loaded, the file can be saved out to disk using...

SAVE filename

Remember that files on disk must be given a filename which conforms to the limitations outlined at the beginning of this section.

If the BASIC programs have been saved with an automatic execution LINE, you will find that attempting to LOAD them will also run them. Obviously you don't want this so, for each program you wish to load, reset the computer, select +3 BASIC and type...


...(rather than LOAD "").

If you have saved data (numeric or string) arrays, it should be an equally simple matter to LOAD them into memory from tape, then SAVE them to disk.

The only file types that may cause difficulty when you want to transfer them from tape to disk are CODE (and SCREEN$) files. To be able to transfer a file of this type you need to know at least two things about it.

1. The address it was saved from.
2. How many bytes it contains.

Tape catalog

This is where the final form of the CAT command comes in. If the file specification given is simply T:, a special form of the CAT command comes into action. After you type...

CAT "t:"

...the +3 will wait for you to play a tape (the CAT "t:" operation can be abandoned by pressing BREAK). When the +3 finds a header on tape it will display the information (in the same form it was saved). This means that there will be a ten character filename in inverted commas. What follows the filename will depend upon the type of file - if it was a BASIC program, the word (BASIC) will be displayed. If a LINE parameter was specified when the file was saved, this will also be shown. If the file holds data, then the word DATA followed by the array name will be displayed, and finally, if the file was saved using CODE (or SCREEN$, which is really just CODE 16384,6912), the word CODE will be printed followed by the start address and length that were specified when the file was saved.

Here is a sample display resulting from a CAT "t:" command, which may make this a little clearer...

"simple    " (BASIC)
"execute   " LINE 10 (BASIC)
"numbers   " DATA f()
"words     " DATA c$()
"m/c       " CODE 30000,12345
"picture   " CODE 16384,6912

The last item was, in fact, saved using...

SAVE "picture" SCREEN$

Just like the other forms of CAT, its output can be directed to a printer using stream 3, ie...

CAT #3,"t:"

(Streams are explained in part 22 of this chapter.) Note that the above CAT #3,"t:" command will not work unless a printer is connected to the +3 and is on-line. To abandon, press BREAK.

From the above it can be seen that if you have loaded (using MERGE "") a program containing an execution LINE parameter, the CAT "t:" display will identify that line number for you. You may then wish to save that program to disk using... that the disk version of that program runs itself automatically.

It is the values for the CODE files that you will probably find most useful from the CAT "t:" display. Either note them down or print them out. Then rewind the tape so it just before the header that has been read. Type...

...where start is the value printed for the start address. Now type...


When the file has loaded into memory and the 0 OK report appears, the file can be saved to disk using...

This technique is only intended for transferring your own code files (where you may have forgotten what start and length values were used when you saved them). Note that using this method to copy commercial software may be a breach of copyright - check with the software author first.

There are several reasons why this simple scheme may not work:

  1. The code, when loaded would overwrite some of the system variables (in the range 23296 (5B00h) to 23755 (5CC6h)). This upper address limit may vary - it is the value held in the system variable PROG (see part 25 of this chapter).

  2. Attempting to load code that has no header (or that is protected in some other way) probably won't even produce any output from CAT "t:" and you certainly won't be able to use the BASIC LOAD command to load it.

  3. If the code file is so long that it stretches right from the screen display area to the end of memory, then it will be possible to load it, but as soon as it has loaded, the machine will crash. This is because BASIC will have 'lost' its stack.


  1. Practise the operations shown in this section until you are completely au fait with manipulating files to and from the disk, the RAMdisk, and cassette unit (if connected).

Part 21
Printer operations

Subjects covered...

The +3 comes with an 8-bit Centronics parallel port and an RS232 serial port. Both are supported by built-in software enabling you to use virtually any printer. These features are usable only in +3 BASIC mode.

The printer must have either a Centronics compatible (parallel) or an RS232 (serial) interface, and if you want to reproduce pictures of the screen, then the printer must have an Epson compatible quadruple-density bit-image graphics mode (ESC L n n).

Make sure you have the correct lead to connect the printer to the +3 - if in doubt, consult your Sinclair dealer.

For further information about which printer and connecting lead to purchase, together with details of the +3's PRINTER and RS232 socket connections, see chapter 10 (Peripherals for your +3).

Parallel printers

When the +3 is first switched on it will assume that, if a printer is present, it will be connected to the (parallel) PRINTER socket. The hardware connection between computer and printer is relatively straightforward - though you must make sure that you don't connect the cable the wrong way up at the computer end (if the cable doesn't have a locating 'key').

Once the connection has been made, the command...

LPRINT "hello"

...should produce some printed output. If not, check the connection and make sure that your printer is set to 'on line'.

Once you have got your printer to print, you may skip to the section ahead entitled 'General printing'.

Serial printers

Unlike parallel printers, the connections between the +3 and a serial (or RS232) printer will vary for different manufacturers' printers. Make sure that your dealer has provided a lead suitable for connecting your particular printer to the +3. A serial printer must be connected to the +3's RS232 socket, and details of connections can be found in chapter 10 (Peripherals for your +3).

The +3 always uses what is known as hardware flow control, or hardware handshaking. This means that it will not transmit characters until certain control signals from the printer have the right values. It is therefore very important that connections are made to the control lines of the +3 as well as the transmit and receive data lines. If your printer does not support hardware handshaking then connect pins 4 and 5 of the +3's RS232 connector socket together. The drawback of not using hardware handshaking is that the odd character may be lost when transmitting a lot of data at high speed.

To get the +3 and the printer communicating with each other, they must both use the same baud rate. The baud rate is the speed at which data is transferred between computer and printer. Although it is possible that your printer can be set to different baud rates, it'll probably be easier to change the rate at the computer end. Somewhere in the printer's operating manual, the baud rate will be specified - find this out and then set the +3 to this rate, using the command...

For example...


(You won't need to do this if your printer normally uses 9600 baud, as the +3 will assume this rate by default.)

As the +3 usually expects to be operating with a parallel printer, it will be necessary to use the command...


...before the +3 will successfully operate with a serial printer. (The R in the above command is short for RS232.)

The command to set the +3 back to parallel (Centronics) mode is...


General printing

Once you have everything set up, you can use three BASIC commands to print things out. The first two, LPRINT and LLIST, are just like PRINT and LIST except that they use the printer instead of the TV screen. Note that the Print option from +3 BASIC's edit menu has the same effect as LLIST, but is included as an easier method of getting a listing.

Try this program for example...

10 LPRINT "This program..."'
20 LLIST 40
30 LPRINT '"...prints out the character set, ie..."'
40 FOR n=32 TO 255
60 NEXT n

It's important to note that LPRINT and LLIST normally take care to screen out any embedded colour codes (and their parameters) before printing or listing anything. Embedded colour codes are a bit of a hangover from the old 48K Spectrum - when included in a string they set INK, PAPER and so on. Printers on the whole tend to use these codes for completely different things like setting italics, underline, etc., so it would be quite dangerous to send colour codes to the printer and hope that nothing untoward happens. A side effect of this is that the +3 will normally not be able to send escape control sequences to the printer. For example, support your printer expects an escape character (character 27) followed by "x"; CHR$ (1) to switch to its NLQ mode; you would normally use the command...

LPRINT CHR$ (27);"x"; CHR$ (1); "This is in Near Letter Quality"

However, in +3 BASIC, you must first issue the command...


This command tells the +3 not to interpret characters as 'Spectrum codes', but as ordinary unexpanded characters (the 'U' is short for unexpanded). If the above command is not issued, then everything above code 165 (see part 28 of this chapter) will be translated as one of the +3's special words, or tokens. Likewise, almost everything below code 32 will be screened out.

If you wish, you can instruct the +3 to interpret characters as Spectrum codes by using...


...(where E stands for expanded). You'll need to do this if you're going to use LLIST. The +3 starts off in expanded mode anyway, so unless you've issued a FORMAT LPRINT "U" command, you won't need to use FORMAT LPRINT "E".

So, to summarise:

...before printing.

...before listing the program.

The third BASIC statement used with a printer - COPY, prints out a copy of the TV screen. To demonstrate, go into the small screen (by selecting the 'Screen' option from the edit menu) and type in the following command.

FOR n=1 TO 20: PRINT n,: NEXT n

The numbers 1 to 20 will be printed in the top part of the screen. Now type...


The COPY command takes about 15-20 seconds to get started, so don't panic if nothing appears to happen immediately. After a while, you'll see a copy of the screen reproduced on the printer. (If all you get from COPY is a lot of random characters on the printer, then it's likely that your printer isn't fully compatible.)

You can always stop printing at any time by pressing the BREAK key. Many printers have what's known as a buffer, which stores text before printing. If your printer has a buffer, then pressing BREAK will not stop the printer immediately (although the +3 will register the break at once).

Note that if the COPY command is stopped by pressing the BREAK key, the printer may be left in graphics mode (this will be indicated by subsequent LPRINT statements) producing a mass of meaningless dots, or printing each line of text partly over the previous line). In these circumstances, switching the printer off then on again is the easiest way to get things back to normal.

As well as the rather simple COPY command, which just produces a black dot on the printer for each dot on the screen (whatever its colour may be), there is an expanded version (COPY EXP) which prints differing combinations of dots depending on the colour of ink that was used on the screen. To demonstrate, type in the following new program...

10 FOR b=0 TO 1
30 FOR i=0 TO 6
40 FOR c=0 TO 31
50 PRINT INK i; i;
60 NEXT c
70 NEXT i
80 NEXT b

...then switch to the bottom part of the screen (using the edit menu's Screen option). Run the program (which displays twelve lines of coloured numbers on the screen), then type in...


The printed output (or dump) from this command is slightly larger than that from the standard COPY command - (EXP is short for expanded). The command reproduces the coloured areas of the screen as different densities of black dots on the printer. (All 24 lines of the screen are reproduced.) Areas that have been printed with BRIGHT 1 will appear lighter than areas printed normally (just as happens on the screen).

The drawback of the COPY EXP command is that it takes a longer time to print (about 10 minutes), but is ideally suited to dumping graphic pictures. The quicker COPY command, on the other hand, is a better bet if you wish to dump text only.

If the screen display to be dumped is predominantly black, then it will not only wear out your printer ribbon rather quickly, but also will probably take longer to dump than a screen that has large areas of white. To prevent this, the COPY EXP command can be followed by the word INVERSE, ie....


As the command suggests, the dump is printed in INVERSE (like a photographic negative) so that all the dark areas of the screen are printed-out light, and vice versa.

Note that INVERSE cannot be used after the simple COPY command - it only works with COPY EXP.

The dump produced by COPY EXP and COPY EXP INVERSE is designed to fit a sheet of A4 paper; however, some printers will not print within about an inch at either end of a sheet. If this problem occurs, then it is possible to reduce the size of the dump slightly by using the command...

POKE 23419,8

This sets the number of 216ths inch used as a line feed at the end of each pass of the print head. It is set to 9 when the +3 is first switched on. Once set, it will not be changed even if the NEW command is used. By reducing this value, each pass of the print head will fractionally overlay the previous pass. As a consequence, the quality of the dump reproduced will be degraded slightly.

If you try to use any of the printer commands when there isn't a printer attached (or if the printer is off line), then the +3 will stop dead while it patiently waits for the (non-existent) printer to respond. In such a case, pressing BREAK twice will bring the +3 back to life.

Try this...

10 FOR n=31 TO 0 STEP -1
20 PRINT AT 31-n,n; CHR$ ( CODE "0"+n);
30 NEXT n

You will see a pattern of characters working down diagonally from the top right-hand corner until it reaches the bottom of the screen, at which point the program asks if you want to scroll.

Now change AT 31-n,n in line 20 to TAB n. The program will have exactly the same effect as before.

Now change PRINT in line 20 to LPRINT. This time there will be no pause to scroll (this does not occur with the printer).

Now change TAB n back to AT 31-n,n still using LPRINT. This time you will get just a single line of symbols. The reason for the difference is that the output from LPRINT is not printed straight away, but is stored in the buffer until either one line's worth of printer output has accumulated, or something else 'flushes' the buffer. Hence, printing only takes place:

  1. When the buffer is full.
  2. After an LPRINT statement that does not end in a comma or semicolon.
  3. When a comma, apostrophe or TAB item requires a new line.
  4. At the end of a program, if there is anything left unprinted.
  5. When you set the printer off line (this depends on your particular printer).

Number 3 above explains why our program with TAB works the way it does. As for AT, the line number is ignored, and the LPRINT position (like the PRINT position) is moved to the column number. An AT item can never cause a line to be sent to the printer.


  1. Make a printed graph of a sine wave by running the first (3 line) program in part 17 of this chapter, then using COPY.
  2. Run the program at the beginning of part 16 of this chapter and try both a COPY EXP and a COPY EXP INVERSE.

Part 22 - Streams

Subjects covered...

The +3 can 'read' data from the keyboard by using INPUT and INKEY$, and it can 'write' data onto the TV screen or a printer by using PRINT and LPRINT. However, these commands are really a form of shorthand designed to protect the user from some of the computer's more complex features.

To the BASIC PRINT command, for example, the screen and the printer are no different. PRINT "Roseanne" really means 'take the characters which make up the word 'Roseanne' and send them somewhere else'. It's just convenient to use the screen most of the time. Likewise, LPRINT usually sends data to the printer. In fact, what these commands really do is to send data to one of a number of channels.

A channel is the way in which the computer communicates with its input and output devices. There are three channels normally available to BASIC. These are...

Of these, the screen is an output-only device, the keyboard is both an input and output device, and the printer is either an output-only device (if it uses the parallel PRINTER socket), or an input and output device (if it uses the serial RS232 socket). Outputting data to the keyboard might seem a funny idea, but the computer uses the lower screen (like INPUT does) to display the characters.

To access a channel, it has to be open. Opening a channel makes it ready to receive or produce data. A channel is opened by connecting it to a stream. From BASIC, you would use a command like...

OPEN #4,"p"

...which means 'connect stream 4 to the printer channel'. Streams are convenient ways for the computer to switch between channels by referring to them as numbers. This idea makes it possible to write programs that can send information to any device without having to use different commands. (This is known as redirectable (or device-independent) I/O.)

This might seem over-complicated, and you may well wish to stick to the standard PRINT and LPRINT commands - that's why they're there, after all.

PRINT and LPRINT are really the same command. When BASIC is running, it has three streams normally open. Stream #1 is connected to the keyboard device (K), and is used by INPUT and INKEY$. Stream #2 is connected to the screen (S), and is used by PRINT and LIST. Stream #3 is connected to the printer (P), and is used by LPRINT and LLIST. All of these commands can be redirected to use another device by including a '#' followed by a current stream number, so...

PRINT #1;"This is the lower screen"

...will print the message on the lower screen. Similarly...

PRINT #3;"Who needs LPRINT, Gladys?"

...will use the printer. Conversely, LPRINT can behave like PRINT...

LPRINT #2;"Confusing, or what?"

...behaves just as if the LPRINT #2 were PRINT.

As they stand, these examples are fairly useless but serve to demonstrate a point. This sort of thing becomes useful if you want to write a program where the results might go either to the printer or the screen, like so...

10 REM squares program for printer
20 INPUT "do you want to print the results?";a$
30 LET stream=2
40 IF a$="y" OR a$="Y" THEN LET stream=3
50 FOR n=0 TO 10
60 PRINT #stream;n,n*n
70 NEXT n

The +3 can cope with 16 streams. As 3 are used by BASIC, and 1 is used internally, this leaves you with 12. You can use these by...

10 REM program to read data from RS232
40 OPEN #4,"p"
60 GO TO 50

...which takes characters in from the RS232 interface and prints them onto the screen.

If you want to read in data from the RS232 into memory directly, you can replace line 50 with...

As we mentioned before, the screen and the parallel PRINTER socket can only be used by the +3 for output. They cannot be used for input, and if you try PRINT INKEY$ #2, for example, you'll receive an error report.

It is theoretically possible to redirect BASIC's normal output streams, so by using...

10 CLOSE #2
20 OPEN #2,"p"

...all the PRINT output will go to the printer instead of the screen. (If you try to do this during editing, the results will be unpredictable, so it's best left alone.)

On the standard +3 system, streams and channels are of mostly academic interest. However, certain peripherals and BASIC language extensions do use the stream system for more complex functions.

Part 23
IN and OUT

Subjects covered...

The processor can read from (ROM and RAM) and write to (RAM) memory by using PEEK and POKE. The processor itself does not really care whether memory is ROM or RAM - it just thinks there are 65536 memory addresses, and it can read a byte from each one (even if it's nonsense), and write a byte to each one (even if it gets lost). In a completely analogous way, there are 65536 of what are called I/O ports (standing for input/output ports). These are used by the processor for communicating with things like the keyboard or the printer, and also for controlling the extra memory and the sound chip. Some of them can be safely controlled from BASIC by using the IN function and the OUT command, but there are locations to which you must not write from BASIC as you will probably cause the system to crash, losing any program and data.

IN is a function like PEEK. Its form is...

It has one argument - the port address, and its result is a byte read from that port.

OUT is a statement like POKE. Its form is...

...which writes the given value to the port with the given address. How the address is interpreted depends very much upon the rest of the computer. Quite often, many different addresses will mean the same. On the +3 it is most sensible to imagine the address being written in binary, because the individual bits (each of which can have the value either 0 or 1) tend to work independently. There are 16 bits, which we shall refer to (using A for address) as...

A15, A14, A13, A12, A11, A10, A9, A8, A7, A6, A5, A4, A3, A2, A1, A0

Here, A0 is the 1s bit, A1 is the 2s bit, A2 is the 4s bit, and so on. Bits A0, A1, A2, A3 and A4 are the important ones. They are normally 1, but if any one of them is 0, then this tells the computer to do something specific. The computer cannot cope with more than one thing at a time, so no more than one of these five bits should 0. Bits A6 and A7 are ignored, so if you are a wizard with electronics you can use them yourself. The best addresses to use are those that are 1 less than a multiple of 32, so that A0 to A4 are all 1. Bits A8, A9, and so on are sometimes used to give extra information, but mostly for the extra memory and sound.

The byte being written or read has 8 bits, and these are often referred to (using D for data) as...

D7, D6, D5, D4, D3, D2, D1, D0

Here follows a list of the port addresses used...

There is a set of input addresses that read the keyboard and the tape interface.

The keyboard is divided up into 8 half-rows of 5 keys each, viz:

(These addresses are 254+256x(255-2^n) as n goes from 0 to 7.)

Remember that digits followed by h signify hexadecimal numbers. If you don't understand hexadecimal numbers, refer to part 32 of this chapter.

In the byte read in, bits D0 to D4 stand for the five keys in the given half-row. D0 is for the outside key, and D4 is for the one nearest the middle. The bit is 0 if the key is pressed, 1 if it is not. D6 is set by the tape interface, and is effectively random if no tape data is present.

For JOYSTICK 1, bit 0 is fire, bit 1 is up, bit 2 is down, bit 3 is right and bit 4 is left. For JOYSTICK 2, bit 0 is left, bit 1 is right, bit 2 is down, bit 3 is up and bit 4 is fire. From BASIC, these read as the number keys.

Port address 00FEh (254 decimal) in output drives the sound (D4) and the save signal to the tape interface (D3), and also sets the border colour (D2, D1 and D0).

Port addresses 00FEh (254), 00F7h (247) and 00EFh (239) are reserved.

Port address 7FFDh (32765) drives the extra memory. Executing an OUT to this port from BASIC will nearly always cause the computer to crash, losing any program and data. There is a fuller description of this port in part 24 of this chapter (under the heading Memory management). This port is write only, ie. you cannot determine the current state of the paging by an IN instruction. This is why the BANKM system variable is always kept up to date with the last value output to this port.

Port address BFFDh (49149) drives the sound chip's data registers. Port address FFFDh (65533) in output writes a register address, and in input reads a register. Judicious use of these two registers can allow sounds to be generated whilst BASIC gets on with something else, but you should be aware that they also control RS232/MIDI and AUX interfaces.

Port address 0FFDh (4093) is used for the parallel (Centronics) interface (ie. PRINTER). When read using an IN instruction bit 0 shows the state of the BUSY signal produced by the printer. If the printer is off line or non-existent, then this bit will be 1. When this port is written to using OUT, it acts as the parallel port data register. In order to print a character it is necessary to wait until BUSY is 0, write the character code to port 0FFDh (4093), and finally, take the STROBE bit in port 1FFDh (8189) low than back high again.

Port address 1FFDh (8189) controls several aspects of the +3. Amongst other things, this port controls the ROM that is switched into the memory area from 0000h...3FFFh (0...16383). As the port is write only, the +3 BASIC maintains a variable, BANK678, that holds the value last output to this port. It is therefore very unwise to OUT values directly to this port without first checking on the current state (which holds its current state in BANKM). The bottom three bits (0..2) of this port (1FFDh) are used to switch RAM/ROM - further details can be found in part 24 of this chapter (under the heading `Memory management'. Bit 3 controls the disk motor (0 is off, 1 is on), though it should not be necessary to control the motor by writing to this port as there are +3DOS routines that will achieve the desired effect. Bit 4 is the parallel port STROBE which is active low - this means that to print the character that has been output to port 0FFDh (4093), the STROBE bit should be brought low and then returned to its normally high state.

Port address 2FFDh (12285) can be used to read the disk controller (µPD765A) chip's main status register. This is unlikely to be very useful without an in-depth knowledge of how the chip operates.

Port address 3FFDh (16381) is the disk controller's data register. This can be both read from and written to, but once again it is unlikely to be useful to the BASIC programmer. Random OUTputting to this port will probably confuse the poor disk controller chip to such an extent that subsequent disk operations (like LOAD and SAVE) will be unreliable. It is entirely possible that ill-informed experiments will corrupt your disks and lose your data - you have been warned!

Run this program to see how the keyboard works...

10 FOR n=0 TO 7: REM half-row number
20 LET a=254+256*(255-2^n)
30 PRINT AT 20,0; IN a: GO TO 30

...and play around by pressing keys (start with the half-row from CAPS SHIFT to V). When you are finished with each half-row, press BREAK and then type...


The control, data and address busses are all exposed at the back of the +3 on the EXPANSION I/O socket. This means that you can do almost anything with a +3 that you could with a raw Z80 chip (although sometimes, the computer's internal workings may get in the way).

See chapter 10 for a diagram and pin-out of the EXPANSION I/O socket.

Part 24
The memory

Subjects covered...

Deep inside the +3, everything is stored as bytes, ie. number between 0 and 255 (FFh). You may think you have stored away the price of Ruddles or the players' names in the Arsenal football team, but in fact, all the information has been converted into collections of bytes, and bytes are what the computer sees.

Each place where a byte can be stored has an address, which is a number between 0 (or 0000h) and 65535 (FFFFh). This means that an address can be stored as two bytes. You can think of the memory as a long row of numbered boxes, each of which can contain a byte. Not all the boxes are the same, however - the boxes from 4000h to FFFFh are RAM boxes, which means you can open the lid and alter the contents, but those from 0 to 3FFFh are ROM boxes, which have a glass lid that cannot be opened - you just have to read whatever was put into them when the computer was made. In the +3, we have crammed in more than twice the amount of memory than can comfortably fit. While the processor can address 65536 bytes, there are in fact 131072 bytes of RAM and 65536 bytes of ROM making 196608 bytes (192K) in all! All this is hidden from the processor by the hardware using a process called paging - BASIC (and the processor) always 'sees' the memory as 16K of ROM and 48K of RAM (or 64K of RAM with no ROM - though this latter combination is never used by BASIC).

65535 FFFFh RAM 0-7 49152 C000h RAM 2 32768 8000h RAM 5 16384 4000h ROM 0-3 0 0000h

To inspect the contents of a box, we use the PEEK function. Its argument is the address of the box, and its result is the contents. For example, this program prints out the first 21 bytes in ROM (and their addresses)...

10 PRINT "Address"; TAB 8; "Byte"
20 FOR a=0 TO 20
30 PRINT a; TAB 8; PEEK a
40 NEXT a

All these bytes will probably be quite meaningless to you, but the processor chip understands them to be instructions telling it what to do.

To change the contents of a box (if it is RAM), we use the POKE command. Its form is...

...where address and contents are numeric expressions. For example, if you type...

POKE 31000,57

...then the byte at address 31000 is given the new value 57. Now type...

PRINT PEEK 31000 prove this. (Try poking in other values, to show that there is no cheating.) The new value must be between -255 and +255; if it is negative, then 256 is added to it.

The ability to poke gives you immense power over the computer if you know how to wield it, and immense destructive possibilities if you don't. It is very easy (by poking the wrong value into the wrong address) to lose vast programs that took you hours to type in. Fortunately though, you won't do the computer any permanent damage.

We shall now take a more detailed look at how the RAM is used. Don't bother to read this unless you're really interested.

The memory is divided into different areas (shown in the diagram ahead) for storing different kinds of information. The areas are only large enough for the information that they actually contain, and if you insert some more at a given point (for instance by adding a program line or variable), then space is made by shifting up everything above that point. Conversely, if you delete information, then everything is shifted down.

The display file stores the contents of the TV screen. It is rather curiously laid out, so you probably won't want to PEEK or POKE in it. Each character position on the screen has an 8 x 8 grid of dots; each dot can be either 0 (paper) or 1 (ink), so by using binary notation we can store the pattern as 8 bytes - one for each row. However, these 8 bytes are not stored together. The corresponding columns in the 32 characters of a single line are stored together as a scan of 32 bytes, because this is what the electron beam in the TV needs as it scans from the left-hand side of the screen to the other. Since the complete picture has 24 lines of 8 scans each, you might expect the total of 192 scans to be stored in order, one after the other - well you'd be wrong! First come the top scans of lines 0 to 7, then the next scans of lines 0 to 7, and so on to the bottom scans of lines 0 to 7; then the same for lines 8 to 15; and again for lines 16 to 23. The upshot of all this is that if you're used to a computer that uses PEEK and POKE on the screen, then you'll have to start using SCREEN$ and PRINT AT instead (or PLOT and POINT).

The attributes are the colours and so on for each character position, using the format of ATTR. These are stored line by line in the order you'd expect.

The way that the computer organises its affairs changes slightly between 48 BASIC and +3 BASIC mode. The area that was the printer buffer in 48 BASIC mode, is used for extra system variables in +3 BASIC mode in much the same way as it was on the Spectrum +2. The variables have changed, though.

5C00h (23552) Printer buffer System variables (48K mode only) 4000h (16384) Display file 5800h (22528) Attributes 5B00h (23296) 5C00h (23552) System variables 5CB6h (23734) CHANS 5CB6h (23734) CHANS Channel information 80h 2 PROG BASIC program VARS Variables 80h E LINE Command or program line being edited NL 80h WORKSP WORKSP INPUT data NL Temporary workspace STKBOT Calculator stack STKEND Spare SP (STACK POINTER) Machine stack GO SUB stack ? RAM TOP 3Eh UDG User defined graphics P RAMT

The system variables contain various pieces of information that tell the computer what sort of state it's in. They are listed fully in part 25 of this chapter, but for the moment, note that there are some (called CHANS, PROG, VARS, E LINE, and so on) that contain the addresses of the boundaries between the various areas in memory. These are not BASIC variables, and their names will not be recognised by the +3.

The channel information contains information about the input and output devices, namely the keyboard (together with the lower half of the screen), the upper half of the screen, and the printer.

Each line of BASIC program has the form...

Most significant byte Least significant byte Line number 2 bytes Length of text + ENTER 2 bytes Text ENTER 0 0 0 0 1 1 0 1

Note that, in contrast with all other cases of two-byte numbers in the Z80, the line number here is stored with its most significant byte first, ie. in the order that you'd write them down.

A numerical constant in the program followed by its binary form, using the character CHR$ 14 followed by five bytes for the number itself.

The variables have different formats according to their different natures. The letters in the names should be imagined as starting off in lower case.

Number whose name is one letter only:

Sign bit 0 1 1 Exponent byte 4 Mantissa bytes Letter-60h Value

Number whose name is longer than one letter:

1 0 1 0 1 5 bytes Letter-60h 2nd character Last character Value

Array of numbers:

1 0 0 2 bytes 1 byte 2 bytes 2 bytes 5 bytes each Letter-60h Total length of elements & dims + 1 for no. of dimensions No. of dims. 1st dims. Last dim Elements

The order of the elements is:

First - the elements for which the first subscript is 1. Next - the elements for which the first subscript is 2. Next - the elements for which the first subscript is 3... ...and so on for all possible values of the first subscript.

The elements with a given first subscript are ordered in the same way using the second subscript, and so on down to the last.

As an example, the elements of the 3 x 6 array 'c' in part 12 of this chapter are stored in the order c(1,1) c(1,2) c(1,3) c(1,4) c(1,5) c(1,6) and c(2,1) c(2,2) ... c(2,6) and c(3,1) c(3,2) ... c(3,6).

Control variable of a FOR...NEXT loop:

Least significant byte Most significant byte 1 1 1 5 bytes 5 bytes 5 bytes 2 bytes 1 byte Letter-60h Value Limit Step Looping line Statement number within line


0 1 0 2 bytes Letter-60h Number of characters Text of string (may be empty)

Array of characters:

1 1 0 2 bytes 1 byte 2 bytes 2 bytes 1 byte each Letter-60h Total length of elements & dims + 1 for no. of dimensions No. of dims. 1st dims. Last dim Elements

The calculator is the part of the BASIC system that deals with arithmetic, and the numbers on which it is operating are held mostly in the calculator stack.

The spare area contains the space so far unused.

The machine stack is the stack used by the Z80 processor to hold return addresses and so on.

The GO SUB stack was mentioned in part 5 of this chapter.

The byte 'pointed to' by RAMTOP has the highest address used by the BASIC system. Even NEW, which clears the RAM, only does so as far as this - so it doesn't change the user-defined graphics. You can change the address RAMTOP by putting a number in a CLEAR statement, ie....

...which does the following:

  1. Clears out all variables.
  2. Clears the display file (like CLS does).
  3. Resets the PLOT position to the bottom left-hand corner.
  4. RESTOREs the DATA pointer.
  5. Clears the GO SUB stack and puts it at the new RAMTOP (assuming that this lies between the calculator and the physical end of RAM; otherwise it leaves RAMTOP where it was).

RUN also performs a CLEAR, although it never changes RAMTOP.

Using CLEAR in this way, you can either move RAMTOP up to make more room for the BASIC by overwriting the user-defined graphics, or you can move it down to make more RAM that is preserved from NEW. It can also be used to ensure that the machine stack is below BFE0h (49120) when intending to call +3DOS - this means that the stack will not have to be subsequently moved within your own machine code.

If you are in an experimental frame of mind you can also use CLEAR to explore the extra memory. CLEAR 49151 moves all of BASIC below the addresses that hold the switchable RAM paging. By using POKE 23388,16+n where 'n' is a number between 0 and 7, you can make the computer switch in page 'n' of the RAM. You will then be able to use PEEK and POKE in the normal way to examine and change the page. Beware - the extra pages are normally used by the system for disk and editor operations, so always reset the +3 after exploring in this way, before doing anything else.

Type NEW, select +3 BASIC, then enter the command CLEAR 23825 to get some idea of what happens to the machine when it fills up.

If you then try to make the +3 compute, (for example, type in PRINT 1+1) you will see the report 4 Out of memory displayed. This means the computer has no more room for information. If you come up against this message while entering a large program, you will have to empty the memory slightly (delete a line or so) in order to control the computer.

Memory management

We mentioned earlier that there is rather more memory in the computer than the processor can deal with. While the processor can indeed address only 64K of memory at once, the extra memory can be slotted in and out of that 64K at will. Consider a TV set. Although it (and you) can only deal with one channel at a time, there are another three channels always there which can be selected with the right buttons. So, even though there's four times as much information as you can use at any one time, you can pick and choose which part is relevant.

It is much the same for the processor. By setting the right bits in an I/O port it can pick and choose which chunks of the 192K of memory it wants to use. For the majority of the time in BASIC it ignores most of the memory, but for games playing, having three times as much RAM is really rather useful. Look again at the +3's memory map (shown at the beginning of this section). RAM pages 2 and 5 are always in the positions shown when BASIC is used, though there's no reason why they shouldn't be in the banked section (C000h to FFFFh) - however, it would be difficult to see any use for this.

The RAM banks are of two types: RAM pages 4 to 7 which are contended (meaning that they share time with the video circuitry), and RAM pages 0 to 3 which are uncontended (where the processor has exclusive use). Any machine code which has critical timing loops (such as music or communications programs) should keep all such routines in uncontended banks. For example, executing NOPs in contended RAM will give an effective clock frequency of 2.66Mhz as opposed to the normal 3.55MHz in uncontended RAM. This is a reduction in speed of about 25%.

The hardware switch normally used to select RAM is at I/O address 7FFDh (32765). The bit field for this address is as follows:

D2...D0 is a three bit number that selects which RAM page goes into the C000h to FFFFh slot. In BASIC, RAM page 0 is normally in situ. When editing or calling +3DOS routines, RAM page 7 is used for various buffers and 'scratchpads'. D3 switches screens: screen 0 is held in RAM 7 (beginning at C000h) and can only be used by machine code programs. It is entirely feasible to set up a screen in RAM 7 and then page it out; this leaves the entire 48K free for data and program. Note that the +3's COPY (file) command may well use buffers in the second screen area (corrupting a second screen which may be 'hidden' there). D4 determines which ROM is paged into 0000h to 3FFFh (in combination with bit 2 of port 1FFDh - see below). D5 is a safety feature - once this bit has been set, no further paging operations will work. This is normally used when the machine assumes a standard 48K Spectrum configuration and all the memory paging circuitry is locked out. It cannot be turned back into a 128K machine other by switching off or pressing RESET button; however, the sound chip can still be driven by OUT. If a 48K Spectrum game loaded from disk will not work, it is possible that by using the SPECTRUM command followed by OUT 32765,48 (which locks bit 5 in this port), the game might then work.

The +3 also uses I/O port 1FFDh for some ROM and RAM switching. The bit field for this address is as follows:

When bit 0 is 0, bit 1 has no effect and bit 2 is a 'vertical' ROM switch (ie. between ROM 0 and ROM 2, or between ROM 1 and ROM 3). Bit 4 in the port at 7FFDh is a 'horizontal' ROM switch (ie. between ROM 0 and ROM 1, or between ROM 2 and ROM 3). The following diagram serves to show the various ROM switching possibilities...

ROM 0 Editor ROM 1 Syntax ROM 2 DOS ROM 3 48 BASIC vertical vertical horizontal horizontal Bit 4 7FFFd (23388) (system variable: BANKM) Bit 2 1FFFd (23399) (system variable: BANK678)
Horizontal and vertical ROM switching

It is best to think of bit 4 in port 7FFDh and bit 2 in port 1FFDh combining to form a 2-bit number (0...3) which determines which ROM occupies the memory area 0000h...3FFFh. Bit 4 of port 7FFDh is the least significant bit and bit 2 of 1FFDh is the most significant bit.

Bit 2 of 1FFDh
(System variable:BANK678)
Bit 4 of 7FFDh
(System variable:BANKM)
Switched ROM at 0000h...3FFFh
0 0 0
0 1 1
1 0 2
1 1 3

ROM switching (with Bit 0 of 1FFDh set to 0) When bit 0 of port 1FFDh is set to 1, bits 1 and 2 switch in various RAM combinations that occupy the full 64K address space. These are not used by +3 BASIC but are provided for authors of operating systems/games. When the +3DOS 'DOS BOOT' routine is used, the bootstrap is loaded into the 4, 7, 6, 3 RAM page environment. The various +3 extra RAM paging options are as follows:

Bit 2 of 1FFDh Bit 1 of 1FFDh RAM pages used
(0000h...3FFFh, 4000h...7FFFh, etc.)
0 0 0, 1, 2, 3
0 1 4, 5, 6, 7
1 0 4, 5, 6, 3
1 1 4, 7, 6, 3

Extended memory paging (with Bit 0 of 1FFDh set to 1)

Part 25
The system variables

Subjects covered...

The bytes in memory from 5B00h (23296) to 5CB6h (23734) are set aside for specific uses by the system. There are a few routine (used to keep the paging in order), and some locations called system variables. You can peek these to find out various things about the system, and some of them can be usefully poked. They are listed here with their uses.

There is quite a difference, as you might expect, between the system variables' area in 48 BASIC mode and in +3 BASIC mode. In 48 BASIC mode, all the variables and routines below 5C00h (23552) do not exist; instead there is a buffer between 5B00h (23296) and 5C00h (23552) which is used for controlling the printer. This was quite a popular location for small machine code programs on the old 48K Spectrum, and if any of these routines are tried in +3 BASIC, the computer will invariably crash. Any old program that uses PEEK, POKE and USR is therefore a safer bet if it is run in 48 BASIC mode (although it can be entered in +3 BASIC mode and transferred using the SPECTRUM command). If there is a chance that a program might inadvertently address the added I/O ports of the +3, then OUT 32765,48 will set bit 5 in port 7FFDh to disable further use of the added ROM/RAM switching.

Although system variables have names, you should not confuse them with the words and names used in BASIC. The computer will not recognise the names as referring to system variables; they are given solely as mnemonics for humans.

The abbreviations in column 1 of the table have the following meanings:

X - The variables should not be poked because the system might crash.

N - Poking the variables will have no lasting effect.

R - Routine entry point. Not a variable.

The number in column 1 is the number of bytes in the variable or routine. For a two-byte word, the first byte is the least significant - the reverse of what you might expect. So, to poke a value 'v' into a two-byte variable at address 'n', use...

    POKE n,v-256* INT (v/256)
    POKE n+1, INT (v/256)

...and to peek its value, use the expression...

    PRINT PEEK n+256* PEEK (n+1)
R16 5B00h (23296) SWAP Paging subroutine.
R17 5B10h (23312) STOO Paging subroutine. Entered with interrupts already disabled and AF, BC on the stack.
R9 5B21h (23329) YOUNGER Paging subroutine.
R16 5B2Ah (23338) REGNUOY Paging subroutine.
R24 5B3Ah (23354) ONERR Paging subroutine.
X2 5B52h (23378) OLDHL Temporary register store while switching ROMs.
X2 5B54h (23380) OLDBC Temporary register store while switching ROMs.
X2 5B56h (23382) OLDAF Temporary register store while switching ROMs.
N2 5B58h (23384) TARGET Subroutine address in ROM 3.
X2 5B5Ah (23386) RETADDR Return address in ROM 1.
X1 5B5Ch (23388) BANKM Copy of last byte output to I/O port 7FFDh (32765). This port is used to control the RAM paging (bits 0...2), the 'horizontal' ROM switch (0<->1 and 2<->3 - bit 4), screen selection (bit 3) and added I/O disabling (bit 5). This byte must be kept up to date with the last value output to the port if interrupts are enabled.
X1 5B5Dh (23389) RAMRST RST 8 instruction. Used by ROM 1 to report old errors to ROM 3.
N1 5B5Eh (23390) RAMERR Error number passed from ROM 1 to ROM 3. Also used by SAVE/LOAD as temporary drive store.
2 5B5Fh (23391) BAUD RS232 bit period in T states/26. Set by FORMAT LINE.
N2 5B61h (23393) SERFL Second-character-received-flag, and data.
N1 5B63h (23395) COL Current column from 1 to width.
1 5B64h (23396) WIDTH Paper column width. Defaults to 80.
1 5B65h (23397) TVPARS Number of inline parameters expected by RS232.
1 5B66h (23398) FLAGS3 Various flags. Bits 0, 1, 6 and 7 unlikely to be useful. Bit 2 is set when tokens are to be expanded on printing. Bit 3 is set if print output is RS232. The default (at reset) is Centronics. Bit 4 is set if a disk interface is present. Bit 5 is set if drive B: is present.
X1 5B67h (23399) BANK678 Copy of last byte output to I/O port 1FFDh (8189). This port is used to control the +3 extended RAM and ROM switching (bits 0..2 - if bit 0 is 0 then bit 2 controls the 'vertical' ROM switch 0<->2 and 1<->3), the disk motor (bit 3) and Centronics strobe (bit 4). This byte must be kept up to date with the last value output to the port if interrupts are enabled.
N1 5B68h (23400) XLOC Holds X location when using the unexpanded COPY command.
N1 5B69h (23401) YLOC Holds Y location when using the unexpanded COPY command.
X2 5B6Ah (23402) OLDSP Old SP (stack pointer) when TSTACK is in use.
X2 5B6Ch (23404) SYNRET Return address for ONERR.
5 5B6Eh (23406) LASTV Last value printed by calculator.
2 5B73h (23411) RCLINE Current line being renumbered.
2 5B75h (23413) RCSTART Starting line number for renumbering. The default value is 10.
2 5B77h (23415) RCSTEP Incremental value for renumbering. The default is 10.
1 5B79h (23417) LODDRV Holds T if LOAD, VERIFY, MERGE are from tape, otherwise holds A, B or M.
1 5B7Ah (23418) SAVDRV Holds T if SAVE is to tape, otherwise holds A, B or M.
1 5B7Bh (23419) DUMPLF Holds the number of 1/216ths user for line feeds in COPY EXP. This is normally set to 9. If problems are experienced fitting a dump onto a sheet of A4 paper, POKE this location with 8. This will reduce the size of the dump and improve the aspect ratio slightly. (The quality of the dump will be marginally degraded, however.)
N8 5B7Ch (23420) STRIP1 Stripe one bitmap.
N8 5B84h (23428) STRIP2 Stripe two bitmap. This extends to 5B8Bh (23436).
X115 5BFFh (23551) TSTACK Temporary stack grows down from here. Used when RAM page 7 is switched in at top of memory (while executing the editor or calling +3DOS). it may safely go down to 5B8Ch (and across STRIP1 and STRIP2 if necessary). This guarantees at least 115 bytes of stack when BASIC calls +3DOS.
N8 5C00h (23552) KSTATE Used in reading the keyboard.
N1 5C08h (23560) LASTK Stores newly pressed key.
1 5C09h (23561) REPDEL Time (in 50ths of a second) that a key must be held down before it repeats. This starts off at 35, but you can POKE in other values.
1 5C0Ah (23562) REPPER Delay (in 50ths of a second) between successive repeats of a key held down - initially 5.
N2 5C0Bh (23565) DEFADD Address of arguments of user defined function (if one is being evaluated), otherwise 0.
N1 5C0Dh (23566) TVDATA Stores bytes of colour, AT and TAB controls going to TV.
X38 5C10h (23568) STRMS Addresses of channels attached to streams.
2 5C36h (23606) CHARS 256 less than address of character set (which starts with space and carries on to ©). Normally in ROM, but you can set up your own in RAM and make CHARS point to it.
1 5C38h (23608) RASP Length of warning buzz.
1 5C39h (23609) PIP Length of keyboard click.
1 5C3Ah (23610) ERRNR 1 less than the report code. Starts off at 255 (for -1) so PEEK 23610 gives 255.
X1 5C3Bh (23611) FLAGS Various flags to control the BASIC system.
X1 5C3Ch (23612) TVFLAG Flags associated with the TV.
X2 5C3Dh (23613) ERRSP Address of item on machine stack to be used as error return.
N2 5C3Fh (23615) LISTSP Address of return address from automatic listing.
N1 5C41h (23617) MODE Specifies K, L, C, E or G cursor.
2 5C42h (23618) NEWPPC Line to be jumped to.
1 5C44h (23620) NSPPC Statement number in line to be jumped to. Poking first NEWPPC and then NSPPC forces a jump to a specified statement in a line.
2 5C45h (23621) PPC Line number of statement currently being executed.
1 5C47h (23623) SUBPPC Number within line of statement currently being executed.
1 5C48h (23624) BORDCR Border colour multiplied by 8; also contains the attributes normally used for the lower half of the screen.
2 5C49h (23625) E PPC Number of current line (with program cursor).
X2 5C4Bh (23627) VARS Address of variables.
N2 5C4Dh (23629) DEST Address of variable in assignment.
X2 5C4Fh (23631) CHANS Address of channel data.
X2 5C51h (23633) CURCHL Address of information currently being used for input and output.
X2 5C53h (23635) PROG Address of BASIC program.
X2 5C57h (23637) NXTLIN Address of next line in program.
X2 5C57h (23639) DATADD Address of terminator of last DATA item.
X2 5C59h (23641) E LINE Address of command being typed in.
2 5C5Bh (23643) K CUR Address of cursor.
X2 5C5Dh (23645) CH ADD Address of the next character to be interpreted - the character after the argument of PEEK, or the NEWLINE at the end of a POKE statement.
2 5C5Fh (23647) X PTR Address of the character after the ? marker.
X2 5C61h (23649) WORKSP Address of temporary work space.
X2 5C63h (23651) STKBOT Address of bottom of calculator stack.
X2 5C65h (23653) STKEND Address of start of spare space.
N1 5C67h (23655) BREG Calculator's B register.
N2 5C68h (23656) MEM Address of area used for calculator's memory (usually MEMBOT, but not always).
1 5C6Ah (23658) FLAGS2 More flags. (Bit 3 set when CAPS SHIFT or CAPS LOCK is on.)
X1 5C6Bh (23659) DF SZ The number of lines (including one blank line) in the lower part of the screen.
2 5C6Ch (23660) S TOP The number of the top program line in automatic listings.
2 5C6Eh (23662) OLDPPC Line number to which CONTINUE jumps.
1 5C70h (23664) OSPPC Number within line of statement to which CONTINUE jumps.
N1 5C71h (23665) FLAGX Various flags.
N2 5C72h (23666) STRLEN Length of string type destination in assignment.
N2 5C74h (23668) T ADDR Address of next item in syntax table (very unlikely to be useful).
2 5C76h (23670) SEED The seed for RND. This is the variable that is set by RANDOMIZE.
3 5C78h (23672) FRAMES 3 byte (least significant byte first), frame counter incremented every 20ms.
2 5C7Bh (23675) UDG Address of first user-defined graphic. You can change this, for instance, to save space by having fewer user-defined characters.
1 5C7Dh (23677) COORDS X-coordinate of last point plotted.
1 5C7Eh (23678) Y-coordinate of last point plotted.
1 5C7Fh (23679) P POSN 33-column number of printer position.
1 5C80h (23680) PR CC Least significant byte of address of next position for LPRINT to print at (in printer buffer).
1 5C81h (23681) Not used.
2 5C82h (23682) ECHO E 33-column number and 24-line number (in lower half) of end of input buffer.
2 5C84h (23684) DF CC Address in display file of PRINT position.
2 5C86h (23686) DF CCL Like DF CC for lower part of screen.
X1 5C88h (23688) S POSN 33-column number for PRINT position.
X1 5C89h (23689) 24-line number for PRINT position.
X2 5C8Ah (23690) SPOSNL Like S POSN for lower part.
1 5C8Ch (23691) SCR CT Counts scrolls - it is always 1 more than the number of scrolls that will be done before stopping with scroll?. If you keep poking this with a number bigger than 1 (say 255), the screen will scroll on and on without asking you.
1 5C8Dh (23692) ATTR P Permanent current colours, etc., (as set up by colour statements).
1 5C8Eh (23693) MASK P Used for transparent colours, etc. Any bit that is 1 shows that the corresponding attribute bit is taken not from ATTR P, but from what is already on the screen.
N1 5C8Fh (23694) ATTR T Temporary current colours, etc., (as set up by colour items).
N1 5C90h (23696) MASK T Like MASK P, but temporary.
1 5C91h (23697) P FLAG More flags.
N30 5C92h (23698) MEMBOT Calculator's memory area - used to store numbers that cannot conveniently be put on the calculator stack.
2 5CB0h (23728) NMIADD Holds the address of the users NMI service routine. NOTE - On previous machines, this did not work correctly and these two bytes were documented as 'Not used.' Programs that user these two bytes for passing values may need to be modified.
2 5CB2h (23730) RAMTOP Address of last byte of BASIC system area.
2 5CB4h (23732) P RAMT Address of last byte of physical RAM.

Part 26
Using machine code

Subjects covered...

This section is written for those who understand Z80 machine code, ie. the set of instructions that the Z80 processor chip users. If you do not, but would like to, there are plenty of books about it. You should get one called something along the lines of... 'Z80 machine code (or assembly language) for the absolute beginner', and if it mentions the '+3' or other computers in the ZX Spectrum range, so much the better.

Machine code programs are normally written in assembly language, which, although cryptic, is not too difficult to understand with practice. You can see the assembly language instructions in part 28 of this chapter. However, to run them on the +3 you need to code the program into a sequence of bytes - then called machine code. This translation is usually done by the computer itself using a program called an assembler. There is no assembler built in to the +3, but you will be able to buy one on disk or tape. Failing that, you will have to do the translation yourself, provided that the program is not too long.

Let's take as an example the program...

ld bc, 99

...which loads the BC register pair with 99. This translates into the four machine code bytes 1, 99, 0 (for ld bc, 99) and 201 (for ret). (If you look up codes 1 and 201 in part 28 of this chapter, you will find that corresponds to ld bc, NN - where NN stands for any two-byte number, and 201 corresponds to ret.)

When you have got your machine code program, the next step is to get into the computer - (an assembler would probably do this automatically). You need to decide whereabouts in memory to locate it - the best thing is to make extra space for it between the BASIC area and the user-defined graphics.

If you type...

CLEAR 65267

...this will give you a space of 100 (for good measure) bytes starting at address 65268.

To put in the machine code program, you would run a BASIC program something like...

10 LET a=65268
20 READ n: POKE a,n
30 LET a=a+1: GO TO 20
40 DATA 1,99,0,201

(This will stop with the report E Out of DATA when it has filled in the four bytes you specified.)

To run the machine code, you use the function USR - but this time with a numeric argument, ie. the starting address. Its result is the value of the BC register on return from the machine code program, so if you type...

 PRINT USR 65268 will get the answer 99.

The return address to BASIC is 'stacked' in the usual way, so return is by a Z80 ret instruction. You should not use the IY and I registers in a machine code routine that expects to use the BASIC interrupt mechanism. If you are writing a program that might eventually run on an older Spectrum (up to and including the +2), you should not load I with values between 40h and 7Fh (even if you never use IM 2). Values between C0h and FFh for I should also be avoided if contended memory (ie. RAM 4 to 7) is to be paged in between C000h and FFFFh. This is due to an interaction between the video controller and the Z80 refresh mechanism, and can cause otherwise inexplicable crashes, screen corruption or other undesirable effects. This, you should only vector IM 2 interrupts to between 8000h and BFFFh, unless you are very confident of your memory mapping (or you are only going to run your program on the +3 where this problem does not exist).

The system variable at 5CB0h (23728) was documented on previous models of the Spectrum as 'Not used'. It is now used on the +3 as an NMI jump vector. If an NMI occurs, this address is checked. If it contains a 0, then no action is taken. However, for any other (non-zero) value, a jump will be made to the address given by this variable. NMIs must not occur while the disk system is active.

There are a number of standard pitfalls when programming a banked system such as the +3 from machine code. If you are experiencing problems, check that your stack is not being paged out during interrupts, and that your interrupt routine is always where you expect it to be (it is advisable to disable interrupts during paging operations). It is also recommended that you keep a copy of the current bank register setting in unpaged RAM somewhere as the ports are write-only. BASIC and the editor use the system variables BANKM and BANK678 for 7FFDh and 1FFDh respectively.

If you call +3DOS routines, remember that interrupts should be enabled upon entry to the routines. Remember also that the stack must be below BFE0h (49120) and above 4000h (16384), and that there must be at least 50 words of stack space available.

You can save your machine code program easily enough with (for example)...

 SAVE "name" CODE 65268,4

On the face of it, there is no way of saving the program so that when loaded it automatically runs itself; however, you can get around this by using the short BASIC program...

 10 LOAD "name" CODE 65268,4
 20 PRINT USR 65268

...which should also be saved (as a separate program) using the command (for example)...

 SAVE "loader" LINE 10

Then you may run the machine code from BASIC using the single command...

 LOAD "loader"

...which loads and automatically runs the BASIC program which in turn loads and runs the machine code.

Calling +3DOS from BASIC

When BASIC's USR function is used, the code it references is entered with the memory configured as illustrated below (left), ie. the ROM switched in at the bottom of memory in the address range (000h...3FFFh) is ROM 3 (the 48 BASIC ROM). The RAM page at the top of memory is page 0 and the machine stack resides in this area (unless the CLEAR command has been used to reduce it to somewhere below C000h). As explained in part 27 of this chapter (which describes the +3DOS routines), DOS can only be called with RAM page 7 switched in at the top of memory, the stack held somewhere in that range 4000h...BFE0h, and ROM 2 (the DOS ROM) switched in at the bottom of memory (000h...3FFFh). This configuration is illustrated below (right).

Page 0 C000h SP Page 2 8000h Page 5 4000h ROM 3 0000h

(using DOS)
Page 7 Page 2 SP Page 5 ROM 2

Consequently, it will be necessary to switch both ROM and RAM, and move the stack before and after calling one of the entries in the DOS jump table. The following very simple example shows one way of achieving the desired set up in order to call DOS CATALOG.

If BASIC's CLEAR command has been used so that the BASIC stack is below BFE0h (49120), then it is not necessary to move the stack. However, we have done so in the following example to demonstrate the technique when this is not the case.

A simple example to call DOS CATALOG...

        org   7000h

mystak        equ 9FFFh  ;arbitrary value picked to be below BFE0h and above 4000h
staksto       equ 9000h  ;somewhere to put BASIC's stack pointer
bankm         equ 585Ch  ;system variable that holds the last value output to 7FFDh
port1         equ 7FFDh  ;address of ROM/RAM switching port in I/O map
catbuff       equ 8000h  ;somewhere for DOS to put its catalog
dos_catalog   equ 011Eh  ;the DOS routine to call


     di                  ;unwise to switch RAM/ROM without disabling interrupts
     ld   (staksto),sp   ;save BASIC's stack pointer
     ld   bc,port1       ;the horizontal ROM switch/RAM switch I/O address
     ld   a,(bankm)      ;system variable that holds current switch state
     res  4,a            ;move right to left in horizontal ROM switch (3 to 2)
     or   7              ;switch in RAM page 7
     ld   (bankm),a      ;must keep system variable up to date (very important)
     out  (c),a          ;make the switch
     ld   sp,mystak      ;make sure stack is above 4000h and below BFE0h
     ei                  ;interrupts can now be enabled

; The above will have switched in the DOS ROM and RAM page 7. The stack has also been
; located in a "safe" position for calling DOS
; The following is the code to set up and call DOS CATALOG. This is where your own
; code would be placed.

     ld   hl,catbuff     ;somewhere for DOS to put the catalog
     ld   de,catbuff+1   ;
     ld   bc,1024        ;maximum is actually 64x13+13 = 845
     ld   (hl),0
     ldir                ;make sure at least first entry is zeroised
     ld   b,64           ;the number of entries in the buffer
     ld   c,1            ;include system files in the catalog
     ld   de,catbuff     ;the location to be filled with the disk catalog
     ld   hl,stardstar   ;the file name ("*.*")
     call dos_catalog    ;call the DOS entry
     push af             ;save flags and possible error number returned by DOS
     pop  hl
     ld   (dosret),hl    ;put it where it can be seen from BASIC
     ld   c,b            ;move number of files in catalog to low byte of BC
     ld   b,0            ;this will be returned in BASIC by the USR function

; If the above worked, then BC holds number of files in catalog, the "catbuff" will
; be filled with the alphanumerically sorted catalog and the carry flag but in "dosret"
' will be set. This will be peeked from BASIC to check if all went well.
; Having made the call to DOS, it is now necessary to undo the ROM and RAM switch and
; put BASIC's stack back to where it was on entry. The following will achieve this.

     di                  ;about to ROM/RAM switch so be careful
     push bc             ;save number of files
     ld   bc,port1       ;I/O address of horizontal ROM/RAM switch
     ld   a,(bankm)      ;get current switch state
     set  4,a            ;move left to right (ROM 2 to ROM 3)
     and  F8h            ;also want RAM page 0
     ld   (bankm),a      ;update the system variable (very important)
     out  (c),a          ;make the switch
     pop  bc             ;get back the saved number of files in catalog
     ld   sp,(staksto)   ;put BASIC's stack back
     ret                 ;return to BASIC, value in BC is returned to USR


     defb "*.*",FFh      ;the file name, must be terminated with FFh


     defw 0              ;a variable to be peeked from BASIC to see if it worked

As some of you may not have an assembler available, the following is a BASIC program that pokes the above code into memory, calls it, and then uses the value returned by the USR function and the contents of 'dosret' to print a very simple catalog of the disk.

  10  LET sum=0
  20  FOR i=28672 TO 28758
  30  READ n
  40  POKE i,n : LET sum=sum+n
  50  NEXT i
  60  IF sum <> 9387 THEN PRINT "Error in DATA" : STOP
  70  LET x= USR 28672
  80  IF INT ( PEEK (28757)/2)= PEEK (28757)/2 THEN PRINT "Disk Error "; PEEK (28758): STOP
  90  IF x=1 THEN PRINT "No file found": STOP
 100  FOR i=0 TO x-2
 110  FOR j=0 TO 10
 120  PRINT CHR$ ( PEEK (32781+i*13+j));
 130  NEXT j
 140  PRINT
 150  NEXT i
 160  DATA 243,237,115,0,144,1,253,127,58,92,91,203,167,246,7,50,92,91,237, 121,49,255,159,251
 170  DATA 33,0,128,17,1,128,1,0,4,54,0,237,176,6,64,14,1,17,0,128,33,81,112, 205,30,1,245,225,34,85,112,72,6,0
 180  DATA 243,197,1,253,127,58,92,91,203,231,230,248,50,92,91,237,121,193, 237,123,0,144,201
 190  DATA 42,46,42,255,0,0

The addresses picked for the above code and its data areas are completely arbitrary. However, it is a good idea to keep things in the central 32K wherever possible so as not to run into the pitfall of accidentally switching out a vital variable or piece of code.

If interrupts are to be enabled (as is the case in the above example), it is imperative that the system is kept up to date about the latest ROM switch. This mean that the user must make the BANK678 system variable reflect the last value output to the port at 1FFDh. As shown by the above example, the general technique is to take a copy of the variable in A, set/reset the relevant its, update the system variable then make the switch with an OUT instruction. Interrupts must be disabled while the system variable does not reflect the current state of the port. The port at 1FFDh doesn't just control the ROM switch, so setting the variable to absolute values would be very unwise. Using AND/OR with a bit mask or SET/RES instructions is the preferred method of updating the variable.

Just as BANK678 reflects the last value output to 1FFDh, BANKM should also be kept up to date with the last value output to 7FFDh. Again, it is unwise to use absolute values, as the port is used for other purposes. For example, the bottom 3 bits of the port are used to select the RAM page that is switched into the memory area C000h...FFFFh (this is also shown in the above example). naturally, when more than one bit is to be set/reset, a bit mask used with OR/AND is the more efficient method. note that RAM paging was described in the section entitled 'Memory management' in part 24 of this chapter.

The above was a very simple example of calling DOS routines. The following shows one or two extra techniques that you may find useful. However, if you are not already familiar with assembler programming, it might be better to skip this example.

Although part 20 of this chapter suggested that the opening menu's Loader option first looks for a file called * and the one called DISK before trying to load the first file from tape - this isn't exactly the whole story. The first operation actually tries to load a bootstrap sector from the disk in drive A. The sector on side 0, track 0, sector 1 will be used as a loader (bootstrap) if the system finds that the 9 bit checksum of the sector is 3. The following program ensures that the checksum of 512 bytes conforms to this requirement, then writes the information to the disk in the correct position. Once a disk has been modified in this way, the Loader option can be used to automatically load and run the disk. Alternatively, the BASIC command LOAD "*" can be used.

This example was developed using M80 on a CP/M based machine - so the method to ensure that the code is assembled relative to the correct address might be different from that used by your own assembler...

; Simple example program to write a boot sector to the disk in drive A:.
; by Cliff Lawson
; copyright (c) AMSTRAD plc. 1987

       .z80                             ; ignore this if not using M80

     bank1               equ  07FFDh    ;"horizontal" and RAM switch port
     bankm               equ  05B5Ch    ;associated system variable
     bank2               equ  01FFDh    ;"vertical" switch port
     bank678             equ  05B67h    ;associated system variable

     select              equ  01601h    ;BASIC routine to open stream
     dos_ref_xdpb        equ  0151h     ;
     dd_write_sector     equ  0166h     ;see part 27 of this chapter
     dd_login            equ  0175h     ;

          org            0
          .phase         07000h

; (This allows M80 to generate a .COM file that has addresses relative to 7000h.
; Assemble with "M80 = prog" and link with "L80 /p:0,/d:0,prog,prog/n:p/y/e"
; This can be headed with COPY...TO SPECTRUM FORMAT and loaded with
; LOAD...CODE 28672.
; A different technique will probably be required for other assemblers.)

     ld   (olstak),sp         ;save BASIC's stack pointer
     ld   sp,mystak           ;put stack below switched RAM pages
     push iy                  ;save IY on stack for the moment

     ld   a,"A"               ;drive A:
     ld   iy,dos_ref_xdpb     ;make IX point to XDPB A: (necessary for calling DD
     call dodos               ;routines)

     ld   c,0                 ;log in disk in unit 0 so that writing sectors
     push ix                  ;wont say "disk has been changed"
     ld   iy,dd_login
     call dodos
     pop  ix

     ld   hl,bootsector
     ld   bc,512              ;going to checksum 512 bytes of sector
     xor  a
     ld   (bootsector+15),a   ;reset checksum for starters
     ld   e,a                 ;E will hold 8 bit sum


     ld   a,e
     add  a,(hl)              ;this loop makes 8 bit checksum of 512 bytes
     ld   e,a                 ;sector in E
     inc  hl
     dec  bc
     ld   a,b
     or   c
     jr   nz,ckloop

     ld   a,e                 ;A now has 8 bit checksum of the sector
     cpl                      ;ones complement (+1 will give negative value)
     add  a,4                 ;add 3 to make sum = 3 + 1 to make twos complement
     ld   (bootsector+15),a   ;will make bytes checksum to 3 mod 256

     ld   b,0                 ;page 0 at C000h
     ld   c,0                 ;unit 0
     ld   d,0                 ;track 0
     ld   e,0                 ;sector 1 (0 because of logical/physical trans.)
     ld   hl,bootsector       ;address of info. to write as boot sector
     ld   iy,dd_write_sector
     call dodos               ;actually write sector to disk
     pop  iy                  ;put IY back to BASIC can reference its system variables
     ld   sp,(olstak)         ;put original stack back
     ret                      ;return to USR call in BASIC

; IY holds the address of the DOS routine to be run. All other registers are passed
; intact to the DOS routine and are returned from it.
; Stack is somewhere in central 32K (conforming to DOS requirements), so save AF and
; BC will not be switched out.
     push af
     push bc                  ;temp save registers while switching
     ld   a,(bankm)           ;RAM/ROM switching system variable
     or   7                   ;want RAM page 7
     res  4,a                 ;and DOS ROM
     ld   bc,bank1            ;port used for horiz ROM switch and RAM paging
     ld   (bankm),a           ;keep system variables up to date
     out  (c),a               ;RAM page 7 to top and DOS ROM
     pop  bc
     pop  af

     call jumptoit            ;go sub routine address in IY

     push af                  ;return from JP (IY) will be to here
     push bc
     ld   a,(bankm)
     and  0F8h                ;reset bits for page 0
     set  4,a                 ;switch to ROM 3 (48 BASIC)
     ld   bc,bank1
     ld   (bankm),a
     out  (c),a               ;switch back to RAM page 0 and 48 BASIC
     pop  bc
     pop  af


     jp   (iy)                ;standard way to CALL (IY), by calling this jump


     dw   0                   ;somewhere to put BASIC's stack pointer
     ds   100

mystak:                       ;enough stack to meet +3DOS requirements


     .dephase                 ;these are M80 pseudo ops. your assembler
     .phase    0FE00h         ;may use something different

; Bootstrap will load into page 3 at address FE00h. The code will be entered at FE10h.
; Before it is written to track 0, sector 1, the bootstrap has byte 15 changed so
; that it will checksum to 3 mod 256.
; Boot will switch the memory so that the 48 BASIC ROM is at the bottom. Next up is
; page 5 - the screen, then page 2, and the top will keep page 3, as it would be
; unwise to switch out the bootstrap. BASIC routines can be called with any RAM
; page switched in at the top, but the stack shouldn't be in the TSTACK area.

; The bootstrap sector contains the 16 bytes disk specification at the start.
; The following values are for a AMSTRAD PCW range CF2/Spectrum +3 format disk.
     db   0                   ;+3 format
     db   0                   ;single sided
     db   40                  ;40 tracks per side
     db   9                   ;9 sectors per track

     db   2                   ;log2(512)-7 - sector size
     db   1                   ;1 reserved track
     db   3                   ;blocks
     db   2                   ;2 directory blocks

     db   02Ah                ;gap length (r/w)
     db   052h                ;page length (format)
     ds   5,0                 ;5 reserved bytes

cksum:         db   0         ;checksum must = 3 mod 256 for the sector
; The bootstrap will be entered here with the 4, 7, 6, 3 RAM pages switched in.
; To print something, we need 48 BASIC in at the bottom, page 5 (the screen and
; system variables) next up. The next page will be 0, and the top will be kept
; as page 3 because it still contains the bootstrap and stack (stack is FE00h
; on entry).
     ld   a,(bankm)
     and  0F8h
     or   3                   ;RAM page 3 (as it holds bootstrap)
     set  4,a                 ;right-hand ROMs
     ld   bc,bank1
     ld   (bankm),a
     out  (c),a               ;switch RAM and horizontal ROM
     ld   a,(bank678)
     and  0F8h
     or   4                   ;set bit 2 and reset bit 0 (gives ROM 3)
     ld   bc,bank2
     ld   (bank678),a
     out  (c),a               ;should now have R3,5,2,3

     ld   a,2
     call select              ;BASIC ROM routine to open stream (A)
     ld   hl,message
     call print               ;print a message

; end with an endless loop changing the border. This is where your own code
; for a game or operating system would go.
     ld   a,r                 ;a not-very-random random number
     out  (0feh),a            ;switch the border
     jr   eloop               ;and loop

     ld   a,(hl)              ;this just loops printing characters
     cp   0FFh                ;until if finds FFh
     ret  z
     rst  10h                 ;with 48K ROM in, this will print char in A
     inc  hl
     jr   print

     defb 16,2,17,7,19,0,22,10,1,"Hello, good evening and welcome",0ffh
     ds   512-(cliff-bootstart),0  ;fill to end of sector with 0s


There are one or two things that may be worth noting about this example. The first is that because BASIC normally has the address of the ERR NR system variable held in IY (so it can easily reference its system variables). It is important to store IY and replace it before returning to the original USR call.

Just as before, the stack is moved so that is sits in the central 32K of memory. This will allow +3DOS routines to be called without having to move it again.

The 'dodos' subroutine may be useful in your own programs. It only uses the IY register - which isn't used by the +3DOS system and allows a call to be made to any of the +3DOS routines.

The program uses DOS REF XDPB to make IX point at the relevant XDPB for drive A:. It then logs in the disk in A: so that it can be written to. After calculating and modifying the checksum byte for the information to be written to the boot sector of the disk, it writes the boot sector using DD WRITE SECTOR.

No checks are made to see that there is even a disk interface, and possible errors are ignored - the routine isn't designed to be used by those unfamiliar with possible pitfalls. The routine can be called with the BASIC command...

 USR 28672

...which will come back with whatever number BC happens to contain after completion of the routine.

The boot sector that is written to the disk has a standard disk specification in the first 16 bytes. This is followed by the bootstrap code that will be entered at address FE10h. As will be described in the interface for DOS BOOT (see part 27 of this chapter), the memory will initially be set up as 4, 7, 6, 3; however, the BASIC system variables are still intact and BASIC can be operated by switching in the correct ROM (3) t5o the bottom of memory and making sure that page 5 is in the 4000h...7FFFh area of memory.

This very simple boot program just uses the BASIC ROM to print a greeting then enters a tight loop changing the border colour. It could be modified to load a large binary file and enter it or perform any other action you desired.

Part 27
Guide to +3DOS

Subjects covered...

This section describes +3DOS - the disk operating system of the +3. The information will probably be of most interest to people familiar with assembly language (machine code) programming (see part 26 of this chapter for more information on this subject). What follows is highly technical, and should not be used by the uninitiated.

The operating software of the +3 is, in effect, held in four ROMs (though the information is actually contained in just two ICs). All four ROMs are addressed between 0000h and 3FFFh, although only one is switched in at a time.

ROM 0 is the 'editor' ROM and is the one entered when the +3 is first switched on. This controls the high level 'menuing' and editing functions.

ROM 1 is the 'syntax' ROM and handles the high level control of +3 BASIC. It contains the code for the BASIC parts of most of the disk based commands.

ROM 3 is the '48 BASIC' ROM and is virtually identical to the ROM used in the very first Spectrum. The only real area where it is different is in the code executed when an interrupt occurs. If non-zero, a 'ticker' variable is decremented every second interrupt, and when it reaches zero, the disk motor is switched off. This variable is held in page 7 along with some of the editor and DOS variables. Page 7 will only be switched in (and this variable decremented) if bit 4 in the FLAGS system variable is set - this is used by the software to identify whether it is running 48 BASIC or +3 BASIC. When 48 BASIC is selected (from the main menu or by the SPECTRUM command), this bit is reset so that this page-switching and ticker-decrementing won't happen. However, if bit 4 in the FLAGS system variable is subsequently set by your own program, this process will start again while interrupt mode 1 is still selected.

The keypad scanning routines of the Spectrum 128 and +2 have been removed from ROM 3 in the +3.

A 'bug' in the original 48 BASIC ROM has been fixed in the +3. When a non-maskable interrupt (NMI) occurs, a jump is made to location 66h. This now checks the contents of the NMIADD system variable. If it is zero, a RETN is executed, otherwise a jump is made to the routine address held in NMIADD. The NMI code in ROM 2 consists of just a RETN.

ROM 3 not only provides the 48 BASIC mode for program compatibility, but executes the majority of +3 BASIC commands that don't make use of the more advanced hardware of the +3.

The fourth ROM (ROM 2) holds +3DOS - the disk operating system. This is the subject of this section. Unlike the other ROMs, which are unlikely to be of much use for assembler programmers (except the 48 BASIC ROM perhaps), the +3DOS ROM has a wealth of routines that may well be of use in your own programs. We strongly recommend that any software that uses the disk drives makes use of these routines as they provide most of the facilities that one could wish for (more than are currently used by BASIC, in fact). Furthermore, the routines should only be accessed via the jump block. This not only makes it easier to write software that can be adapted to and from the AMSTRAD CPC range of computers, but also affords upwards compatibility for the future. The entry points for each routine are held in a jump table at address 0100h (256) in the ROM. Part 26 of this chapter gave a couple of examples of the way in which these routines can be called.

+3DOS provides the following facilities:

+3DOS interface

+3DOS's interface is a set of routines accessed via a jump block. The routines provided fall into three categories:

The following is a list of the routines in each of these categories (together with brief descriptions of the routines' functions):

Essential filing system routines

DOS VERSION Get +3DOS issue and version numbers
DOS OPEN Create and/or open a file
DOS CLOSE Close a file
DOS ABANDON Abandon a file
DOS REF HEAD Point at the header data for this file
DOS READ Read bytes into memory
DOS WRITE Write bytes from memory
DOS BYTE READ Read a byte
DOS BYTE WRITE Write a byte
DOS CATALOG Catalog disk directory
DOS FREE SPACE Free space on disk
DOS DELETE Delete a file
DOS RENAME Rename a file
DOS BOOT Boot an operating system or other program
DOS SET DRIVE Set/get default drive
DOS SET USER Set/get default user number

Additional routines for games and operating systems

DOS GET POSITION Get file pointer for random access
DOS SET POSITION Set file pointer for random access
DOS GET EOF Get end of file position for random access
DOS GET 1346 Get memory usage in pages 1, 3, 4, 6
DOS SET 1346 Re-allocate memory usage in pages 1, 3, 4, 6
DOS FLUSH Bring disk up to date
DOS SET ACCESS Change open file's access mode
DOS SET ATTRIBUTES Change a file's attributes
DOS OPEN DRIVE Open a drive as a single file
DOS SET MESSAGE Enable/disable error messages
DOS REF XDPB Point at XDPB for low level disk access
DOS MAP B Map B: onto unit 0 or 1

Low level floppy disk driving routines

DD INTERFACE Is the floppy disk driver interface present?
DD INIT Initialise disk driver
DD SETUP Specify drive parameters
DD SET RETRY Set try/retry count
DD READ SECTOR Read a sector
DD WRITE SECTOR Write a sector
DD CHECK SECTOR Check a sector
DD FORMAT Format a track
DD READ ID Read a sector identifier
DD TEST UNSUITABLE Test media suitability
DD LOGIN Log in disk, initialise XDPB
DD ASK 1 Is unit 1 (external drive) present?
DD DRIVE STATUS Fetch drive status
DD EQUIPMENT What type of drive?
DD ENCODE Set intercept routine for copy protection
DD L XDPB Initialise an XDPB from a disk specification
DD L DPB Initialise a DPB from a disk specification
DD L SEEK µPD765A seek driver
DD L READ µPD765A read driver
DD L WRITE µPD765A write driver
DD L ON MOTOR Motor on, wait for motor-on time
DD L T OFF MOTOR Start the motor-off ticker
DD L OFF MOTOR Turn the motor off

Games and other non-BASIC programs

+3DOS provides facilities specifically for non-BASIC programs:

Using +3DOS without a floppy disk interface

Even if the floppy disk interface were not present, +3DOS could still be used as follows:

File attributes

Bit 7 of the name and type field characters are the file attributes. The top bits of the name field characters are denoted f1...f8. The top bits of the type field characters are denoted t1...t3. They have the following meanings:

A read-only file cannot be written to, erased or renamed. System files can, optionally, be omitted from the directory catalog. The archive attribute is ignored by +3DOS.

Newly created files have all attributes set to 0. An existing file's attributes can only be changed by DOS SET ATTRIBUTES (as used by BASIC's MOVE command).

File headers

Tape files have headers which contain some system information. +3DOS files may, or may not, have headers. All files created by BASIC's SAVE command will have headers.

The +3DOS header mechanism provides a dedicated 8 byte area in each headed file reserved for BASIC's use. The remainder of the header is reserved for +3DOS. This 8 byte header is utilised in files created by BASIC commands (see DOS OPEN description).

+3DOS files may have a single header in the first 128 bytes of the file - the header record. These headers are detected by a 'signature' and checksum. If the signature and checksum are as expected, then a header is present; if not, these is no header. Thus, it is possible, but unlikely, that a file without a header could be mistaken for one with a header.

The format of the header record is as follows:

The issue and version numbers are provided for any future expansion. The issue number must equal the software's issue number; the version number must be less than or equal to the software's version number.

+3DOS performs all the necessary header 'house-keeping'. A pointer to +3 BASIC's 8 byte header area may be returned using DOS REF HEAD. It is never necessary to write directly to the 128 byte header.

AMSDOS headers (as used on the AMSTRAD CPC range of computers) will not be recognised. AMSDOS files will be treated by +3DOS as headerless, and vice versa.

Disk formats

+3DOS supports exactly the same disk format as CP/M Plus and LocoScript on the AMSTRAD PCW range of computer/word processors (ie. the first format listed below).

The following formats are automatically detected when the disk is first accessed:

Note that the AMSTRAD CPC range's IBM format is not supported.

Other disk formats can be used by patching the XDPB for a drive. The XDPB is the same as for the first format listed above; it is not the same as on the CPC range.

Disk formats are subject to the following restrictions:

Logical tracks and sectors

The disk driver routines require 'logical' tracks and sectors. These are used to hide information concerning the number of sides and the actual sector numbers from +3DOS, which knows nothing about them.

Logical track numbers on a single sided disk are the same as physical track numbers.

For double sided disks, two options are available:

  1. Alternating sides...

    side 0 track 0 = logical track 0 side 1 track 0 = logical track 1 side 0 track 1 = logical track 2 side 1 track 1 = logical track 3 side 0 last track = logical track n-1 side 1 last track = logical track n

  2. Successive sides...

    side 0 track 0 = logical track 0 side 0 track 1 = logical track 1 side 0 track 2 = logical track 2 side 0 last track = logical track n/2-1 ...and then... side 1 last track-1 = logical track n/2 side 1 last track-2 = logical track n/2+1 side 1 last track-3 = logical track n/2+2 side 1 track 0 = logical track n

...where n is the total number of logical tracks (ie. 2 x number of tracks per side).

Logical sectors hide the actual physical sector numbers. Logical sector numbers always start from 0.

Logical sector = physical sector - first sector

Disk specification

The PCW range disk format (used by the +3) is, in fact, a family of formats the precise member of which is defined in the 'disk specification' which is recorded on bytes 0...15 of sector 1, track 0 side 0. The format used on the +3 is the same as disk type 0 below. The sector holding this specification is also that used for a bootstrap program. An example of how it may be set up is shown in the second example in part 26 of this chapter.

Byte 0 Disk type
  1. Standard PCW range DD SS ST (and +3)
  2. Standard CPC range DD SS ST system format
  3. Standard CPC range DD SS ST data only format
  4. Standard PCW range DD DS DT
All other values reserved
Byte 1 Bits 0...1 Sidedness
  1. Single sided
  2. Double sided (alternating sides)
  3. Double sided (successive sides)
Bits 2...6 Reserved (set to 0)
Bit 7 Double track
Byte 2 Number of tracks per side
Byte 3 Number of sectors per track
Byte 4 Log2(sector size) - 7
Byte 5 Number of reserved tracks
Byte 6 Log2(block size / 128)
Byte 7 Number of directory blocks
Byte 8 Gap length (read/write)
Byte 9 Gap length (format)
Bytes 10...14 Reserved
Byte 15 Checksum (used only if disk is bootable)

When a disk is logged on, the disk specification is used to initialise the relevant XDPB.

Extended disk parameter blocks (XDPB)

Associated with each (logical) drive is an extended disk parameter block (XDPB). This contains a standard DPB which is the same as that used by CP/M Plus. It also contains information required by +3DOS to support the different formats. It may be patched in order to use differently formatted disks (provided that the restrictions detailed in the previous table are obeyed).

XDPB structure:

Bytes 0...1 SPT records per track
Byte 2 BSH log2 (block size / 128)
Byte 3 BLM block size / 128 - 1
Byte 4 EXM extent mask
Bytes 5...6 DSM last block number
Bytes 7...8 DRM last directory entry number
Byte 9 AL0 directory bit map
Byte 10 AL1 directory bit map
Bytes 11...12 CKS size of checksum vector (bit 15 = permanent)
Bytes 13...14 OFF number of reserved tracks
Byte 15 PSH log2 (sector size / 128)
Byte 16 PHM sector size / 128 - 1
Byte 17 Bits 0...1 Sidedness
  1. Single sided
  2. Double sided (alternating sides)
  3. Double sided (successive sides)
Bits 2...6 Reserved (set to 0)
Bit 7 Double track
Byte 18 Number of tracks per side
Byte 19 Number of sectors per track
Byte 20 First sector number
Bytes 21...22 Sector size
Byte 23 Gap length (read/write)
Byte 24 Gap length (format)
Byte 25 Bit 7 Multi-track operation
  1. single-track
  2. multi-track
Bit 6 Modulation mode
  1. FM mode
  2. MFM mode
Bit 5 Skip deleted data address mark
  1. don't skip deleted address mark
  2. skip deleted data address mark
Bits 0...4 = 0
Byte 26 Freeze flag
00h (0) = auto-detect disk format
FFh (255) = don't auto-detect disk format

Byte 25 is normally set to 60h (96). Multi-track operation is not recommended.

Setting the freeze flag (byte 26) prevents +3DOS from trying to determine the format of a disk. This should be used when patching an XDPB for a non-standard format.

The XDPBs for the three main formats are as follows:

AMSTRAD PCW range single track format (type 0) (As used by the +3)

36 SPT, records per track
3 BSH, block shift
7 BLM, block mask
0 EXM, extent mask
174 DSM, number of blocks - 1
63 DRM, number of directory entries - 1
C0h (192) AL0, 2 directory blocks
00h (0) AL1
16 CKS, size of checksum vector
1 OFF, reserved tracks
2 PSH, physical sector shift
3 PHM, physical sector mask
0 Single sided
40 Tracks per side
9 Sectors per track
1 First sector number
512 Sector size
42 Gap length (read/write)
82 Gap length (format)
60h (96) MFM mode, skip deleted data address mark
0 Do auto select format

AMSTRAD CPC range SYSTEM format (type 1)

36 SPT, records per track
3 BSH, block shift
7 BLM, block mask
0 EXM, extent mask
170 DSM, number of blocks - 1
63 DRM, number of directory entries - 1
C0h (192) AL0, 2 directory blocks
00h (0) AL1
16 CKS, size of checksum vector
2 OFF, reserved tracks
2 PSH, physical sector shift
3 PHM, physical sector mask
0 Single sided
40 Tracks per side
9 Sectors per track
41h (65) First sector number
512 Sector size
42 Gap length (read/write)
82 Gap length (format)
60h (96) MFM mode, skip deleted data address mark
0 Do auto select format

AMSTRAD CPC range DATA ONLY format (type 2)

36 SPT, records per track
3 BSH, block shift
7 BLM, block mask
0 EXM, extent mask
179 DSM, number of blocks - 1
63 DRM, number of directory entries - 1
C0h (192) AL0, 2 directory blocks
00h (0) AL1
16 CKS, size of checksum vector
0 OFF, reserved tracks
2 PSH, physical sector shift
3 PHM, physical sector mask
0 Single sided
40 Tracks per side
9 Sectors per track
C1h (193) First sector number
512 Sector size
42 Gap length (read/write)
82 Gap length (format)
60h (96) MFM mode, skip deleted data address mark
0 Do auto select format

CP/M File compatibility

+3DOS uses the CP/M file structure, subject to the following restrictions:

File model

A file is an array of bytes which may be of any length from 0 to 8 megabytes. Associated with each open file is a 24 bit file pointer. The file pointer is the address of the next byte to be written or read. The file pointer is automatically advanced after each read or write operation, however, the user may set it to any value required for random access.

The end of file position (EOF) is the lowest byte position that is greater than all written byte positions. Files without headers can only record their EOF position to the start of the next 128 byte record, ie. ceiling(EOF/128). Files with headers have their EOF position recorded exactly.

Writing a byte after the EOF position will extend the file and advance the EOF position.

Reading a byte at (or beyond) the EOF position will return an EOF error.

Reading an unwritten byte below the EOF position will either return a nonsensical byte or an EOF error. (Reading unwritten bytes is not recommended.)

Changing disks

Under +3DOS, a disk may be changed or removed whenever the drive is not being accessed (and there are no files open on that drive). There is no need to log in a disk.

A disk should not be changed while there are files open on it. If, however, a disk is changed while there are still files open on it, then as soon as +3DOS detects this, the user will be prompted to insert the correct disk. +3DOS can only detect this changed when it reads the directory from the disk.

Note that changing a disk while it is still being written to may corrupt the data on the disk.

Logical to physical drive mapping

If required, two logical drives (A: and B:) can be mapped onto a single physical drive (unit 0). This may be useful for single disk drive systems.

To enable this mapping, the routine DOS MAP B is called, passing to it the address of a routine CHANGE DISK. Whenever unit 0 is accessed, a check is made to see if the disk in unit 0 is for the required logical drive. If not, then CHANGE DISK is called. CHANGE DISK is passed the address of a message and the required logical drive, and the user should be prompted with the message...

Please put the disk for x: into the drive then press any key

...(where x is the name of the logical drive, eg. A: or B:). The routine should then wait for a key to be pressed before returning, after which it is assumed that the disk in unit 0 is for the required logical drive.

DOS MAP B can also be used to re-map B onto unit 1. If unit 1 does not exist, then drive B: is disabled.

+3DOS Error codes

Many +3DOS routines can fail. This is indicated with 'carry' false and an error code in the A register. The error codes are...

Recoverable disk errors:

0 Drive not ready
1 Disk is write protected
2 Seek fail
3 CRC data error
4 No data
5 Missing address mark
6 Unrecognised disk format
7 Unknown disk error
8 Disk changed whilst +3DOS was using it
9 Unsuitable media for drive

Non-recoverable errors:

20 Bad filename
21 Bad parameter
22 Drive not found
23 File not found
24 File already exists
25 End of file
26 Disk full
27 Directory full
28 Read-only file
29 File number not open (or open with wrong access)
30 Access denied (file is in use already)
31 Cannot rename between drives
32 Extent missing (which should be there)
33 Uncached (software error)
34 File too big (trying to read or write past 8 megabytes)
35 Disk not bootable (boot sector is not acceptable to DOS BOOT)
36 Drive in use (trying to re-map or remove a drive with files open)

As an example, the report Unsuitable media for drive is caused by trying to write to a single track disk in a double track drive, or trying to read or write a double track disk in a single track drive.

The report Missing address mark is the error returned when trying to access a disk that is not formatted (although this is not the sole reason for the error).

+3DOS Messages

If error messages are enabled (DOS SET MESSAGE) then, in the event of a recoverable disk error, +3DOS will pass the ALERT routine a message and the user should be prompted to - Retry, Ignore or Cancel? If the user replies R, then the disk operation is retried. If the reply is I, then the error is ignored, and if the reply is C, then the operation is cancelled and an error condition is returned to the caller. If error messages are disabled or if the error is not recoverable, then no message is displayed and an error condition is returned to the caller.

The recoverable disk errors (in the range 0..9) are:

0 Drive x: not ready
1 Drive x: disk write protected
2 Drive x: track ttt, seek fail
3 Drive x: track ttt, sector sss, data error
4 Drive x: track ttt, sector sss, no data
5 Drive x: track ttt, sector sss, missing address mark
6 Drive x: bad format
7 Drive x: track ttt, sector sss, unknown error
8 Drive x: disk changed, please replace
9 Drive x: disk unsuitable

...where X is the disk drive (eg. A: or B:), ttt is the track number, and sss is the sector number.

The above messages are all followed by - Retry, Ignore or Cancel?

The ALERT routine is called to produce one of these messages if the error occurs once +3DOS is committed ot execute a DOS routine. For example, if DOS OPEN is called (with access of exclusive write or read/write) and the disk in the drive is write protected, then it will return immediately with carry clear A=1 (the ALERT routine will not be called).

If, however, while readin the data during DOS READ, a bad sector is found, ALERT will be called to warn the user. This will then offer the opportunity of retrying it (if, for example, the disk was not properly seated in the drive), ignoring (so that bad sector will be ignored allowing as much of the file as possible to be recovered), or cancelling (perhaps because the problem is obviously irrecoverable).

(Note that the routine interface for DOS SET MESSAGE has changed between versions V1.0 and V1.1 of +3DOS. It is important, therefore, that DOS VERSION is called, and that if the version and mark are greater than V1.0, the new routine interface is used. This is the only change between V1.0 and V1.1 and will only be apparent in non-UK machines.)

+3DOS requirements

When any of the +3DOS routines are called, the following store configuration is required.

The stack must be below BFE0h (49120) and above 4000h (16384). The upper value is BFE0h (rather than C000h) because the top 30 bytes of page 2 are used to implement inter-page block moves. This area is not reserved by +3DOS; it is merely required that the stack is not there. The stack must have at least 50 words available.

+3DOS supports up to 16 files open at any time. Note, however, that file numbers 0...2 are utilised by +3 BASIC, so it would be unwise to use these if there is a chance that a +3 BASIC command might be executed while a file is still open. File 0 will always be clsoed when BASIC reports an error (even if the report is 0 OK).

For each of the routines described in this section, interrupts must be enabled on entry, and will still be enabled on exit.

+3DOS Store usage

RAM pages 1, 3, 4, 6 are treated as an array of 128 sector buffers, (numbered 0...127), each of 512 bytes long. The RAMdisk, M: and the sector cache occupy two separate (contiguous) areas in this array. Their sizes and locations are present during initialisation and can be subsequently reset. Any bufers not used by the RAMdisk or cachge are free for any other purpose. Changing the size or location of the RAMdisk deletes all of its files.

All +3DOS routines will exit with the same memory configuration as on entry.

The addresses of filenames, buffers, etc. passedto these routines must be visible, ie. the RAM page in which they are located must be switched in.

The DOS jump block is located in ROM 2 from address 0100h (256) onwards. The addresses and interface for each routine are as follows.

Essential filing system routines

DOS INITIALISE 0100h (256)


DOS VERSION 0103h (259)

Get the DOS issue and version numbers.


DOS OPEN 0106h (262)

Create and/or open a file

There is a choice of action depending on whether or not the file already exists. The choices are 'open action' or 'create action', and are specified in DE. If the file already exists, then the open action is followed; otherwise the create action is followed.

Open action

  1. Error - File already exists.
  2. Open the file, read the header (if any). Position file pointer after header.
  3. Open the file, ignore any header. Position file pointer at 000000h (0).
  4. Assume given filename is filename.type. Erase filename.BAK (if it exists). Rename filename.type to filename.BAK. Follow create action.
  5. Erase existing version. Follow create action.

Create action

  1. Error - File does not exist.
  2. Create and open new file with a header. Position file pointer after header.
  3. Create and open new file without a header. Position file pointer at 000000h (0).

(Example: To simulate the tape action of... 'if the file exists open it, otherwise create it with a header', set open action = 1, create action = 1.)

(Example: To open a file and report an error if it does not exist, set open action = 1, create action = 0.)

(Example: To create a new file with a header, first renaming any existing version to .BAK, set open action = 3, create action = 1.)

Files with headers have their EOF position recorded as the smallest byte position greater than all written byte positions.

Files without headers have their EOF position recorded as the byte at the start of the smallest 128 byte record position greater than all written record positions.

Soft-EOF is the character 1Ah (26) and is nothing to do with the EOF position, only the routine DOS BYTE READ knows about soft-EOF.

The header data area is 8 bytes long and may be used by the caller for any purpose whatsoever. If open action = 1, and the file exists (and has a header), then the header data is read from the file, otherwise the header data is zeroised. The header data is available even if the file does not have a header. Call DOS REF HEAD to access the header data.

Note that +3 BASIC makes use of the first 7 of these 8 bytes as follows:

BYTE 0 1 2 3 4 5 6
Program 0 file length 8000h or `LINE` offset to prog
Numeric array 1 file length xxx name xxx xxx
Character array 2 file length xxx name xxx xxx
CODE or SCREEN$ 3 file length load address xxx xxx

(xxx = doesn't matter)

If creating a file that will subsequently be LOADed within BASIC, then these bytes should be filled with the relevant values.

If the file is opened with exclusive-write or exclusive-read-write access (and the file has a header), then the header is updated when the file is closed.

A file that is already open for shared-read access on another file number may only be opened for shared-read access on this file number.

A file that is already open for exclusive-read or exclusive-write or exclusive-read-write access on another file number may not be opened on this file number.


DOS CLOSE 0109h (265)

All opened files must eventually be closed (or abandoned). A file number cannot be reused until it is closed (or abandoned).


DOS ABANDON 010Ch (268)

Abandon a file.

Similar to DOS CLOSE, except that any header, or data, or directory data yet to be written to disk is discarded. This routine should only be used to force a file closed in the event that DOS CLOSE is unable to close the file (for example, if the media is damaged or permanently changed or removed).


DOS REF HEAD 010Fh (271)

Point at the header data for this file.

The header data area is 8 bytes long and may be used by the caller for any purpose whatsoever. It is available even if the file does not have a header; however, only files with a header and opened with write access will have the header data recorded on disk.

Note that +3 BASIC uses these 8 bytes (see the note under DOS OPEN which gives the details). If creating a file that will subsequently be LOADed within BASIC, then those bytes should be filled with the relevant values.


DOS READ 0112h (274)

Read bytes from a file into memory.

Advance the file pointer.

The destination buffer is in the following memory configuration:

The routine does not consider soft-EOF.

Reading EOF will produce an error.


DOS WRITE 0115h (277)

Write bytes to a file from memory.

Advance the file pointer.

The source buffer is in the following memory configuration:


DOS BYTE READ 0118h (280)

Read a byte from a file.

Advance the file pointer.

Tests for soft-EOF (1Ah (26)). As this condition is not latched, it is possible to read past soft-EOF.

EOF is latched.

The caller must decide whether or not soft-EOF is of interest. This would normally be the case only when reading an ASCII file.

Reading EOF will produce an error.


DOS BYTE WRITE 011Bh (283)

Write a byte to a file.

Advance the file pointer.


DOS CATALOG 011Eh (286)

Fills a buffer with part of the directory (sorted).

The filename specifies the drive, user and a (possibly ambiguous) filename.

Since the size of a directory is variable (and may be quite large), this routine permits the directory to be catalogued in a number of small sections. The caller passes a buffer pre-loaded with the first required filename, or zeroes for the start of the directory. The buffer is loaded with part (or all, if it fits) of the directory sorted in ASCII order. If more of the directory is required, this routine is re-called with the buffer re-initialised with the last file previously returned. This procedure is followed repeatedly until all of the directory has been catalogued.

Note that +3DOS format disks (which are the same as single-sided, single track AMSTRAD PCW range format disks) may have a maximum of 64 directory entries.

Buffer format:

Entry 0 must be preloaded with the first filename.type required. Entry 1 will contain the first matching filename greater than the preloaded entry (if any). A zeroised preload entry is OK.

If the buffer is too small for the directory, this routine can be called again with entry 0 replaced by entry n to fetch the next part of the directory.

Entry format (13 bytes long):

The file size is the amount of disk space allocated to the file, not necessarily the same as the amount used by the file.


DOS FREE SPACE 0121h (289)

How much free space is there on this drive?


DOS DELETE 0124h (292)

Deletes an existing file.

File must not be open on any file number.


DOS RENAME 0127h (295)

Rename an existing file.

File must not be open on any file number. A file with the new filename must not exist. The new name must specify, or default to, the sme drive as the old name.


DOS BOOT 012Ah (298)

Boot from disk.

This routine loads a single bootstrap sector from the disk in drive A: into memory and enters it. This is for loading games or other operating systems.

Bootstrap environment:

The bootstrap sector is on side 0, track 0, sector 1. It is loaded at FE00h (65024) and entered at FE10h (65040). Interrupts are disabled. SP is at FE00h (65024). The sum of all bytes in the sector must equal 3 MOD 256 (byte 15 can be set to the required value to achieve this).




DOS SET DRIVE 12Dh (301)

Set the default drive (ie. the drive implied by all filenames that do not specify a drive).

The default drive is initially A:.

Does not access the drive, but merely checks that there is a driver for it (which does not imply that the drive exists).

This only affects routines that take filename parameters.


DOS SET USER 0130h (304)

Set the default user area, ie. the user area implied by all filenames that do not specify a user number.

The default user number is intially 0.

This only affects routines that take filename parameters.


Additional routines for games and operating systems

DOS GET POSITION 0133h (307)

Get the file pointer.


DOS SET POSITION 0136h (310)

Set the file pointer.

Does not access the disk.

Does not check (or care) if pointer is >= 8 megabytes.


DOS GET EOF 0139h (313)

Get the end of file (EOF) file position greater than all written byte positions.

Does not affect the file pointer.

Does not consider soft-EOF.


DOS GET 1346 013Ch (316)

Get the current location of the cache and RAMdisk.

Pages 1, 3, 4, 6 are considered as an array of 128 sector buffers (numbered 0...127), each of 512 bytes. The cache and RAMdisk occupy two separate (contiguous) areas of this array.

Any unused sector buffers may be used by the caller.

Note that the sizes may be smaller than those specified in DOS SET 1346, as there is an (unpublished) maximum size of cache and a minimum size of RAMdisk (4 sectors).




DOS SET 1346 013Fh (319)

Rebuild the sector cache and RAMdisk.

This routine is used to make some store available to the user, or to return store to DOS.

Note that if the RAMdisk is moved, ot its size is changed, then all files thereon are erased.

Pages 1, 3, 4, 6 are considered as an array of 128 sector buffers (numbered 0...127), each of 512 bytes. The cache and RAMdisk occupy two separate (contiguous) areas of this array.

The location and size of the cache and RAMdisk can be specified separately; any remaining buffers are unused by DOS and are available to the caller.

Note that the sizes actually usedd may be smaller than those specified as in practice, there is a maxximum cache size and a minimum size of RAMdisk (4 sectors).

A cache size of 0 will still work but will seriously impair the floppy disk performance.

This routine will fail if there are any files open on drive M:.


DOS FLUSH 0142h (322)

Write any pending headers, data, directory entries for this drive.

This routine ensures that the disk is up to date. It can be called at any time, even when files are open.


DOS SET ACCESS 0145h (325)

Try to change the access mode of an open file.

This routine will fail if the file is already open, in an incompatible access mode, or if write access is required for a read-only file or disk.



Set a file's attributes.

Only the file attributes f1'...f4', t1'...t3' can be set or cleared. The interface attributes f5'...f8' are always 0.

This routine first sets the attributes specified in D, then clears those attributes specified in E, ie. E has priority.


DOS OPEN DRIVE 014Bh (331)

Open the disk in this drive as a single file.

The whole disk is presented as a single file regardless of any real files on the disk. This routine can be used to examine/poke directories, files, etc. It should not be used by the uninitiated, the faint hearted, or by anyone who values their files!

Sets file pointer to 000000h (0).

If there are any files open on this drive from other file numbers with shared-read access, then the disk can only be opened with shared-read access from this file number.

If there are any file open on this drive from other file numbers with exclusive access, then the disk cannot be opened from this file number.



Enable/disable disk error messages.

This should be used to make +3DOS aware of your own ALERT subroutine. When +3DOS detects an error, it will call your ALERT subroutine, passing to it the values documented below. The ALERT subroutine shouls print the text of the message that +3DOS passes it, then should wait for the user to press a key. If the key is in the reply string (that +3DOS also passes - version V1.0 only), then a 'ret' should be made with A = 0, 1 or 2, or containing the character (depending on the version of +3DOS).


Note that if you are substituting your own ALERT subroutine, the 'entry conditions' are the conditions passed to your subroutine and the 'exit conditions' are the values that your subroutine must produce and the registers you are allowed to corrupt.

Note that there are two routine interfaces for ALERT. The first, (which is used in machines with +3DOS version V1.0) should have the entry and exit conditions shown ahead.



The second version of ALERT, which allows the user to provide non-UK error messages and is generally more flexible, is present in +3DOS versions V1.1 and upwards.



If you provide an ALERT function, you should have two subroutines (or one with switchable entry and exit conditions), and check the +3DOS version number before deciding which one to use.

DOS REF XDPB 0151h (337)

Point at the XDPB for this drive. (The XDPB is required by the floppy disk driver routines.)


DOS MAP B 0154h (340)

Map drive B: to unit 0 or unit 1. (This routine will fail if drive B: has files open.)

If mapping B: to unit 0, then each time unit 0 is accessed, a check is made that the drive mapping is correct. If it isn't, then a reverse call to CHANGE DISK is made, to ask the user to change the disk in unit 0.

If mapping B: to unit 1, then if unit 1 does not exist, drive B: is disabled.


The definition of the subroutine CHANGE DISK is as shown ahead. Note that if you are substituting your own CHANGE DISK subroutine, the 'entry conditions' are the conditions passed to your subroutine, and the 'exit conditions' are registers you are allowed to corrupt.


Ask the user to change the disk in unit 0.

Wait for the user to acknowledge the change.


Low level floppy disk driving routines

The following are the floppy disk driver routines. The unit number is 0...3 for the uPD765A. On the +3, unit 0 is drive A: and unit 1 is drive B:, or optionally, both A: and B: may be mapped onto unit 0. Units 2 and 3 are not used.

With the exception of DD INTERFACE, none of these routines may be called if the floppy disk interface is not present.

All routines assume that interrupts are enabled on entry, and will still be enabled on exit.

DD INTERFACE 0157h (343)

Is the floppy disk drive interface present? (This information is also held by BASIC in bit 4 of the FLAGS3 system variable.)




DD INIT 015Ah (346)

Initialise the disk driver.




DD SETUP 015Dh (349)

Set up disk parameters.

Send a specify command.

Parameter block format:


DD SET RETRY 0160h (352)

Set the try and retry count. (A value of 1 will try the operation once, ie. no retry.)


DD READ SECTOR 0163h (355)

Read a sector.


DD WRITE SECTOR 0166h (358)

Write a sector.


DD CHECK SECTOR 0169h (361)

Check a sector. (Uses the uPD765A scan equal command.)

Checks that the sector on disk is the same as the copy in memory.

Note that FFh (255) on disk or in memory always matches anything (see uPD765A specification for further details).


DD FORMAT 016Ch (364)

Format a track. (Uses the uPD765A format track command.)

Buffer contains 4 bytes for each sector as follows:


DD READ ID 016Fh (367)

Read a sector identifier.



Check that disk is suitable to write to.

A single track disk will not work in a double track drive, and vice versa.


If suitable:

DD LOGIN 0175h (373)

Log in a new disk.

Initialise the XDPB.

This routine does not affect or consider the freeze flag.


DD SEL FORMAT 0178h (376)

Initialise an XDPB for a standard format.

This routine does not affect or consider the freeze flag.


DD ASK 1 017Bh (379)

Check to see if unit 1 is present. (BASIC holds this information in bit 5 of the FLAGS3 system variable.)

Turn motor on.

Fetch drive status.

If unit 1 is not-ready and write-protected, then unit 1 is missing. Start motor off timeout.

Note that this routine can be fooled by disks which are almost, but not quite, inserted in the drive.

This routine assumes that when a disk is not in the drive, then write-protect is true. This is indeed the case for 3 inch and 8 inch disk drives, but is not the case for 5 1/4 inch disk drives.





Issue a sense drive status command.


DD EQUIPMENT 0181h (385)

Ask what type of drive this is (ie. single/double track, single/double sided).

Track information can only be determined once a disk has been seen and had its type identified during logging in.

Side information can only be detected after a double sided disk has been seen and has its type identified during logging in.


DD ENCODE 0184h (388)

Set the copy protection ENCODE subroutine.

Copy protected disks have some of their track and sector numbers encoded on disk. Before each disk access, the ENCODE subroutine is called to encode the physical track and sector numbers.

These encoded track and sector numbers must match those in the sector identifier.

Note that tracks 0...2 on either side of a disk should not be encoded.


The definition of the subroutine ENCODE is as shown ahead. Note that if you are substituting your own ENCODE subroutine, the 'entry conditions' are the conditions passed to your subroutine, and the 'exit conditions' are the values that your subroutine must produce and the registers you are allowed to corrupt.



DD L XDPB 0187h (391)

Initialise an XDPB for a given format.

This routine does not affect or consider the freeze flag.


DD L DPB 018Ah (394)

Initialise a DPB for a given format.

This routine does not affect or consider the freeze flag.


DD L SEEK 018Dh (397)

Seek to required track.

Retry if fails.


DD L READ 0190h (400)

Low level uPD765A read command.

Read data.

Read deleted data.

Read a track.

Parameter block format:

Writes commands.

Reads data.

Reads results.

Motor must be running.


DD L WRITE 0193h (403)

Low level uPD765A write command.

Write data.

Write deleted data.

Format a track.

Scan equal.

Scan low or equal.

Scan high or equal.

Parameter block format:

Writes commands.

Writes data.

Reads results.

Motor must be running.


DD L ON MOTOR 0196h (406)

Turn on the motor.

Wait for the motor on time as set by DD SETUP.




DD L T OFF MOTOR 0199h (409)

Start the motor off time-out.




DD L OFF MOTOR 019Ch (412)

Turn off the motor.




Part 28
Spectrum character set

Subjects covered...

This is the complete Spectrum character set, with codes in decimal and hex. If one imagines the codes as being Z80 machine code instructions, then the right hand columns give the corresponding assembly language mnemonics. As you may be aware certain Z80 instructions are 'compounds' starting with CBh or EDh, these are shown in the two right hand columns. Where a character changes between 48K and +3 (128K) modes, the 48K version is given in brackets after the +3 one.

0 not used 00 nop rlc b
1 not used 01 ld bc,NN rlc d
2 not used 02 ld (bc),a rlc e
3 not used 03 inc bc rlc h
4 not used 04 inc b rlc l
5 not used 05 dec b rlc (hl)
6 PRINT comma 06 ld b,N rlc a
7 [EDIT] 07 rlca rlc a
8 cursor left 08 ex af,af' rrc b
9 cursor right 09 add hl,bc rrc c
10 cursor down 0A ld a,(bc) rrc d
11 cursor up 0B dec bc rrc e
12 [DELETE] 0C inc c rrc h
13 [ENTER] 0D dec c rrc l
14 number 0E ld c,N rrc (hl)
15 not used 0F rrca rrc a
16 INK control 10 djnz DIS rl b
17 PAPER control 11 ld de,NN rl c
18 FLASH control 12 ld (de),a rl d
19 BRIGHT control 13 inc de rl e
20 INVERSE control 14 inc d rl h
21 OVER control 15 dec d rl l
22 AT control 16 ld d,N rl (hl)
23 TAB control 17 rla rl a
24 not used 18 jr DIS rr b
25 not used 19 add hl,de rr c
26 not used 1A ld a,(de) rr d
27 not used 1B dec de rr e
28 not used 1C inc e rr h
29 not used 1D dec e rr l
30 not used 1E ld e,N rr (hl)
31 not used 1F rra rr a
32 space 20 jr nz,DIS sla b
33 ! 21 ld hl,NN sla c
34 " 22 ld (NN),hl sla d
35 # 23 inc hl sla e
36 $ 24 inc h sla h
37 % 25 dec h sla l
38 & 26 ld h,N sla (hl)
39 ' 27 daa sla a
40 ( 28 jr z,DIS sra b
41 ) 29 add hl,hl sra c
42 * 2A ld hl,(NN) sra d
43 + 2B dec hl sra e
44 , 2C inc l sra h
45 - 2D dec l sra l
46 . 2E ld l,N sra (hl)
47 / 2F cpl sra a
48 0 30 jr nc,DIS
49 1 31 ld sp,NN
50 2 32 ld (NN),a
51 3 33 inc sp
52 4 34 inc (hl)
53 5 35 dec (hl)
54 6 36 ld (hl),N
55 7 37 scf
56 8 38 jr c,DIS srl b
57 9 39 add hl,sp srl c
58 : 3A ld a,(NN) srl d
59 ; 3B dec sp srl e
60 < 3C inc a srl h
61 = 3D dec a srl l
62 > 3E ld a,N srl (hl)
63 ? 3F ccf srl a
64 @ 40 ld b,b bit 0,b in b,(c)
65 A 41 ld b,c bit 0,c out (c),b
66 B 42 ld b,d bit 0,d sbc hl,bc
67 C 43 ld b,e bit 0,e ld (NN),bc
68 D 44 ld b,h bit 0,h neg
69 E 45 ld b,l bit 0,l retn
70 F 46 ld b,(hl) bit 0,(hl) im 0
71 G 47 ld b,a bit 1,a ld i,a
72 H 48 ld c,b bit 1,b in c,(c)
73 I 49 ld c,c bit 1,c out (c),c
74 J 4A ld c,d bit 1,d adc hl,bc
75 K 4B ld c,e bit 1,e ld bc,(NN)
76 L 4C ld c,h bit 1,h
77 M 4D ld c,l bit 1,l reti
78 N 4E ld c,(hl) bit 1,(hl)
79 O 4F ld c,a bit 1,a ld r,a
80 P 50 ld d,b bit 2,b in d,(c)
81 Q 51 ld d,c bit 2,c out (c),d
82 R 52 ld d,d bit 2,d sbc hl,de
83 S 53 ld d,e bit 2,e ld (NN),de
84 T 54 ld d,h bit 2,h
85 U 55 ld d,l bit 2,l
86 V 56 ld d,(hl) bit 2,(hl) im 1
87 W 57 ld d,a bit 2,a ld a,i
88 X 58 ld e,b bit 3,b in e,(c)
89 Y 59 ld e,c bit 3,c out (c),e
90 Z 5A ld e,d bit 3,d adc hl,de
91 [ 5B ld e,e bit 3,e ld de,(NN)
92 \ 5C ld e,h bit 3,h
93 ] 5D ld e,l bit 3,l
94 ^ 5E ld e,(hl) bit 3,(hl) im 2
95 _ 5F ld e,a bit 3,a ld a,r
96 ` 60 ld h,b bit 4,b in h,(c)
97 a 61 ld h,c bit 4,c out (c),h
98 b 62 ld h,d bit 4,d sbc hl,hl
99 c 63 ld h,e bit 4,e ld (NN),hl
100 d 64 ld h,h bit 4,h
101 e 65 ld h,l bit 4,l
102 f 66 ld h,(hl) bit 4,(hl)
103 g 67 ld h,a bit 4,a rrd
104 h 68 ld l,b bit 5,b in l,(c)
105 i 69 ld l,c bit 5,c out (c),l
106 j 6A ld l,d bit 5,d adc hl,hl
107 k 6B ld l,e bit 5,e ld hl,(NN)
108 l 6C ld l,h bit 5,h
109 m 6D ld l,l bit 5,l
110 n 6E ld l,(hl) bit 5,(hl)
111 o 6F ld l,a bit 5,a rld
112 p 70 ld (hl),b bit 6,b in f,(c)
113 q 71 ld (hl),c bit 6,c
114 r 72 ld (hl),d bit 6,d sbc hl,sp
115 s 73 ld (hl),e bit 6,e ld (NN),sp
116 t 74 ld (hl),h bit 6,h
117 u 75 ld (hl),l bit 6,l
118 v 76 halt bit 6,(hl)
119 w 77 ld (hl),a bit 6,a
120 x 78 ld a,b bit 7,b in a,(c)
121 y 79 ld a,c bit 7,c out (c),a
122 z 7A ld a,d bit 7,d adc hl,sp
123 { 7B ld a,e bit 7,e ld sp,(NN)
124 ` ` 7C ld a,h bit 7,h
125 } 7D ld a,l bit 7,l
126 ~ 7E ld a,(hl) bit 7,(hl)
127 © 7F ld a,a bit 7,a
128 80 add a,b res 0,b
129 81 add a,c res 0,c
130 82 add a,d res 0,d
131 83 add a,e res 0,e
132 84 add a,h res 0,h
133 85 add a,l res 0,l
134 86 add a,(hl) res 0,(hl)
135 87 add a,a res 0,a
136 88 adc a,b res 1,b
137 89 adc a,c res 1,c
138 8A adc a,d res 1,d
139 8B adc a,e res 1,e
140 8C adc a,h res 1,h
141 8D adc a,l res 1,l
142 8E adc a,(hl) res 1,(hl)
143 8F adc a,a res 1,a
144 (a) 90 sub b res 2,b
145 (b) 91 sub c res 2,c
146 (c) 92 sub d res 2,d
147 (d) 93 sub e res 2,e
148 (e) 94 sub h res 2,h
149 (f) 95 sub l res 2,l
150 (g) 96 sub (hl) res 2,(hl)
151 (h) 97 sub a res 2,a
152 (i) user 98 sbc a,b res 3,b
153 (j) graphics 99 sbc a,c res 3,c
154 (k) 9A sbc a,d res 3,d
155 (l) 9B sbc a,e res 3,e
156 (m) 9C sbc a,h res 3,h
157 (n) 9D sbc a,l res 3,l
158 (o) 9E sbc a,(hl) res 3,(hl)
159 (p) 9F sbc a,a res 3,a
160 (q) A0 and b res 4,b ldi
161 (r) A1 and c res 4,c cpi
162 (s) A2 and d res 4,d ini
163 SPECTRUM (t) A3 and e res 4,e outi
164 PLAY (u) A4 and h res 4,h
165 RND A5 and l res 4,l
166 INKEY$ A6 and (hl) res 4,(hl)
167 PI A7 and a res 4,a
168 FN A8 xor b res 5,b ldd
169 POINT A9 xor c res 5,c cpd
170 SCREEN$ AA xor d res 5,d ind
171 ATTR AB xor e res 5,e outd
172 AT AC xor h res 5,h
173 TAB AD xor l res 5,l
174 VAL$ AE xor (hl) res 5,(hl)
175 CODE AF xor a res 5,a
176 VAL B0 or b res 6,b ldir
177 LEN B1 or c res 6,c cpir
178 SIN B2 or d res 6,d inir
179 COS B3 or e res 6,e otir
180 TAN B4 or h res 6,h
181 ASN B5 or l res 6,l
182 ACS B6 or (hl) res 6,(hl)
183 ATN B7 or a res 6,a
184 LN B8 cp b res 7,b lddr
185 EXP B9 cp c res 7,c cpdr
186 INT BA cp d res 7,d indr
187 SQR BB cp e res 7,e otdr
188 SGN BC cp h res 7,h
189 ABS BD cp l res 7,l
190 PEEK BE cp (hl) res 7,(hl)
191 IN BF cp a res 7,a
192 USR C0 ret nz set 0,b
193 STR$ C1 pop bc set 0,c
194 CHR$ C2 jp nz,NN set 0,d
195 NOT C3 jp NN set 0,e
196 BIN C4 call nz,NN set 0,h
197 OR C5 push bc set 0,l
198 AND C6 add a,N set 0,(hl)
199 <= C7 rst 0 set 0,a
200 >= C8 ret z set 1,b
201 <> C9 ret set 1,c
202 LINE CA jp z,NN set 1,d
203 THEN CB set 1,e
204 TO CC call z,NN set 1,h
205 STEP CD call NN set 1,l
206 DEF FN CE adc a,N set 1,(hl)
207 CAT CF rst 8 set 1,a
208 FORMAT D0 ret nc set 2,b
209 MOVE D1 pop de set 2,c
210 ERASE D2 jp nc,NN set 2,d
211 OPEN # D3 out (N),a set 2,e
212 CLOSE # D4 call nc,NN set 2,h
213 MERGE D5 push de set 2,l
214 VERIFY D6 sub N set 2,(hl)
215 BEEP D7 rst 16 set 2,a
216 CIRCLE D8 ret c set 3,b
217 INK D9 exx set 3,c
218 PAPER DA jp c,NN set 3,d
219 FLASH DB in a,(N) set 3,e
220 BRIGHT DC call c,NN set 3,h
221 INVERSE DD prefixes
using ix
set 3,l
222 OVER DE sbc a,N set 3,(hl)
223 OUT DF rst 24 set 3,a
224 LPRINT E0 ret po set 4,b
225 LLIST E1 pop hl set 4,c
226 STOP E2 jp po,NN set 4,d
227 READ E3 ex (sp),hl set 4,e
228 DATA E4 call po,NN set 4,h
229 RESTORE E5 push hl set 4,l
230 NEW E6 and N set 4,(hl)
231 BORDER E7 rst 32 set 4,a
232 CONTINUE E8 ret pe set 5,b
233 DIM E9 jp (hl) set 5,c
234 REM EA jp pe,NN set 5,d
235 FOR EB ex de,hl set 5,e
236 GO TO EC call pe,NN set 5,h
237 GOTO ED set 5,l
238 GO SUB EE xor N set 5,(hl)
239 GOSUB EF rst 40 set 5,a
240 INPUT F0 ret p set 6,b
241 LOAD F1 pop af set 6,c
242 LIST F2 jp p,NN set 6,d
243 LET F3 di set 6,e
244 PAUSE F4 call p,NN set 6,h
245 NEXT F5 push af set 6,l
246 POKE F6 or N set 6,(hl)
247 PRINT F7 rst 48 set 6,a
248 PLOT F8 ret m set 7,b
249 RUN F9 ld sp,hl set 7,c
250 SAVE FA jp m,NN set 7,d
251 RANDOMIZE FB ei set 7,e
252 IF FC call m,NN set 7,h
253 CLS FD prefixes
using iy
set 7,l
254 DRAW FE cp N set 7,(hl)
255 CLEAR FF rst 56 set 7,a

Part 29

Subjects covered...

Reports appear at the bottom of the screen whenever the +3 has stopped executing some BASIC. They explain why it has stopped - be it for some natural reason, or because an error has occurred.

Most reports have a code number or letter (so that you can refer to the table ahead), a brief message explaining what happened, and the line number (and the statement number within the line) where BASIC stopped. (A command is shown as line 0. Within a line, statement 1 is at the beginning, statement 2 comes after the first colon (or THEN), and so on.)

Reports pertaining to disk operation (or +3DOS) do not start with a number or letter - they are shown ahead in alphabetical order.

The behaviour of the CONTINUE command depends very much on the reports. Normally, CONTINUE goes to the line and statement specified in the last report, but there are exceptions with reports 0, 9 and D.

Here is a table showing all the reports. The right-hand column tells you in which circumstances the report can occur, and this refers you to part 31 of this chapter. For example, you can see from the table that the error A Invalid argument can occur with SQR, LN, ACS, ASN and USR. If you then look up these keywords in part 31 of this chapter, you will be able to find out just which arguments are invalid.

Disk errors marked by RIC (in the left-hand column) will normally be displayed followed by the options: - Retry, Ignore or Cancel?. If the cancel option is chosen, then the report shown in the second column will be displayed.

0 OK
Successful completion, or jump to a line number bigger than any existing. This report does not change the line and statement jumped to by CONTINUE.
1 NEXT without FOR
The control variable does not exist (it has not been set up by a FOR statement), but there is an ordinary variable with the same name.
2 Variable not found
For a simple variable, this will happen if the variable is used before it has been assigned to by a LET, READ or INPUT statement, loaded from disk (or tape), or set up in a FOR statement. For a subscripted variable, it will happen if the variable is used before it has been dimensioned in a DIM statement, or loaded from disk (or tape).
3 Subscript wrong
A subscript is beyond the dimension of the array, or there are the wrong number of subscripts. If the subscript is negative or bigger than 65535, then error B will result.
Subscripted variables, strings
4 Out of memory
There is not enough room in the computer for what you are trying to do. If the computer really seems to be stuck in this state, you may have to clear out the command line using DELETE and then delete a program line or two (with the intention of putting them back afterwards) to give yourself room to manoeuvre.
LET, INPUT, FOR, DIM, GO SUB, LOAD, MERGE, Sometimes during expression evaluation.
5 Out of screen
An INPUT statement has tried to generate more than 23 lines in the lower half of the screen. Also occurs with PRINT AT 22,xx.
6 Number too big
Calculations have yielded a number greater than approximately 1038.
Any arithmetic
7 RETURN without GO SUB
There has been one more RETURN than there were GO SUBs.
9 STOP statement
After this, CONTINUE will not repeat the STOP, but carries on with the statement after.
A Invalid argument

The argument for a function is unsuitable (for some reason).

SQR, LN, ASN, ACS, USR (with string argument)
B Integer out of range
When an integer is required, the floating point argument is rounded to the nearest integer. If this is outside a suitable range, then this error results.

For array access, see also error 3.
C Nonsense in BASIC
The text of the (string) argument does not form a valid expression. Also used when the argument for a function or command is outrageously wrong.
D BREAK - CONT repeats
BREAK was pressed during some peripheral operation. The behaviour of CONTINUE after this report is normal in that it repeats the statement. Compare with report L.
LOAD, SAVE, VERIFY, MERGE, Also used when the computer asks scroll? and you press N, BREAK or the space bar
E Out of DATA
You have tried to READ past the end of the DATA list.
F Invalid filename
SAVE with filename empty (or longer than 10 characters using tape).
G No room for line
There is not enough room left in memory to accommodate the new program line.
Entering a line into the program
Some INPUT data started with STOP. Unlike the case with report 9, after this report, CONTINUE will behave normally, by repeating the INPUT statement.
I FOR without NEXT
There was a FOR loop to be executed no times (eg. FOR n=1 TO 0) and the corresponding NEXT statement could not be found.
J Invalid I/O device
You are attempting to input characters from (or output characters to) a device that doesn't support it. For example, it is not possible to input characters from the screen stream. A command such as INPUT #2,a$ will therefore result in this error.
Stream operations; OPEN #, CLOSE #, INPUT #, PRINT #, etc.
K Invalid colour
The number specified is not an appropriate value.
INK, PAPER, BORDER, FLASH, BRIGHT, INVERSE, OVER; also after one of the corresponding control characters
L BREAK into program
BREAK pressed. This is detected between two statements. The line and statement number in the report refer to the statement before BREAK was pressed, but CONTINUE goes to the statement after (allowing for any jumps to be made), so that it does not repeat any statements.
M RAMTOP no good
The number specified for RAMTOP is either too big or too small
CLEAR; possibly in RUN
N Statement lost
Jump to a statement that no longer exists.
O Invalid Stream
Trying to input from (or output to) a stream that isn't open or that is out of range (0...15), or trying to open a stream that is out of range.
P FN without DEF
User-defined function used without a corresponding DEF in the program.
Q Parameter error
Wrong number of arguments, or one of them is the wrong type (string instead of number, or vice versa).
R Tape loading errorA file on tape was found but for some reason could not be read in, or would not verify. VERIFY, LOAD or MERGE
d Too many brackets
Too many brackets around a repeated phrase in one of the arguments.
j Invalid baud rate
The baud rate for the RS232 was set to zero.
k Invalid note name
PLAY came across a note or command it didn't recognise, or a command which was in lower case.
l Number too big
A parameter for a command is an order of magnitude too big.
m Note out of range
A series of sharps of flats has taken a note beyond the range of the sound chip.
n Out of range
A parameter for a command is too big or too small. If the error is very large, error [l][#error-l] results.
o Too many tied notes
An attempt was made to tie too many notes together.
Bad filename
The filename used in any of the disk commands does not conform to the limits described in part 20 of this chapter.
Bad parameters
One of the values passed to +3DOS by BASIC is out of range. It is unlikely that this error will ever be seen.
RIC CRC data error
The cyclic redundancy check (checksum byte) for a sector is incorrect. This is a rare error that is produced if the disk being read has been corrupted in some way (perhaps magnetically).
Code length error
Trying to load a CODE file from disk that is longer than the value given in the LOAD command.
Destination cannot be wild
Trying to give a wildcard file specification for the destination in a COPY command when the source also contains wildcard characters. In this case, the destination can only be a drive letter.
Destination must be drive
The source filename in a COPY command contains wildcard characters, but the destination is only a single file name. In this case, the destination can only be a drive letter.
Directory full
Trying to create the 65th file on a disk; (the normal disk directory can only have 64 entries).
Disk full
Saving or copying files to a disk has used the last byte of free space. The CAT command can be used to check that there is sufficient free space before attempting such an operation. When copying, any partially-copied files will be deleted. However, when saving, it is possible that part of the file may be left on the disk - this part should be erased, as any attempt to use it will fail.
RIC Disk has been changed
While executing a command, +3DOS has noticed that the disk in the drive is not the same one that was present at the beginning of command execution. If a machine code program has opened files on a disk (then the disk is changed) and a +3 BASIC command tries to access the disk, then this report will be produced.
Disk is not bootable
An attempt has been made to load the 'bootstrap' program from a disk that doesn't have a boot sector.
LOAD "*"
RIC Disk is write protected
An attempt has been made to write to a disk whose write protect hole is open. Write protection may be disabled by sliding closed the appropriate tab, before the disk is written to.
Drive B: is not present
An attempt has been made to use the FORMAT command on the external disk drive (drive B:) when it has not been connected.
Drive in use
An attempt has been made to re-map a drive that has files open on it. It is very unlikely that this error will ever be seen.
Drive not found
A filename used in a disk command contains a drive letter specifying a drive that isn't present. For example, ERASE "c:fred".
RIC Drive not ready
A disk command has been attempted when the drive was not ready. This usually happens because there is no disk in the drive. It will usually be possible to simply put a disk in the drive and type R.
End of file found
An attempt has been made to read a byte past the end-of-file position. It is unlikely that this report will be seen.
File already exists
The destination filename in a MOVE command (that is being used to rename a file) already exists.
File already in use
If a machine code program has opened files 1...3, then a +3 BASIC command might fail with this error when it tries to open a file that was already open. It is unlikely that this error will ever be seen.
File is read only
Trying to update, erase or save using the name of a file that has its protection attribute set (using the command MOVE filename TO "+P"). Use the command MOVE filename TO "-P" to remove write protection.
File not found
The filename given for one of the disk reading commands specifies a file that does not exist.
File not open
A disk command has tried to operate on a file which has not been opened. It is very unlikely that this error will ever be seen.
File too big
An attempt has been made to write a file that is greater than 8 megabytes in length. It is very unlikely that this error will ever be seen.
Invalid attribute
The attribute character following + or - in a MOVE command is not P, S or A (or there is more than one character after the + or -).
Invalid drive
A drive letter other than A: or B: has been specified in a FORMAT command.
RIC Missing address mark
A sector being read from the disk does not contain the usual information that is used by the system to identify where it is on the disk. This almost invariably means that an attempt is being made to read a disk that has not been formatted. The error may possibly occur when trying to read a disk that has become corrupted in some way, or one that employs some form of in-built protection.
Missing extent
Files are essentially made up of 16K blocks and each of these is known as an extent. This error might occur while reading a file from disk if the disk is changed after the system has read the directory entry for a file (but before it has read a particular extent). However, it is very unlikely that this error will ever be seen.
RIC No data
This is a low level disk error that occurs when a sector identifier cannot be found. It is possible that the error might occur while trying to copy a disk that employs some form of in-built protection.
No rename between drives
An attempt has been made to use the MOVE command specifying source and destination filenames that are on different drives.
RIC Seek fail
This is a hardware error that means the drive is unable to locate the track that has been requested. If this error persists, it may indicate that the computer needs to be serviced.
This is an internal system error and it is very unlikely that it will ever be seen.
RIC Unknown disk error
An error has occurred that the system is not familiar with. It is very unlikely that it will ever be seen.
RIC Unrecognised disk format
While trying to read/write a disk, +3DOS has been unable to recognise its format, ie. it has read the disk specification but has found information there that doesn't make sense. This error may occur when trying to access disks which employ some form of in-built protection.
RIC Unsuitable media
The disk in the drive has a format that is not suitable. This error might occur when, for example, trying to write to an 80 track disk placed in the (40 track) disk drive of the +3.

Part 30
Reference section

Subjects covered...

The +3 is designed around the Z80A microprocessor, which runs at a speed of 3.5469MHz (about three and half million cycles per second).

The +3's memory is divided into 64K ROM and 128K RAM, arranged in 16K pages. The four ROM pages (0-3) can be mapped into the bottom 16K (0000h-3FFFh) of the memory map. The eight RAM pages (0-7) are usually mapped into the top 16K (C000h-FFFFh) of the memory map. RAM page 5 is also mapped into the range 4000h-7FFFh, and RAM page 2 is mapped into the range 8000h-BFFFh. There are also several RAM page combinations that occupy the full 64K address range. These were given in part 24 of this chapter, under the heading 'Memory management'.

Physically speaking, the ROMs are two 32K devices (similar to the 27256), which are both treated by the system as two 16K chips. The RAM is composed of four 16K x 4 bit chips (41464), some of which (RAM banks 4-7) are time-shared between the circuitry that produces the screen display, and the Z80A. The others (RAM banks 0-3) are for the exclusive use of the Z80A, as in the ROM.

For the contended RAM (which shares time between the video circuitry and the processor), during 128 out of every 228 CPU T states (1 TV line), and during 192 out of every 311 TV lines (1 frame) the CPU is allowed only 1 access to contended RAM in every 8 T states. The CPU is controlled by introducing wait states.

Executing NOP instructions in contended RAM will have an effective average clock frequency of 2.66MHz (a reduction of about 25%).

The Uncommitted Logic Array (ULA) handles most of the I/O such as keyboard, tape interface, part of the printer interface and screen handling. It converts bytes in memory into patterns and colours on the screen, and allows the Z80A to scan the keyboard and read and write data to tape.

The three-channel sound is produced by the AY-3-8912 - a very popular sound chip, and this device also controls the RS232/MIDI and AUX ports.

The two serial ports can be driven only by software. The +3 has no software support for the AUX port - this is left to the user's discretion. The RS232/MIDI port is fully supported from +3 BASIC.

The way in which the AY-3-8912 works is quite complex, and the would-be experimenter is advised to get the manufacturer's data sheet. The following information should be enough to get things underway, however.

The sound chip contains sixteen registers which are selected by writing first to the address write port FFFDh (65533) with the register number, and then reading the register value (same address), or writing to the data register write address BFFDh (49149). Once a register has been selected, any number of data read/writes can be made; the address write port need only be re-written if a different register needs to be addressed.

The basic clock frequency of the circuit is 1.7734MHz (to 0.01%).

The registers do the following:

The tone of a channel is a 12 bit value taken from the sum of D3-D0 of the coarse register, and D7-D0 of the fine register. The basic unit of tone is the clock frequency divided by 16 (ie 110.83KHz), and with a 12 bit counter range, frequencies from 27Hz to 11KHz can generated.

The period of the noise source is taken by counting down the lower 5 bits of the noise register every sound clock period divided by 16.

This register controls both the mixing of noise and tone values for each channel, and the direction of the 8 bit I/O port. A zero in a mix bit indicates that the function is enabled.

These three registers control the amplitude of each channel and whether or not it is modulated by the envelope registers.

The eight bit values in RB+RC are summed to produce a 16 bit number which is counted down in units of 256 multiplied by the sound clock. Envelope frequencies can be between 0.1Hz and 6KHz.

The diagram of envelope shapes (in part 19 of this chapter) gives a graphical illustration of the possible settings for this register.

The disk drive is controlled by the uPD765A floppy disk controller chip. As described in part 23 of this chapter, the data register for this device is at address 3FFDh (16381) and the status register is at 2FFDh (12285). This is a very complex device and it would be unwise to attempt to use it without full details of its operation (see the manufacturer's data sheet).

The Centronics parallel printer port is basically just an 8 bit data latch (74273) whose address is 0FFDh (4093). The STROBE signal for the printer is produced by the ULA and is accessed using the bit 4 of address 1FFDh (8189). The state of the BUSY line from the printer is read from bit 0 of address 0FFDh (4093).

Part 31

Subjects covered...

Numbers are stored to an accuracy of 9 or 10 digits. The largest number you can get is about 1038, and the smallest (positive) number is about 4 x 10-39.

Unless a number represents an exact power of 2 there is a possibility that mathematical inaccuracies may become apparent after repeated addition, subtraction, etc. This is true of all computers that do not use BCD arithmetic. Use of integers is suggested if absolute mathematical accuracy is required.

A number is stored in the +3 in floating point binary with one exponent byte e (1<=e<=255), and four mantissa bytes m (½<=m<1). This represents the number m x 2^e-128.

Since ½<=m<1, the most significant bit of the mantissa m is always 1. Therefore, in actual fact we can replace it with a bit to show the sign - 0 for positive numbers, 1 for negative.

Small integers have a special representation in which the first byte is 00h (0), the second is a sign byte (00h or FFh) and the third or fourth are the integer itself (in twos complement form) with the least significant byte first.

Numeric variables have names of arbitrary length, starting with a letter and continuing with letters and digits. Spaces are ignored and all letters are converted internally to lower-case letters.

Control variables of FOR...NEXT loops have names a single letter long.

Numeric arrays have names a single letter long, which may be the same as the name of a simple variable. They may have many dimensions of arbitrary size. Subscript values start at 1.

Strings are completely flexible in length. The name of a string consists of a single letter followed by $.

String arrays can have many dimensions of arbitrary size. The name is a single letter followed by $ but may not be the same as the name of a simple string variable. All the strings in a given array have the same fixed length, which is specified as an extra final dimension in the DIM statement. Subscript values start at 1.

Slicing: substrings of strings may be specified using slicers. A slicer can be one of the following:

(i) empty


(ii) a numerical expression


(iii) optional numerical expression TO optional numerical expression

...and is used in expressing a substring by either...

(a) string expression (slicer)


(b) string array variable (subscript, ... subscript, slicer)

...which is the same as...

string array variable (subscript, ... subscript, slicer)

In (a), suppose the string expression has the value s$, then if the slicer is empty, the result is s$ (considered as a substring of itself).

If the slicer is a numerical expression with value m, then the result is the nth character of s$ (a substring of length 1).

If the slicer has the form (iii), then suppose the first numerical expression has the value m (the default value is 1), and the second, n (the default value is the length of s$). If 1<=m<=n<=the length of s$, then the result is the substring of s$ starting with the mth character and ending with the nth.

If 0<=n<m, then the result is the empty string. Otherwise, error 3 results.

Slicing is performed before functions or operations are evaluated (unless brackets dictate otherwise).

Substrings can be assigned to (see LET). If a string quote is to be written in a string literal, then it must be doubled.


The argument of a function does not need brackets if it is a constant or a variable (optionally subscripted or sliced).

ABS number Absolute magnitude.
ACS number Arccosine in radians. Error A if x not in the range -1...+1.
AND binary operation, right operand always a number
numeric left operand a AND b a if b<>0 or 0 if b=0
string left operand a$ AND b a$ if b<>0 or "" if b=0
ASN number Arcsine in radians. Error A if x not in the range -1...+1.
ATN number Arctangent in radians.
ATTR two arguments, x and y, both numbers (enclosed in brackets) A number whose binary form codes the attributes of line x, column y on the screen. Bit 7 (most significant) is 1 for flashing, 0 for steady. Bit 6 is 1 for bright, 0 for normal. Bits 5...3 are the paper colour. Bits 2...0 are ink colour. Error B unless 0<=x<=23 and 0<=y<=31.
BIN binary number This is not really a function, but an alternative notation for numbers: BIN followed by a sequence of 0s and 1s is the number with such a representation in binary.
CHR$ number The character whose code is x, rounded to the nearest integer.
CODE string The code of the first character in x (or 0 if x is the empty string)
COS number (in radians) Cosine x.
EXP number ex.
FN FN followed by a letter calls up a user-defined function (see DEF). The arguments must be enclosed in brackets - (even if there are no arguments, the brackets must still be present).
IN number The result of inputting at processor level from port x (0<=x<=FFFFh). Loads the BC register pair with x and does the assembly language instruction in a,(c).
INKEY$ none Reads the keyboard. The result is the character representing the key pressed (if there is exactly one), else the empty string.
INT number Integer part (always rounds down).
LEN string Length.
LN number Natural logarithm (to base e). Error A if x<=0.
NOT number 0 if x<>0, 1 if x=0. NOT has priority 4.
OR binary operation, both operands numbers a OR b 1 if b<>0 or a if b=0
OR has priority 2.
PEEK number The value of the byte in memory whose address is x (rounded to the nearest integer). Error B if x is not in the range 0...65535.
PI none π (3.1415927...).
POINT two arguments, x and y, both numbers (enclosed in brackets) 1 if the pixel at (x,y) is ink colour. 0 if it is paper colour.
Error B unless 0<=x<=255 and 0<=y<=175.
RND none The next pseudo-random number in a sequence generated by taking the powers of 75 modulo 65537, subtracting 1 and dividing by 65536. Yields a number in the range 0<=x<1.
SCREEN$ two arguments, x and y both numbers (wrapped in brackets) The character that appears (either normally or inverted) on the screen at line x, column y. Returns the empty string if the character is not recognised.
Error B unless 0<=x<=23 and 0<=y<=31.
SGN number Sign of number. Returns -1 for negative, 0 for zero, or +1 for positive.
SIN number (in radians) Sine x.
SQR number Square root.
Error A if x<0.
STR$ number The string of characters that would be displayed if x were printed.
TAN number (in radians) Tangent.
USR number Calls the machine code subroutine whose starting address is x. On entry to the routine at address x the memory is configured so that 0000h...3FFFh (0...16383) is occupied by ROM 3 (48 BASIC), 4000h...7FFFh (16384...32767) is occupied by RAM page 5, 8000h...BFFFh (32768...49151) is occupied by RAM page 2, and C000h...FFFFh (49152...65535) is occupied by RAM page 0. If +3DOS routines are to be called, RAM page 7 should be switched in at C000h...FFFFh (49152...65535), and ROM 2 (+3DOS) should be switched in at 0000h...3FFFh (0...16383). See part 26 of this chapter for further details.
On return, the result is the contents of the BC register pair.
USR string The address of the bit pattern for the user-defined graphic corresponding to x.
Error A if x is not a single letter between 'a' and 'u', or a user-defined graphic.
VAL string Evaluates x (without its bounding quotes as a numerical expression.
Error C if x contains a syntax error, or gives a string value. Other errors possible, depending on the expression.
VAL$ string Evaluates x (without its bounding quotes) as a string expression.
Error C if x contains a syntax error of gives a numerical value. Other errors possible (as for VAL).
- number Negation.

The following are binary operations:

The following require both operands be of the same type. The result is a number: 1 if the comparison holds, 0 if it does not.

Functions and operations have the following priorities:

Subscripting and slicing 12
All functions except NOT and unary minus 11
^ (exponentiation) 10
- Unary minus (used to negate) 9
*, / (multiplication, division) 8
+, - (addition, subtraction) 6
=, >, <, <=, >=, <> (relational operators) 5
OR 1


The following notation is applicable in the remainder of this section:

Note that optional expressions are enclosed in [square brackets].

Arbitrary expressions are allowed everywhere (except for the line number at the beginning of a statement).

All statements except INPUT, DEF FN and DATA can be used either as commands or in programs (although they may be more sensible in one than the other). A command or program line can have several statements, separated by colons. There is no restriction on whereabouts in a line any particular statement can occur; however, see IF and REM.

BEEP x,y Sounds a note through the TV's speaker for x seconds at the pitch y semitones above middle C (or below middle C if y is negative)
BORDER m Sets the border colour around the screen, and also the paper colour for the lower part of the screen. Error K unless 0<=m<=7 (ie. unless m is not in the range 0...7).
BRIGHT m Sets brightness of characters subsequently printed; 0 for normal, 1 for bright, 8 for transparent. Error K unless m is 0, 1 or 8.
CAT [#n,] [d] [a] The CAT command produces an alphanumerically sorted catalog of files on a disk. If used in the form CAT #n,... the output is directed to stream n. If an unambiguous filename (or an ambiguous file specification) is included, then only those files that 'match' will be displayed. When CAT is followed by a drive letter only, then all files on that drive will be displayed. If the drive letter specified is T:, then a catalog of tape filenames will be displayed (together with information that will be useful for tape-to-disk file transfer).
CAT [#n,] [d] [a] EXP Operates as per the CAT command, but produces an expanded catalog that includes system files, and displays those files whose write protection, system status and archive attributes have been set. (See MOVE u TO f.)
CIRCLE x,y,z Draws an arc of a circle, centre (x,y) radius z.
CLEAR Deletes all variables, freeing the space they previously occupied. Executes a RESTORE and CLS, resets the PLOT position to the bottom left-hand corner and clears the GO SUB stack.
CLEAR n Like CLEAR, but if possible, changes the system variable RAMTOP to n and puts the new GO SUB stack there. (Note that this command may be used to ensure the machine stack is below BFE0h (49120) when entering a routine that calls +3DOS from BASIC.)
CLOSE #n Marks stream n as being unattached to any channel. It may then be used in a subsequent OPEN #n,f statement.
CLS (Clear screen). Clears the display file.
CONTINUE Continues executing a program from the point at which it stopped with a report (other than 0). If the report was 9 or L, then execution continues with the following statement (taking any jumps into account); otherwise repeats the statement where the report occurred. If the last report was in a command line, then CONTINUE will attempt to continue the command line, and will either go into a loop (if the error was in 0:1), generate report 0 (if it was in 0:2), or report N (if it was in 0:3 or greater).
COPY Sends (dumps) a copy of the top 22 lines of the screen display to the printer (if connected) in quad density Epson bit map format; otherwise does nothing. Report D if BREAK pressed. Note that if the dump is prematurely stopped, the printer may be left in graphics mode and the line feed set to an odd value.
COPY EXP [INVERSE] Sends a copy of all 24 lines of display to the printer (if connected) in quad density Epson bit map format; otherwise does nothing. Each coloured dot on the screen is printed with a different pixel pattern thus providing different grey levels for each colour. The BRIGHT attribute is also taken into account. The optional INVERSE modifier allows the dump to be 'reversed' (like a negative) in order to save ribbon wear when printing-out predominantly black dumps. Report D if BREAK pressed. Note that if the dump is prematurely stopped, the printer may be left in graphics mode and the line feed set to an odd value.
COPY u1 TO u2
Copies the first named file to the second named file. The names must be different. Drive letters and user numbers may be specified within the filename.
If the source (u1) is an ambiguous file specification, then the destination (u2) must only be a drive letter. (In this case, the destination files will have the same name as the source.)
If both source and destination names are just drive letters, a complete disk-to-disk transfer will be made (note that any files previously on the destination disk will be deleted). If the destination disk is not +3 format, then the disk-to-disk transfer will not work.
When copying files, if the destination filename already exists, then the report File already exists will be displayed. If the report Missing address mark is displayed, then it is likely that the destination disk has not been formatted.
COPY u TO SCREEN$ Displays the contents of a disk file on the screen. Control characters (tabs, line feeds, etc.) are replaced by spaces. This command can only sensibly be used to inspect ASCII files (though BASIC programs will be displayed, albeit without the correct formatting).
COPY u TO LPRINT The contents of the named disk file are sent to the printer. No character translations are made. If the command FORMAT LPRINT "r" has been issued (to divert printer output to the serial (RS232 socket), then this form of the COPY command may be used as a method of exporting programs to an external machine.
COPY u TO SPECTRUM FORMAT This allows a +3DOS file header to be added to a binary file created on a different type of machine. A new file with the name: u.HED is created.
DATA e1,e2,e3,... Part of the DATA list. Must be in a program; otherwise has no effect.
DEF FN l(l1, User-defined function definition. Must be in a program, otherwise has no effect. Each of l and l1, is either a single letter or a single letter followed by $ for string argument or result. Takes the form DEF FN l()=e if no arguments.
DIM l(n1,...nk) Deletes any array with the name l, and sets up an array l of numbers with k dimensions n1,...nk. Initialises all the values to 0.
DIM l$(n1,...nk) Deletes any array or string with the name l$, and sets up an array l$ of characters with k dimensions n1,...nk. Initialises all the values to "". This can be considered as an array of strings of fixed length nk, with k-1 dimensions (n1,...nk-1). An array is undefined until it is dimensioned by DIM. Error 4 if there is no room to fit the array in.
DRAW x,y DRAW x,y,0
DRAW x,y,z Draws a line from the current plot position, moving x horizontally and y vertically relative to it, while turning through angle z. Error B if line runs off the screen.
If a single file is specified, then that file will be erased from either the default drive or the drive identified in the filename. If an ambiguous file name is specified, a message asking for confirmation will appear. If Y is pressed, then all files that match the specification will be erased. If ERASE is followed by a drive letter only, then all files on that drive will be erased without confirmation being sought.
FLASH Defines whether characters will be flashing or steady; n=0 or steady, n=1 for flash, n=8 for no change.
FOR l=x TO y FOR l=x TO y STEP 1
FOR l=x TO y STEP z Deletes any simple variable l and sets up a control variable with value x, limit y, step z, and looping address referring to the statement after the FOR statement. Checks if the initial value is greater (if z>=0) or less (if z<0) than the limit, and if so then skips to statement NEXT l, giving error 1 if there is none. See NEXT. Error 4 if there is no room for the control variable.
FORMAT d Prepares the disk in the specified drive (A: or B:) to be used. If the disk has already been formatted on a +3, a message allowing the operation to be abandoned will produced. Disks formatted on other machines (except the AMSTRAD PCW range (CF-2) format) will not be recognised.
FORMAT LINE n Sets the baud rate of the RS232 interface to n. Valid baud rates are in the range 75...19200.
FORMAT LPRINT f1[;f2] Allows printer output to be redirected and token expansion to be switched on or off. If string f1 is "C", then subsequent printer output will be via the Centronics interface (the PRINTER socket). If string f1 is "R", then printer output will be directed to the RS232 socket. String f1 can also be "E" (for expanded), in which case characters below CHR$ 32 are not sent to the printer, and those above CHR$ 127 are converted to the letters of the appropriate BASIC token. When string f1 is "U" (for unexpanded), all characters that follow are sent to the printer without translation. This allows ESC (escape) sequences to be sent. If f1 is either "C" or "R", a second string, f2, may be specified, this can be either "E" or "U" (described above).
GO SUB n Pushes the line number of the GO SUB statement onto a stack, then operates as per GO TO n. Error 4 may occur if there are not enough RETURNs.
GO TO n Jumps to line n (or, if there is none, the first line after that).
IF x THEN s If x is true (non-zero), then s is executed. Note that s comprises all the statements until the end of the line. The form IF x THEN line number is not allowed.
INK n Sets the ink (foreground) colour of characters subsequently printed; n is in the range 0...7 for a colour, 8 for transparent, 9 for contrast. Error K unless 0<=n<=9.
INPUT [#n,]... The '...' is a sequence of INPUT items, separated (as in a PRINT statement) by commas, semicolons or apostrophes. An INPUT item can be any of the following:
(i) Any PRINT item not beginning with a letter.
(ii) A variable name.
(iii) LINE, then a string type variable name.
The PRINT items and separators in (i) are treated exactly as in PRINT, except that everything is printed in the lower part of the screen. For (ii) the computer stops and waits for input of an expression from the keyboard - the value of this is assigned to the variable. The input is echoed in the usual way and syntax errors give the flashing ?. For string type expressions, the input buffer is initialised to contain two string quotes (which can be erased if necessary). If the first character in the input is STOP (SYMB SHIFT and A), then the program stops with error H. (iii) is like (ii) except that the input is treated as a string literal without quotes, and the STOP mechanism won't work; to stop it you must press cursor down instead.
INVERSE n Controls inversion of characters subsequently printed. If n=0, then characters are printed in normal video, ie. as ink colour on paper colour. If n=1, then characters are printed in inverse video, ie. paper colour on ink colour.
Error K unless n=0 or 1.
Note that in 48 BASIC, pressing the INV VIDEO key is equivalent to INVERSE 1; pressing the TRUE VIDEO key is equivalent to INVERSE 0.
LET v=e Assigns the value of e to the variable v. LET cannot be omitted. A simple variable is undefined until it is assigned to in either a LET, READ or INPUT statement. If v is a subscripted string variable, or a sliced string variable (substring), then the assignment is Procrustean (fixed length), ie. the string value of e is either truncated or filled out with spaces on the right, to make it the same length as specified in v.
LIST [#m] LIST [#m,] 0
LIST [#m,] n Lists the program to the upper part of the screen, starting at the first line whose number is at least n, and makes n the current line. If #m is included, the output is sent to the channel currently assigned to stream m.
LLIST n Like LIST, but using the printer. By default, output will be to the Centronics (PRINTER) socket; however, printer output can be directed to the RS232 socket using the command FORMAT LPRINT "R". In order that BASIC listings appear correctly, token codes are expanded to the relevant letters of each token, (codes below 32 are not printed). The command FORMAT LPRINT "E" can be used to restore this state if it has been changed (by FORMAT LPRINT "U").
LOAD d Makes the named drive the current default input device for all subsequent disk operations (COPY, ERASE, MOVE etc.). If the drive letter specified is T:, then all subsequent LOADs will default to tape.
LOAD f Loads the program and variables from disk (or tape). The string f that specifies the file to be loaded may optionally include a drive letter and user number when operating from disk. If a drive letter is not specified, then the default drive is used.
If the string f contains just an asterisk, ie. LOAD "*", an attempt is made to boot the disk in drive A:. This may be used to load alternative operating systems or some games disks.
LOAD f DATA l() Loads a numeric array l() from file f.
LOAD f DATA l$() Loads character array l$() from file f.
LOAD f CODE m,n Loads (at most) n bytes, starting at address m.
LOAD f CODE m Loads bytes starting at address m. If a file from another machine has been converted to Spectrum format (using the command COPY u TO SPECTRUM FORMAT), then this is the form of LOAD command to use (as the header will not contain a load address).
LOAD f CODE Loads bytes back to the address from where they were saved.
LOAD f SCREEN$ LOAD f CODE 16384,6912
LPRINT Like PRINT, but using the printer. Use the FORMAT LPRINT command to direct output to the Centronics (PRINTER) or RS232 socket and to set expansion of tokens on or off. By default, output will be sent to the PRINTER socket with tokens expanded and codes below 32 not printed. If ESC (escape) sequences are to be printed (for print formatting), issue the command FORMAT LPRINT "U" before using LPRINT. If printer output has been set to RS232 (using the command FORMAT LPRINT "R"), then LPRINT can be used to send strings of characters to a remote computer/terminal.
MERGE f Like LOAD f, but does not delete old program lines or variables, except to make way for new ones with the same line number or name. Like LOAD, the filename may include a drive letter and user number. If a drive letter is not specified, the default drive will be used.
MOVE f1 TO f2 This will rename file f1 to f2. Both files f1 and f2 must be on the same drive.
MOVE u TO f The string f may be "+P", "+S", "+A", "-P", "-S" or "-A". This allows the attributes of the file specified by u to be set (+) or unset (-). The attribute letters in the string f control write protection (P), system status (S), or archive status (A). The CAT...EXP command can be used to display current settings. Protected files cannot be erased, saved over, or have any operation that would change them in any way performed upon them. System files are hidden from the normal catalog display and are only shown by the CAT...EXP command. Archive status is provided for compatibility with CP/M based machines, and has no other relevance to the +3.
NEW Starts the BASIC system afresh, deleting any program and variables, and using the memory up to and including the byte whose address is in the system variable RAMTOP.
The system variables UDG, P RAMT, RASP and PIP are preserved. Returns control to the opening menu, but does not erase files held on drive M: (the RAMdisk).
NEXT l (i) Finds the control variable l.
(ii) Adds its step to its value.
(iii) If the step >=0 and the value > the limit; or if the step <0 and the value < the limit, then jumps to the looping statement.
Error 2 if there is no variable l.
Error 1 if variable l does not match control variable in FOR statement.
OPEN #n,f Allows stream number to be attached to the channel identified by string f. Stream numbers may be in the range 0...15, however the system itself makes use of 0...3 (so their use is not advised). Possible strings are "S" (for the screen channel), "K" (for the keyboard channel) and "P" (for the printer channel). The printer channel may be further re-directed to the Centronics (PRINTER) or RS232 sockets using the FORMAT LPRINT command. Trying to input from a stream that is set to a channel that only supports output, or vice versa, will cause an Invalid I/O device report.
OUT m,n Outputs byte n at port m at processor level. (Loads the BC register pair with m, the A register with n, and executes the assembly language instruction out (c),a.)
Error B unless 0<=m<=65535 and -255<=n<=255.
OVER n Controls overprinting for characters subsequently printed. If n=0, characters obliterate previous characters at that position. If n=1, then new characters are mixed in with old characters to give ink colour wherever either (but not both) has ink colour, and paper colour where they were both paper or both ink.
Error K unless n is 0 or 1.
PAPER n Like INK, but controlling the paper (background) colour.
PAUSE n Stops computing and displays the display file for n frames (there are 50 frames per second), or until a key is pressed. If n=0 then the pause is not timed, but lasts until a key is pressed.
Error B unless 0<=n<=255.
PLAY f1[,f2,...f8] Interpret up to eight strings and play them simultaneously. The first three strings play via the TV speaker and (optionally) via the MIDI socket; and subsequent strings can be output only via MIDI.
PLOT c;m,n Prints an ink dot (subject to OVER and INVERSE) at the pixel (m,n), moving the PLOT position thereto. Unless the colour items c specify otherwise, the ink colour at the character position containing the pixel is changed to the current permanent ink colour, and the others (paper colour, flashing and brightness) are left unchanged.
Error B unless 0<=m<=255 and 0<=n<=175.
POKE m,n Writes the value n to the byte in store with address m.
Error B unless 0<=m<=65535 and -255<=n<=255.
PRINT [#n,]... The '...' is a sequence of PRINT items, separated by commas, semicolons or apostrophes, and they are written to the display file for output to the screen.
When used in the form PRINT #n,... output is directed to stream n rather than the screen (unless that stream has been opened to the screen channel "S"). A semicolon between two items has no effect - it is used purely to delimit the items. A comma shifts printing forward to the next print zone, while an apostrophe generates a carriage return/line feed (which is generated by default if a PRINT statement is not terminated by a semicolon, comma or apostrophe).
A PRINT item can be:
(i) Empty, ie. nothing.
(ii) A numerical expression. First a minus sign is printed if the value is negative. Now let x be the modulus of value - If x<=10-5 or x>=1013, then it is printed using scientific notation. The mantissa part has up to eight digits (with no trailing zeroes), and the decimal point (absent if only one digit) is after the first. The exponent part is E, followed by + or -, followed by one or two digits. Otherwise x is printed in ordinary decimal notation with up to eight significant digits, and no trailing zeroes after the decimal point. A decimal point right at the beginning is always followed by a zero, so for instance .03 and 0.3 are printed as such. Zero is printed as a single digit 0.
(iii) A string expression. The tokens in the string are expanded, possibly with a space before or after.
Control characters have their control effect.
Unrecognised characters print as ?.
(iv) AT m,n. Outputs an AT control character followed by a byte for m (the line number) and a byte for n (the column number).
(v) TAB n. Outputs a tab control character followed by two bytes for n (least significant byte first) - the tab stop.
(vi) A colour item, which takes the form of a PAPER, INK, FLASH, BRIGHT, INVERSE or OVER statement.
RANDOMIZE n Sets the system variable (called SEED) used to generate the next value of RND. If n<>0, then SEED is given the value n. If n=0 then SEED is given the value of another system variable (called FRAMES) that counts the frames so far displayed on the screen, and so should be fairly random.
Error B unless 0<=n<=65535.
READ v1,v2,...vk Assigns to the variable using successive expressions in the DATA list.
Error C if an expression is the wrong type.
Error E if there are variables left to be read when the DATA list is exhausted.
REM... No effect. The '...' can be any sequence of characters terminated by ENTER. No statements in the line will be acted upon after the REM, and colons will not be treated as separators.
RESTORE n Restores the DATA pointer to the first DATA statement in line n. If line n doesn't exist (or is not a DATA statement), then the first DATA statement after line n is restored, and the next READ statement will start reading from there.
RETURN Takes a reference to a statement off the GO SUB stack, and jumps to the line after it.
Error 7 when there is no statement reference on the stack - (this probably means that there is some mistake in your program - ensure that all GO SUBs are balanced by RETURNs).
RUN n CLEAR, and then GO TO n.
SAVE d Makes the named drive the current default output device for all subsequent disk operations (COPY, ERASE, MOVE, etc.). If the drive letter specified is T:, then all subsequent SAVEs will default to tape.
SAVE f Saves the program and variables to disk (or tape), giving it the name f. The filename may optionally include a drive letter and user number when operating with disks. If a drive letter is not specified, then the default drive is used.
Error F if f is empty, or is greater than ten characters in length (on tape).
SAVE f LINE m Saves the program and variables so that if they are loaded, there is an automatic jump to line m.
SAVE f DATA l() Saves the numeric array l() to the file f.
SAVE f DATA l$() Saves the character array l$() to the file f.
SAVE f CODE m,n Saves n bytes starting at address m.
SAVE f SCREEN$ SAVE f CODE 16384,6912. Saves the current screen display.
SPECTRUM Switches from +3 BASIC into 48 BASIC, maintaining any program in RAM. There is no switch back to +3 BASIC. Note that ROM/RAM switching is not disabled when entering 48 BASIC using this command; (this is not the case when the option 48 BASIC is selected from the opening menu).
STOP Stops the program with report 9. The CONTINUE command will resume the program from the following statement.
VERIFY f Like LOAD (from tape), but the tape information is not loaded into RAM - instead, it is just compared against what is already in RAM.
If the filename specifies a disk file (or if the current default drive is A: or B:), then no action is taken.
Error R if the comparison shows different bytes.

Part 32
Binary and hexadecimal

Subjects covered...

This section describes how computers count, using the binary system.

Most European languages count using a more or less regular pattern of tens - in English, for example, although it starts off a bit erratically, if soon settles down into regular groups...

...and so on, and this is made even more systematic with the numerals that we use. However, the only reason for using ten (the decimal system) is that we happen to have ten digits on our hands (fingers and thumbs).

Instead of using the decimal system - based on ten, computers use a form of binary called hexadecimal (or 'hex' for short) which is based on sixteen. As there are only ten digits available in our number system we need six extra digits to do the counting. So we use A, B, C, D, E and F. And what comes after F? Well, just as we, with ten fingers, write 10 for ten (a hand full), so computers use 10 for sixteen. Comparing counting in decimal to hex...

0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 A
11 B
12 C
13 D
14 E
15 F
16 10
17 11
25 19
26 1A
27 1B
31 1F
32 20
33 21
158 9E
159 9F
160 A0
161 A1
255 FF
256 100
...and so on.

If you are using hex notation and you want to make the fact quite plain, then write 'h' at the end of the number, and say 'hex'. For instance, for one hundred and fifty eight (decimal), write '9Eh' and say 'nine E hex'.

You may be wondering what all this has to do with computers. In fact, computers behave as though they had only two digits, represented by a low voltage (or off) known as 0, and a high voltage (or on) known as 1. This is called the binary system, and the two binary digits are called bits - so a bit is either 0 or 1.

So to expand the previous table of counting to include binary...

0 0 0
1 1 1
2 2 10
3 3 11
4 4 100
5 5 101
6 6 110
7 7 111
8 8 1000
9 9 1001
10 A 1010
11 B 1011
12 C 1100
13 D 1101
14 E 1110
15 F 1111
16 10 10000
17 11 10001

It is customary to 'pad out' binary numbers with leading zeroes so that they always contain at least four bits - for example, 0000, 0001, 0010, 0011 (representing 0 to 3 decimal).

Converting between binary and hex is very easy (use the previous table to help you).

To convert a binary number to hex, split the binary number into groups of four bits (starting at the right of the number) and convert each group of four bits into is corresponding hex digit. Finally, put the hex digits together to form the complete hex number. For example, to convert 10110100 binary into hex, convert the first (right-hand) group of four bits (0100) to 4 hex, then convert the next group of four bits (1011) to 8 hex, put them together, and you have the complete hex number - B4h. If the binary number is longer than eight bits, you can continue converting each group of four into one hex digit. For example, 1101011110000 binary corresponds to 3AF0h.

To convert a hex number to binary, change each hex digit into four bits (again, starting at the right) then put the bits together to form the complete binary number. For example, to convert F3h to binary, first convert 3 which corresponds to 0011 binary (remember - you must use zeroes to make the binary number four bits long), then convert F which corresponds to 1111 binary, put them together, and you have the complete binary number - 11110011.

Although computers use a pure binary system, humans often write the numbers stored inside a computer using hex notations - after all, the number 3AF0h (for example) is far more likely to be easily and correctly read than 0011101011110000 in sixteen bit binary notation.

The bits inside the computer are mostly grouped into sets of eight - these are called bytes. A single byte can represent any number from 0 to 255 decimal (11111111 binary or FFh).

Two bytes can be grouped together to make what is technically called a word. A word can be expressed using sixteen bits or four hex digits, and represents a number from 0 to 65535 decimal (1111111111111111 binary or FFFFh).

A byte is always eight bits, but words vary in length from computer to computer.

The BIN notation (used in part 14 of this chapter) provides a means of entering numbers in binary on the +3, ie. BIN 10 represents 4 decimal, BIN 111 represents 7 decimal, BIN 11111111 represents 255 decimal, and so on.

You can only use 0s and 1s for this, so the number must be a non-negative whole number - for instance, you cannot use BIN -11 to represent -3 decimal, but you can use -BIN 11 instead. The number must also be no greater than decimal 65535 - ie. it can't have more than sixteen bits. If you pad out a binary number with leading zeroes, for example, BIN 00000001, the BIN function will rightly ignore them and treat the number as if it were BIN 1.

Part 33
Example programs



This short program is an aid to the renumbering facility provided by the edit menu's Renumber option. If you MERGE this program into the program you are developing (or wish to renumber), you will be able to select both the starting line number and the step size (between successive program lines).

Type RUN 9000 to run the program, enter the start line (in the range 1...9999), enter the step size (in the range 1...9999), then press the EDIT key and select the Renumber option from the edit menu.

9000 INPUT "Start size",st
9010 INPUT "Step size",sp
9020 LET hst= INT (st/256)
9030 LET hsp= INT (sp/256)
9040 POKE 23413,st-256*hst
9050 POKE 23414,hst
9060 POKE 23415,sp-256*hsp
9070 POKE 23416,hsp
9080 PRINT "Press EDIT then select Renumber option"


This program sets up the +3 as an analogue (and digital) clock.

Type RUN to start the program, enter the hour (in the range 1...12) and enter the minute (in the range 0...59). The clock will then start.

  10 DIM s(60): DIM c(60)
  30 PRINT AT 10,1;"Hold on while I calculate"
  40 PRINT AT 11,2;"some sines and cosines"
  50 GO SUB 370
  60 LET z$="00"
  70 CLS
  80 INPUT "What hour is it ";h
  90 INPUT "How many minutes past ";m
 100 LET s=0: POKE 23672,0: POKE 23673,0
 110 IF h=12 THEN LET h=0
 120 LET xc=112: LET yc=90: LET r=70: LET rh=r/2: LET rm=r*3/4: LET rs=r*5/6
 130 CIRCLE xc,yc,r
 140 INK 1
 150 FOR i=0 TO 359 STEP 30
 160 PLOT (r+1)*s(i/6+1)+xc,(r+1)*c(i/6+1)+yc
 170 NEXT i
 180 INK 4
 190 OVER 1: GO SUB 500
 200 GO SUB 470
 210 GO SUB 440
 220 LET tm=INT ((PEEK 23672+256*PEEK 23673)/50)
 230 IF s+1=tm THEN LET os=s: LET s=s+1: GO TO 250
 240 GO TO 220
 250 IF s=60 THEN LET s=0: POKE 23672,0: POKE 23673,0: LET om=m: LET m=m+1: GO TO 290
 260 PLOT xc,yc: DRAW rs*s(os+1),rs*c(os+1)
 270 GO SUB 440
 280 GO TO 220
 290 IF m=60 THEN LET m=0: LET oh=h: LET h=h+1: GO TO 330
 300 PLOT xc,yc: DRAW rm*s(om+1),rm*c(om+1)
 310 GO SUB 470
 320 GO TO 260
 330 IF h=12 THEN LET h=0
 340 PLOT xc,yc: DRAW rh*s(oh*5+1),rh*c(oh*5+1)
 350 GO SUB 500
 360 GO TO 300
 370 PRINT AT 14,0
 380 FOR i=6 TO 360 STEP 6
 390 PRINT ".";
 400 LET s(i/6)=SIN ((i-6)*PI/180)
 410 LET c(i/6)=COS ((i-6)*PI/180)
 420 NEXT i
 440 PLOT xc,yc: DRAW rs*s(s+1),rs*c(s+1)
 450 LET s$=STR$ (s): PRINT OVER 0;AT 18,27; INK 4;":"; INK 6; z$( TO 2-LEN (s$));s$
 470 PLOT xc,yc: DRAW rm*s(m+1),rm*c(m+1)
 480 LET m$=STR$ (m): PRINT OVER 0;AT 18,24; INK 2;":"; INK 5; z$( TO 2-LEN (m$));m$
 500 PLOT xc,yc: DRAW rh*s(h*5+1),rh*c(h*5+1)
 510 LET ph=h: IF ph=0 THEN LET ph=12
 520 LET h$=STR$ (ph): PRINT OVER 0; INK 3;AT 18,22;"  "( TO 2-LEN (h$));h$


This program provides a colourful and entertaining little game for one player against the computer.

To play the game, type RUN, then press any key to start.


Note the following when typing in the listing:

  1. The "BBBBBBB..."s shown in lines 30 and 50 are graphics characters. They are produced by pressing the GRAPH key once (to switch graphics mode on), typing the charactres (using the B key), then pressing the GRAPH key again (to switch graphics mode off).
  2. The "3333"s shown in line 210 are also graphics characters. Again, they are produced by pressing GRAPH once, pressing the 3 key four times, then pressing GRAPH again. (Note that these characters will look like black blocks on the screen.)
  3. The "A" shown in line 430 is also a graphics character. Again, it is produced by pressing GRAPH once, pressing the A key once, then pressing GRAPH again.
  20 GO SUB 560
  40 LET s$="                                ": REM 32 spaces
  50 PRINT AT 3,12; INK 7; FLASH 1;"BUSTOUT"; FLASH 0;AT 6,9; INK 1;"B"; INK 7;" = 20 Points";AT 8,9; INK 4;"B"; INK 7;" = 10 Points";AT 10,9; INK 2;"B"; INK 7;" =  5 Points"
  60 PRINT AT 14,1; INK 4;"Press SPACE or FIRE to trade";AT 16,3; "a life for a new sheet."
  70 PAUSE 200
  80 LET hiscore=0
  90 LET tscore=0
 100 LET lives=5
 110 LET score=0
 120 CLS
 130 INK 7: PLOT 12,13: DRAW 0,160: DRAW 230,0: DRAW 0,-160: INK 0
 140 PRINT AT 1,2; INK 1;b$;AT 2,2; INK 4;b$
 150 FOR r=5 TO 6: PRINT AT r,2; INK 2;b$: NEXT r
 160 LET bx=9
 170 PRINT AT 19,5; INK 6;"PRESS ANY KEY TO START";AT 17,4; "Use < and > to move bat"
 180 PAUSE 0
 190 PRINT AT 19,5; INK 0;s$( TO 24);AT 20,0;s$( TO 32);AT 17,4;s$( TO 24)
 200 PRINT AT 21,0; INK 0;s$( TO 32): GO SUB 540: GO TO 220
 210 PRINT AT 20,bx; INK 0;" "; INK 5;"3333"; INK 0;" ": RETURN
 220 LET xa=1: LET ya=1: IF INT (RND*2)=1 THEN LET xa=-xa
 230 GO SUB 210
 240 LET x=bx+4: LET y=11: LET xc=x: LET yc=y
 250 REM main loop
 260 IF score>1100 THEN GO TO 110
 270 IF INKEY$=" " OR INKEY$="0" THEN IF lives>1 THEN LET lives=lives-1: GO TO 110
 280 LET xc=x+xa: LET yc=y+ya
 290 REM scan the keyboard
 300 GO SUB 470
 310 IF yc=20 THEN IF ATTR (yc,xc)=69 THEN PLAY "N1g": LET ya=-ya: LET yc=yc-2: IF xc=bx+1 OR xc=bx+4 THEN LET xa=-xa: LET xc=x+xa
 320 IF yc=21 THEN PLAY "O3N7#d": PRINT AT y,x;" ": GO TO 450
 330 GO SUB 470
 340 IF yc=20 THEN GO TO 430
 350 LET t=ATTR (yc,xc)
 360 IF t=71 THEN GO TO 410
 370 IF t=64 THEN GO TO 420
 380 LET ya=-ya: LET xz=xc: LET yz=yc: LET yc=yc+ya: GO SUB 510: IF t=66 THEN PLAY "N1e": LET score=score+5: LET tscore=tscore+5: GO SUB 540: GO TO 350
 390 IF t=68 THEN PLAY "N1c": LET score=score+10: LET tscore=tscore+10: GO SUB 540: GO TO 350
 400 IF t=65 THEN PLAY "N1a": LET score=score+20: LET tscore=tscore+20: GO SUB 540: GO TO 350
 410 LET xa=-xa: LET xc=xc+2*xa: PLAY "N1f"
 420 IF yc=1 THEN LET ya=1
 430 PRINT AT y,x; INK 0;" ";AT yc,xc; INK 3;"B": LET x=xc: LET y=yc
 440 GO TO 250
 450 LET lives=lives-1: IF lives=0 THEN GO TO 530
 460 GO SUB 540: GO TO 220
 470 LET a$=INKEY$
 480 IF (a$=CHR$ (8) OR a$="6") AND bx>1 THEN LET bx=bx-1: GO SUB 210: RETURN
 490 IF (a$=CHR$ (9) OR a$="7") AND bx<25 THEN LET bx=bx+1: GO SUB 210: RETURN
 510 IF yz=20 THEN RETURN
 520 PRINT AT yz,xz; INK 0;" ": RETURN
 530 GO SUB 540: PRINT AT 10,10; INK 7;"GAME OVER";AT 12,8;"You scored : "; tscore: FOR i=1 TO 300: NEXT i: GO TO 90
 540 IF tscore>hiscore THEN LET hiscore=tscore
 550 PRINT AT 21,11; INK 6;"HISCORE ";hiscore;AT 21,1;"SCORE ";tscore; AT 21,24;"LIVES ";lives: RETURN
 560 FOR i=USR "a" TO USR "b"+7
 570 READ b
 580 POKE i,b
 590 NEXT i
 610 REM ball
 620 DATA 0,60,126,126,126,126,60,0
 630 REM brick
 640 DATA BIN 11111111
 650 DATA BIN 10000001
 660 DATA BIN 10111101
 670 DATA BIN 10111101
 680 DATA BIN 10111101
 690 DATA BIN 10111101
 700 DATA BIN 10000001
 710 DATA BIN 11111111

Telly tennis

This program sets up the +3 to play one of the most well-known and enduring of computer games. For two players, or one player against the computer.

Type RUN to start the program, then type 1 or 2 (for the number of players) to play.


Note the following when typing in the listing:

  1. The "66"s shown in lines 150 are graphics characters. They are produced by pressing the GRAPH key once (to switch graphics mode on), typing the charactres (using the 6 key), then pressing the GRAPH key again (to switch graphics mode off). (Note that these characters will look like black blocks on the screen.)
  2. The "8"s shown in lines 150, 250 and 540 are also graphics characters. Again, they are produced by pressing GRAPH once, holding down CAPS SHIFT and pressing the 8 key once, then pressing GRAPH again. (Again, note that these characters will look like black blocks on the screen.)
  3. The "A" shown in line 330 is also a graphics character. Again, it is produced by pressing GRAPH once, pressing the A key once, then pressing GRAPH again.
  20 CLS
  30 GO SUB 730
  40 DIM x(2): DIM y(2): DIM p(2)
  50 LET comp=1: LET sc1=0: LET sc2=0: LET z$="0"
  70 PRINT AT 8,3;"ONE OR TWO PLAYERS (1/2)?"
  80 LET i$=INKEY$
  90 IF i$="1" THEN PRINT AT 12,8;"Use A to go up";AT 14,8; "and Z to go down": GO TO 120
 100 IF i$="2" THEN PRINT AT 10,3;"Player 1 use A to go up";AT 12,12; "and Z to go down";AT 14,3;"Player 2 use K to go up";AT 16,12; "and M to go down": LET comp=0: GO TO 120
 110 GO TO 80
 120 FOR i=0 TO 200: NEXT i
 130 LET x(1)=2: LET y(1)=3
 140 LET x(2)=29: LET y(2)=18
 150 LET e$="8": LET f$="66"
 160 PRINT AT 1,0;
 170 GO SUB 400: REM top edge
 180 FOR i=3 TO 19
 190 PRINT AT i,0; INK 6;f$; INK 0;TAB 30; INK 6;f$
 200 NEXT i
 210 PRINT AT 20,0;
 220 GO SUB 400: REM bottom edge
 230 PRINT AT 0,0; INK 1;"Player 1: 00";AT 0,19; INK 2;"Player 2 : 00"
 240 LET n=INT (RND*2)
 250 FOR i=1 TO 2: PRINT AT y(i),x(i); INK i;"8";AT y(i)+1,x(i);"8": NEXT i
 260 IF n=0 THEN LET xb=21: LET dx=1: GO TO 280
 270 LET xb=19: LET dx=-1
 280 LET yb=12: LET dy=INT (RND*3)-1
 290 GO SUB 440: REM move bats
 300 LET oxb=xb: LET oyb=yb: LET scd=0
 310 GO SUB 580: REM move ball
 320 PRINT AT oyb,oxb; INK 0;" "
 330 PRINT AT yb,xb; INK 7;"8"
 340 IF scd=0 THEN GO TO 290
 350 PRINT AT yb,xb; INK 0;" "
 360 GO SUB 380
 370 GO TO 240
 380 PRINT AT 0,10; INK 1;z$( TO 2-LEN (STR$ (sc1)));sc1;AT 0,30; INK 2; z$( TO 2-LEN (STR$ (sc2)));sc2
 400 FOR i=1 TO 64
 410 PRINT INK 5;e$;
 420 NEXT i
 440 LET a$=INKEY$
 450 IF a$="a" THEN LET p(1)=-1
 460 IF a$="z" THEN LET p(1)=2
 470 IF comp=1 THEN LET p(2)=(2*(y(2)<(yb))-(y(2)>(yb))): GO TO 500
 480 IF a$="k" THEN LET p(2)=-1
 490 IF a$="m" THEN LET p(2)=2
 500 FOR i=1 TO 2
 510 LET a=ATTR (y(i)+p(i),x(i))
 520 IF p(i)=2 THEN LET p(i)=1
 530 IF a=32 THEN PRINT INK 0;AT y(i),x(i);" ";AT y(i)+1,x(i);" "; AT y(i)+1,x(i);" ": LET y(i)=y(i)+p(i)
 540 PRINT AT y(i),x(i); INK i;"8";AT y(i)+1,x(i);"8"
 550 LET p(i)=0
 560 NEXT i
 580 LET w=ATTR (yb+dy,xb+dx)
 590 IF w=32 THEN LET xb=xb+dx: LET yb=yb+dy: RETURN
 600 IF w=33 OR w=34 THEN LET dx=-dx: PLAY "V15O7N1g": LET dy=INT (RND*3-1): RETURN
 610 IF w=38 THEN GO TO 640
 620 IF w=37 THEN PLAY "V15O7N1c": LET dy=-dy
 640 PLAY "O3V15#d": IF dx>0 THEN LET sc1=sc1+1: GO TO 660
 650 LET sc2=sc2+1
 660 LET d=(sc1=15)+2*(sc2=15): LET scd=1
 670 IF d<>0 THEN GO SUB 380: PRINT INK 7;AT 10,8;"Player ";d;" wins."; AT 12,7;"Play again (y/n)?": GO TO 690
 690 IF INKEY$="" THEN GO TO 690
 720 GO TO 690
 730 FOR i=0 TO 7
 740 READ n
 750 POKE USR "a"+i,n
 760 NEXT i
 780 DATA 0,60,126,126,126,126,60,0

Chapter 9
Using the calculator

Subjects covered...

The +3 can be used as a full function calculator.

To use the calculator, call up the opening menu and select the Calculator option. (If you don't know how to select a menu option, refer back to chapter 2.)

The calculator may be selected as soon as the +3 is switched on. Alternatively, if you are working on a +3 BASIC program, you may select the calculator by choosing the Exit option from the edit menu (which returns you to the opening menu), at which point you can select the Calculator option. Note that any BASIC program which was being worked on (when you selected the calculator) will be remembered and restored when you exit from the calculator and return to +3 BASIC.

When you have selected the Calculator option, the screen will change to...

...and the +3's calculator is ready to accept your first entry. Type in...


As soon as you press ENTER, the answer 10 will appear. (Note that you don't key in = as you would on a conventional calculator.)

You will see that the cursor is positioned to the right of the answer, which is a running total (like on a conventional calculator). This means that you can simply type in the next operation to be carried out on the running total (without having to type in a whole new calculation). So, with the cursor still positioned to the right of the 10 on the screen, type in...


...and back comes the answer 2. Now type in...


This produces the result 6.2831853 on the screen. The +3 has used its built-in π function - all you had to do was type in PI. This applies to all the +3's mathematical functions. To demonstrate, type in...

*ATN 60

...which gives the result 9.7648943. You may also 'edit' the contents of the screen. To demonstrate, move the cursor (using the cursor left key) to the beginning of the line and then type in INT so that the line reads...

INT 9.7648943

...and as soon as ENTER is pressed, back comes the answer 9. This also demonstrates that the +3 doesn't have to perform a calculation in order to print the value of an expression. As another example, press ENTER and type...


...and back will come the value of that expression. Notice that before you typed in 1E6, you pressed ENTER on its own - this tells the +3 that you are about to start a new calculation.

One extremely useful feature of the +3's calculator is that it will allow you to assign values to variables and then use them in subsequent calculations. This is achieved by using the LET statement (as you would in BASIC). To demonstrate, press ENTER and type in the following...

LET x=10

(You must then press ENTER twice for the +3 to accept the variable assignment.) Now verify that the variable x is being used, by typing...




If you are using the calculator whilst working on a BASIC program, then any variables used by the calculator should be chosen so that they do not conflict with those used by the program itself.

BASIC keywords are not allowed to be used as variable names.

When you have finished using the calculator, press the EDIT key. The screen will change to...

Select the Exit option to return to the opening menu. If you were working on a +3 BASIC program before you started using the calculator, then you may return to the program by selecting the +3 BASIC option. (If you wish to continue using the calculator, then select the Calculator option.)

Note that if you have set up any user defined functions (using the DEF FN statement) whilst working on a BASIC program, you will be able to invoke that function when using the calculator. To illustrate this point, return to +3 BASIC and type in (for example)...

9000 DEF FN c(n)=n*n*n

...which sets up the user defined function FN c(n) which returns the 'cube' of n (the number you type into the brackets). Now exit from +3 BASIC and return to the calculator - you can now use this user defined function as if it were one of the +3's own built-in functions. For example, enter...

FN c(3)

...and the calculator will print the number 27 (ie. the cube of 3).

Chapter 10
Peripherals for your +3

Subjects covered...

The +3 is capable of operating with a wide range of add-ons (peripherals) such as joystick(s), printer, cassette unit, etc. This section contains all the information necessary to connect these.

Cassette unit

Programs may be loaded from, or saved to tape instead of disk, (the commands which instruct the computer to direct data to and from disk or tape were explained earlier in this manual).

To connect your cassette unit to the +3, you will require a suitable interconnecting lead, wired as follows...

TAPE/SOUND socket on the +3
Input (EAR) Output (MIC) GND (common) Output (MIC) GND (common) Input (EAR) Casette unit To EAR socket To MIC socket (red)

You will see that the shaft of one of the jack plugs is divided into 3 separate metal sections - this is the plug that should be inserted into the socket marked TAPE/SOUND at the back of the +3

The shafts of the other two jack plugs are divided into only 2 separate metal sections - these are the plugs that should be inserted into the sockets on your cassette unit marked MIC and EAR. (On most commercially available leads, the plug for the MIC socket is coloured red.)

(On some cassette units, the MIC socket may be labelled COMPUTER IN or INPUT. Likewise, the EAR socket may be labelled COMPUTER OUT or OUTPUT.)

It is important to remember that the successful transfer of programs to and from tape is largely dependent on the correct setting of the LEVEL or VOLUME control on your cassette unit. If you cannot load or save program easily, try experimenting with different LEVEL control positions until the optimum setting is found. If you cannot seem to load or save any programs at all, try reversing the plugs to the MIC and EAR sockets on your cassette unit.

Details of tape operation will be found in chapter 4 and chapter 8 parts 20 and 27.


The +3 may be used with any Centronics compatible parallel printer. We would particularly recommend the AMSTRAD DMP range of printers (eg. models DMP2000, DMP3000, DMP3160 or DMP4000) for use with the +3.

If you intend to connect the AMSTRAD DMP2000 to the +3, simply use the interconnecting lead provided with the printer.

If you wish to use any other Centronics compatible printer, you will require the AMSOFT PL-1 printer interconnecting lead.

Connect the end of the lead which is fitted with the flat edge-connector plug, into the socket marked PRINTER at the back of the +3.

Connect the other end of the lead (which is fitted with a Centronics style plug) into the socket on the printer. If your printer is equipped with security clips at each side of the socket, these may be clipped into the cut-outs at the side of the printer plug.

17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19

viewed from rear

PRINTER socket
2 D0 20 GND
3 D1 21 GND
4 D2 22 GND
5 D3 23 GND
6 D4 24 GND
7 D5 25 GND
8 D6 26 GND
9 D7 27 not used
10 not used 28 GND
11 BUSY 29 not used
12 not used 30 not used
13 not used 31 not used
14 GND 32 not used
15 not used 33 GND
16 GND 34 not used
17 not used 35 not used
18 does not exist 36 does not exist

Although there are only 34 terminations at the +3's PRINTER socket, the pins are numbered 1...17 and 19...35 (with 18 and 36 non-existent) for equivalence with the Centronics socket on the printer itself.

Note that printers for use with the +3 must generate their line feeds internally. If you experience problems with printer line feeds, try adjusting the appropriate 'DIP switch' inside your printer. (On the AMSTRAD DMP range of printers, DIP switch DS1-4 controls the line feed setting.)

The +3 may also be used with most serial printers conforming to the RS232 standard. It is recommended that inexperienced users should not attempt to experiment with serial interface connections. You should obtain a suitable computer-to-serial printer lead from your Sinclair dealer, and you should always follow the printer manufacturer's installation and operation instructions.

A serial printer should be connected to the RS232/MIDI socket at the back of the +3.

Details of (parallel and serial) printer operation will be found in chapter 8 parts 21 and 22.

Additional disk drive

The AMSTRAD model FD-1 may be added to the +3 system as an additional disk drive.

Thanks to the versatility of +3 BASIC, you can do all necessary file maintenance, copying, erasing, etc., on a single disk drive. However, a second drive will certainly speed up these operations and reduce the scope for accidents.

To connect the FD-1 to the +3, you will require the AMSOFT DL-2 disk interconnecting lead.

Connect the end of the lead which is fitted with the larger edge-connector plug, into the socket marked DISK B: at the back of the +3.

Connect the other end of the lead which is fitted with a smaller plug, into the socket at the back of the FD-1 disk drive.

Important - Before connecting or disconnecting the additional disk drive, make sure that any disks are removed from both drives, and that the system is switched off. If connections are altered while the system is on, it is likely that the system will crash, losing any program or data. Always save any valuable programs before meddling with connections!

When the FD-1 is connected to the +3, first switch on the FD-1 (using the slide switch at the back of the disk drive), then switch on the +3 (by plugging in the PSU). Both the green and red indicators on the front panel of the FD-1 should be illuminated. The two-drive system will then be ready to operate.

2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33

viewed from rear

DISK B: socket
4 GND 21 not used
8 GND 25 not used
9 TRACK 0 26 GND
12 GND 29 not used
14 GND 31 not used
15 STEP 32 GND
16 GND 33 not used

Details of two-drive operation will be found in chapter 8 parts 20 and 27.


We recommend that you use the Sinclair SJS range of joystick(s) with the +3. Other types of joystick (eg. Atari) will not operate directly, as their connecting plugs are wired differently.

There are two joystick sockets at the left-hand side of the +3. In general, games use the JOYSTICK 1 socket.

If a program offers you a choice of joystick types, then choose the 'Interface Two' (or 'Sinclair') option (as the +3's joystick circuitry is designed to work exactly like the Interface Two).

It is safe to plug in (or unplug) a joystick while the +3 is switched on.

1 not used
2 common
3 not used
4 fire
5 up
6 right
7 left
8 common
9 down
1 2 3 4 5 6 7 8 9
JOYSTICK 1 and JOYSTICK 2 sockets

VDU Monitor

The +3 can use a monochrome or colour VDU monitor (or a French standard PERITEL TV) instead of (or in addition to) an ordinary TV. If the monitor that you wish to use isn't quoted as being Spectrum +3 compatible, then the chances are you'll have to buy a lead for it (contact your Sinclair dealer).

A VDU monitor (or PERITEL TV) should be plugged into the RGB/PERITEL socket at the back of the +3.

1 +12V
3 audio out
4 composite sync
5 +12V
6 green
7 red
8 blue
7 6 8 3 1 5 4 2

When using a monitor, some provision may have to be made for sound (if required). If the monitor has an audio input, then this should be connected either to pin 3 of the RGB/PERITEL socket or to the TAPE/SOUND socket at the back of the +3. If the monitor is not capable of producing sound, then an external amplifier will have to be used. See the next paragraph for further details.


The +3 normally reproduces sound through the TV set it is connected to. However, if a VDU monitor is being used, or if you would like to record or amplify the sound further, then a sound signal is available from the TAPE/SOUND socket at the back of the +3. This is a 3.5mm jack socket producing 200mV pk-pk at approximately 5 Kohms impedance. When using an amplifier, it is worth remembering that if you have connected a cassette unit to the +3, the tape 'load' and 'save' signals are also fed to the TAPE/SOUND socket (and therefore the amplifier's volume control should be turned down when performing these operations).

Another point to note is that the level of sound produced by the BEEP command is set to be the same as that of all three channels of PLAY running at the same time. In practice, this means that BEEP will sound quite a lot louder than PLAY (which may cause problems if sound levels are critical).

It is safe to plug in (or unplug) an amplifier, tape recorder, etc. into the TAPE/SOUND socket while the +3 is switched on.

(not used) Audio output GND (common) Audio output GND (common) (not used)

Details of the +3's sound facilities will be found in chapter 8 part 19.

Serial devices

To connect any serial device to the +3, you will require a Spectrum +3 serial lead - available from your Sinclair dealer.

If you wish to wire-up your own, then the connections are as follows...

6 +12V
6 5 4 3 2 1
RS232 socket

Details of serial operations will be found in chapter 8 part 21.

MIDI device

Although the +3's MIDI (Musical Instrument Digital Interface) socket shares the same socket as the RS232, you will need a different lead for it (available from your Sinclair dealer). The lead should be connected into the 'MIDI IN' socket on your synthesiser, drum machine, etc. There is no provision for the +3 to receive MIDI data - it can only act as a source. No setting up of the MIDI is necessary before use (except the inclusion of the Y parameter within the PLAY command to turn it on).

Using the MIDI interface will not disturb the RS232's baud rate setting.

2 not used
3 not used
4 not used
6 not used
MIDI socket

Details of MIDI operations will be found in chapter 8 part 19.

Auxiliary interface

The AUX (auxiliary interface) socket supports two input lines (pins 2 and 5) and two output lines (pins 2 and 4). The I/O lines are driven by 1488 and 1489 line driver chips which are, in turn, connected to the I/O lines of the AY-3-8912 (see the manufacturer's data sheet for this device). Basically, register 16 of the AY-3-8912 controls eight I/O lines, the bits are designated as follows:

0 AUX pin 2 (out)
1 AUX pin 4 (out)
2 RS232 pin 5 (CTS out)
3 RS232 pin 3 (RXD out)
4 AUX pin 3 (in)
5 AUX pin 5 (in)
6 RS232 pin 4 (DTR in)
7 RS232 pin 5 (TXD in)

Using software control loops, the I/O lines could be driven as a second RS232 port (in the same way as the RS232/MIDI socket is driven using bits 2, 3, 6 and 7). Alternatively, the I/O lines could be used to drive, for example, a robot or some other external device.

6 +12V
AUX socket

Expansion devices

The +3 can connect to a very wide range of peripherals via the EXPANSION I/O socket at the back of the machine. Although this socket is much the same as on the old-style Spectrum 48K, there is no guarantee that a device which ran correctly on a Spectrum 48K will run on a +3. You should, therefore, before you purchase any expansion device or add-on, verify that it will work with the +3, and not just with a 48K Spectrum.

WARNING - It is very dangerous indeed to plug in (or unplug) any device from the EXPANSION I/O socket while the +3 is switched on - you will probably damage both the +3 and the expansion device if you do so.

U L 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
1 A15 A14
2 A13 A12
3 D7 +5V
4 ROM 1 OE not used
5 D0 GND
6 D1 GND
7 D2 CK
8 D6 A0
9 D5 A1
10 D3 A2
11 D4 A3
12 INT not used
19 not used RESET
20 WAIT A7
21 +12V A6
22 -12V A5
23 M1 A4
24 RFSH not used
26 A10 A9
27 RESET A11

Details of the +3's hardware will be found in chapter 8 part 30.



Original manual by Ivor Spital, Cliff Lawson, Rupert Goodwins, Steve Vickers and Robin Bradbeer.

Markdown conversion, JavaScript, style, screenshots, and most SVG drawings by Damien Guard. Music scale (part 19) and screen diagram (part 15) diagrams by mjwilson.

Original ASCII manual prepared by:

Revision history