How do I load .p files

A .p file is a single zx81 program. To load one, ensure the tape source is set to Tape Manager (Select Options->Tape->Source->Tape Manager).

Then Select File->Open Tape

Choose the .p file you want to load.

In the emulator, press J. LOAD will appear at the cursor. Then, holding down shift, press P twice. The screen will now show LOAD "". Press Enter.

If the program automatically runs, it will now start. However, you may now see the message 0/0 at the bottom of the screen. This means the program loaded successfully. Usually to start the program press R (RUN will now appear) then press Enter.


How do I load a .T81 file

A .T81 is an image of a real tape file. It can hold several programs, just as if they were stored on tape. To load the first program in the file, ensure the tape source is set to Tape Manager (Select Options->Tape->Source->Tape Manager).

Then Select File ->Open Tape

Choose the .T81 file you want to load.

In the emulator, press J. LOAD will appear at the cursor. Then, holding down shift, press P twice. The screen will now show LOAD "". Press Enter.

If the program automatically runs, it will now start. However, you may now see the message 0/0 at the bottom of the screen. This means the program loaded successfully. Usually to start the program press R (RUN will now appear) then press Enter.

If the .T81 file contains several programs and you know the name of the program you want to load, you can type

LOAD "name" where name is the name of the program. EightyOne will skip to that particular program and load it.


How do I load a .tzx file

Like .T81 files a .tzx is an image of a real tape file (.tzx holds more information about the image than .T81 and may be more beneficial if you want to transfer the image back onto real tape). It can hold several programs, just as they are stored on tape. To load the first program in the file, ensure the tape source is set to TZX Manager (Select Options->Tape->Source->TZX Manager).

Open The TZX Manager (Tools->TZX Manager)

In the TZX Window, Select File->Open TZX

Choose the .TZX file you want to load.

In the emulator, press J. LOAD will appear at the cursor. Then, holding down shift, press P twice. The screen will now show LOAD "". Press Enter.

If the program automatically runs, it will now start. However, you may now see the message 0/0 at the bottom of the screen. This means the program loaded successfully. Usually to start the program press R (RUN will now appear) then press Enter.

If the .T81 file contains several programs and you know the name of the program you want to load, you can type

LOAD "name" where name is the name of the program. EightyOne will skip to that particular program and load it.


How do I load a .wav file

A .wav file is an audio recording of a real tape. .wav files are usually significantly larger than their equivalent .T81/TZX but should be able to store anything a ZX81 may write to tape. To load the first program in the file, ensure the tape source is set to Wav Loader (Select Options->Tape->Source->Wav Loader).

Open The Wav Loader (Tools->Wav Loader)

In the WAV Window, Select File->Open WAV

Choose the .wav file you want to load.

In the emulator, press J. LOAD will appear at the cursor. Then, holding down shift, press P twice. The screen will now show LOAD "". Press Enter.

If the program automatically runs, it will now start. However, you may now see the message 0/0 at the bottom of the screen. This means the program loaded successfully. Usually to start the program press R (RUN will now appear) then press Enter.

You may use the slider under the graphical display to move the position of the "tape", fast forwarding and rewinding as necessary. You may also drag the Green bar in the display to adjust the sensitivity of the ZX81s ear port. The two controls on the right of the display allow you to adjust the volume and DC Offset of the incomming signal.


How do I Run EightyOne full screen

You may switch between Windowed and Full Screen at any time by pressing the Escape key on your keyboard.


I try to load a file but EightyOne just shows D/0 at the bottom of the screen.

This is a common problem with new users to EightyOne.

When you attempts to load from a .T81 file, the emulator moves the virtual tape head along the virtual tape. If the named program (or any program when LOAD "" is used) is not found before the end of the tape is reached, the LOAD stops with a D/0 error.

To avoid this error, in the Tape Manager, ensure "AutoRewind at End" is ticked in the Options menu.

When this option is selected, when the emulator comes to end of the tape, it will automatically rewind the tape and start at the beginning.


ZX 16k Ram Pack - Instructions for use

This RAM Pack will expand the memory capacity of your Sinclair Person Computer to 16K bytes (1K byte = 1024 units of storage, i.e. 1024 characters) - which is the maximum it can handle. The ZX 16K RAM is not expandable in stages and so is supplied with the 16K of memory built in. All you have to do is plug it onto the expansion edge connector at the back of your computer. It will take its power from the existing power supply.

IMPORTANT - Make sure that the computer is switched off before plugging or unplugging the memory. Otherwise you may damage the RAM pack or computer - also the computer's operation will be interupted for a short while and it may get stuck in a 'non communicative' state. You will then need to switch off and on again anyway. Any program that was in the computer will certainly be lost; so if you think a particular program may need a lot of memory, it is wise to plug on the RAM pack before entering it. As a guide, the computer's internal memory can handle 30-60 lines of program, but things like large arrays or a lot of data can cut this down considerably.

A little mental arithmetic should show that the computer can theoretically handle up to 960 program lines when fitted with the expansion pack. In practise, no program is likely to need this much (no prizes for trying!) except programs with a lot of data. In fact, the only evidence the user sees of the RAM pack's operation - apart from almost never running out of memory - is that the inverse 'K' takes a little longer to appear after switching on. This is because the computer tests the memory after switch on to see how much there is. The results of the test arn't directly available, but a simple machine code program can be used to reassure the operator that he or she really has got the memory available:

MEMORY TEST PROGRAM

1 POKE 18000,33
2 POKE 18001,11
3 POKE 18002,0
4 POKE 18003,57
5 POKE 18004,68
6 POKE 18005,77
7 POKE 18006,201
8 PRINT (USR (18000)-16373)/1024;"K"

If run on your computer without the RAM pack the answer will be 1K - the amount of memory present in the system. With the 16K RAM pack, however, the answer will be 16K. Note that this program does not say how many bytes a free for a program, only how many are available to the computer, which will use some of them for the display file, stack, etc.


INTRODUCTION

MEMOTEXT is a word-processing program specially developed to run on the Sinclair ZX-81. It is supplied in the form of a ROM cartridge that fits neatly onto the back of the computer. It supports both the Memotech RS232 and the Memotech Centronics interfaces, and can therefore be used with a large number of printers.

The main features of MEMOTEXT are as follows:

- The Keyboard input routine is completely redefined. Input can be done at full typing speed.

- Two complementary sorts of file are supported. As well as the normal text files, you can also set up data files for mailshots etc.

- You can set up prompts within, your text. Then, whenever that file is printed you will be prompted for certain information. You thus have the ability to set up general letters, and personalisemthem to suit specific needs.

- Documents can be justified. The justification routine uses a flip-flop algorithm to ensure an even ratio of black to white all the way across the page

- All normal word-processing facilities are available, including Search/Exchange/Move functions.

- The screen is "word-Wrapped" for ease of reading. (Words are never split over two lines).

- Facilities exist to save each of your files individually, or alternatively you can save a whole group together.

- You can insert printer-specific commands within your text so that if your printer has emphasising or underlining capabilities etc., you can make good use of them.

- Headings and page numbering are supported.

- Certain information (e.g. Dates), can be set up when you first enter the program. These will be picked up automatically on printing, so you do not need to access your text to put them in.

The remainder of this manual will tell you how to take advantage of all the facilities that MEMOTEXT has to offer.


KEYBOARD LAYOUT

The keyboard has been programmed to function as follows:

Letter keys (unshifted) | Lower case letters
Letter keys (shifted) | Upper case letters
Space Key | Space regardless of shift
Full Stop/Comma key | Comma if shifted, otherwise Full Stop
Number keys (unshifted) | The relevant number
Number keys (shifted) | "1" - Command symbol "2" - No effect "3" - Change to extended mode "4" - No effect "5-8" - Move cursor "9" - No effect "0" - Rub out character
Symbol keys | To get the symbol on the key, you should press the Shift key and the Newline key together. this will result in the cursor shown on screen changing to solid black. You should then press the symbol key. Holding down the shift key at the same time as pressing the symbol will result in the symbol being shown on a black backqround. Yrou should consult the Memotech interface manual to see, the ASCII character that will be printed when such a symbol is met.

The table above tells you how the keyboard is interpreted while you are inputting test files. Under other circumstances there are monor differences. These differences are mainly restrictions. (MEMOTEXT incorporates the tried and trusted principle that it is better to stop, you putting in wrong information at all, rather than trying to sort out errors at a later stage.) These differences are itemised below:

1) While feeding in information on data records:

a) Shifted 1 and shifted 3 have no etfect.

b) Shifted 6 moves the cursor to the start of the next field.

c) Shifted 7 moves the cursor to the start of the previous field.

d) Pressing the Newline key on its own writes the record to the file. (You should note that the unshifted Newline key has no effect during text file processing as line spacing on the print-out is controled by commands embedded in the text file.)

2) While feeding in information in response to selection prompts: Selection prompts are where you are asked to choose between two or three possibilities. Here, you will notice that no cursor appears at the bottom of the screen and that the first letters of the various choices given in the prompt are inverted. You should reply by pressing the appropriate (unshifted) Ietter . No other reply will be accepted.

3) While putting in information in response to "Function?" and "Name?" prompts: The only valid characters are the unshifted Ietters and numbers; the sideways cursor move keys (shifted 5 & 8); the rubout key (shifted 0); and the Newline key to indicate that you have finished entry.

4) While putting in information in reply to other program prompts: As 3) above except that you can use any symbol and also use spaces.

5) While replyinq to "INPUT" prompts prior to printing: INPUT prompts are prompts that you have embedded in your text file and that will be used to prompt for information when you come to print that text file.MEMOTEXT does not restrict the length of your reply as it does with the other prompts, and in fact you will be given the impression that you are setting up a text file . However, you will not be able to put in the command symbol (shifted 1), and the extended commands you can use are restricted. You still have to use the extended command "q" to end the input, just as in text files. (It is too easy to hit the Newline key by mistake.)


LIST OF COMMANDS

The following commands are available within MEMOTEXT. Note that they are all 3-letters, and that with the exception of DSP they are simply the starting letters of the words describing the function.

ADF | Amend Data File
ATF | Amend Text File
CDF | Create Data File
CTF | Create Text File
DDF | Delete Data File
DSP | Display files currently in memory
DTF | Delete Text File
LAF | Load All Files
LDF | Load Data File
LTF | Load Text File
MDF | Maintain Data File
PTF | Print Text File
RDF | Rename Data File
RTF | Rename Text File
SAF | Save all Files
SDF | SAve Data Files
STF | Save Text Files

You should note that you cannot rename text or data files by the ATF & ADF functions. You must use the Rename functions. Note also that function ADF only allows you to change what you call the individual fields within a data file. To amend any of the records themselves, (or indeed to create & delete records), you need to use function MDF.

More details on each of these functions follows in subsequent sections.


STARTING UP

When you first plug in MEMOTEXT and switch on the power to your computer, the first prompt will ask you if you are using the Centronics or the RS232 Interface. In common with all prompts where you are asted to make a simple choice between alternatives, you should reply by typing the first letter of the alternative you require. If you are operating with a Centronics Interface you should reply "C", and with our RS232 Interface you should reply "R".

When using the MEMOTECH RS232 Interface you s should remember to set the Baud rate before you switch on the MEMOTEXT. (Refer to the MEMOTECH RS232 booklet for further information)

Having specified the interface the prompt "DATE1?" will appear. The information you put in in reply to this prompt will be substituted in your text files when you print them (assuming you have the relevant substitute command in your text files of course). As the prompt suggests, a suggested use for this is for dates, but if you want you can put in something else you might want to substitute, e.g. a reference of some sort. The next prompt is "DATE2?". Again this is a general substitute string and the previous comments apply.

You have now set up all the initialisation information,and have entered the main loop of the program. You will see the prompt "FUNCTION?". From now on you can execute various functions. As you finish each one you will be returned to this point in the program ready to start the next.

You can now therefore put in the 3 code- letters of the function that you wish to use. If it is a valid function you will be prompted for further information specific to that function.


LOOKING AFTER TEXT FILES

Functions CTF ; ATF ; RTF & DTF.

1) PRINCIPLES OF TEXT FILES

People use word-processors because they want the facility to be able to modify documents easily. If you typed in the document in exactly the format that you wanted it to be printed in, you would have the same difficulties in modifying it that you would have on a normal typewriter. For example, adding, or deleting a word may involve not only adjusting the affected line, but also perhaps many other lines to compensate for the addition/deletion.

Sometimes you may be substituting different information in your text every time you print it. Here you will have difficulty laying out a format on the screen as the final appearance of the document will vary conciderably depending on whether you have to substitute one word or ten lines. As well as this of course, an A4 document normally has about 66 characters on each line, and there is no way that this can be displayed on the 32-character screen ot the ZX81.

The point to emphasise is that in using word-processors you should not be trying to mkte what appears on the screen look like your finished document. Rather, you should be using control codes to tell the computer how to turn your text into the finished document. Then, if you have to make a change to the document, you can normally just make the change in the text without having to worry about knock-on effects. You have the further advantage that changing indentation-etc. can normally be done simply by putting in a control code.

To illustrate this principle, imagine that you have just reached the end of a paraqraph. On a typewriter,you would advance the paper and start typing on the next line. On a word-processor like MEMOTEXT you simply put in a control code to tell the computer to jump to the next line at that point when it comes to print the document.

2) CREATING TEXT FILES

To create a text file you should reply CTF to the "Function?" prompt. You will then be asked for a name. This is the name that you want to give to the text file. It can be up to 9 characters long. (If you put in more than 9, the excess will be ignored.) You will find that you can only use letters and numbers and that you must put something in.

The next prompt you will see will be "Datafile Name?". A data file consists of a number of records with "personalising" information on them. A good example might be Name & Address records of all clients on a mailing list. By associatinq the text with a data file you can use MEMOTEXT to produce the same basic document over and over again, substituting information from each record in the data file in turn.

If you want to use this text with a data file you shculd put in the name of the data file at this point. Otherwise just press Newline.

You will now have set up an empty text file. At the top of the screen you will see the name of the text file and of the data file, and on the line below a cursor will have appeared. You can now start to put in your text and control commands.

Note that unless yOU tell it differently the computer will assume that you are printing a typical A4 document, and that there will be 66 characters on each line, 60 lines with printing on every page and 6 blank lines between pages. You can change all of these by suitable control commands.

When you have finished putting in your text and want to get out of the function, you have to use the extended control command "Q" (for Quit) . Before allowing} you to quit however the program l,will check to make sure that there are no control syntax errors in your text. If it finds one, it will dispIay a meaningful enror message and show you where the error lies for you to correct. Otherwise it will return you to the main loop and you will see the prompt "Function?"

3) TEXT FILE PRINT CONTROL COMMANDS

You can embed the following control commands within your text to control how it is printed. The control command must be preceded by the symbol " ", which tells the computer that the letters that follow make up a control command. (This character is obtained by pressing "1" while the shift key is being held down.)

In the table below:-

"nn" following a letter indicates that the letter must be followed by a number up to 2 digits long.

"nnn" following a letter indicates that the letter must be followed by a number that can be up to 3 digits long (but must be less than 150).

"zz" following a letter indicates that the letter must be followed by a number that is up to 2 digits Jong but which may be zero.

"bb" indicates that a number is not mandatory but that numbers up to 2 digits long will be checked for.

lf you use less numbers than the maximum you should ensure that the text following the control command does not start with a number.

Ann

Advance so that the next character is printed in column nn of the line. This command will be ignored if you are already beyond this position in the line or if nn is beyond the width of the paper.

Bzz

Leave zz lines between pages.

C

Centre everything between this command C ancl the next cammand C. If you are not right at the start of a line then an advance to the start of the next line will automatically be done in response to the first command. However, no advance is made after the second command C, so you can set up a title in the dead centre of a line and still put a page number on the right.

H

Everything between two command H's is considered to be a header that will be printed at the top of every subsequent page. Note that providing there is no text before the first command H in your text file then the header will be printed at the top of page 1. Note also that you can put in a new header anywhere in your text file which will be printed starting the next time a header is produced, so that when you get to the end of a chapter a new heading can be set up.

Izz

Indent zz columns. Thus if zz equals 4 subsequent lines will be printed with 4 blanks on the left hand side. To outdent you use the same command followed by zeroes. Note that characters will be printed using the indentation currently in force, so that if 10 characters have been printed on a line and you then indent 30 columns the next character will be printed in column 31. Conversely if no characters have been printed on a line and you indent to zero (outdent) then no matter what the pretwious indendation the next character will be printed in column 1.

Lbb

Advance bb lines. Note that if you are using justification then the line immediately preceding this command is not justified so that it loos like the end of a paragraph. L on its own; L followed by 0; and L followed by 1, all have the same effect - they move the print position onto the start of the next line. To leave 1 clear line between paragraphs you should use command L followed by 2. For 2 clear lines use commancl L followed by 3 etc.

Nnn

Stipulates that there are nn lines per page on which printing is possible. This includes any lines used by the header.

P

Move on to the start of the next page.

R

Print everything between here and the end of the line (which you would normally control by using a command L)as far to the right of the line as possible.

S1

Substitute whatever you keyed in in response to the "Date1?" prompt at this point when printing.

S2

Substitute whatever you keyed in in reply to the "Date2?" prompt at this point when printing.

SD(Data-Field),

Go to the data file associated with this text file, and from the record currently being processed, take the data recorded for this Data-Field, and substitute it in the text at this point. Note that there must be a comma at the end of the command to tell the program which characters belong to the data field.

SP(Prompt),

Before printing display the prompt and ask for input. This input will then be taken and substituted at this point in the text. Again the comma at the end must be there to act as a delimiter.

To make it quite clear, in the previous two commands you should put either the data field you want or the prompt you want between the first 2 letters of the command and the comma. Thus if you wanted to pick up information from data field "ADDRESS", the command you would use is "SDADDRESS,". You can only use letters & numbers as part of these command strings.

U

Convert the hexadecimal numbers between this U command and the next U command to binary, and send them straight out to the interface at this point when printing. This is used to allow you to send specific control commands to your printer. Basically you feed in a string of hexadecimal numbers (Your printer manual will often tell you what these strings are), and MEMOTEXT will pass them through direct. It can be used to control underlining, character width etc. etc.

When you quit the text file FlEMOTEXT will check to make sure that everything between the two U commands is really hexadecimal. The error-message "Half-Number" indicates that there are an uneven number of digits, and so no conversion to hexadecimal is possible. If there are any spaces between the two command "U"s, the program will ignore them.

Wnnn

Allow nnn characters to be printed on each line. (More correctly this might be expressed as setting the right hand margin position.)

Z

Find the current page number and print it at this point.

- (minus sign)

In Memotext the command - is used to indicate a soft-hyphen. (i.e. It indicates that the word can be split at this point if there is not enough room for all of it on the current print line, but that if it can all be fitted on the same line then there is no need to use the hyphen at all.)

4) EXTENDED CONTROL COMMANDS

Whereas the normal print commands detailed in the previous secticn result in characters being inserted in the text file, extended control commands are used to perform complex functions within the text itself.

The extended functions fall into 3 groups:-

1) Fast scan through the files.

2) Quitting text file editing.

3) Searching for/Exchanging/Moving blocks of text.

To get an extended command you should first prese the 3 key and the shift key at the same time. You will see that the cursor changes to look like " ". You must then press a code letter or number to perform the function you want. If you press shifted 3 by mistake, you can return to normal editing simply ty pressing shifted 3 again, and the normal cursor will reappear once more.

4.1) Fast scan through the files

Extended shifted 6 | This causes an advance through the text equivalent to one entire screenful.
Extended shifted 7 | This causes the text to roll back through one screenful.

You should notice that the 6 & 7 keys. have arrows on them to tell you which direction the text will move. If you have a very long piece of text you may find it quicker to use the search function described in 3) below to get to specific parts of the text.

4.2) Quitting the text file

Extended Q

When you have finished editing your text file the only way to quit is to use this comand. A simpler method would be too easy to hit by mistake.) Before allowing you to quit, the program will run through the text and ensure that all the print control commands are complete and valid. If it detects an error, it will display that part of the text where the error ocurrs, and tell you why there is an error at the top of the screen. Normally the cursor will be positioned in front of the command where the error lies. (The exceptions to this are where you have used one command "C" or "H", and have not closed it off by a second.) If an error is pointed out, you should correct it, and then try quitting again.

This "debugging" process will catch all logical errors in the print control commands, so that the only thing you will have to do when you print the text is to check the content and format.

4.3) Finding/Exchanging/Moving blocks of text

Extended F

This causes a search to be made through the file for a specific block of text. You first must specify what you want to find, so when you enter this command you will be asked for "Search String?", You should type in the piece of text you want to search for. Spaces and the print control symbol are perfectly valid charactercs to be included in this search string. You must begin the search string with a print control character and end it with the same. These two delimiting character will not be used on the search, but. they are needed to tell the program where the string starts and ends. (As you must have the facility to include spaces in the string, there has to be something to differnetiate between where you want to have a space as the last character in the search string, and where is no space at the end.)

When you press Newline to indicate that you have finished the string, the computer will scan through the file. Whenever it finds a match it will display the prompt "Next"Stop?", and display the file at that point. If this is the bit you were trying to find you should press "S", ans you will then be able to edit the file at that point. Otherwise you should press "N", and the program will search for the next occurance of the string. If it reaches the end of the file then it will put you back into editing mode at the begining of the file.

HINT Because no lower case letters are displayed on the ZX81, you may find that you sometimes put normal letters at the begining of sentences. If you have a long text file you may find it useful to search through on strings such as "a"; b" etc. to check that you have not mised a capital.

This is used where you want to exchange one string for another. You will first be asked for the "Search String?", and you should type in the string that you want to replace. The rules for its format are exactly the same as for the search string in the FIND function above. You will then be asked for the "Exchange String?", and you should type in whatever you want to go in place of the search string. The format is exactly the same as for the search string.

The program will then search through your text file stopping whenever it matches on the search string, and displaying the text at that point and the prompt "Ex./Next/Stop?". Replying "N" or "S" have exactly the same effect as in the FIND function. If you reply "E", then the matching text will be replaced by the exchange string and the program will proceed to look for any more matches. If the end of file is reached you will be put back into editing mode at the start of the text file.

HINT lf you are using the print control "U" character to put in printer-specific commands in your text, for such things as underlining etc., you may find it faster to put in a dummy string wherever you want such commands to go in the text, and then use this function to replace these dummies with the full hexadecimal control string.

This is used to move large blocks of text from one position in your file to another. It works like this:

While still editing put two adjacent print control characters (shifted 1's) at the beginning of the block you want to move, and do the same at the beginning of the block.

Position the cursor in the text file at the point where you want the block to be moved and ONLY THEN use the extended M command.

The program will then move the block; automatically remove the control characters ; and then put you back in text file editing close to where the block has been moved to.

It will not be able to do the move if you ask it to move the block somewhere stupid - like in the middle of where it alreacly is, and you will see the error message "Move in between" if you try.

Sometimes there may not be enough room to store the block that you want moved while it makes space for it in the new position. So, if you see the message "Short od space",you should try splitincg the block into ssub-blocks and moving each of these in turn.

5) AMENDING/RENAMING/DELETING TEXT FILES

To amend a text file you should use function ATF, giving the name of the text file in response to the subsequent "Name?" prompt. This will take you directly into text editing mode at the start of the file.

You cannot change the name of the data file associated with the text file by this function. to do this you must use function RTF.

To rename a text file or to supply a new or amended datafile name, you should use function RTF. This will first ask you for the "Name?" of the file you want to change, and then prompt you to supply its new name and any new data file name.

Note that even if you are not changing a data file name (and the file needs one), then you must reinput the old data file name, otherwise it will get lost.

To delete a text file you should use function DTF. Immediately after you have supplied its name, the file will be deleted. If you enter this function by mistake you should type in garbage in response to the "Name?" prompt so that the program will not be able to find a match.


LOOKING AFTER DATA FILES

FUNCTIONS CDF ; ADF ; MDF ; DDF & RDF

1) DATA FILE PRINCIPLES

Data files are files used to store sets of related information, that can be used to "personalise" letters etc. As an example, imagine that you have several customers and want to produce an invoice for them. You would use MEMOTEXT to set up a text file giving the format of the fnvoice, and then create a data file for your customers. The set of information or "record" would be all the information concerning one customer, and there would be 1 record for each customer in the data file. To produce an invoice all you would need to do would be to tell MEMOTEXT that you wanted to produce a print from the text file "INVOICE", and then scan through the data file "CUSTOMERS" until you found the customer record that you wanted to use to "personalise" that invoice. (You can also ask MEMOTEXT to produce an invoice for all customers if you so wish.)

Setting up data files is done by a 2-stage process. Firstly you define the name of the file and tell the program what sorts of information each record is to contain (i.e. the "Data-fields" in each record). Secondly you set up the records themselves.

Defining the data file is done by function CDF. You can change this definition by function ADF later if you want. To actually put information into the file, or indeed to change or delete information ,you use the MDF function.

To rename the file you use RDF, and to delete it you use function DDF.

Data files can be used by any number of test files. For example, a file of Names & Addresses of customers could be used to produce invoices; statements; and to send out price change notifications.

2) DEFINING THE DATA FILE

Function CDF is used to define a new data file. You will first be asked to supply a name for the file. Having done this you will be asked to supply 6 field names. Each field name can be up to 9 characters long (normal letters & numbers only), and should be meaningful to you. For example in a customer file the first two fields may be "Name" and "Address1" representing the customer name and the first line of his address

These data field names are used for a variety of purposes. Firstly, when you come to use function MDF tc~ put the proper information into your data file, they will be used as part of the display to show you where each field is to go. Secondly, you will want to indicate which field is to go where in your text file , so that when you come to print, the correct information is picked up from the data file and substituted in the text. To do this you put the data field name in the substitute command in your text file.

You should ensure that the most important piece of information coes in the first data field. This is because you may want to print a text file, and pick some information up from a data file, and be prompted by the computer to supply some other information. In order to tell you which data record is about to be printed the computer will display the contents of the first data file field on the record ue for printing as well as the prompt message. If you were producing statements and were supplying the statement amount you would probably want to know the name of the customer rather than a poctal code!

You can redefine the field names later- if you wish using function ADF. Note that neither of these functions will give you access to the data itself. This is obtained through function MDF.

3) PUTTING INFORMATION INTO THE DATA FILE

Information is put into data files via function MDF - Maintain Data File. You will first be asked for the data file name, and then a screen showing the first data file record will be displayed. (Or if there are no records in the file the message "No More Records" will be there.)

The screen will display not only the contents of the record but also the data field names so that you know what every piece of information is. At the top of the screen you will see the prompt "Action?". The following are valid replies to this prompt.

A | Amend the recorcd currently on the screen.
B | Blank out the information currently on the screen and then as action C
C | Create a new record to be inserted after the one currently on the screen. Normally you migtht choose to use action B for most of your creations, but where a new record has a lot of information in common with an existing record action C can save you time.
D | Delete the record currently being displayed. When the deletion is finished the record prior to the one you have just deleted will be displayed, or failinq that the 1st record in the file.
F | Display the First record in the file.
N | Display the Next record in the file.
P | Display the Previous record in the file
Q | Quit processing on the data file.

If you select actions A ; B or C. then the cursor will appear at the start of the first field on the screen. You can movee it between fields with the shifted 6 &hifted 7 keys. To indicate that you have finished dealing with the record you press NEWLINE, and the "Action?" prompt will reappear and you can make your next selection.

While using actions P or N to scan through the recordcs, if you reach the end of the file in either direction then you will see the message "No More Recs". This might also appear if you delee a record and none are left in the file.

MEMOTEXT will use "data compression" techniques on the records. This means that if you only put 10 characters in a field, then MEMOTEXT will only store 10 characters, so that you are able to fit a large number of records in your file. Because of these techniques MEMOTEXT does not recognise spaces at the end of any field, so if you want a space at the end of any field when you come to print a document, you must put the space in your text file.

You limited to 30 characters in any one field, but as nospaces are inserted at the end of fields, there is nothing to stop you making a larger field by putting the information into two adjacent fields and putting two substitute commands one after the other in your text file with no space in between.


PRINTING

FUNCTION PTF

To print your documents you should use function PTF. This will firstly take you through a series of prompts to establish the "rules" for how you want the print to proceed.

The first prompt you will see will be the "Name?" prompt. You should key in the name of the text file that you want to print. (You can not print data files direct - the data is picked up by substitute commands in the text.)

The program will then ask you whether you are using single sheets or continuous stationery by the prompt "Single/Cont?". You should reply S or C accordingly.

You will next see the prompt "Justify Y/N?". This is asking you whether you want MEMOTEXT to insert spaces between the words in each line so that all lines end in the same column giving a neat block appearance. You should reply Y or N depending on whether you desire this option or not. In general terms, it will only be effective if your line width exceeds 35 characters. Certain printers have proportinal spacing abilities. If you are using such a printer MEMOTEXT will not be able to justify exactly, as it assumes that every character is the same width.

The next prompt asks for a "Page Number?". You must reply by keying in a number, even if you are not including page numbering in your document. The maximum number allowed is 159. You are allowed to put in 0 to allow for a fronticpiece to your document. There is another reason why page numbering does not automatically start at 1. This is to allow you to set up several "chapters" as separate text files, and to print them individually, but to allow consistent page numbering when you come to put them together.

If there is a data file defined in the text file then the prompt "All/Select/Input?" will appear. The meanings of these are explained below.

All - denotes that you want the program to print one copy of the document for every record in the data file, (picking up "personalising" information from each individual record in turn).

Select - denotes that you want the program to display each record in the data file in turn and ask you (by the prompt "Print/Skip?") whether you want to produce a copy using that particular set of information or whether you want to skip through to the next record without printing.

Input - denotes that you only want to procduce one copy of the document, and that you do not want to go to the data file at all, but rather have the program prompt you (using the data field names embedded in your text as prompts) to provide the information. This is a useful facility to test the format of a new document. It also may prove beneficial when you want to produce something like an invoice for a casual customer who you never expect to do any further business with and who you do not want to set up as an entry in your data file.

If you reply A or S to the prompt and the data file is not currently present in memory then you will get an error message. In addition, if the program cannot find any field name specified in your text file, in the data file you will get a mismatch messacge.

If you have asked the program to prompt for information, either by replying I to the prompt above, or by substitute & prompt commands (SP(Prompt)) in your text file, you will then be prompted to supply the requisite information. If a data file is being used at the same time, the contents of the first data field for the record currently being processed will be shown as well as the prompt so that you know which record you are dealing with.

You should note that input in reply to these prompts is put in to a screen that looks very much like that used for text editing. In fact in some respects the screen behaves like the text editing screen. It will for example scroll up automatically if you fill it. However you will not be allowed to use print control characters, and the only extended command that you will be allowed to use is Q (which you must use to indicate that you have finished, because just as in text file editing, pressing NEWLINE by mistake would be too easy). You need not put any characters in if you do not want in reply to the INPUT prompts.

When the computer has all the information it needs to print the document, the printing will start. If you are using continuous stationery printing will start at once. If you have said that you are using single sheets the prompt "Press P to print" will be displayed, and printing will start when you press P. (For single sheets this prompt will also be displayed when the program, gets to the end of every page. You can if you wish reply Q to the prompt which will take you out of the PTF function.)

When the computer has finished the document it will either redisplay the 'Function?" prompt, ready for your next instruction, or, if a data file is being used, proceed to gather information for and print the text file using information from the next data file record, until all records in the data file have been processed.

To stop the print at any time you should hold down the shift key and the space key together. Thia may sometimes take a few seconds to have an effect.


SAVING & LOADING FILES

FUNCTIONS STF ; SDF ; SAF ; LTF ; LDF & LAF

MEMOTEXT does not use the same save & load routines as the normal ZX-81 , although the routines are similar enough to ensure that cassette- recorders that load normal ZX-81 programs will load MEMOOTEXT files.

Within MEMOTEXT you have the ablility to load & save files individually. This means that, for example, you could keep 1 data file, loading this separately, and then only load any text files containing standard correspondence as they were required.

If you are used to seeing the screen display while a ZX-81 program is loading or saving, you will notice some differences when you load or save a MEMOTEXT file. This is because these processes are carried out in 2 stages. There is first a burst of activity while the amount of space taken up by the file is transfered, (This is necessary to check that there will be enough space for the file in memory), then the screen goes silent for a while, and finally the file contents are transfered.

To save text files you use function STF, and to save data files you use function SDF. The program will then ask you for the name of the file that you want to save. This is the name that the file will be saved under, and this is the name that you must use when you come to reload the file. Providing the file exists, the save will start as soon as you press the NEWLINE key, so you should start the cassette-recorder recording before pressing it.

To load text/data files you use functions LTF/LDF. Again the program will ask for the name of the file. It will then check to make sure that this file is not already present in memcory. If it is it will tell you, and stop the functicn. Otherwise it will scan the tape until it finds the file you want and then load it. If there is not enough space in memory to accommodate the new file, it will display a suitable error message ansd stop the load. If this happens you should make some more space, probably by deleting from memory any files you are no longer using (remember to save them first if you have made any changes to them, and then try the load once again.

You also have the facility to save all files in memory, and then to reload them as one block. You might use this to save & load all your standard everyday letters at one go. The functions to do this are SAF & LAF. You must still supply a name when you save & load the files and you will not be allowed to use function LAF if there are any other files in memory at the time.

DISPLAYING FILES CURRENTLY IN MEMORY - FUNCTION DSP

To see what files you currently have in memory, you use function DSP. This will display the first file name at the top of the screen tell you whether it is a text or a data file. It will also ask if you want to see the next file. Pressing N will give you the next file, and pressing S will stop the function. When there are no more files left for you to see, the program will tell you that the end of files has been reached.


OUT OF SPACE & SHORT OF SPACE MESSAGES

If there is not enough space to load a file MEMOTEXT will give you the "Short of Space" message.

If during text editing or data file maintenance you run out of space, then you will get the "Out of Space" message and you will not be able to put in more information until you make more space. (By deleting records or deleting some text or deleting whole files.)

During text editing the program is continually checking the space available. It will give you some warning if you are running outby displaying the "Short of Space" message. If you can finish the text in another few lines then do so. Otherwise you are advised to stop at the end of the sentence, and look for ways of making more room.


A PRACTICAL SCENARIO

Most of this document has been explaining how to put things into MEMOTEXT. In actual fact after a few days spent putting information and text in, you will only rarely need to do this.

Having set up your basic data files & text files a typical day might well be like this:

Arrive at work; switch on MEMOTEXT; load a file of normal letters; load a data file containing names & addresses of clients.

From time to time during the day go to MEMOTEXT; tell it which standard letter you want; if it is for an existing client scan through the data file for his details; if it is for a new client select the I option for data file printing and be prompted for the information needed by the standard letter.

At the end of the day switch off MEMOTEXT and go home.

Once a week add new clients to the name & address data files and make a new copy of this file for use from then on.

Once a month produce statements for each of your clients using the A option for data file printing.

Occasionally produce a new newsletter or product announcement or price list to be sent to all of your clients.

This manual was keyed in, formatted & printed using MEMOTEXT.

THE END


MEMOTECH Centronics Type Parallel Printer Interface

Hello User,

With this pack we launch you into the world of commercial computer printing and out of the world of silver bus-tickets ! There are now a number of low-cost but powerful commercial printers on the market which can print 80 characters per line or more; we are making a substantial choice of them available with this interface. You can now print in upper or lower case, single or double width, in character o. graphics mode.

Which printers can be used with the Centronics Interface?

The first point to make is that "Centronics" refers not to the Centronics printers themselves but to the type of parallel interface common to Centronics and other printers. This has become an industry standard generally referred to as the 'Centronics Interface' and it works with most parallel interface printers. One parallel interface which is not of the Centronics type is the IEEE standard, of which the Commodore Pet printer's interface is the best known example. Our pack cannot be used for the iEEE type interface, but it makes available a good range of printers of the dotmatrix and daisy-wheel types. For the sake of clarityt all the examples in this booklet were written and tested on a Seikosha GP-100A dot-matrix printer.

How do I set up the Centronics Interface pack?

There's nothing to it. Place it behind your ZX81 and plug in. The larger connector is for a memory pack or other standard add-ons. The smaller connector is for the Centronics type printer. You should not try to run a ZX81 printer at the same time. You will have to connect the ribbon cable and plug you require. For a diagram illustrating the pin connections see the back of the booklet.

It is also advisable to re-set the printer before running a program, or to include a blank LPRINT at the start. First, we'll talk about using LPRINT. The interface uses space addressed from 10K up and is therefore compatible with our Hi-Res Graphics pack. With a MEMOPAK 64K you will have to make sure switch 3 is OFF and operate in MODE B or D. Information about ZX81-ASCII conversion, lower-case, single and double width characters, graphics printing (for example with the MEMOPAK HRG) and COPY and LLIST functions comes later.

How do I use LPRINT?

LPRINT may be used in a number of ways, so we will talk about these separately. Note however that by consulting your printer manual you may find machine- specific ways to control your output.

LPRINT with single strings and LET

At the simplest level, you can LPRINT a line at a time, with each line set up in a string with a LET statement. It's best to set the printer initially with a blank LPRINT to clear the buffer. At the end, the print command (in this case for a Seikosha), will ensure that you have printed everything in your buffer.

10 LPRINT
20 LET X$= "DEAR JOHN,"
30 LPRINT X$
40 LET Y$ = "I HOPE YOU ARE WELL."
50 LPRINT Y$
60 LPRINT CHR$ 155;"K"

Lines of up to 80 characters can be printed in this way, and any longer strings will continue on the next line.

Note. To ensure single spacing with more than 64 characters on a line, key in

LPRINT Y$; CHR$ 155; "A"

This will avoid a double line feed. Actually this example is a wasteful way of coding, because the LET statements cause the characters of the text to be stored twice - once in the instruction file and once in the array file. So let's try INPUT.

LPRINT with single strings and INPUT

INPUT allows you the freedom to decide your text as the program goes along. You need to let the program know when you are finished, so we will use an asterisk as terminator:

10 LPRINT
20 INPUT X$
30 IF X$="*" THEN GOTO 60
40 LPRINT X$
50 GOTO 20
60 LPRINT CHR$ 155; " K"

LPRINT with a string table and INPUT

From here it's a small step to setting up a whole page in your array. The advantage is that you can keep all your text lines simultaneously in memory, and so edit them later. Suppose you want to print 40 lines per page with up to 80 characters per line.

 10 DIMX$(40,80)
 20 LPRINT
 30 PRINT"WHICH JOB?"
 40 PRINT "1 = ENTER"
 50 PRINT "2 = ALTER"
 60 PRINT "3 = PRINT"
 70 PRINT "4 = QUIT"
 80 INPUT Y
 90 CLS
100 IF Y = 1 THEN GOSUB 200
110 IF Y = 2 THEN GOSUB 300
120 IF Y = 3 THEN GOSUB 400
130 IF Y< >4 THEN GOTO 30
140 STOP
200 FOR X=1 TO 40
210 INPUT X$(X)
220 IF X$(X,1)="*" THEN GOTO 240
230 NEXT X
240 RETURN

300 PRINT"LINE NUMBER"
310 INPUT X
320 PRINT "NEW VERSION"
330 INPUT X$(X)
340 CLS
350 RETURN
400 FOR X = 1 TO 40
410 IF X$(X,1 ) = "*" THEN GOTO 440
420LPRINT X$(X); CHR$ 155;"A";
430 NEXT X
440 LPRINT CHR$ 155; "K"
450 RETURN

LPRINT with a giant single string

An excellent method is to set up all your text as one long string. The value of this is that you can use the Sinclair EDIT functions to give yourself a simple word processing capability for a whole page. So if you take out or put in an early word in the text, the rest of the text will move along to accommodate the change. The text can also be chopped up for you into sausage-lengths as required. In this case you may also like to include in your program a routine which will prevent your words being split up in an unreadable way. Try the following program.

 10 LET X$= "TEXT ETC"
 20 PRINT "ENTER MAXIMUM LINE LENGTH "
 30 INPUT Z
 40 CLS
 50 LPR I NT
 60 IF LEN X$>Z THEN GOTO 100
 70 LPRINT X$;
 80 LPRINT CHR$ 155; "K"
 90 STOP
100 LET Y = 0
110 IF Y = Z THEN GOTO 60
120 LET Y$= X$(Z-Y)
130 IF X$(Z+1-Y) =" " OR X$(Z+1-Y) = "inv " OR Y$=","
    OR Y$="." OR Y$=";" OR Y$="?" OR Y$=CHR$11 THEN GOTO 170
140 LET Y=Y+ 1
150 GOTO 110
160 LET Y=0
170 LPRINT X$(TO Z-Y); CHR$ 155;"A"
180 LET X$ = X$(Z + 1-Y TO)
190 IF X$(1) = " " OR X$(1)="inv "THEN LET X$= X$(2 TO)
200 GOTO 60

Why not adapt this program to handle multi-page texts?

LPRINT with TAB

The problem with TAB is that it still reduces the column number modulo 32 (divides by 32 and takes the remainder). If you would like to TAB a higher column number, split your TAB functions into two or more, bein careful not to use a column number above 31. So, to get the equivalent o TAB 40 you could key in:

LPRINT TAB 31; TAB 9; "HELLO USER"

Well, no doubt you can think of other ways to tailor a program to suit your needs.

Will the pack automatically convert from ZX81 code to ASCII code? Yes. See back of the booklet for conversion tables for both normal or inverse characters.

Can I use the Sinclair COPY and LLIS functions without any special routines?

Yes. Naturally these will only take up the leftmost 32 print positions, unless you use the double-width character option (see below).

Can l print in lower-case?

Yes. The inverse alpha characters of the Sinclair set will appear on the printed output as lower-case. To save changing mode for the spaces between words, the Sinclair 'inverse' space is printed out as an ordinary blank space.

Can I print double-size characters?

Yes. It will be necessary to precede your Sinclair instructions with the appropriate control code. For example with a Seikosha, Epsom or NEC printer you could use:

LPRINT CHR$ 155; "E"

To return to single-size characters use the control characters CHR$ 155 "F". Other printers may have different control codes.

What is ASCII?

ASCII stands for the American Standard Code for Information Interchange and is the code expected by commercial printers. For example the byte code 65 will cause the printer to print "A"; 66 will cause "B" etc. See table at the back of the booklet. Exceptionally, the ZX81 has its own code which is not directly compatible with ASCII printers.

Does the Memopak Centronics Interface provide automatic conversion?

Yes. It will convert to most of the standard characters, including all alpha-numerics (including lower-case) and most symbols. Lower-case characters can be obtained from the ZX81 inverse alpha character set. Standard symbols not available in the ZX81 code can be obtained by referring to the required output symbol on the conversion table. For example to print

    "'Hello User!" you would need to key in
        LPRINT "H{inv}E{inv}L{inv}L{inv}O U{inv}S{inv}E{inv}R{inv}?"

What about control codes?

ASCII codes 0-31 are usually used as control codes (e.g. carriage return, line feed etc). These control codes need to be sent to the printer in a different format. So to send ASCII code 10 (LF) you would need to key:

LPRINT CHR$ 155;"A"

as shown in the table. Similarly to send ASCII 27 (ESC) and ASCII 10 (LF) you need:

LPRINT CHR$ 155;"R"; CHR$ 155; "A"

CHR$ 155 tells the conversion routine that we are dealing with a control code not a literal character.

Using control characters without affecting the print-line

Normally, using a semi-colon or a comma after these LPRINT statements has the same effect as any other LPRINT statement. That is to say, a carriage return or TAB will be automatically generated. You may wish to send control codes but avoid the generation of a carriage return or TAB. In this case, you can terminate the sequence of control characters with a double CHR$ 155:

10 LPRINT CHR$ 155 ; "E";CHR$ 155; CHR$ 155
20 LPRINT "ABC"

CHR$ 155;"E" in line 10 tells a Seikosha and similarly organised printers to print in double-width characters. Normally a carriage return would be generated since there is no comma or semi-colon, but in this case only ASCII code 14 is sent to the printer to be followed by "ABC".

Warning: when using any of the CHR$ 155 functions, both characters must be in the Sinclair buffer at the same ti e. J st occasionalIy when the buffer is full the pair will be split between buffers and in this case the function will not work.

How can I send code to the Printer without converting it to ASCII?

There is an alternative way of sending code to the printer. In the example, we're going to send the message

"HELLO BADGER". '8 BADGERt' will be sent in the usual way, but it will be preceded by the "HELLO" sent in the alternative way. For the new method, the numeric code must be POKEd into a REM statement which must be the first line in the program. 16514 is always the first byte following a first REM statement in a program. The sequence of numbers being POKEd must be terminated by a zero.

    10 REM AAAAAA
    20 POKE 16514,72
    30 POKE 16515,69
    40 POKE 16516,76
    50 POKE 16517,76
    60 POKE 16518,79
    70 POKE 16519,0
        80 LPRINT CHR$ 6; " BADGER"

The POKE statements replace the A's In the REM statement with the code values for the string '"HELLO". This code is then sent to the printer by the graphics control character CHR$ 6 (found on the T key). This method is especially useful for sending the machine-specific codes which are associated with values above 127. These will differ from printer to printer and you will need to consult your printer manual. Remember, however, that the Sinclair printer buffer isn't necessarily transferred to the printer at each LPRINT statement. To ensure printing of characters the double CHR$ 155 terminator should be used:

10 REM AA
20 POKE 16515, 0
30 FOR X = 32 TO 255
40 POKE 16514,X
50 LPRINT CHR$ 6; CHR$ 155; CHR$ 155
60 NEXT X

I've also got the Memopak HRG

There are some functions in the MEMOPAK Centronics Interface fimware which are for use with the MEMOPAK High Resolution Graphics Pack. If you want to print out the contents of an HRG video page you need to code as follows:

10 LET V = 19000
20 LPRINT CHR$ 155; "8"
30 LPRINT CHR$ 136
40 LPRINT CHR$ 155; "F"

V is the parameter variable for the start of the video page in memory, as described in the MEMOPAK HRG booklet. CHR$ 155; "8" informs the Seikosha printer that it is now to print in graphics mode. CHR$ 136 tells it to print out a video page. CHR$ 155; "F" returns it to normal printing mode. There is another speciaI function which is a general purpose HRG printing routine. It allows all or part of an HRG page to be printed on any graphics printer. It requires six parameters:

V = Start address of video page.

X = Horizontal HRG co-ordinate in range 0-247 of the top left-hand corner of block to be printed.This value will automatically be rounded to the start of the byte area in which it falls.

Y = Vertical HRG co-ordinate in range 0-191 of the top left-hand corner of the block to be printed, counted from base of screen.

E = Width of the block to be printed in bytes, range 1-32.

S = Number of horizontal dot-lines to be printed (counting down from and including Y). Maximum value is the number of dots in depth of the graphics characters of the particular printer - probably 6, 7 or 8 (7 for Seikosha).

Q = Constant that needs to be added to a code to produce the graphics character, usually 0, 32 or 128 (seikosha = 128).

The special character is CHR$ 137, so your code might be, after setting the parameters:

100 LPRINT CHR$ 155; "8"
110 LPRINT CHR$ 137
120 LPRINT CHR$155; "F"

With this function, no carriage return is generated and so it is possible to mix HRG graphics and Sinclair output on the same line.

Note. You may find it quicker to use the graphics character instead of the CHR$ + value mode. For example, LPRINT "inv.K" instead of LPRINT CHR$ 155; "K". A table of those used in this booklet appears below. However, the use of these characters will prevent the normal functioning of LLIST and COPY, since they will activate the printer.

CHR$ 155
CHR$ 6
CHR$ 136
CHR$ 137

MEMOTECH CONNECTOR
/STROBE | 1 | 2 | TO GND
DATA1 | 3 | 4 | TO GND
DATA2 | 5 | 6 | TO GND
DATA3 | 7 | 8 | TO GND
DATA4 | 9 | 10 | TO GND
DATA5 | 11 | 12 | TO GND
DATA6 | 13 | 14 | TO GND
DATA7 | 15 | 16 | TO GND
DATA8 | 17 | 18 | TO GND
/ACK | 19 | 20 | TO GND
BUSY | 21 | 22 | TO GND
NC | 23 | 24 | TO GND
NC | 25 | 26 | NC
NC | 27 | 28 | /ERROR
NC | 29 | 30 | GND
GND | 31 | 32 | NC
GND | 33 | 34 | NC
A typical Commercial Printer Connector Seikosha GP100-A

Use a connector, AMP CHAMP 36 BAIL LOCK TYPE, to input data into the Printer. Pin configuration and its signals of the receptacle in left rear of the Printer are described below. Pins 18 and 36 are not linked.

      \	     18.................1      /
      \                              /
      \    36................19    /
PIN | SIGNAL | PIN | SIGNAL
1 | STROBE | 19 | TGP(PAIR WITH 1 PIN)
2 | DATA 1 | 20 | TGP(PAIR WITH 2 PIN)
3 | DATA 2 | 21 | TGP(PAIR WITH 3 PIN)
4 | DATA 3 | 22 | TGP(PAIR WITH 4 PIN)
5 | DATA 4 | 23 | TGP(PAIR WITH 5 PIN)
6 | DATA 5 | 24 | TGP(PAIR WITH 6 PIN)
7 | DATA 6 | 25 | TGP(PAIR WITH 7 PIN)
8 | DATA 7 | 26 | TGP(PAIR WITH 8 PIN)
9 | DATA 8 | 27 | TGP(PAIR WITH 9 PIN)
10 | ACK | 28 | TGP(PAIR WITH 10 PIN)
11 | BUSY | 29 | TGP(PAIR WITH 11 PIN)
12 | GND | 30 | GND
13 | NC | 31 | /INITIAL (PAIR WITH 14 PIN)
14 | GND | 32 | /ERROR (PAIR WITH 15 PIN)
15 | GND | 33 | GND
16 | GND | 34 | /CLK (PAIR WITH 33 PIN)
17 | CHASSIS GND | 35 | /TEST (PAIR WITH 16 PIN)
l8 | + 5V 80mA Max. | 36 | + 5V

NOTES:

1. The combined output of pins 18 and 36 is 80 mA maximum.

2. NC stands for no connection.

3. TPG stands for twisted pair ground.

Connecting the MEMOPAK to the printer

The most convenient cable is an Insulation Displacement Cable (IDC) ribbon made up as in the diagram above, where:

A is a 36-way delta-type plug to the printer (3M part number 336S1001)

B is a 34-way low profile header socket to the MEMOPAK interface (3M part number 3414-6000)

The ribbon cable is 34-way with pins 18 and 36 omitted on plug A. Socket B is connected to J1 on the Centronics Interface ( pin 1 to pin 1). Plug A is connected to the printer. The above configuration gives a tidy connection which allows other packs to plug on the back with the ribbon cable passing beneath them.


MEMOTECH KEYBOARD AND BUFFER PACK

Hello User

We hope you like the look of the Memotech Keyboard. This booklet will help you get the best out of it.

What you will find very quickly is that, instead of having to prod patiently at the ZX81 plastic membrane and check the character on the screen every time, the Memotech Keyboard with its light-touch positive stop keys will allow you to go faster, more accurately and more confidently.

To speed you even faster, we have added an extra key to the array; at the top right there is a SHIFT key which mimics the one at bottom left. This new key will for example enable you to operate DELETE (shown as DEL RUBOUT on our key) as a simultaneous stroke with SHIFT.

If you want to get started now, just disconnect your ZX81 power supply and plug the Memopak Keyboard Buffer into your ZX81. If you have other Memopaks they can be plugged onto the back. Reconnect the power supply and off you go!

Good luck from all at Memotech!

HOW IS THE MEMOTECH KEYBOARD ARRANGED?

The ordering of the alphanumeric keys is exactly the same as the standard QWERTY typewriter layout: the keys are set at full-sized typewriter pitch and are raked and terraced to give a natural typewriter 'feel'. The terracing allows the placing of legends on the front as well as on the top of the keys.

The 'shift' mode labels (printed in red on the ZX81 membrane) are printed on the key face at the top, and the 'command' labels (like PRINT) at the bottom. The 'function' mode labels are printed on the front of the keys.

HOW FAST CAN I GO?

Limitation on your speed of program and data entry is no longer the durabllity of your fingertips or the keys themselves (which are actually very fast); but there is a debounce routine within the ZX81 - part of its software. If you find you are 'losing' characters at the input stage, try adopting a more even tempo of keystroking (just like a good typist).

The constraint on stroke rate will be most apparent when entering text, rather than data or program. MEMOTEXT, the new word processor pack from Memotech, incorporates software which lifts this ZX81 barrier and replaces it with a very much faster debounce routine of its own.

DO I NEED TO BREAK INTO MY ZX? DO I NEED TO SOLDER THINGS MYSELF? DO I NEED TO SQUEEZE MY ZX INTO ANOTHER BOX? DOES IT LIMIT WHAT ELSE I CAN ADD ON?

No, no, no and no!

HOW DO I INTERPRET THE GRAPHlCS SYMBOLS ON THE KEYS?

The background colour of the keys (blue) is equivalent to the background colour of the screen (white on a TV, green on a monitor probably). What is printed on the keys is equivalent to what gets printed on the screen.

The printing on the keys is extremely durable and will not wear off in normal use.

WHAT HAPPENS TO THE ZX PLASTIC MEMBRANE?

Nothing. Plugging in the Memotech Keyboard Buffer does not disable the ZX membrane, so two people can interact with the ZX at the same time (gamesplayers take note).

IS THE ORDER OF THE MEMOPAKS IMPORTANT?

Not terribly, but the 'big' Memopaks containing 16K, 32K, or 64K should come last. If you've got a Memopak HRG (High Resolution Graphics), it's best to put that first, next to the ZX81. All Memopaks come with extender boards at the back, so adding on to your add-ons is no problem.

Keep a lookout for our ads to see what is coming next.

NOTE

The Memotech Keyboard has been designed to work with all our units as well as with the ZX81 and the Sinclair 16K RAM pack.

With some ZX81s of recent issue and a Memopak 16K, the user may find a series of 32 vertical lines appearing on the screen. In this event, place the keyboard buffer pack behind the MEMOPAK 16K and set the switches into SLAVE mode ( I and 4 UP and ON; 2 and 3 DOWN and OFF).

GUARANTEE - January, 1983

This product is guaranteed free from defects in material and workmanship for a period of six months from the date of purchase subject to the following conditions:

1. The guarantee does not cover any damage caused through neglect, incorrect adjustment, accident or misuse and will be invalidated if the the product is modified or altered in any way or repaired by anyone other than Memotech Ltd.

2. Claims under this guarantee must be made by sending the product (well packed preferably in its original packing) to the address below.

Memotech Limited,
Station Lane, Witney, Oxon.
OX8 6BX. England.
Telephone: (0993) 2977
Telex: 83372 MEMTEC G;
 NOTE both keyboard and
buffer units must be returned
for a valid claim.

This Guarantee does not affect the customer's statutory rights.

Model: Memopak Keyboard
Serial No: (if any) ...............................................
Date of purchase    ...............................................
Owner's Name        ...............................................
Owner's Address     ...............................................
                    ...............................................
                    ...............................................
Method of Purchase*   .............................................
Point of Purchchase ...............................................

* Please enclose evidence of purchase (receipt etc) as without this we we will be unable to give a refund of replace this item.


MEMOTECH MEMOCALC Spreadsheet Analysis

Hello User!

More and more people are using the ZXE1 in business and engineering. Systems of all kinds require planning, and planning recuires a model of the future (or possible futures). This is where MEMOCALC comes in. You can now use powerful and rapid projection techniques on your ZX81

In this booklet you'll find all the functions and error messages explained, and some worked examples to demonstrate these.

Good luck from all at Memotech!

What is spreadsheet analysis?

Spreadsheet analysis is a system for entering data and equations relating to those data in a common rectangular grid. When the grid is eva uated, each equation is solved to give a value which then appears in the cell where the equation was entered.

What then is MEMOCALC?

MEMOCALC is a spreadsheet analysis package with a grid size of up to 7000 numbers. It lets you use all the functions of the ZX81 to build up simple or sophisticated models for business, engineeriny and other applications.

The program comes in the form of an EPROM pack that fits snugly on the back of the ZX81. No time is wasted loading the program, and all your BASIC addressable memory is available for holding grid data.

The program is easy to use once the basic principles are grasped. All inputs are prompted and if an error occurs a meaningful message is given. What's more, column and line headings are shown on the screen, so you always know where you are.

You can display figures with two decimal places or with none (but the values are held internally with greater accuracy to prevent the build-up of rounding errors). There are totalling and sub-totalling facilities, and a special feature to enable the months of the year to be put in rapidly.

You may want to print the results of your model. As well as supporting the ZX printer, MEMOCALC can be used with other printers through the MEMOTECH printer interfaces to give your results a truly professional appearance.

How do I get started?

First set up your configuration with at least the ZX81, the MEMOCALC pack and a MEMOPAK or Sinclair 16K RAM pack in that order. MEMOCALC is addressed between 12 and 16K. You can either switch on your MEMOCALC by hand (at the side of the pack) to jump straight in, or make a USR call at 13824 (eg RAND USR 138324) after you have powered up. Note that if you have a Memopak HRG in your configuration with Memocalc, the HRG will only be accessible when Memocalc is switched off.

Immediately you will be prompted to choose between L for LOAD (to read an existing grid from tape) or I for INIT (to start afresh). For your first time around you will need to key in 1, whereupon the prompt NO. OF LINES? will appear.

What does the spreadsheet grid look like?

Unless your grid is very small, you will never see it all at once, but the screen acts like a window through which you can see 3 columns and 15 lines at a time. At the top and down the left hand side are the text areas, separated from the main body of the grid by broad black lines. The cursor is a bar of 7 black squares, and by pressing 5,6,7 or 8 you can move it around the grid in the direction of the associated arrow. If you 'shift' these keys, the window moves around the grid and the cursor rnoves with the window.

What can I do with tho grid?

There are a number of functions you can call by entering the first letter. If you enter H for the HELP function you will see what they are. The letter will be stored in the top lefthand corner of the screen to remind you which function you are using. One of the main function codes is I for INPUT. If you press I when the cursor is in the text area, you will be prompted TEXT?; you can then enter a label for a line or column. If your cursor is situated in the main body of the grid then you will be prompted with VALUE/EQUATION? V is for VALUEs or raw numbers, E is for EQUATIONs for generating new values from previous ones. There is also R for REPEAT and T for TOTAL which are discussed below, and C for CALCULATE. If you get into a tangle, shifted 1 (EDIT) will abandon the current function.

How do I enter positions and equations?

Positions are defined by grid references with numbers representing the columns, and letters representing the lines. For example, A1 is Line A Col 1; C8 is Line C Col 8. Note that when all the single letters have been used up then double letters are used, i.e. AA is Line 27, AK Line 28 and IO is Line 250 - the last possible line. Whenever the program prompts POSITION? you shouid supply the grid reference in this form.

Equations are expressed using position references as variables, the left hand side of the expression being the cursor location. For example, if you want to assign to cell A1 twice the value of cell D12, you should move the cursor to A1 (using G (GOTO) or the 5, 6, 7, 8 keys) and then key in I (INPUT), E (EQUATION), and D12 * 2.

Equations can be self referential. To set a initial value to a cell, use the I V function; an equation can then be entered in the same cell referring to itself. It will immediately evaluate itself. For an example of this, see CALCULATE in the List of Functions below.

A MINI-EXAMPLE

Green the Grocer has a value for each kind of produce he thinks he will sell in January. He thinks apples will then increase each month by 10%, pears will decrease by 5%, sprouts will double and leeks halve. He would like to examine the overall situation for the quarter, with separate monthJly sub totals made on fruit and vegetables, and totats and running totals for each month.

After I for INIT he enters 4 for NO. OF COLUMNS? (1 per month and 1 for a quarter's totals) and 15 (the minimum) for NO. OF LINES? He then proceeds to set up his grid labels. In each case he first moves the cursor to the appropriate position, then enters his function(s) and then the text, followed by NEWLINE. There are two rows available for labelling columns (called here 'upper' and 'lower' ) .

CURSOR POSITION FUNCTION(S) ENTRY

TYPED IN

Upper label col 1 | GREEN
Upper label col 2 | THE
Upper label col 3 | GROCER
Lower label col 1 | JAN
Lower label col 2 | FEB
Lower label col 3 | MAR
Label line A      | APPLES
Label line B      | PEARS
Label line C      | (left blank)
Label line D      | FRUIT
Label line E      | (left blank)
Label line F      | SPROUTS
Label line G      | LEEKS
Label line H      | (left blank)
Label line I      | VEG
Label line J      | (left blank)
Label line K      | TOTAL
Label line L      | (left blank)
Label line M      | RUNNING

That completes the labelling.

Say his initial values for apples, pears, sprouts and leeks are 100, 150, 200 and 250 respectively. He proceeds:

CURSOR POSITION
A1 I V 100
B1 I V 150
F1 I V 200
G1 I V 250
100 150 200 250

Next he enters equations by which the program will generate the future values,

A2 I E A1*1.1
B2 I E B1*.95
F2 I E F1*2
G2 I E G1*.5
A2 R A3
B2 R B3
F2 R F3
G2 R G3

Note that Mr Green has saved time by using the R (REPEAT) function: with the cursor at A2, R A3 means repeat the equation which is in A2 along line A as far as A3. After the C O (CALCULATE ONCE) function has been performed, a D (DECODE) function with the cursor at A3 will reveal A2*1.1

He wants line totals generated in column 4, so he first moves the window:

Shifted 8 (moves window to the right by 1 column)
Lower label col 4 | QTR
A4 T T L
B4 T T L
F4 T T L
G4 T T L
Shifted 5 (moves window to the left by 1 column)

And lastly the column sub totals and totals.

D1 T S C
D1 R D4
I1 T S C
I1 R I4
K1 T T C
K1 R K4
M1 I E K1
M2 I E M1 + K2
M2 R M3

At the end, or at any point in the input procedure, he can enter C for CALCULATE to see the results, followed by the letter O since he only wants to calculate ONCE. After any amendments, C should be re-entered to see the new values.

The final result should look something like this:

memocalc GREEN THE GROCER
              1     2     3    4
            JAN   FEB   MAR  QTR
a APPLES a  100   110   121  331
b PEARS     150   142   135  427
c
d FRUIT     250   252   256  758
e
f SPROUTS   200   400   800 1400
g LEEKS     250   125    62  437
h
h VEG       450   525   862 1837
i
j TOTAL     700   777  1118 2596
k
l RUNNING   700  1477  2596
m

What form do the entries take?

All inputs are in response to prompts and can be of two types - single characters or strings. If a single character is required no cursor will appear at the bottom of the screen, and afterwards there's no need to press NEWLINE. Sometimes you are asked to make a choice of two letters shown on a black background Just press the key corresponding to the desired letter.

If a string is required, an L cursor will appear at the base of the screen. As you enter the string it is displayed below. Afterwards you must press NEWLINE before the computer wil pay any attention to it. You must enter at least one character before you press NEWLINE. The program may limit the characters you are permitted (eg for numbers it only allows keys 0-9). Normal ZX81 editing features are supported.

At the base of the screen, input can be up to 4 lines long. If you go over 4 lines, the input will be rejected and TOO LONG displayed. If the input has format or syntax errors, it will be redisplayed with a marker at the error which can then be edited or re-entered. If an input is syntactically correct but cannot logically be implemented in the grids it will be rejected with an error message.

LIST OF FUNCTIONS

SHIFTED 1 (EDIT)-abandons current function.

UNSIFIFTED 5, 6, 7 AND 8 moves the cursor around the screen, in the direction shown on the arrow.

SHIFTED 5, 6, 7 AND 8- moves the 'window' on the data that is currently being displayed.

B - BLANK blanks out the value/equation/subtotal/total at the position on the screen occupied by the cursor. For the purposes of calculating, blank positions have a value of zero.

C-CALCULATE forces a recalculation of all values in the matrix (ie evaluates all the equations, subtotals and totals) A prompt of ONCE/MANY? will be displayed Press O if you want the matrix to be evaluted just once. Note that calculations are done from left to right within an overall top-to-bottom progression. You can only evaluate equations from entered values or from results of previous equations. You should ensure that equations only refer to the positions above or on the same line to the left, unless the values are fixed. A line of running totals may easily be accumulated beneath a line of absolute column totals, but carrying forward from the base of one column to the top of another is not possible with the O option.

Pressing M for MANY causes the matrix to be evaluated and the bottom right cell to be tested for its value. If this value is exactly 0 (and a blank will count as 0), the cycle is deemed to be finished and the calculation will stop. Entering a non-zero VALUE in that cell will cause the matrix to be re-evaluated cyclically until the BREAK key is pressed. Using that cell only, a simple counter can be inserted to give a known number of cycles; for example, in a 3-column; 15-line matrix the entries at cell 03

I V 21
I E03-1

will cause the matrix to be evaluated 20 times and then stop.

D-DECODE tells you how the value at the cursor position is derived. This will either be an equation or the codes BL-blank/ VL-value, SC-subtotal column, SL-subtotal line, TC total column, or TL-total line.

G-GOTO moves the 'window' on the grid so that the top left hand corner is the line/column you supply in the response to the POSITION? prompt. The cursor will be over the position supplied.

H-HELP lists available functions; these appear beneath the grid and are removed when another function is selected.

I- INPUT enters information where the cursor is resting. If this is in a heading position (above or to the left of the grid) then text will be expected and the prompt TEXT? wiil be displayed. In text mode all characters (but not graphics symbols} are acceptabie; only the first 7 are used.

If the cursor is resting over the body of the table, then the prompt EQUATION/VALUE? will be displayed. If the entry in the cell is not to be dependent on other values in the table, then the VALUE option should be used. Otherwise use EQUATION. In response to these choices the prompts VALUE? or EQUATION? respectively will be displayed.

In the case of EQUATION a valid mathematical expression should be entered using position references as variables. The RND function is supported as are the logical operators (AND, OR and NOT). Upon entry, the program will check the equation for vaXidity and redisplay any invalid expression with an error marker and with the cursor positioned after the offending character. If the expression is valid, then its results will be calculated and displayed immediately and every time the CALCULATE command is given. Note that EQUATIONs can be copied into other positions in the grid, whereac VALUEs cannot. To effectively copy a vaiue, enter it first as an EQUATION but without position reference variables.

L- LOAD loads a grid from tape or sets up a new grid. Any grid already in RAM is lost. The prompt LOAD/INIT? will be displayed.

If you press I, existing data will be erased immediately. The prompt NO. OF COLUMNS? will then appear. Reply with the number of columns of data you expect to use (leave some room for expansion - big empty matrices take longer to SAVE than small ones, but no longer to CALCULATE). The number of columns must be in range 3-99. Following this, the prompt NO. OF LINES? will appear. The permissible range is 15-250.

The program will then see whether there is space in memory for an array of this size. Generally, lines x columns should not exceed 1800 for 16K, 4400 for 32K, and 7000 for the 48K RAM in the Memopak 64K. If your demands exceed the space available, you will be asked for NO. OF COLUMNS? again.

If you choose the L (LOAD) option, you will be prompted for the NAME? of the grid you wish to load; this must be exactly the same as the name it was saved under. There is no default loading of the first thing on the tape, so remember to record the names you assign to your grids. Start the cassette recorder and press NEWLINE; when you press this key, any existing data in RAM will be cleared The screen will go blank for a few seconds when the load is completed while the display is built up. If an error occurs in the load you will be returned to the LOAD/INIT? prompt so that you can try again.

M - MODE switches between integer and 2-decimal display modes. Integer display occurs initially, but you can switch between modes at any time. Existing data on the screen is not immediately changed, but new entries are in the new mode. When the screen is re-displayed (on CALCULATE or GOTO) the new mode is employed.

Note that the largest number that can be displayed is 9999999 in integer mode and 9999.99 in 2-decimal mode. Although larger numbers can be handled and stored, they will overwrite the previous column in the display and printout. If you think this will be a problem, just use every other column in the grid, though you will then be restricted to column REPEATs only.

P- PRINT elicits the SCREEN/ALL? prompt. Pressing S will cause what is on the screen to be copied to the printer. A for ALL will ask you for the NO OF COLUMNS? you want printed across on your printout; the maximum number of columns you can print across a sheet is as follows:

ZX printer 3 columns

80 character printer 9 columns

132 character printer 15 columns.

Either print option can be halted by pressing the BREAK key.

Q- QUICK Converting between internal floating point numbers and displayed decimals is a slow process. In QUICK mode, existing data are not displayed although labels are, and shifting the window becomes viritually instantaneous. All data are however displayed after CALCULATE or GOTO. To get back out of OUICK mode, simply press C again .

R - REPEAT repeats an equation (or total/ subtotal) from the cell where the cursor is resting to another position which must be either on the same line or in the same column. Note that the repetition is relative to position, i e if the initial equation is A1*2 and you are REPEATing it downwards, the DECODE function would reveal B1*2 in the next cell, then C1*2, and so on.

S - SAVE saves the entries in the grid. In response to NAME? you should enter a name of up to 12 characters. You do not need quote marks as in the normal ZX81 SAVE. Escape from the SAVE can be effected using the BREAK key

T-TOTAL/SUBTOTAL works down a column or across a line. You will be prompted TOTAL/SUB-TOTAL? and should respond T or S accordingly. Then the LINE/COLUMN? prompt will appear; responding L accumulates values to the left on your line, and C accumulates above in your column. For examples T S C means TOTAL function/ Subtotal of Column. It works upwards accumulating values in the column until it reaches either a previous column subtotal or the first line. It ignores any column totals but will include line subtotals and totals.

Y - YEAR provides a fast method of entering the months of the year as labels. The cusorshould be positioned over a label cell containing the first three letters of a month (JAN,FEB, etc.). When Y is pressed the remaining months of the year will be set up in the succeeding cells (to the right if a column label, downwards if a line label). If the initial cell contains some other information in the four remaining character spaces (eg JAN'84), that information will be copied with the succeeding months. The effects of the Y function are immediate, but are not displayed until a CALCULATE or GOTO command is given.

ERROR MESSAGES

CALC. ERROR (functions C, I & R)-A mathematical error was detected during processing. The line/column reference at which the error was detected is given, and this is followed by the ZX8l error code (see Appendix B of the Sinclair manual). If function R is being used then the chances are the equation you are trying to repeat uses grid references and that there are no corresponding grid references in the repeat-to position. ( Function D can often be used profitably when this occurs to help you track down the source of error).

CANT EXTEND (function Y) The box over which the cursor is resting does not contain a recognised month of the year (or contains DEC which cannot be extended), or the dimensions of the grid do not allow any extension to take place.

EDIT USED (any function) - The EDIT key was pressed during INPUT. Nothing you have done so far within this function has affected the data.

SAVE ERROR (function S) - An error occurred on the SAVE (or you pressed the BREAK key to terminate it intentionally).

INV.REPEAT POS ( function R ) - The REPEAT position is invalid, either because both line and column references of this posistion are different to the cursor location, or because this position is not below or to the right of the cursor location.

NOT A NO (functions B, D, R, T) -The cursor is resting over a header field, so that these functions which are concerned with the body of the grid cannot be used. (To blank out a value in a header field use function I and key in spaces).

NOT EQUATION (function R) The cursor is resting over a position which contains a VALUE not an EQUATION. Such values cannot be repeated. (If you want to REPEAT a value you should set it up as an equation without position references).

NOT TEXT (function Y)-The cursor is not resting over a header field.

OUT OF RANGE (functions L, P and during the initial entry to the program) If you are using function P, then the number you entered after the NO. OF COLUMNS? prompt was not in the range 1-15. When setting up the dimensions of the model, the number of columns must be in the range 3-99, and the number of lines in the range 15-250.

TOO BIG-REINPUT - There is not enough room in memory to accommodate the number of columns and lines you have requested (and still leave some room for equations).

TOO LONG (function I) - This error message arises a) because the attempted INPUT has exceeded 4 lines in length, or b) because no more room exists for equations. Room can be cleared by BLANKing out unwanted entries.

A BIGGER EXAMPLE

You are a manufacturer who expects sales of 1000 units of value in January, rising by 1% per month for the year. Your nett costs are 90% of sales value. You want to know your profit and accumulated profit at each month.

Press I for INIT, 4 for NO. OF COLUMNS? (to allow for sales, costs, profit, and accumulated profit) and NEWLINE, and 15 for NO. OF LINES? (which is the minimum, and allows for 12 months and a total) and NEWLINE.

The empty grid will come up, showing columns 1-3 and lines A-O; the cursor will be at A1, and the prompt FUNCTION? will be at the base. Remember that if you want to cancel the function you're in for whatever reason, you can get out with EDIT (shifted 1 ).

Before you enter the function command move the cursor.

Put the cursor above the black line which marks the edge of the table so that when you enter I the prompt TEXT? appears. Enter SALES, and move the cursor across for COSTS in column 2, and PROFIT in column 3. In order to enter CUM in column 4 you will have to shift the 'window' using shifted 8. When this is done you can GOTO A1 again.

Move the cursor to the left to enter the label for line A: enter JAN 84. You could then enter all the other months of the year yourself, but to make it easier leave the cursor where it is and enter function Y. Now C (CALCULATE) and see the effect of that.

The cursor will now be back at A1 and you can enter the initial value of sales. Press I V 1000 and NEWLINE.

Sales for FEB are a 1% increase over JAN's, so move the cursor to A2 and enter I E 1.01-A1. When you press NEWLINE the value 1010 will appear there.

You could now enter a similar equation at C1, which would be 1.01+B1, and so on for all the other months. The R (REPEAT) function is designed to save you this trouble; it gives you the prompt POSITION? which asks you how far down the column you would like the pattern of the equation to be repeated. This pattern is relatively positioned, so the equation is understood to mean 'multiply the value above by 1.01 and place the result here'. Leave the cursor at B1 and enter R. In response to the prompt, enter L1 (corresponding to DEC 84), and CALCULATE, ONCE.

If you're interested, move the cursor to I1 and DECODE. Press M for MODE and CALCULATE. Press H and see what else there is.

To get on with the COSTS column, move the cursor to A2. Costs are 90% of sales value, so enter I E 0.9*A1, R to L2, and C O.

Profits are sales minus costs, so move the cursor to A3. The entries here are I E A1-A2, R L3, C O.

To see column 4, use shifted 8. JAN's cumulative profit is simply the profit in JAN, so with the cursor at A4 enter I E A3. For the second and subsequent months, the cumulative profit is the previous cumulative profit plus current profit. Move the cursor down to B4 and enter I E A4+B3, and REPEAT down to L4. C O will give you the results as usual.

All that remains now is to produce annual totals for the columns: these can go in line N. Entering G (GOTO) N1 will put the cursor where you want it, and T T C will give yot your column total. Until you CALCULATE, 0 will appear there to show that something has been accepted. R N3 and C O will complete this spreadsheet. You should get a total profit for the year of 1268.

Sometimes figures do not appear to add up. This will be because values are always rounded down for display. Function M will change from integer to decimal (or decimal to integer) modes. Then you have to key G for GOTO and reply A1 to POSITION? to see the more accurate figures. (G for COTO is very useful to move among larger models).

If this were a real model, you might want to SAVE it or PRINT it. See the list of functions. If you like you can change the value in A1 and re-calculate the whole grid. Or you could try and cycle the program to show the profit after 5 years.

STRANGE RESULTS

If you get results that are unexpected, then almost certainly something is wrong with the equations. You should check that equations refer only to grid references where the value at that cell has been evaluated first (remember that the calculation works from left to right and from top to bottom), and that are not set to blank.

HINTS ON MATHEMATICAL FUNCTIONS

MEMOCALC supports all the mathematical functions of the ZX81. This makes it ideal fo engineering applications as well as financial projections.

The RND function

This is an important simulation device. Looking at the last worked example, we assumed that sales increased smoothly. This is ver unlikely to happen - there may be a underlying upward trend, but sales in each month may show peaks and troughs.

If sales are expected to be random within plus or minus 10% of the expected sales, we could model this quite simply with an equation such as:

Random sales= Expected sales * (.9+ .2 * R N D)

More sophisticated equations can be used to model statistical distributions, or to reflect relationships between monthly sales. (If, for example, you had a good sales month in January, it may well be that some of February's sales came early).

The advantage of incorporating RND in such equations is that you will get different random values every time you calculate, and apart from pressing C you do not have to put in much effort. Done several times, this may reveal potential problem outcomes that you might not have considered.

LOGICAL OPERATORS

AND, OR and NOT can be used to put conditions into the model. The costs in the worked example are to say the least, simplistic. A more realistic situation might be that there are fixed non-production costs of 300, a material cost of 0.3 per unit sales, and that factory; labour and overhead costs are a minimum of 300 no matter how many are being made; but that anything over 1000 units produced will incur an excess factory cost of 0.4 per unit. We can then write a mathematical expression for the costs as:

(300+ 0.3 * SALES + 300) + 0.4 * (SALES-1000) AND (SALES >1000)

The right hand part of this expression means that a cost of 0.4 per unit is incurred on sales in excess of 1000 only if it is true that saies exceed 1000.

Such instructions are very useful in incorporating differential tax bands or interest rates etc. Chapter 10 of the Sinclair ZX81 manual goes into more detail.

MEMOCALC was written by John Reidy for MEMOTECH LIMITED.

MEMOCALC (c) R. BRANTON & G. A. C. BOYD 1982


Memotech 16k Ram Pack

Hello User,

We expect you are already getting lots of fun and use out of your Sinclair ZX81 computer. We think this will grow with the addition of the MEMOPAK 16K as you will now be dealing with much bigger programs and arrays. You're now in a position to compete with some of the much more expensive home, office and workshop computers on the market.

This version of the MEMOPAK 16K is fully compatible with either the Sinclair 16K or another MEMOPAK 16K; or a MEMOPAK 32K; or you can work with it just by itself. And later on, if you expand even further, you can part-exchange your MEMOPAK 16K for the full MEMOPAK 64K. See the back of this booklet for more details. We also hope you like the elegant design. Now let's try to answer some of your queries.

How do I set up the MEMOPAK 16K?

Make sure your power supply is not connected to the ZX81 when you attach the pack. We recommend that the ZX81 + MEMOPAK configuration should go in this order, according to what add-ons you have:

ZX81 + [Printer I/F] + [HRG] + Master Memopak 16K or 32K + [Sinclair Printer] + [Slave Memopak or Sinclair 16K].

We supply a Velcro tab which you can cut up and use to get maximum stability on the connections.

What about the switch settings?

There are two possible modes for using the MEMOPAK 16K: MASTER and SLAVE. The mode you require depends on which of the possible memory configurations you are using. The configurations and modes are as follows:

a) MEMOPAK 16K alone (MASTER)

b) MEMOPAK 16K (MASTER) + MEMOPAK 16K (SLAVE)

c) MEMOPAK 16K (MASTER) + SINCLAIR 16K(SLAVE)

d) MEMOPAK 32K (MASTER) + MEMOPAK 16K (SLAVE)

Now, if your MEMOPAK 16K is being used as a MASTER (alone or with a SLAVE pack attached somewhere behind) then switches 2 and 3 should be ON and switches 1 and 4 should be OFF. This is how the pack should reach you. On the other hand, if your MEMOPAK 16K is sitting behind a MEMOPAK 32K or another 16K then it should be switched into SLAVE mode (1 and 4 ON and 2 and 3 OFF). Remember ON is UP. Now you can join up the power supply to your ZX81.

What should I do to use the new, larger memory area?

On powering up, a small K will appear in the bottom left-hand corner of the screen. This means your system is ready to go. If you only have 16K of RAM you do not need to set a higher RAMTOP. If you have a total of 32K RAM then to make the most of it you'll need to key in:

POKE 16389,192

to raise the RAMTOP. For the 48K RAM, you should key in:

POKE 16388,255
POKE 16389,255

After that, you must do a NEW statement to activate the new memory limits. For a quick check that the memory is now at your finger-tips you can now try the following:

For 16K RAM key in

DIM A(3000)
For 32K, key in
DIM A(6000)
For 48K, key in
DIM A(9000)
You should get 0/0 appearing at the bottom of the screen if your large array has been accepted by the system.

To check your RAMTOP, type in:

PRINT PEEK 16389

you will get back the current RAMTOP. If this does not correspond with what you POKED into 16389, then something is wrong. If you did not set RAMTOP, however, then it should still be set at the default of 128.

What is where?

As programs are entered into the system the elements are sifted into the instruction file and the array file. The instruction file, the display file (holding screen data) and the array file lie next to each other in that order at the bottom end of memory.

Gradually, as the instruction file increases, the other files are pushed up through memory. Remember,the original 1 K of RAM in the ZX81 (located at 16K+) has been disabled and all its functions take place in the MEMOPAK. This pushing goes on until either the array file reaches the top of the memory or until the display file begins to straddle the 32K mark (by going above 32767). Naturally, this last situation won't occur if you've only got 16K of RAM .

Does this mean if I've got 32K or more of RAM, I still can't have more than 15K or so of instructions?

No. Many people think you are restricted but there is a neat trick where you can force your display file to leap the 32K mark in one bound by putting in a large, dummy instruction. The important thing is to make sure that the dispiay file never straddles the 32K mark. Here is how:

a) On input check from time to time the value in the VARS system variable, as this lies just above the end of the displayfile:

PRINT PEEK 16401 * 256 + PEEK 16400

b) When the values of VARS approaches 32767, enter a huge line into the program, like:

LET ZERO = 0 + 0 + 0 + 0 etc.
with about 100 repetitions of [+0]. This will push the display file entirely above 32768.

c) Check the system variable D-FILE to make sure the display file now begins above 32768:

PRINT PEEK 16397 * 256 + PEEK 16396
if it is, then you can carry on programming.

How can I use the MEMOPAK 16K if I've got a white ZX80?

In principle this works, but MEMOTECH cannot guarantee it happening in any particular case. The casing and/or boards may have to be altered or separated, and the pack will probably stick out to one side! In addition the following hardware modifications need to be carried out:

a) Break the connecting track between IC6-Pin7 and IC2-Pin20.

b) Put a 680 ohm resistor between the IC6-Pin7(74LS157N) and IC2-Pin20 (ROM ).

c) Connect IC2-Pin20 to the edge connector plug 23B (ROM C.S.). This is the finger furthest away from the keyway slot and on the underside of the board.

We regret we cannot offer this service ourselves and we cannot accept responsibility for malfunction as a result of this modification.

Have you any tips for running a full ZX81 system?

Yes. These are the hints buzzing around the users. They may or may not help in your situation. You may need to make sure that LOADing takes place with cassette recorder volume set at maximum. If possible make sure that your cassette recorder and ZX81 are plugged into different mains sockets.

Maybe you shouldn't have the LOAD (EAR) and SAVE (MIKE) connectors plugged in at the same time. LOADing is more likely to be successful if you quote the filename, rather than null ("") Always clean your connectors. Don't use the first 20 seconds of a cassette tape as that's where a lot of LOAD bugs live.

Can I run programs written for the ZX81 alone with the MEMOPAK 16K?

Yes, they should run straight away, but things are a little tricky if you want to enlarge your arrays to use the larger memory and you have been SAVEing your data. Basically, you have to re-enter all data after you have re-dimensioned, to be sure that the right data is going to be accessed. What you can do is:

a) LOAD the original program.

b) Edit in a special routine which will list and label the contents of all variables on the printer.

c) Run this routine. You now have a hard copy of your data.

d} Re-set your dimensions. Also enter a routine to allow you to reinput all your old values plus any new ones.

e) Run your program and enter the values.

It's probably quickest to start afresh ! You may also encounter problems if you have been using machine code routines with the ZX81 alone.


Memotech 32k Ram Pack

Hello User,

We expect you are already getling lots of fun and use out of your Sinclair ZX81 Computer (or your ZX80!).

We think this will grow with the addition of the MEMOPAK 32K, as you will now be dealing with much bigger programs and arrays. You're now in a position to compete with some of the much more expensive home, office and workshop computers on the market . And if you already have a 16K memory pack, you will now have a total of 48K RAM. See the back of this booklet for detaiis of how to use both of them together. We hope you like the elegant design. Now let's try to answer some of your queries.

How do I set up the MEMOPAK 32K?

Make sure your power supply is not connected to the ZX81 when you plug the pack into the back. You will find it plugs it firmly enough to be used safely, but to cut all wobble, you can use the three Velcro tabs as well.

Now you will have the ZX81 and the pack looking and acting like one unit. If you have the Sinclair printer, this will plug neatly into the back of the memory. Now you can join up the power supply to your ZX81.

What should I do to use the new, larger memory area?

On powering up, a small K will appear in the bottom left hand corner of the screen. This means that your system is ready to go, but the computer is expecting to use only a maximum of 16K. So you'll probably want to tell the computer that more memory is present. On the other hand, you do not have to use all available memory (See Chapter 26 of the ZX81 handbook).

There is a memory location which you change in order to tell the computer the upper limit of your memory (or RAMTOP if you're into the jargon). This is 16389. To set top of RAM at 48K, type the following:

POKE 16389, 192
(this is usually set at 128 for a 32K limit).
NEW
(the memory is now cleared to start afresh; and will now be organised to the new limit)

To check the current top of RAM, type

PRINT PEEK 16389
and the value of 192 should appear in the top left-hand corner of the screen.

For a quick check that the memory is now at your finger tips you can now try the following little programs:

10 DIM A$(60,500)
 or
10 DIM A(6000)
 or
10 POKE 4800O, 128
20 PRINT PEEK 48000

What is where?

As programs are entered into the system the elements are sifted into the instruction file and the array file. The instruction file, the display file (holding screen data) and the array file lie next to each other in that order at the bottom end of memory. Gradually, as the instruction file increases, the other files are pushed up through memory. Remember, the original 1K of RAM in the ZX81 (located at 16K+) has been disabled and all its functions take place in the MEMOPAK.

This pushing goes on until either the array file reaches the top of the memory or until the display file begins to straddle the 32K mark (by going above 32767).

Does this mean if I've got 32K or more of RAM, I still can't have more than 15K or so of instructions?

No. Many people think you are restricted but there is a neat trick where you can force your display file to leap the 32K mark in one bound by putting in a large, dummy instruction. The important thing is to make sure that the display file never straddles the 32K mark. Here is how:

a) On input check from time to time the value in the VARS system variable, as this lies just above the end of the displayfile:

PRINT PEEK 16401 * 256 + PEEK 16400

b) When the values of VARS approaches 32767, enter a huge line into the program, like:

LET ZERO = 0 + 0 + 0 + 0 etc.
with about 100 repetitions of [+0]. This will push the display file entirely above 32768.

c) Check the system variable D-FILE to make sure the display file now begins above 32768:

PRINT PEEK 16397 * 256 + PEEK 16396

if it is, then you can carry on programming.

How can I use the MEMOPAK 32K if I've got a white ZX80?

The MEMOPAK 32K drives the ROM directly - but with the ZX80 it can't do this unless you first carry out the following simple hardware modifications.

a) Break the connecting track between IC6-Pin 7 and IC2 Pin 20.

b) Put a 680 ohm resistor between IC6-Pin 7 (74LS157N) and IC2 Pin 20 (ROM).

c) Connect IC2-Pin 20 to the edge connector plug 23B (ROM C.S.) This is the finger furthest away from the keyway slot and on the underside of the board.

We regret we cannot offer this service ourselves and we cannot accept responsibility for malfunction as a result of this modification such as screen glitches.

Have you any tips for running a full ZX81 system?

Yes. These are the hints buzzing around the users. They may or may not help in your situation. When connected to MEMOPAK 32K and printer, make sure that LOADing takes place with cassette recorder volume set at maximum. If possible make sure that your cassette recorder and ZX81 are plugged into different mains sockets.

Maybe you shouldn't have the LOAD (EAR) and SAVE (MIKE) connectors plugged in at the same time. LOADing is more likely to be successful if you quote the filename, rather than null ("") Always clean your connectors. Don't use the first 20 seconds of a cassette tape as that's where a lot of LOAD bugs live.

Can I run programs written for a 16K pack with the MEMOPAK 32K?

Yes, they should run straight away, but things are a little tricky if you want to enlarge your arrays to use the larger memory and you have been SAVEing your data. Basically, you have to re-enter all data after you have redimensioned, to be sure that the right data is going to be accessed. What you can do is:

a) Load the original program

b) Edit in a special routine which will list and label the contents of all v ariables on the printer.

c) Run this routine. You now have a hard copy of your data.

d) Re-set your dimensions. Also enter a routine to allow you to re-lnput all your old values plus any new ones.

e) Run your program and enter the values.

It's probably quickest to start afresh! You may also encounter problems if you have been using machine code routines with the ZX81 alone.

A couple of program examples

BASIC strings are stored in the instruction area of RAM. This means that when you set a literal, say,

LET A$="CAT"

the word CAT is actually duplicated, once as a literal as part of the instruction, and once in the variable areas A$. It would be more economic if we could set up an initialisation routine which would store all literals once only- in the variables area. This simple loop would let you input up to 10 strings of 20 characters each:

10 DIM A$(10, 20)
20 INPUT K
30 IF K = 0 THEN GOTO 70
40 INPUT B$
50 LET A$(K) = B$
60 GOTO 20
............................
70 INPUT K
30 IF K=0 THEN GOTO 110
90 PRINT A$(K)
100 GOTO 70
...........................
110 REM AUTOMATIC SELF SAVE
120 SAVE "SELF"
130 GOTO 20
140 STOP

Breakdown:
Lines 20-60 Store strings
Lines 70-100 Display strings
Lines 110-140 Save program with string arrays

Now look carefully at the instructions from line 110. With increased array capacity in the memory you will probably want to store your data more permanently and it is possibte to save your arrays (and their contents) along with your program.

However, it's important that when you next load the program, it does not carry out a RUN but a GOTO instead; otherwise RUN will automatically clear the arrays. This program will SAVE itself automatically (line 120).

When you next LOAD it will pick up straight away at line 130 -the line after the SAVE- and branch back to the line quoted there (in this case 20). In this way the RUN instruction is avoided and the variables are not cleared. But make sure you don't branch back to a point where you re-dimension the array you're trying to save!

Can I use the MEMOPAK 32K in conjunction with a 16K pack?

Yes, all you have to do is plug your other pack as a slave unit onto the back of our 32K pack. There are three possible slave units:

a) Our standard MEMOPAK 16K. This is the one with switches, which should be set in SLAVE mode (1 and 4 ON; 2 and 3 OFF).

b) Our MEMOPAK BASELINE 16K. This just fits on the back (or with the ZX printer in front of it).

c) The Sinclair 16K pack. This also fits on the back just like the BASELINE 16K.

Fit the ZX81 and the packs and the printer together. You will now have 48K of RAM available, and to use this you will need to set a new RAMTOP each time you power up:

POKE 16389, 255
NEW

Good Luck from all at MEMOTECH


Memotech 64k Ram Pack

Hello User,

We expect you are already getting lots of fun and use out of your Sinclair ZX81 Computer (or your ZX80!)

We think this will grow with the addition of the MEMOPAK 64K, as you will now be dealing with much bigger programs and arrays. We've given you as much direct memory as the ZX81 can take, and you're now in a position to compete with some of the much more expensive home, office and workshop computers on the market. We hope, you also like the elegant design. Now let's try to answer some of your queries

How do I set up the MEMOPAK 64K?

Make sure your power supply is not connected to the ZX81 when you plug the pack into the back. You will find it plugs In firmly enough to be used safely: but to cut out all wobble, you can use the three Velcro tabs as well.

Now you will have the ZX81 and the pack looking and acting like one unit. If you have the Sinclair printer this will plug neatly into the back of the memory. Make sure that switch 1 is OFF and at least one but no more than two of the other switches are ON. Now you can join up the power supply to your ZX81. Whatever power supply you use for your ZX81 and printer no extra supply is needed for the MEMOPAK.

What should I do, to use the new, larger memory area?

On powering up a small K will appear in the bottom left hand corner of the screen. This means that your system is ready to go, but the computer is expecting to use only a maximum of 16K. So you'll probably want to tell the computer that more memory is present. On the other hand you do not have to use all available memory. (See Chapter 26 of the ZX81 handbook). There are two memory locations which you change in order to tell the computer the upper limit of your memory (or RAMTOP If you' re into the jargon) These are 16389 and 16388. To set top of RAM at 64K type the following

POKE 16388,255
(this is not usually needed)
POKE 16389,255
(this is usually set at 128 for a 32K limit)
NEW
(the memory is now cleared to start afresh and will now be organised to the new limit)

To check the current top of RAM type:

PRINT PEEK 16389

and the value will appeari n the top left-hand cornerer of the screen. For a quick check that the memory is now at your finger tips you can now try the following little programs:

 10 DIM A$(90, 500)
or
 10 DIM A(9000)
or
 10 POKE 65000,128
 20 PRINT PEEK 65000

These programs reach the top end of memory. Remember numeric fields take up five bytes. (Tip - if you want to store more numbers and they are integers which don't axceed 255, thern why not use the ASC and CODE functions to store values as single byte characters?)

How can I test that all my variable locations are good?

First set top of RAM back to 32K (just reconnect the power supply or

POKE 16389,128
) Type in this programl which will test every bit in the 32-64K area.

 10 FOR I = 32768 TO 65535
 20 POKE I,255
 30 LET A= PEEK I
 40 POKE I,0
 50 LET B = PEEK I
 60 IF A <>255 OR B <>0 THEN GOSUB 110
 70 SCROLL
 80 PRINT I
 90 NEXT I
100 STOP
110 PRINT "ERROR AT: ",I
120 STOP
130 RETURN

As each Byte is tested it will be printet on the screen. If a bad location is found, the progamm will stop with an error message. Otherwise, reset top of RAM and start that big program.

What is where?

Confusing isn't it? But not really. First of all, our pack does contain a full 64K RAM (and this can be used by other Z80 processors, in principle). But the ZX81 can only address 64K locations altogether, and the first 8K are obviously dedicated to its own ROM. So although we've got 64K RAM and the ZX81 can address 64K locations this MEMOPAK can't add on more than 56K to the ZX81 ROM. This brings the ZX81 MEMOPAK configuration to 64K total. The original 1K of RAM of the ZX81 ( located at 1 K + ) is disabled and its functions will take place in the MEMOPAK 64K RAM.

Still confused? There's a diagram on the inside back cover, to sort lt out. The main thing to remember is that the top 48K is automatically used by the ZX81 BASIC. It puts instructions into the 16-32K area and puts arrays and variables into 32-64K area. When this top area is all used up with arrays it moves down into the 16-32K area, thus giving you a maximum array of something under 48K. You won't quite reach 48K of array because the ZX81 also keeps its display file - the screen memory - and system variables in this area.

What about the mysterious 8-16K area?

This does not exist in the ZX81 when oor its own. We have supplied it and you con now reach it directly in your BASIC program, using PEEK and POKE. The sort of thing you can use it for will depend on how expert you are, but we can suggest:

a) storing data and machine code subroutines

b) passing then from one program to another

c) memory mapping buffer areas for ad-ons

If you want to use the 8-16K area you will have to make sure certain switches are set, as shown here. There are five modes of working.

 | Switch |  |  |  |
Mode | 1 | 2 | 3 | 4
A | ON | OFF | OFF | OFF | This mode provides 64K of memory and is for future developments
B | OFF | ON | OFF | OFF | Memory is provided between 8K and 12K.
C | OFF | OFF | ON | OFF | Memory is provided between 12K and 16K
D | OFF | OFF | OFF | ON | No memory is available between 8K and 16K
E | OFF | ON | ON | OFF | Memory is awailable between 8K and 16K

For ZX81 users, switching between modes B, C, D, and E is possible, as long as at least one and no more than two switches are ON at the same time. Never have more than two switches on at a time, as this can lead to overloading.

How can I use the MEMOPAK 64K if I've got a white ZX80?

The MEMOPAK 64K drives the ROM directly - but with the ZX80 it can't do this unless you first carry out the following simple hardware modifications.

a) Break the connecting track between IC6-Pin 7 and IC2 Pin 20.

b) Put a 680 ohm resistor between IC6-Pin 7 (74LS157N) and IC2 Pin 20 (ROM).

c) Connect IC2-Pin 20 to the edge connector plug 23B (ROM C.S.) This is the finger furthest away from the keyway slot and on the underside of the board.

We regret we cannot offer this service ourselves and we cannot accept responsibility for malfunction as a result of this modification such as screen glitches.

Have you any tips for running a full ZX81 system?

Yes. This is the word buzzing around the users. They may or may not help In your situation. When connected to MEMOPAK 64K and printer, make sure that LOADing takes place with cassette recorder volume set at maximum. If possible make sure that your cassette recorder and ZX81 are plugged into different mains sockets.

Don't have the LOAD (EAR) and SAVE (MIKE) connectors plugged in at the same time. LOADing is more likely to be successful if you quote the filename, rather than null ("").

Can I run programs written for a 16K pack on the MEMOPAK 64K?

Yes, they should run straight away, but things are a little tricky if you want to enlarge your arrays to use the larger memory and you have been SAVEing your data. Basically, you have to re-enter all data after you have redimensioned, to be sure that the right data is going to be accessed. What you can do is:

a) Load the original program

b) Edit in a special routine which will list and label the contents of all v ariables on the printer.

c) Run this routine. You now have a hard copy of your data.

d) Re-set your dimensions. Also enter a routine to allow you to re-lnput all your old values plus any new ones.

e) Run your program and enter the values.

One more thing: to use the memory fully it is much better to use a multi- dimensional string array than a simple string, since the ZX81 limits single sizes to a maximum length of 16K.

A couple of program examples

BASIC strings are stored in the instruction area of RAM (16-32K) This means that when you set a literal, say

LET A$ ="CAT"

the word CAT is actually duplicated, once as a literal as part of the instruction and once in the variable area A$. It would be more economic if we could set up an initialisation routine which would store all literals once only in the variables area. This simple loop would let you input up to 10 strings of 20 characters each.

 10 DIM A$(10,20)
 20 INPUT I
 30 IF I = 0 THEN GOTO 70
 40 INPUT B$
50 LET A$(I) =B$
60 GOTO 20
............................
70 INPUT I
30 IF I=0 THEN GOTO 110
90 PRINT A$(I)
100 GOTO 70
...........................
110 REM AUTOMATIC SELF SAVE
120 SAVE "SELF"
130 GOTO 20
140 STOP

Breakdown:

Lines 20-60 Store strings
Lines 70-100 Display strings Lines 110-140 Save program with string arrays

Now look carefully at the instructions from line 110. With increased array capacity in the memory you will probably want to store your data more permanently. The ZX81 system does not(at least yet) support freestanding files but it is possible to save your arrays (and their contents) along with your program.

However, it's important that when you next load the program, it does not carry out a RUN but a GOTO instead, otherwise RUN will automatically clear the arrays. This program will SAVE itself automatically (line 120) When you next LOAD it will pick up straight away at line 130 - the line after the SAVE - and branch back to the line quoted there (in this case 20) In this way the RUN instruction is avoided and the variables are not cleared. But make sure you don't branch back to a point where you re-dimension the array you're trying to save!

MEMOTECH are a so planning to bring out the following ZX81 add-ons in the near future.

a high resolution graphics pack

a digitiser

a 16K RAM pack which will be partexchangeable for the MEMOPAK 64K

an RS232 interface

a Centronics printer interface

We're sorry but we cannot accept any orders or enquiries at this stage. Please watch the magazine advertisements.

Good Luck From all at MEMOTECH


Memotech HRG

Hello User,

By now you may have become quite expert at BASIC programming on the Sinclair ZX81. You're probably making good use of one of the Memotech MEMOPAKs or another commercial RAM pack. But you'd like to try graphics - programming in a new dimension. Graphics can be great fun. Apart from space zombies to be zapped without serious risk to your health, there is a new world of design, animation, geometry and presentation to try. Again, we hope that you like our elegant design. Now let's tell you how it works.

How do I set up the MEMOPAK HRG?

Disconnect your ZX81 power supply, and install your HRG pack between the ZX81 and your RAM pack. You need a RAM pack because the HRG routines operate primarily on the memory,- a screen image is held as a 'video page' in about 6.2K of RAM. The more RAM you've got the more video pages you can use. We recommend you use the Sinclair 1200 milliamp power supply as supplied with the Sinclair printer and recent ZX81's. You will find all MEMOPAK units plug in firmly, but for the best connection we suggest you cut up and use the velcro tabs provided. Moreover, our HRG pack utilises the addresses between 8 and 10K, so if you have a MEMOPAK 64K you will have to make sure this area is switched out. This means you must set your switch either in MODE B (2 ON; 1, 3 and 4 OFF) or MODE D (4 ON; 1, 2 and 3 OFF). Remember ON is UP. With a 64K RAM pack you will probably want to put your video page above 49152. In this case you should remove the little square jumper switch next to the back connector board. It's best to use a pair of tweezers or pliers (but disconnect the power first). To keep the jumper safe, you can replace it on just one pin.

Is there a quick test to show my pack is running OK?

Yes. Choose a spare memory area of at least 6.2K and set V to its start byte address. Then do our special call. So enter as follows:

LET V= 19000
 (with jumper in) or
LET V = 50000
 (with jumper out)
RAND USR 8619

What you should get is MEMOTECH appearing in white on a black background. If not, check your configuration and your connectors, and try again. When it's working, you can test the 'BASIC RE-SET' button which is located on the side of your pack. This is for returning you from your HRG display to your normal BASIC display.

Where and how are the HRG routines kept?

The MEMOPAK HRG contains a 2K EPROM where our subroutines reside and it's full to bursting. We have provided at least 30 functions in the firmware to help the user get the most out of the HRG. Our philosophy here has been in the Sinclair tradition: help the user to help himself. We have increased the scope of your activity; we leave you free to explore the new territory.

How does the HRG work?

Simply, the HRG allows you to output in dots rather than characters

(1 character=8x8=64 dots) or Sinclair pixels (1 pixel = 4 x 4= 16 dots).

Since the dot is the smallest graphics item, it offers the maximum flexibility. Any shape, character or pattern can be generated by the right combination of dots, and the possibility of smoother curves increases.

In everyday life, to fill a page with dots is a laborious process. But here the sweat is taken out of it by a number of means:

a) Subroutines which work much faster because they operate directly in machine code.

b) Full use of looping facilities in both BASIC and machine code.

c} The ability to pre-plot special characters or mix in characters from the Sinclair range.

d) Powerful rolling and scrolling facilities.

The range of subroutine calls is listed in a table in the back of the booklet. They span many functions, and are particularly powerful in their ability to make the most of your memory. They also span a number of different levels - dot, line, character, block and page.

How is the screen related to the memory?

As far as our pack is concerned, your screen is made up of 192 x 248 dots or HRG pixels (the equivalent area of 24 x 31 BASIC screen character positions). The leftmost column of the screen is ignored by the HRG - for subtle software reasons. All screen activity takes place in a 'video page' of memory which you can show on the screen at the same time. You can also manipulate the 'video page' without showing it on the screen; or you can be looking at another video page while doing so!

How is a video page organised?

A variable is reserved by the HRG system to hold the memory address of the start byte of the video page. So always remember to set variable V to the start of the particular video page you want to reach.

Roughly speaking, one screen dot (or HRG pixel) is stored in one bit of memory. However when placed in memory each horizontal 'line' of 248 graphics bits is preceded by 2 bytes of control data. In addition, there is a single byte of screen control data terminating the whole video page. So the arithmetic looks like this:

Bit Summary
 | Line Control | Screen Graphics | HRG Memory
Line | 16 | + 248 | = 264
Page | 3072 | + 47616 | = 50688
1 video page= 50688+8 page control bits= 50696 bits.

Byte Summary
 | Line Control | Screen Graphics | HRG Memory
Line | 2 | + 31 | = 33
Page | 384 | + 5952 | = 6336
1 video page= 6336+1 page control bits= 6337 bits.

Whereabouts in memory can I put a video page?

You must choose an area which is not otherwise occupied by the system variables, the instructions, the display file or your other arrays. The simplest thing is to set a low RAMTOP leaving you enough space (6337 bytes per video page) between that and your real limit of memory. Clever users may find other ways.

How do I use the HRG subroutines?

A subroutine is called by using the Sinclair USR function. We recommend the use of an instruction such as RAND, as this has few side effects, but other instructions may do. All the subroutines can be called initially from one address (8192), so that the same call can be used for any function:

 RAND USR 8192

If however you want to reserve RAND to set the seed for the randomizer, then use, say, LET A = USR 8192. To nominate a particular subroutine however you must first specify its name in a reserved variable Z$. So to call for example the simple PLOT function (which sets a bit in the video page) you must first enter the instruction:

LET Z$= "PLOT"

"PLOT" in turn uses the X and Y variables to find out the co-ordinates to be plotted. So the whole step goes like this:

LET X = 64
LET Y = 100
LET Z$= "PLOT"
RAND USR 8192

This little routine, provided the right initialisation steps have been taken, will set one bit in the video page specified.

How do I use the MEMOPAK HRG with a BASIC program?

The MEMOPAK HRG has been designed so that you can use it in ordinary BASIC. There are also routines which allow you to switch the screen from conventional BASIC display to the HRG display and back again. While you are developing your program, you can use the manual 'BASIC RETURN' button on the side of the pack which puts you back into BASIC display mode, without in any way endangering your graphics data. When you return back to the BASIC display mode, you may be upset to find a blank screen. This is blank simply because although your BASIC program is running, it has not been requested to output anything to the screen. You'll probably want to look at your program listing at this point, so you need to use the Sinclair BREAK and LIST functions.

What about FAST mode?

These routines work rapidly in FAST mode, at least as rapidly as graphics on the Sinclair Spectrum and with more pixels. However, in FAST mode you lose the screen and the gratifying experience of seeing the graphics at work for you. Moreover in FAST mode the 'BASIC RETURN' button cannot work, so if you want to get back to BASIC display manually, you have to break in and enter"SLOW" even though there will be no screen response until you've done it. Now you can use the 'BASIC RETURN' button.

How do I initiate an HRG routine in my BASIC program? (Page functions}

The first thing is to set the start byte of your video page in the reserved variable V. Then you must cite an activate the "START" function. Functions must always be cited in reserved variable Z$ prior to the call. "START" does two things: initiates the HRG system and assigns the video page area (start address cited in V) to it. (Later in the program the "PAGE" function could be used to assign another video page without reinitiating the system.) (Note: the groups of instructions which follow are typical enoughl but when all put together they may form a pretty absurd program. For 'real' program examples see the back of this booklet). Your routine so far could well look like this:

10 LET V = 40000
20 LET Z$ = " START"
30 RAND USR 8192

You may now want to clear the video page area initially (or else you may pick up what you left there before remember an area above RAMTOP is not cleared by Sinclair).

40 LET Z$="CLEAR"
50 RAND USR 8192

Note the same USR address is used whatever the function. "CLEAR" also uses variable V to find out where the page to be cleared is located. Since we are talking about the same page that was assigned with the "START" function, there is no need to re-set V. All the activity so far has gone on in the memory video page and we haven't seen a thing. To keep your eye on what's going on, let's do an "HRG" call. This will do an HRG display of the memory page rather than display anything your BASIC program may have output. Don't worry, your BASIC outputs are still accessible (they're still in the Display or D-FILE), but they are now invisible.

60 LET Z$="HRG"
70 RAND USR 8192

Note that as we are still talking about the same video page, we still have not re-set V. The screen is now locked into our video page and anything that happens there, we can watch. "HRGINV" will also show what is in the page, but in reverse, and without changing the bits in the memory. So in just seven lines we are ready to start depicting something. If seven lines is too much for you, we have kindly provided you with a macro (multiple) function: "STARCH". "STARCH" sounds like a new concept in programming for laundry control but really it simply means "START"+ "CLEAR" + "HRG" and the above program can now be shortened to 3 instructions:

10 LET V = 40000
20 LET Z$="STARCH"
30 RAND USR 8192

To summarise: the HRG system is initialised; a video page is assigned from 40000 onwards; the page is cleared and the contents (blanks or unset HRG pixels) displayed. We can just mention 3 other page level functions:

"PRINT" will transfer any video page to the Sinclair printer.

"STRING" will let you pass a video page into a long string which can then be SAVEd on cassette by the ZX81.

"UNSTRING" will unpack a string into a video page for you on re-LOADing.

The video string is always S$. You can use "STRING" simply to clear space for yourself above RAMTOP. But don't try to "UNSTRING" something which you did not "STRING" first, unless you are sure you have got the control characters right. When re-loading a video page with "UNSTRING" that has been stored and SAVED within the "STRING" function) it is necessary to:

a) make sure you do not use RUN for the re-load section but GOTO, in order to prevent S$ from being cleared.

b) make sure you do not redimension S$ on re-entering as this will also lose the array

c) remember to re-set V and call the "STARCH", "UNSTRING" and "HRG" subroutines to see the video page again.

Sample re-load subroutine. Enter program with GOTO 1000.

 990 STOP
1000 LET V = 50000
1010 LFT Z$= "STARCH"
1020 RAND USR 8192
1030 LET Z$ = "UNSTRING"
1040 RAND USR 8192
1050 LET Z$= "HRG"
1060 RAND USR 8192
1070 GOTO....

Incidentally, if you don't like the idea of repeating the subroutine call - e.g . RAND USR 8192 - all the time, you may like to place it in a little subroutine. For some repeated calls, you might also like to set the parameters from within the routine as well.

What can I do now?

You are now free to experiment with the other subroutine functions (and their parameters) listed at the back.

They are broken down into five kinds: page functions, block functions, character functions, line functions and dot (or HRG pixel) functions. The page functions have already been described above. As for the rest, let's start small.

HRG pixel (or dot) routines

The simplest function is "PLOT" which requires X and Y co-ordinate parameters in addition to V:

 80 LET X = 50
 90 LET Y = 60
100 LETZ$="PLOT"
110 RAND USR 8192

This will place a dot on your screen. Remember that the co-ordinates in X and Y work like this:

Axis | Range | Direction
X Horizontal | 0 - 247 | Left to right
Y Vertical | 0 - 191 | Bottom to top

"UNPLOT" works in exactly the same way, so:

120 LET Z$ = "UNPLOT"
130 RAND USR 8192

will take the dot away again. If you want to find out whether an HRG pixel is set use "TEST", this time calling the routine with the Basic LET instruction for the reply:

140 LET Z$="TEST"
150 LET K=USR 8192
160 IF K=0 THEN .........
170 IF K= 1 THEN .........

Any variable may be used; if the routine returns 0 then the pixel is unset, if 1 then set; and you can take action accordingly. In this case, since the routine is still testing the old X,Y locations, which we UNPLOTted, then the reply will be zero. With "HRG" called, your screen displays an image of the video page. However you can use the "LOCATE" function to find the absolute memory address of a pair of co-ordinates, and so manipulate the video page directly. Remember however, that the video page is not exactiy the same as a screen; there are two control bytes preceding each line (the first one is a Sinclair newline byte (118) and the second one is zero) and one more byte after the last line in the page (also 118). So if you want to interfere with a video page directly, take these into account. To find out where in memory our pixel location is, enter:

180 LET Z$="LOCATE"
190 LET K= USR 8192

and K will receive the address.

Can I run two or more video pages together?

Yes, they can be located next to each other in memory and will effectively be joined vertically. In this case the first line control byte of the later video page should be the same as the last page control byte of the first video page. It is now possible to look at any 'intermediate' page made up of later lines of the earlier page and earlier lines of the later page. To call such a page make sure that your start byte value placed in V is displaced from the start bytes of the 'real' video page by a multiple of 33.

What about Geometry?

At this point we can introduce our simple geometric functions. We could have provided more but we think it is an excellent chance for users to brush up on their skills. The only functions we provide are "LINE", "UNLINE", "BLINE" and "WLINE"; any other shape can be effected by combinations of these or the "PLOT" call, and the Sinclair maths functions.

You'll need to work on your algebraic geometry, or dust off a text-book to get algorithms for curves, sine waves and so on. Try this natural log curve:

200 LET Z$ = "PLOT"
210 FOR X= 1 to 245
220 LET Y= 33 * LN X
230 RAND USR 8192
240 NEXT X

Line routines

"LlNE" will join the points specified in the pairs of co-ordinates P, Q and X, Y and you should be able to do straight-edge geometry yourself. "UNLINE" will wipe out a line in the same way. "BLINE" (black line) and "WLINE" (white line) are used only for vertical plotting and will draw a line upwards from X, Y until a bit of the same setting is encountered. The vertical coordinate of the setting is returned in Y. Used in conjunction with the "LAUNCH" routine, some sophisticated shading routines are possible. See our example at the back. Lastly, for the zappers, there is our "LAUNCH" routine. This will fire a laser beam vertically up the screen and detect a 'hit' (i.e. if any of the bits in its path were set). If there is a hit, it passes back the vertical co-ordinate and vanishes. Otherwise, it disappears off the top of the screen. "LAUNCH" need not be used so aggressively; it can also serve as a 'radar' function to detect the presence of the first bit set in a vertical column rising from the X, Y position cited. This can be used for shading or blocking in.

Character routines

There are two kinds of character you can plot - those you've designed yourself and those Sinclair provides. To design a simple horizontal line of bit settings, simply set up a string of O's and 1's in C$, with a colon as terminator:

250 LET C$="10101:"

Instead of 0, you can use * to avoid disturbing the initial status of a bit. To design a 2-dimensional character you can simply use N, S, E or W (or a combination) to re-set the start location of the next series of bit settings, and continue. So we could plan a cross on the screen instead:

Type in

250 LET C$="1***1NE1*1NE1NW1*1NW1***1 :"
260 LET X = 30
270 LET Y = 40
280 LET Z$="SKETCH"
290 RAND USR 8192

and the cross will appear with the bottom left-hand point located at 30,40. In this example, we built the character upwards using N, but we could have dropped it downwards using S, or missed out a line altogether using SS.

"UNSKETCH" has the effect of unsetting the bits set in the string.

"INVSKETCH" is like "SKETCH" except that it reverses the bit settings, placing a reverse image of your character in the video page itself.

"SINCH" does the same thing as "SKETCH" except that you need to cite a Sinclair character. For reverse images, you can use Sinclair's own inverse functions.

A whole string of Sinclair characters can be displayed anywhere in the page, starting at the X, Y point which represents the bottom left-hand corner of the first character. To wipe out a "SINCH" display, use the Sinclair space character.

Block handling routines

For block handling routines, to save on tedious co-ordinates we have hit on the concept of north, south, east and west. For this reason, variables N S, E and W are called. We have two dynamic routines which can be useful for animated displaysroll and scroll. The "roll" functions take a block and shift the constituent lines up or down, taking the line that has dropped off the block at one end and adding it on at the other. This is done according the following 2-character command strings -"RU" (roll up) and "RD" (roll down), and these will use the N, S, E and W parameters. A similar set of commands exist for the scroll functions. "Scroll" differs from "roll" in that the line that drops off will completely disappear and a blank line will step in at the other end. Scrolling can be done horizontally as well as vertically. So these are the last four command strings you've got: "SU", "SD", "SR" and "SL". Note that when moving horizontally, E must be greater than W; when going vertically, N must be greater than S.

Scrolling and rolling is most effective when set in a loop.

Subroutine Calls

Command String (z$) | Function | Parameter
Page routines
START | Initiates HRG system and assigns memory video page | V
PAGE | assigns memory video page | V
CLEAR | Clears a page | V
HRG | Displays a page | V
HRGINV | Displays a page inversly | V
STARCH | Macro = Start + Clear + HRG | V
PRINT | Prints a video page | V
PRINT1 | Prints top line of video page | V
BASIC | Displays current BASIV page | none
STRING | Copies page into BASIC string | V, S$
UNSTRING | Copies string into video page (requires DIM S$(6337) or more) | V, S$
Block routines
RU | Roll Block up | V,N,S,E,W
RD | Roll Block down | V,N,S,E,W
SU | Scroll Block up | V,N,S,E,W
SD | Scroll Block down | V,N,S,E,W
SR | Scroll Block right | V,N,S,E,W
SL | Scroll block left | V,N,S,E,W
Character routines
SKETCH | Plots user-defined character | V,X,Y,C$
UNSKETCH | Unplots userdefined character | V,X,Y,C$
INVSKETCH | Reverses user defined character in page and screen | V,X,Y,C$
SINCH | Plots ZX81-defined character | V,X,Y,C$
Line routines
LINE | Draws a line | V,X,Y,P,Q
UNLINE | Wipes out a line | V,X,Y,P,Q
*BLINE | Draws black line 'UP' until set BIT | V,X,Y
*WLINE | Draws white line 'UP' until set BIT | V,X,Y
*LAUNCH | Draws momentary line 'UP' until set BIT | V,X,Y
Dot routines
PLOT | Sets one BIT/HRG pixel | V,X,Y
UNPLOT | unsets one BIT/HRG pixel | V,X,Y
*TEST | Gets a setting of a BIT | V,X,Y
*LOCATE | Gets a memory location of a BIT | V,X,Y

* These calls elicit a reply and so should be made with the LET statement:

LET G = USR 8192

will place the reply in G. "LAUNCH", "BLINE" and "WLINE" will get a value of the vertical coordinate or zero if none is found. "TEST" will get a value of zero for an unset, one for a set bit. "LOCATE" will get the absolute memory address of a bit set. Or you can use a logic test:

IF NOT USR 8192 THEN GOTO 1000

HRG Parameters

Z$ | = Command string
V | = Start byte of assigned video page
X | = Horizontal co-ordinates (0-247)
Y | = Vertical co-ordinates (0-191 )
P | = Secondary horizontal co-ordinates (0-247)
Q | = Secondary vertical co-ordinates (0-191)
N | = Uppermost block line (0-191 )
S | = Lowest block line (0-191 )
E | = Rightmost block line (0-247)
W | = Leftmost block line (0-247)
C$ | = String for "SKETCH", "SINCH" etc.
S$ | = String for storing video page data

HRG error codes

L | = Parametervariable not declared
M | = HRG command string not known
N | = Horizontal parameter too large
O | = Vertical parameter too large
P | = Invalid element in "SKETCH" string

Here are some examples to try:

A) To draw two waves, and shade in the areas between.

 10 LET V = 40000
 20 LET Z$ = "STARCH"
 30 RAND USR 8192
 40 LET Z$ = "PLOT"
 50 FOR X = 0 TO 247
 60 LET Y = 100+50*SIN(X/20)
 70 RAND USR 8192
 80 LET Y = 100 + SIN (X/30) * COS(X/15) * 50
 90 RAN D USR 8192
100 NEXT X
110 FOR X = 0 TO 247
120 LET Y = 0
130 LET Z$ = "LAUNCH"
140 LET Y=1 + USR 8192
150 LET P = USR 8192
160 IF P = 0 THEN GOTO 190
170 LET Z$ = "BLINE"
180 RAND USR 8192
190 NEXT X

Run it and see. Is it a bird? Is it a Loch Ness Monster?

A few notes about the program: "LAUNCH" detects the first set bit in a vertical pattern. In line 140 we add 1 and use that as the start of "BLINE" which will draw a black line up until the next set bit. Sometimes, we don't want to draw a line up, so we test to make sure that a second bit exists as in lines 150-160.

B) To make a beautiful pattern from curves. Is it a bird? is it a seal?

 10 LET V = 40000
 20 LET Z$= "STARCH"
 30 RAND USR 8192
 40 LET Z$ = "PLOT"
 50 FOR A= 10 TO 100 STEP 3
 60 LET D = A * A
 70 LET C = D * 190
 80 FOR X = 0 TO 247
90 LET Y = C/(X * X + D)
100 RAND USR 8192
110 NEXT X
120 NEXT A

C) Here is a program which shows a funny clock. We're sure you could make it better- more accurate; with hours as well. Change line 80 to make it slow down or speed up.

 10 LET V = 40000
 20LET Z$ = "STARCH"
 30 RAND USR 8192
 40 LET P= 100
 50 LET Q= 100
 60 FOR T=1 TO 60
 70 GOSUB 130
 80 FOR Z= 1 TO 20
 90 NEXT Z
100 GOSUB 210
110 NEXT T
120 STOP
130 LET X= 100 + 50*SIN (T* PI/30)
140 LET Y= 100 + 50*COS (T* PI/30)
150 LET Z$ = "SlNCH"
160 LET C$ = STR$ T
170 RAND USR 8192
180 LET Z$ ="LINE"
190 RAND USR 8192
200 RETURN
210 LET X= 100+50*SIN(T* PI/30)
220 LET Y = 100 + 50*COS (T* PI/30)
230 LET Z$ = "UNLINE"
240 RAND USR 8192
250 RETURN

Good Luck from all at MEMOTECH


G007 Graphics

Conditions Of Use

The G007 requires the following:

1. An external RAM pack, of 8K or more.

2. The 1K or 2K internal RAM must be present.

3. Any additional hardware used with the module must reside between the G007 module and the RAM pack.
The exception is the ZX81 printer, which fits between the G007 and the ZX81.

4. The memory between 2000H and 3000H may only be used by the G007.
This does not stop 64K RAM packs being used, but the G007 will disable this area of memory in the RAM pack. Due to the many add-ons available, we cannot guarantee the G007 to work with any add-on other than the Sinclair RAM pack and printer. However, most of the alternative RAM packs, including 64K ones, should be fine.


G007 Graphics

1.Introduction

Welcome to the world of high-resolution graphics! The G007 provides a 256x192 pixel display mode and graphics command extensions to the BASIC interpreter.
Over 100 different operations may now be performed with the modified statements:

PLOT n,x,y , CLS n, COPY n, SLOW n, FAST n

These are all multipurpose statements, now, with the different functions being selected by the new parameter 'n'. The really versatile statement is PLOT n,x,y which can now do such things as line drawing and textured area filling. The G007 also provides powerful facilities for printing on the high-res screen, using the PRINT statement.

User defined characters can be used, allowing space invaders, lower-case etc., and text may be placed at any high-res screen position.

This manual contains a brief introductory section, describing the main features of the high-res display mode, and gives a few notes to get you started with the G007 commands. Most of the rest of the manual forms a reference guide to the facilities offered by the G007 module. The appendices at the end of the manual summarise the BASIC statements, and describe how the memory used by the G007 is organised.

Finally, a few sample programs are included, to demonstrate the capabilities of the G007 High-res graphics.


G007 Graphics

1.1.The High Resolution Display

The new high-resolution display mode of the G007 graphics module is in addition to the existing low-res mode. The ZX81 may switch freely between them without losing the contents of either. The high-res display requires 6.4 K of RAM, and is automatically set-up by the first hi-res command after applying power.

In hi-res mode, the screen has two parts, just as in lo-res. The top part is the actual hi-res display, and is always the full 256x192 pixels. The lower part is quite different, just a single text line which is actually the bottom of the lo-res screen. This line is displayed only while a program is not running, and is used to show reports, input data or commands entered at the keyboard.


G007 Graphics

1.2. Setting Up

While not powered, plug the G007 between the ZX81 and its external RAM pack. The latter is essential. The ZX printer may be used, and plugged between the ZX81 and the G007.

After applying power, all G007 commands can be used immediately, since all hi-res details are set-up automatically. If there is not enough memory, error 4 results.

Existing programs which do not use PLOT will LOAD and RUN without modification


G007 Graphics

1.3. Getting Started

Read the following to avoid confusion. All G007 commands can be used in programs or as commands, but the rest of this section assumes command mode.

To enter hi-res mode, simply enter SLOW 2 and note the ZX81 will now accept a number after SLOW. The report: 0/G007 shows the display has been set up. The following command sequence should give you an idea of what is now possible:

CLS 1
CLS 2
PLOT 2, 150, 60
PLOT 2, 30, 180
PLOT 74,60,60
PLOT 42,0,0
CLS 3

N.B. If the top of the screen bends to the right, you may correct this with POKE 8833,0.
You may have gathered that PLOT 2 draws lines, while PLOT 42 and PLOT 74 fill triangles. These commands, and many variations, are explained in the rest of the manual.

The high-res screen is not cleared between commands. It is not even cleared by RUN, so a CLS 1 or CLS 2 statement is usually needed at the start of every hi-res program. Programs cannot be listed on the hi-res screen, so they should be entered in lo-res mode. Entering programs in hi-res mode may have some odd but harmless effects.

SLOW returns to lo-res mode.

LIST will end with G007, which is actually the "number" of a program line containing the hi-res display file. This is ignored by the BASIC interpreter. This line cannot be listed, deleted or edited.

You may wish to try some of the example programs in the appendix.


G007 Graphics

2. The BASIC Statements

Most of these work by adding an optional extra parameter n to the existing BASIC graphic commands. Parameters can be any numeric expression, but they will be rounded to the nearest integer. All of these commands (except PLOT) will work in the original way if n is omitted.

PRINT only prints the hi-res display if hi-res mode is set. Other commands imply which display file is used, and hence it does not matter which mode is set.


G007 Graphics

2.1. Setting High or Low Resolution Mode

These two statement always set the relevant SLOW or FAST mode, and select the display mode. With n=0, or n omitted, low-resolution mode is selected. With n=1 to 6, high-res mode is selected, and n also determines the mode of operation for the PRINT statement.
The most commonly used hi-res mode is SLOW 2 (or FAST 2), in which PRINT will operate in the normal manner, albeit on the high-res screen. The other more advanced PRINT modes are explained later.


G007 Graphics

2.2. Clearing the Display

This is the only statement that can clear the high-res display, and should always be done at the start of a program. CLS N will also set the graphics origin to the bottom left of the screen.

CLS 0 clears the low res display
CLS 1 clears the high res display to black
CLS 2 clears the high res display to white
CLS 3 inverts the high res display
CLS 1 and CLS 2 also reset the PLOT position to 0,0 at the bottom left corner of the screen (see section 4 for an explanation of these terms).


G007 Graphics

2.3. Copying the Display file to the Printer

COPY copies the lo-res display to the ZX printer.
COPY 0 copies the lo-res display to the ZX printer.
COPY 1 copies the hi-res display to the ZX printer.

If the printer is not fitted, this command is ignored.


G007 Graphics

2.4. Point Plotting, Line Drawing and Triangle filling

PLOT n,x,y is the real work-horse of the G007, and behaves quite differently to the old PLOT. The parameter n can range from -1 to 130, giving 115 separate functions for the statement. The large number of options arises from having several modes for plotting individual pixels in lines, prints and triangles, and form the alternative means of specifying co-ordinates. The statement also incorporates such advanced features as different line types for drawing lines and for textured triangle filling.

The Old PLOT and UNPLOT Functions

The original functions of PLOT and UNPLOT have been retained, but only for use on the low-res display. PLOT x,y has been replaced by PLOT -1,x,y and UNPLOT x,y has been replaced by PLOT 0,x,y. The UNPLOT statement now does exactly the same as PLOT.

Co-ordinates

The co-ordinates x and y in the PLOT statement specify a position on the screen called the 'PLOT position'. More than one PLOT position is needed to draw a line or triangle, so the ZX81 remembers the PLOT positions from the previous two PLOT statements.

The PLOT statement can use either absolute or relative co-ordinates.
Absolute co-ordinates are x pixels to the right and y pixels up from the current graphics origin. Relative co-ordinates are x pixels to the right and y pixels up from the previous PLOT position. The hi-res screen is 256 pixels wide by 192 pixels high, and the graphics origin is normally located at the bottom left of the screen. Hence x has a range from 0 to 255, and y ranges from 0 to 191. The PLOT position may lie off the screen (except when filling triangles) and the co-ordinates in the PLOT statement may take any value, even negative ones. Note that it is very easy to run off the screen using relative co-ordinates.

Plotting Points

Individual pixels may be plotted in 3 basic modes: white, black, or inverted (also known as exclusive-or). These modes are also available in line drawing and triangle filling. PLOT may also be used to simply move the PLOT position without affecting any pixels. The effect of PLOT n,x,y for the following values of n are as follows:

9: | Plot a pixel in white, absolute co-ordinates
10: | Plot a pixel in black, absolute co-ordinates
11: | Invert a pixel, absolute co-ordinates
12: | Move to absolute co-ordinates
13-16: | As for 9-12, but using relative co-ordinates

Drawing Lines

Lines may be drawn in white, black or invert modes. the line is drawn from the previous plot position to the current plot position. The line is drawn even if one of the ends lies off the screen.

Using invert mode, the line may be drawn missing the last point, so that successive lines may chain together properly. Three other types of line are available, giving dotted and dashed lines. These are useful for identifying different lines when drawing graphs.

1: | Draw a line in white, absolute co-ordinates
2: | Draw a line in black, absolute co-ordinates
3: | Invert a line, absolute co-ordinates
4: | As 3, but omit last point.
5-8: | As 1-4, but use relative co-ordinates
33-40: | As 1 to 8, but with coarse dotted line
65-72: | As 1 to 8, but with fine dotted line
97-104: | As 1 to 8, but with chain dotted line

Note that broken line types are obtained by adding 32, 64 or 96 to the values of n for solid line types.

Filling Triangles

Triangle filling statements are similar to line drawing ones. The vertices of the triangle consist of the current and the previous two PLOT positions. Triangles are filled only if they lie completely in the screen area. This is to achieve a reasonable speed by using 8-bit arithmetic (instead of the usual 16-bits). If any vertices lie off-screen, an error B results.

Using invert mode, triangles may omit the last edge (between the current and previous PLOT positions) so that adjacent triangle can join up properly. There is also a textured triangle fill which makes shading, cross-hatching, etc. possible. The texture is user-definable, making this a very powerful facility.

41: | Fill triangle in white, absolute co-ordinates.
42: | Fill triangle in black, absolute co-ordinates.
43: | Fill triangle inverted, absolute co-ordinates.
44: | As 43, but omit last edge
45-48: | As 41 - 44, but with relative co-ordinates
73-80: | As 41 - 48, but fill with texture (not available in invert mode)

The default texture is a chequer-board pattern, giving a grey effect. The texture can be re-defined by poking the bytes at 8970 and 8971. The effect of these bytes is described in the following section on advanced PLOT facilities, but poking 8970 with 1 or 17 gives a coarse or fine diagonal shading.


G007 Graphics

2.5 Advanced Plot Facilities

Moving the Graphics Origin

As mentioned earlier, the graphics origin is normally located at the bottom left corner of the screen. It can be repositioned by the statement PLOT 130, x, y. The co-ordinates x and y give the new position of the graphics origin relative to the bottom left corner of the screen.

Filling In Shapes And Drawing Radial Lines

The PLOT statement has a special facility to make it easy to fill circles and other shapes using triangles. This allows pie charts etc. to be easily produced, and can also be used for drawing radial lines.

Normally, the current PLOT position of a statement will be move to the 'previous' PLOT position when it has completed. At the same time, the 'previous' plot position is moved to the 'twice previous' PLOT position. In effect, the PLOT position is moved into a queue and discarded after two more PLOT statements.

If 16 is added to the parameter n, the queue-shifting sequence is different. On completion of the current PLOT statement, it is saved as the 'twice previous' position, instead of the 'previous' position. This has the effect the the 'second' vertex of successive triangles will remain at the same point, or the starting point of successive lines will be fixed. This makes it simple to fill in shapes, such as circles, with triangles. The PLOT position is moved to a point within the shape (using PLOT 12,x,y) and then triangles are plotted by moving around the periphery of the shape (using PLOT 58,x,y for instance). Example program 1 demonstrates this facility, along with other forms of the PLOT statement.

Triangle Texturing

Triangle textures are defined by bytes 8970 and 8971. These are rotated by 1 and 3 bits to the right, respectively, for each new row of the triangle. They are then ORed together, and the resulting pattern is used to fill that row of the triangle.

More complex patterns can be obtained by POKEing these bytes. You can experiment to find effects.

8970 | 8971 | Pattern
85 | 0 | 'Grey'
0 | 17 | Left diagonal shading
17 | 0 | Right diagonal shading
1 | 0 | Right diagonal shading, coarse
17 | 17 | Cross hatching
0 | 1 | Fine dots

Further Line Types

The four standard line types are determined by the bytes 9012 to 9015 respectively. These can be redefined by POKEing, the line pattern being the inverse of the bit pattern.

Read Point Function

Any pixel may be read by moving the PLOT position to that pixel (using PLOT12,x,y) and then PEEKing 8983. If the number is zero, then the pixel is white, else a single bit of this byte will be set indicating the pixel is black.

Printing on the High Resolution Screen

The high resolution screen allows great scope for printing character. They may be placed anywhere on the screen, no longer limited to the normal 32x24 character grid. Also, new character shapes can be defined, and there is no liit to the number of characters that may be used in the same display. You can even superimpose graphics and characters.

The G007 provides six different PRINT modes when using the high-res screen. The PRINT mode set is given by the parameter n that was used in the statement SLOW n or FAST n that set the high res mode.

In all PRINT modes, text can be printed right down to the bottom of the high-res screen.

Note that the PRINT statement will only print string results. If you need to print a numeric result, you must first convert it to a string by preceding it with STR$.

The SCROLL statement is completely inoperative in high-res mode.

PRINT modes 1 and 2 work just as in low res mode, except that in mode 1 the character pixels are reversed (white foreground, black background).

PRINT modes 3 to 6 print at the position of the last PLOT statement. The PLOT position is moved after each character is printed. The first character will be printed with its top left corner at the PLOT position. If the PRINT statement ends in a semicolon, the PLOT position will be moved one pixel to the right of the top right corner of the last character printed, else it will go to the pixel below the bottom left corner of the first character printed. This ensures character printing places text in a similar manner as the low-res screen.

To use these modes, the PRINT statement is usually preceded by a statement to set the PLOT position (e.g. PLOT 12,x,y or PLOT 16,x,y). The PRINT AT and TAB work only in low-res, not high res mode. The

Mode | Effect
3 | Character foreground printed in white
4 | Character foreground printed in black
5 | Character background inverted
6 | Character foreground inverted

Note that characters may be superimposed, as only the foreground (or background in mode 5) is printed.

User Defined Characters

Because the high-res PRINT modes allow characters to be printed in normal and inverse video, the old ZX81 inverse video characters (CHR$ 128 to 191) are redundant and thus free for redefinition.

The G007 allows the 32 chaarcters from CHR$ 160 to 191 to be readily redfined, and reserves memory for this purpose. You can actually redefine all 128 characters, but you must allocate memory to do this - see Appendix B.

The character table containing the definitions of the 32 new characters is stored in 256 bytes of RAM starting at address 8448. This area is fully protected from NEW et.c Each character definiton consists of eight bytes, corresponding to eight rows of pixels in the character. The eight pixels in each row of the character correspond to the 8 bits (binary digits) in each byte, with the most significant bit at the left.

To redefine a character, you need to work out the eight bytes. This is best done by drawing the character first. The numbers should then be poked into eight consecutive memory location in the appropriate place in the character table. For character number K, the first location is at 8448+8*(160-K), where K is between 160 and 191 inclusive. Locations outside 8448 to 8703 must not be POKEd, or the computer may crash.

Example program 2 shows in detail how the step involved in defining a new character.

The redefined characters can only be printed in high-res mode of course. In low-res mode, the original character will be obtained. It is usually best to print the new characters using CHR$ K, to avoid confusion.

The inverse characters 'A' to 'Z' could be redefined as lower case. If so, then if the inverse video characters are used in PRINT statements when the program is typed in, these will appear in lower case when they are printed to the high-res screen.

If a user definable character is printed before it has been defined, a 'garbage' character will appear.


G007 Graphics

2.6. Miscellaneous

Saving High Resolution Pictures

The high-res display file is normally deleted automatically by the SAVE command, so that excesive time is not spent saving the 6K of display data. The high-res display (and program) can be saved by directly calling the saving routine, with RAND USR 764. FAST mode must be set to do this. The program will be saved without a name, so will have to be loaded using an empty string as a name, i.e. with LOAD "". Before loading the program, make sure a high-res display file is already set up (e.g. by typing CLS 2), otherwise the newly loaded display will be deleted by the first high-res statement.

Deleting The High Res Display File

This can be done by USR 11737, at any time. This could be done to aquire extra memory for example.

Correcting Television Picture Distortion

If you find the top of the TV picture bends slightly to the right,
you may be able to correct this with POKE 8833, 0.


G007 Summary of BASIC Statements

Summary of BASIC Statements

SLOW n and FAST n

SLOW or SLOW 0 sets low res mode
SLOW 1 to SLOW 6: Sets high-res mode, and additionally sets the high-res print mode as follows:
SLOW 1: Print as normal, but with inverse video characters.
SLOW 2: Print as normal
SLOW 3: Print at PLOT position, with text foreground in white.
SLOW 4: Print at PLOT position, with text foreground in black.
SLOW 5: Print at PLOT position, with text background inverted.
SLOW 6: Print at PLOT position, with text foreground inverted.

CLS n

CLS 0 clears the low res display
CLS 1 clears the high res display to black
CLS 2 clears the high res display to white
CLS 3 inverts the high res display
CLS 1 and CLS 2 also reset the PLOT position to 0,0 at the bottom left corner of the screen (see section 4 for an explanation of these terms).

COPY n

COPY copies the lo-res display to the ZX printer.
COPY 0 copies the lo-res display to the ZX printer.
COPY 1 copies the hi-res display to the ZX printer.

PLOT n,x,y

1: | Draw a line to absolute co-ordinates, in white.
2: | Draw a line to absolute co-ordinates, in black.
3: | Draw a line to absolute co-ordinates, inverting.
4: | As 3, but omit last point.
5-8: | As 1-4, but use relative co-ordinates
33-40: | As 1 to 8, but with coarse dotted line
65-72: | As 1 to 8, but with fine dotted line
97-104: | As 1 to 8, but with chain dotted line
9-16: | As 1-8, but plot a single pixel Note that PLOT 12 and PLOT 16 miss out the pixel, so simply move the PLOT position.
41-48: | As 1-8, but draw and fill triangle between the current and previous two PLOT positions.
73-80: | As 41 - 48, but fill with texture (not available in invert mode)


G007 Memory

The information here may be useful to machine code programmers. The layout of the high-res display file and the variables used by the high-res graphics routines are described.

The entry points of some of the most useful routines are given, together with the addresses of areas of RAM that are available for storing machine code.

The G007 modifies the ZX81 memory map in several ways. Firstly, the decoding disables all the 'aliases' of the 8K BASIC ROM, so that it only appears once, in the bottom 8K. The 2K G007 ROM appears at 10K to 12K. The ZX81's on-board RAM is re-mapped to the 2K block at 8K to 10K. It appears twice if it is a 1K device, and the G007 only accesses the lower 1K. If it is a 2K device, you are free to use the upper 1K for your own purposes. The G007 uses the lower 1K for graphics variables, including the table of user definable characters.

The Display File

This is stored in a BASIC program line at the end of the program area. It is set up when needed, and moves around in memory as BASIC lines are added or deleted. The ZX81 ignores this line, because the line number is immediately followed by two "NEWLINE" characters.

The display file is laid out straightforwardly. Each row of pixels is mapped onto 34 consecutive bytes in the display file. In each byte, the most significant pixel is the leftmost pixel. Note the display is actually 272 pixels across, but the last two bytes (16 pixels) are normally kept blank. This keeps the display central, and the graphics routines simple. Rows follow straight on from one another, from top to bottom of the display. There are no "NEWLINE" characters at the end of each row.


G007 Example Programs

Example 1. Drawing Circles.

This demonstrates several forms of plotting.

10 REM CIRCLES
20 LET D = 0.099
30 LET X = 90
40 LET Y = 0
50 CLS 2 set hi-res
60 SLOW 4
70 PLOT 130,127,95 move origin to centre
80 PLOT 12,X,Y initialise plot positions
90 PLOT 12,X,Y
100 FOR I = 0 TO 63
110 LET X = X + D * Y calculate next x, y
120 LET Y = Y - D * X
130 PLOT 10,X,Y+X*D/2 plots the point
140 NEXT I

This plots a circle of black pixels. Changing the plot number from 10 will draw and fill the circle. Before altering the program, return to low-res mode using the command SLOW.

Try changing the plot number from 10 to 2. This will draw the circle as a series of straight lines. Now change line 30 to LET X = 130 and notice how the lines are quite happily drawn to points off screen.

Change line 30 back to LET X = 90 then try the following plot numbers in line 130: 34, 66, 98 and 18. With other plot numbers in line 130, the program will fill the circle.

Try each of the following plot numbers: 58, 59 and 60. Note how the triangles are drawn with a common vertex. PLOT 59 and PLOT 60 both fill in inverting mode, but with PLOT 60 the last pixel in the triangle is missed out so that triangles join up but do not overlap.

If the PLOT number in line 130 is change to 90, the circle is filled with a texture.
Initially "grey", you can POKE 8970, 17 to get diagonal shading.
You can experiment with effects by POKEs to 8970 and 8971.
Finally, change the plot number to 12, and insert the following line:

125 PRINT CHR$(I)

This prints the character set round the circle. Note characters can be printed anywhere on the screen.

Example 2.

The following example shows how user defined characters can be generated. The first step is to draw the character on an 8x8 pixel grid, like so for this stick man:

128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | Byte
0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | = 28
0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | =28
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | =8
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | =127
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | =8
0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | =20
0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | =34
0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | =65

This program will POKE the 8 bytes defining the character into the correct locations. Simply RUN the program and enter the 8 bytes worked out above. The character will then be printed.

10 SLOW
20 LET C = 170
30 FOR I = 0 TO 7
40 PRINT AT 0,0; "GIVE ROW"; I+1
50 INPUT K
60 POKE(8488+8*(C-160)+I),K
70 NEXT I
80 CLS 2
90 SLOW 2
100 FOR I = 1 TO 255
110 PRINT CHR$ C;" ";
120 NEXT I

Example 3. Moire Pattern

This program generates a Moire pattern by using the invert mode for drawing lines. That pattern arises due to the steps in the drawn lines.

10 REM MOIRE PATTERN
20 CLS 2
30 SLOW 2
40 FOR I = 0 TO 255
50 PLOT 12,I,0
60 PLOT 3,255-I,191
70 NEXT I
80 FOR I = 0 TO 191
90 PLOT 12,0,I
100 PLOT 3,255,191-I
110 NEXT I

Type CLS 3 to reverse the video of this pattern.

Example 4

Examples 4 and 5 show the sort of 3-dimensional effects you can get with high-res graphics.

10 CLS 2
20 SLOW 2
30 PLOT 130,127,10
40 FOR P = 0 TO 12
50 LET X1 = P * 10
60 LET Y1 = P * 7
70 FOR Q = 0 TO 12
80 LET Z = -20 * SIN (P/2)*SIN (Q/2)
90 LET X2 = (P-Q) * 10
100 LET Y2 = Z + (P+Q)*7
110 PLOT 12,-X1,Y1
120 PLOT 12,-X2,Y2
130 PLOT 12, X1,Y1
140 PLOT 2, X2,Y2
150 LET X1 = X2
160 LET Y1 = Y2
170 NEXT Q
180 NEXT P

Example 5.

This program takes about 4 minutes to run, but the result is quite spectacular.

 10 CLS 1
 20 FAST 2
 30 PLOT 130,127, 100
 40 FOR X = 1 TO 120 STEP 2
 50 LET U = X * X
 60 LET L = INT ( 0.5 + SQR(14400-U)/4)
 70 LET M = -100
 80 FOR Y = -L TO L
 90 LET R = (U+Y*Y*16)/1000
100 LET Z = 2.5 * Y - 150/R * SIN R
110 IF Z < M THEN GOTO 150
120 LET M = Z
130 PLOT 9,X,Z
140 PLOT 9,-X,Z
150 NEXT Y
160 NEXT X


ZX81 BASIC Programming by Steven Vickers

Sinclair ZX81 BASIC Programming
by Steven Vickers
Second Edition 1981
Copyright 1980 Sinclair Research Limited

Converted to HTML by Robin Stuart
Please send any comments to rstuart@ukonline.co.uk

Front cover illustration by John Harris of Young Artists,
specially commissioned by Sinclair Research Limited.

Last updated 13th October 2001


Chapter 1: Setting up the ZX81

 Chapter 1 - Setting up the ZX81

Unpack the ZX81, you will have found

1. This manual.

2. The computer. This has three jack sockets (marked 9V DC IN, EAR & MIC), one aerial socket, & an exposed part of its circuit board where you can plug extra equipment. It has no switches - to turn it on you just connect it to the power supply.

3. A power supply.

This converts mains electricity into the form that the ZX81 uses. If by accident you plug it into the wrong socket in the computer you will do no damage. If you want to use your own power supply, it should give 9 volts DC at 700mA unregulated, & end in a 3.5mm jack plug with positive tip.

4. An aerial lead about 4 feet (120cm) long, which connects the computer to a television.

5. A pair of leads about a foot (30cm) long with 3.5mm jack plugs at both ends. These connect the computer to a tape recorder.

You will also need a television - the ZX81 can work without one, but you won't be able to see what it's doing! It must be a UHF television - if it's not built to receive BBC2 (in the UK) then it's no good.

Later you will need a cassette recorder. This is because when you turn a ZX81 off, all the information stored in it is permanently lost. The only way to keep it for later is by recording it on a cassette tape - you'll see how to do this in chapter 16. You can also buy tapes that other people have prepared, & so run their programs.

When you've got everything together (except the cassette recorder) connect them as shown on previous page.

If your television has two aerial sockets, marked UHF & VHF, then use the UHF one.

Turn the power on, & switch on the television. You now need to tune the television in. The ZX81 operates on channel 36 UHF, & when it is first plugged in and properly tuned it gives a picture like this:

When using the computer, you will probably want to turn the volume right down.

If your television has a continuously variable tuning control, then you just have to adjust it until you get this picture. Many televisions now have an individual push button for each station. Choose an unused one (e.g. ITV2), & tune it in.

If you get stuck with the computer, remember that you can always reset the computer & get back this picture by taking out the '9V DC IN' plug and putting it back again. This should be a last resort, because you lose all the information in the computer.

Note: This description of the television applies to Britain, where there is a UHF system using 625 lines at 50 frames per second. This will work in some other countries (for instance most Western European countries except France). The USA, uses VHF & 525 lines at 60 frames per second.

Now that you've set up the computer, you'll want to use it. If you already know the computer language BASIC, then read appendix C & use the rest of the manual only to clarify the obscure points.

If you're a novice, then the main part of the manual has been written for you. Don't ignore the exercises; many of them raise interesting points that are not dealt with in the text. Look through them, & do any that take your fancy, or that seem to cover ground you don't understand properly.

Whatever else you do, keep using the computer. If you have a question 'What does it do if I tell it such & such?' then the answer is easy: type it in & see. Whenever the manual tells you to type something in, always ask yourself, 'What could I type instead?' & try out your replies. The more of your own stuff you write, the better you will understand the ZX81. (This is called unprogrammed learning.) Regardless of what you type in, you cannot damage the computer.

Next: Chapter 2


Chapter 2: Telling the computer what to do

 Chapter 2 - Telling the computer what to do

Turn the computer on (by plugging it in) and get the blank screen with the write-on-black K, as in the picture in chapter 1. To make it do something, you have to type in a message that it understands; for instance the message

PRINT 2+2

tells it to work out the sum 2+2 and display the answer on the TV screen.

A message like this, telling the computer to do something straight away, is a command; this particular one is a PRINT command, but also a PRINT statement. Calling it a PRINT statement just specifies its form without referring to how the computer is going to use it. Thus every command takes the form of a statement, but so do some other things - program lines do, as we shall see in chapter 8.

To type in this command,

1. First type PRINT. But, although as you can see the keyboard has a key for each letter, you do not spell the word out P, R, I, N, T. As soon as you press P the whole word will come up on the screen, tohether with a space to make things look nice, and the screen will look like this:

The reason for this is that at the beginning of each command the computer is expecting a keyword - a word that specifies what kind of command it is. The keywords are written above the keys, and you will see that 'PRINT' appears above the P key, so that to get 'PRINT' you have to press P.

The computer lets you know that it expects a keyword by the [image] that you had to start off with. There is almost always some white-on-black (inverse video) letter, either [image] or [image] (or, we shall see later, [image] or [image]), called the cursor. The [image] means 'whatever key you press, I shall interpret it as a keyword'. As you saw, after you had pressed P for PRINT, the [image] changed to an [image].

This system of pressing just one key to get more than one symbol is used a lot on the ZX81. In the rest of this manual, words with their own keys are printed in BOLD TYPE.

You must remember that it is useless trying to spell these words out in full, because the computer just won't understand.

2. Now type 2. This should cause no problems. Again, you should see 2 appear on the screen, and the L move along one place.

Note also how much space is automatically put in between PRINT & 2 to make it look neat. This is done as much as possible, so that you hardly ever have to type a space. If you do type a space, it will appear on the screen, but it will not affect the meaning of the message at all.

3. Now type +. This is a shifted character (they are marked in red - the colour of SHIFT itself on its key - in the top right hand corner of each key), and to get '+' you must hold down the key [image] and while you are still doing that, press the key [image].

4. Now type 2 again. The screen will look like this:

5. Now - and you must always remember this - press NEWLINE, the key [image]. This means 'message complete', or 'all right, computer, lets see some action'. The computer will now read the message, work out what has to be done, and do it. In this case, the screen will change to

4 is the answer - but of course you do not need to buy a computer to work that out.

0/0 (Note how zero is written with a slash to distinguish it from capital O. This is fairly common in computing circles.) is the report in which the computer tells you how it got on. The first 0 means 'OK, no problems'. (In appendix B there is a list of the other report codes that can arise, for instance if something goes wrong.) The second 0 means 'the last thing I did was line 0'. You will see later - when you come to write programs - that a statement can be given a number & stored away for execution later: it is then a program line. Commands do not actually have numbers, but for the sake of reports the computer pretends that they are line 0.

You should imagine a report as hiding a [image] cursor - if you press P for PRINT now, the report will disappear and the screen will change to

The cursor can also be used for correcting mistakes: type ++2, to get

PRINT ++2

on the bottom line, Pretty incomprehensible stuff, and when you press NEWLINE you get

The [image] is the syntax error marker (the syntax is the grammar of the message, saying which are allowed and which are not), and shows that the computer got as far as 'PRINT', but after that decided that it was not a proper message.

What you want to do of course is rub out the first +, and replace it by - let us say - 3. First you have to move the cursor so that it is just to the right of the first +; there are two keys, [image] and [image] (shifted 5 and shifted 8), that move the cursor left and right. Holding SHIFT down, press the [image] key twice. This moves the cursor left two places to give you

PRINT + [image] +2

Now press the RUBOUT key (shifted 0), and you will get

PRINT [image] +2

RUBOUT rubs out the character (or keyword) immediately to the left of the cursor.

If you now press 3 this will insert a '3', again immediately to the left of the cursor, giving

PRINT 3 [image] +2

and pressing NEWLINE gives the answer (5).

The [image] key (shifted 8) works just like the [image] key, except that it moves the cursor right instead of left.

Summary

This chapter has covered how to type messages in for the ZX81, explaining the single keystroke system for words,

the [image] & [image] cursors,

reports,

the syntax error marker,

& how to correct mistakes using [image], [image] and RUBOUT.

The keyboard

Here is a picture of the keyboard.

Remember that to use SHIFT, you have to hold it down at the same time as you press another key. Do not confuse digit 0 with letter O.

Previous: Chapter 1 Next: Chapter 3


Chapter 3: A History lesson

 Chapter 3 - A History lesson

The messages that you type in are in a computer language called BASIC (standing for Beginners' All-purpose Symbolic Instruction Code). It actually takes the computer quite a lot of effort to break down the BASIC messages into its own rudimentary operations, but, after all, that's what it's paid to do. The BASIC messages contain enough English words (like PRINT) to make them fairly easy for an English speaking human to learn.

BASIC was designed at Dartmouth College in New Hampshire, USA in 1964, & since then it has come to be by far the most widely used computer language by beginners & hobbyists. This is largely because it is very well adapted for on-line use where the user types something in & the computer answers straight away. There are other languages - such as ALGOL (in fact a whole family of ALGOLs) & PASCAL - with a much neater structure & greater power than BASIC, but only a few - such as the relatively unknown APL & POP-2 - are as easy to use on-line. Some others that must be mentioned are FORTRAN, PL1 & COBOL.

Many personal computing magazines publish programs in BASIC, & are well worth looking through for ideas. You will almost certainly have to adapt them slightly because every computer that uses the BASIC language has its own dialect, different from all the others.

Previous: Chapter 2 Next: Chapter 4


Chapter 4: The Sinclair ZX81 as a calculator

 Chapter 4 - The Sinclair ZX81 as a calculator

Turn the computer on. You can now use it as a calculator, along the lines of chapter 2: type PRINT, then whatever it is that you want working out, & then NEWLINE. (We shan't usually bother to tell you to type NEWLINE.)

As you would hope, the ZX81 can not only add, but also subtract, multiply using a star * instead of the usual times sign - this is fairly common on computers) & divide (using / instead of [image]). Try these out.

+, -, * and / are operations, & the numbers they operate on are their operands.

The computer can also raise one number to the power of another using the operation ** (Shifted H. Do not type * - shifted B - twice): type

PRINT 2**3 (Remember the NEWLINE.)

& you will get the answer 8 (2 raised to the power 3, or 23, or 2 cubed)

The ZX81 will also work out combinations of the operations. For instance.

PRINT 20-2*3**2+4/2*3

gives the answer 8. It goes all round the houses to get this, because first it works out all the powers (**) in order from left to right, & then all the multiplications & divisions (* & /), again from left to right, & then the additions & subtractions (+ & -), yet again from left to right. Thus our example is worked out in the following stages:

We formalize this by giving each operation a priority, a number between 1 & 16. The operations with highest priority are evaluated first, & operations with equal priority are evaluated in order from left to right.
** | has priority 10
* and / | have priority 8
+ & - | have priority 6

When - is used to negate something, as when you write -1, then it has priority 9. (This is unary minus, as opposed to the binary minus in 3-1: a unary operation has one operand, while a binary operation has two. Note that on the ZX81 you cannot use + as a unary operation.)

This order is absolutely rigid, but you can circumvent it by using brackets: anything in brackets is evaluated first & then treated as a single number, so that

PRINT 3*2+2

gives the answer 6+2 = 6, but

PRINT 3*(2+2)

gives the answer 3*4 = 12.

A combination like this is called an expression - in this case, an arithmetic or numeric expression because the answer is a number. In general, whenever the computer is expecting a number from you, you can give it an expression instead and it will work out the answer.

You can write numbers with decimal points (use the full stop), & you can also use scientific notation - as is quite common on pocket calculators. In this, after an ordinary number (with or without a decimal point), you can write an exponent part consisting of the letter E, then maybe + or -, & then a number without a decimal point. The E here means '*10**' ('times ten to the power of'), so that
2.34E0 | = 2.34 * 10**0 = 2.34 |
2.34E3 | = 2.34 * 10**3 = 2340 |
2.34E-2 | = 2.34 * 10**-2 = 0.0234 | & so on.

(Try printing these out on the ZX81.)

The easiest way of thinking of this is to imagine the exponent part shifting the decimal point along to the right (for a positive exponent) or to the left (for a negative exponent).

You can also print more than one thing at once, separating them either with commas (,) or semicolons (; or shifted X). If you use a comma, then the next number will be displayed starting either at the left hand margin, or in the middle of the line in the 16th column. If you use a semicolon, then the next number will be displayed immediately following the last one.

Try

PRINT 1;2;3;4;5;6;7;8;9;10

&

PRINT 1,2,3,4,5,6,7,8,9,10

to see the differences. You can mix commas & semicolons within a single PRINT statement if you want.

Summary

Statements: PRINT, with commas & semicolons

Operations: +,-,*,/,**

Expressions, scientific notation

Exercises

1. Try

PRINT 2.34E0

PRINT 2.34E1

PRINT 2.34E2

and so on up to

PRINT 2.34E15

You will see that after a while the ZX81 also starts using scientific notation. This is because it never takes more than 14 spaces to write a number in. Similarly, try

PRINT 2.34E-1

PRINT 2.34E-2

& so on.

2. Try

PRINT 1,,2,,3,,,4,,,,5

A comma always moves you on a bit for the next number. Now try

PRINT 1;;2;;3;;;4;;;;5

Why is a string of semicolons no different from a single one?

3. PRINT gives only 8 significant digits. Try

PRINT 4294967295, 4294967295 -429E7

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

4. If you've got some log tables, then test out this rule:

Raising 10 to the power of a number is the same as taking the antilog of that number.

For instance, type

PRINT 10**0.3010

& look up the antilog of 0.3010. Why are the answers not exactly equal?

5. The ZX81 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 9 1/2 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 & 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, & the 1 to be added on in fact gets rounded up to 2. Here the numbers 5E9+1 & 5E9+2 appear to the computer to be equal.

The larger integer (whole number) that can be held completely accurately is 232-1 (4,294,967,295).

Previous: Chapter 3 Next: Chapter 5


Chapter 5: Functions

 Chapter 5 - Functions

Mathematically, a function is a rule for giving a number (the result) in exchange for another (the argument, or operand) & so is really a unary operation. The ZX81 has some of these built into it & their names are the words written under the keys. SQR, for instance, is the familiar square root function, and

PRINT SQR 9

gives 3, the square root of 9. (To get SQR, you first press the FUNCTION key - shifted NEWLINE. This changes the cursor to [image]. Now press the SQR key (H): SQR appears on the screen and the cursor changes back to [image]. The same method works for all the words that are written underneath the keys, almost all of which are function names.)

Try

PRINT SQR 2

You can test the accuracy of the answer by

PRINT SQR 2*SQR 2

which ought to give 2. Note that both SQRs are worked out before the *, and in fact all functions (except one - NOT) are worked out before the five operations +, -, *, / and **. Again, you can circumvent this rule using brackets -

PRINT SQR (2*2)

gives 2.

Here are some functions (there is a complete list in appendix C). If your maths is not up to understanding some of these, it does not matter - you will still be able to use the computer.

SGN | The sign function (sometimes called signum to avoid confusion with SIN). The result is -1, 0 or +1 according as the argument is negative, zero or positive.
ABS | The absolute value, or modulus. The result is the argument made positive, so that ABS -3.2 = ABS 3.2 = 3.2
SIN | *
COS | *
TAN | *
ASN | arcsin *
ACS | arccos *
ATN | arctan *
LN | natural logarithm (to base 2.718281828459045..., alias e)
EXP | exponential function
SQR | square root
INT | integer part. This always rounds down, so INT 3.9 = 3 & INT -3.9 = -4. (An integer is a whole number, possibly negative.)
PI | = 3.1415265358979..., the girth in cubits of a circle one cubit across. PI has no argument. (Only ten digits of this are actually stored in the computer, & only eight will be displayed.)
RND | Neither has RND an argument. It yields a random number between 0 (which value it can take) & 1 (which it cannot).

* The trigonometrical functions. These work in radians, not degrees.

Using the jargon of the last chapter, all these except PI & RND are unary operations with priority 11. (PI & RND are nullary operations, because they have no operands.)

The trigonometrical functions, & EXP, LN & SQR, are generally calculated to 8 digits accuracy.

RND & RAND: These are both on the same key, but whereas RND is a function, RAND is a keyword, like PRINT. RAND is used for controlling the randomness of RND.

RND is not truly random, but follows a fixed sequence of 65536 numbers that happen to be so jumbled up as to appear random (RND is pseudo-random). You can use RAND to start RND off at a definite place in this sequence by typing RAND, & then a number between 1 & 65535, & then NEWLINE. It's not so important to know where a given number starts RND off, as that the same number after RAND will always start RND off at the same place. For instance, type

RAND 1 (& NEWLINE)

& then

PRINT RND

& type both these in turn several times. (Remember to use FUNCTION to get RND.) The answer from RND will always be 0.0022735596, not a very random sequence.

RAND 0

(or you can miss out the 0) acts slightly differently: it judges where to start RND off by how long the television has been on, & this should be genuinely random.

Note: In some dialects of BASIC you must always enclose the arguments of a function on brackets. This is not the case in ZX81 8K BASIC.

Summary

Statement: RAND

Functions: SGN. ABS, SIN, COS, TAN, ASN, ACS, ATN, LN, EXP, SQR, INT, PI, RND

FUNCTION

Exercises

1. To get common logarithms (to base 10), which are what you'd look up in log tables, divide the natural logarithm by LN 10. For instance, to find log 2,

PRINT LN 2/LN 10

which gives the answer 0.30103.

Try doing multiplication & division using logs, using the ZX81 as a set of log tables in this way (for antilogs, see chapter 2, exercise 3). Check the answer using * and / - which are easier, quicker, more accurate, & much to be preferred.

2. EXP & LN are mutually inverse functions in the same sense that if you apply one & then the other, you get back to your original number. For instance,

LN EXP 2 = EXP LN 2 = 2

The same also holds for SIN & ASN, for COS & ACS, & for TAN & ATN. You can use this to test how accurately the computer works out these functions.

3. radians are 180°, so to convert from degrees to radians you divide by 180 & multiply by [image]: thus

PRINT TAN (45/180*PI)

gives tan 45° (1).

To get from radians to degrees, you divide by [image] & multiply by 180.

4. Try

PRINT RND

a few times to see how the answer varies. Can you detect any pattern? (Unlikely.)

How would you use RND & INT to get a random whole number between 1 & 6, to represent the throw of a die? (Answer: INT (RND *6) +1.)

5. Test this rule:

Suppose you choose a number between 1 & 872 & type

RAND & then your number (& NEWLINE)

Then the next value of RND will be

(75 * (your number + 1) - 1)/65536

6. (For mathematicians only.)

Let p be a [large] prime, & let a be a primitive root modulo p.

Then if bi is the residue of ai modulo p (1 [image] bi < p-1), the sequence

bi-1 / p - 1

is a cylindrical sequence of p-1 distinct numbers in the range 0 to 1 (excluding 1). By choosing a suitably, these can be made to look fairly random.

65537 is a Mersenne prime, 216-1. Use this & Gauss' law of quadratic reciprocity, to show that 75 is a primitive root modulo 65537.

The ZX81 uses p=65537 & a=75, & stores some bi-1 in memory. The function RND involves replacing bi-1 in memory by bi+1-1, & yielding the result (bi+1-1)/(p-1). RAND n (with 1 [image] n [image] 65535) makes bi equal to n+1.

7. INT always rounds down. To round to the nearest integer, add 0.5 first. For instance,
INT (2.9+0.5) = 3 | INT (2.4+0.5) = 2
INT (-2.9+0.5) = -3 | INT (-2.4+0.5) = -2

Compare these with the answers you get when you don't add 0.5

8. Try

PRINT PI, PI -3, PI -3.1, PI -3.14, PI -3.141

This shows how accurately the computer stores [image].

Previous: Chapter 4 Next: Chapter 6


Chapter 6: Variables

 Chapter 6 - Variables

'My pocket calculator,' you will be saying, 'can store a number away & remember it later. Can your ZX81 do that?'

Yes. In fact it can store away literally hundreds, using the LET statement. Suppose that eggs cost 58p a dozen, & you want to remember this. Type

LET EGGS=58 (& NEWLINE, of course)

Now first, the computer has reserved a place inside itself where you can store a number, & second, it has given this place the name 'EGGS' so you can refer to it later. This combination of storage space & name is called a variable. Third, it has stored the number 58 in the space: we say that it has assigned the value 58 to the variable [whose name is] EGGS. EGGS is a numeric variable, because its value is a number.

Do you want to know how much eggs cost? Type

PRINT EGGS

If you want to know the cost of half a dozen eggs, then type

PRINT EGGS/2

In fact, should you want to know the square of the cosine of the price of one egg, you can type

PRINT COS (EGGS/12)**2

'How very easy,' you must think, & you will be wondering what to do next, when in rushes your housekeeper saying 'Glory be, eggs have just gone up to 61p a dozen.'

Well. There is no time to lose. Type

LET EGGS=61

This does not reserve any extra storage space, but replaces the old value of 58 with 61. Now you can type

PRINT EGGS

confident in the expectation of getting the most up-to-date price available.

Now type

PRINT MILK

You will get a report 2/0, & looking up 2 in appendix B, you will see that it means 'variable not found' - the computer hasn't the faintest idea how much milk costs, because you haven't told it. Type

LET MILK=18.5

& all will be all right.

(Type

PRINT MILK

again.)

A variable need not be named after groceries - you 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.

For instance, these are allowed to be the names of variables:

TWO POUNDS OF APPLES BUT NOT GOLDEN DELICIOUS
RADIO 3
RADIO 33
X
K9P

but these are not:

3 BEARS (begins with a digit)
TALBOT? (? is not a letter or a digit)
. (inverse video characters not allowed)
FOTHERINGTON-THOMAS (- is not a letter or a digit)

Now type

CLEAR

&

PRINT EGGS

You will get report 2 (variable not found) again. The effect of CLEAR is to release all the storage space that had been reserved for variables - then every variable is as though it had never been defined. Turning the computer off & on will also do this - but then it doesn't remember anything at all when it is turned back on.

Expressions can contain the name of a variable anywhere they can have a number.

Note: In some versions of BASIC you are allowed to omit LET & just type in (say)

EGGS=58

This is not allowed on the ZX81. In any case, you'd find it rather difficult to type in.

Also in some versions, only the first two characters in a name are checked, so that RADIO 3 & RADIO 33 would count as the same name; & in some others a variable name must be a letter followed by a digit. Neither of these restrictions applies to the ZX81.

Yet again, in some versions of BASIC, if a variable has not yet appeared on the left-hand side of a LET statement then it is assumed to have a value 0. As you saw above with PRINT MILK, this is not so on the ZX81.

Summary

Variables

Statements: LET, CLEAR

Exercises

1. Why do variable names (that is to say, names of variables) have to begin with a letter?

2. If you're unfamiliar with raising to powers (**, shifted H) then do this exercise.

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) = A**B * A**C

You should not need much convincing that this works when B & 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**0 | = 1
A**(-B) | = 1/A**B
A**(1/B) | = the Bth root of A
&
A**(B*C) = (A**B)**C

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

A**-1 = 1/A
&
A**(1/2) = the square root of A

& maybe when you're familiar with these the rest will begin to make sense.

Experiment with all this by telling the computer to print various expressions containing **: e.g.

PRINT 3**(2+0),3**2*3**0

PRINT 4**-1,1/4

3. Type

LET E=EXP 1

Now E has the value 2.718281828..., the base of natural logarithms. Test the rule

EXP a number = E ** the number

for various numbers.

Previous: Chapter 5 Next: Chapter 7


Chapter 7: Strings

 Chapter 7 - Strings

One thing the ZX81 can do that pocket calculators cannot is deal with text. Type

PRINT "HI THERE. I AM YOUR ZX81." (" is shifted P.)

The chilling greeting inside the quotes is called a string (meaning a string of characters), & can contain any characters you like except the string quote,". (But you can use the so-called quote image, "" (shifted Q), & this will be printed as " by a PRINT statement.)

A common typing error with strings is to miss out one of the quotes - this will give you the [image] marker.

If you are printing numbers out, you can use these strings to explain what the numbers mean. For instance, type

LET EGGS=61

& then

PRINT "THE PRICE OF EGGS IS ";EGGS;" NEW PENCE A DOZEN."

(Don't worry about this going over the end of the line.)

This statement displays three things (PRINT items), namely the string "THE PRICE OF EGGS IS ", the number 61 (the value of the variable EGGS), & then the string " NEW PENCE A DOZEN." In fact you can PRINT any number of items you like, & any mixture of strings & numbers (or expressions), note how the spaces in a string are just as much part of it as the letters. They are not ignored even at the end.

There are lots of things you can do with strings.

1. You can assign them to variables. However, the name of the variable must be special to show that its value is a string & not a number: it must be a single letter followed by $ (shifted U). For instance, type

LET A$="DOUBLE GLOUCESTER"

&

PRINT A$

2. You can add them together. This is often called concatenation, meaning 'chaining together', & that is exactly what it does. Try

PRINT "GAMMO" + "N RASHERS"

You cannot subtract, multiply or divide strings, or raise them to powers.

3. You can apply some functions to strings to get numbers, & vice versa.

LEN |  | This is applied to a string, & the result is its length. For instance LEN "CHEESE" = 6.
VAL |  | This applied to a string, & the result is what that string gives when evaluated as an arithmetic expression. For instance (if A = 9), VAL "1/2+SQRA" = 3.5. If the string to which VAL is applied contains variables, then two rules must be obeyed.
 | (i) | If the VAL function is part of a larger expression, it must be the first item; e.g. 10 LET X = 7+VAL "Y" must be changed to 10 LET X = VAL "Y" +7.
 | (ii) | VAL can only appear in the first coordinate of a PRINT AT, PLOT or UNPLOT statement (see Chapter 17 and 18) e.g. 10 PLOT 5, VAL "X" must be changed to 10 LET Y = VAL "X" 15 PLOT 5, Y

STR$ This is applied to a number, & the result is what would appear on the screen if the number were displayed by a PRINT statement. For instance STR$ 3.5 = "3.5".

4. Just as for numbers, you can combine these to make string expressions, like

VAL (STR$ LEN "123456"+"-4")

which is evaluated as

Summary

Strings

Operation: + (for strings)

Functions: LEN, VAL, STR$

Exercises

1. Type

LET A$="2+2"

& then

PRINT A$;" = ",VAL A$

Try changing A$ to more complicated things & doing the same, e.g.

LET A$="ATN 1*4"

(The answer here should be [image].)

2. The string "" with no characters is called the empty or null string. It is only string whose length is 0. Remember that spaces are significant and an empty string is not the same as one containing spaces.

Do not confuse it with the quote image, "" (a single token, shifted Q). This is a special device to get over the fact that you cannot write an ordinary string quote in the middle of a string (why not?). When the quote image appears in a string that has its quotes at the end (for instance in the listing of a program), it shows up as two quote symbols, to distinguish it from the ordinary quote; but when it is displayed by a PRINT statement, it is as just one quote symbol.

Try

PRINT "X";"";"X",""""."""";"";""""

3. If you enjoy humiliating computers, type

PRINT "2+2 = ";2+1

Previous: Chapter 6 Next: Chapter 8


Chapter 8: Computer programming

 Chapter 8 - Computer programming

And now at last you shall write a computer program. Turn the computer off & on, just to make sure that it is clear. Now type

10 LET BUTTER=75 (& NEWLINE)

& the screen will look like this:

This is different from what happened with EGGS in chapter 6; if you type

PRINT BUTTER

you will see (from the report 2) that the variable BUTTER has not been set up. (Press NEWLINE again & the screen should go back to looking like the picture.)

Because the LET statement had a number, 10, in front of it, the computer did not execute it straight away, but saved it for later. 10 is its line number, & is used to refer to it rather in the same way that names are used to refer to variables. A set of these stored statements is called a

program. Now type

20 PRINT BUTTER

& the screen should look like this:

This is a listing of your program. To have the program carried out (or executed or run), type

RUN (don't forget the NEWLINE)

& the answer 75 will appear in the top left-hand corner of the screen. At the bottom left-hand corner you will see the report 0/20. 0, as you know, means 'OK, no problems', & 20 is the number of the line where it finished. Press NEWLINE, & the listing will come back.

Note that the statements were executed in the order of their line numbers.

Now suppose you suddenly remember that you also need to record the price of yeast. Type

15 LET YEAST=40

& in it goes. This would have been much harder if the first two lines had been numbered 1 & 2 instead of 10 & 20 (line numbers must be whole numbers between 1 & 9999), so that is why, when first typing in a program, it is good practice to leave gaps in the line numbers.

Now you need to change line 20 to

20 PRINT BUTTER, YEAST

You could type out the replacement in full, but there is a way to use what is there already. You see that little [image] by line 15? This is the program cursor, & the line it points to is the current line. Press the [image] key (shifted 6), & it will move down to line 20. ( [image] moves it up again.) Now press the EDIT key (shifted 1), & a copy of line 20 will be displayed at the bottom of the screen. Press the [image] key 7 times so that the [image] cursor moves to the end of the line, & then type

,YEAST (without NEWLINE)

The line at the bottom should now read

20 PRINT BUTTER, YEAST

Press NEWLINE & it will replace the old line 20. The screen will now look like this:

RUN this program & both prices will be displayed.

(Here is a useful trick involving EDIT, to use when you want to clear the bottom part of the screen altogether. Press EDIT, & the current line will be brought down from the program, replacing what you wanted deleting. If you now press NEWLINE, the line will be put back in the program, making no difference to it, & the bottom part of the screen will be cleared leaving just the cursor.)

Now type - in a fit of absent-mindedness -

12 LET YEAST=40

This will go up into the program & you will realise your mistake. To delete this unnecessary line, type

12 (with NEWLINE, of course)

You will notice with surprise that the program cursor has gone. You should imagine it as being hidden in between lines 10 & 15, so if you press [image] it will move up to line 10, while if you press [image] it will move down to line 15.

Last, type

LIST 15

You will now see on the screen

15 [image] LET YEAST=40

20 PRINT BUTTER, YEAST

Line 10 has vanished from the screen, but it is still in your program - which you can prove by pressing NEWLINE again. The only effect of LIST 15 are to produce a listing that starts at line 15, & to put the program cursor at line 15.

LIST

on its own makes the listing start at the beginning of the program.

Summary

Programs

Editing programs using [image], [image] & EDIT.

Statements: RUN, LIST

Exercises

1. Modify the program so that it displays not only the two prices, but also messages to ahow which is which.

2. Use the EDIT key to change the price of butter.

3. Run the program & then type

PRINT BUTTER, YEAST

The variables are still there, even though the program has finished.

4. Type

12 (& NEWLINE)

Again, the program cursor will be hidden between lines 10 & 15. Now press EDIT, & line 15 will come down: when the program cursor is hidden between two lines, EDIT brings down the second one. Type NEWLINE to clear the bottom part of the screen.

Now type

30

This time, the program cursor is hidden after the end of the program; & if you press EDIT, then line 20 will be brought down.

5. Put a LIST statement in the program so that when you run it, it lists itself.

Previous: Chapter 7 Next: Chapter 9


Chapter 9: More computer programming

 Chapter 9 - More computer programming

Type

NEW

This will erase any old programs & variables in the ZX81. (This is rather like CLEAR, but CLEAR only erases the variables.) Now carefully type in this program:

10 REM THIS PROGRAM EXTRACTS SQUARE ROOTS

20 INPUT A

30 PRINT A,SQR A

40 GOTO 20

(You will need to type in most of the spaces yourself in line 10).

Now run it. Apparently the screen goes blank, & nothing happens, but look at the cursor in the bottom left-hand corner: where you might have expected a [image] there is instead an [image] - the machine has gone into input mode. This is the effect of the INPUT statement in line 20. The machine is waiting for you to type in a number (or even an expression), & it won't carry on until you have. After that, it will have the effect of

20 LET A=... whatever you typed

Just a minute though, what happened to line 10? It looks as though the computer has completely ignored it. Well, it has. REM in line 10 stands for remark, or reminder, & there solely to remind you of what the program does. A REM statement consists of REM followed by anything you like, & the computer will ignore it.

All right, so we're in input mode for line 20. Type some number, 4, say, & then NEWLINE. The 4 & its square root appear on the screen, & you might think that was that. But, no - it seems to want another number. This is because of line 40, GOTO 20, which means exactly what it says. Instead of running out of program & stopping, the computer jumps back to line 20 & starts again. So, type another number (2, say; at any rate you had better make it positive).

After a few more of these you might be wondering if the machine will ever get bored with this game; it won't. Next time in its instability it asks for another number, type STOP (shifted A) instead; it will take the hint. The computer reports back with report D/20 - look up D in the list of reports (appendix B). 20 is the line where it was waiting for some input when you stopped it.

Have you suddenly remembered some more numbers that you wanted the square root of? Then type

CONT

(short for CONTINUE) & the computer will clear the screen & ask you for another number.

For CONT, the computer remembers the line number in the last report that it sent you that had a code other than 0, & jumps to that line. Since the last report was D/20 (& D is not 0), in our case CONT is identical to GOTO 20.

Now type in numbers until the screen starts getting full. When it is full, the computer will stop with the report 5/30. 5 means 'screen full', & 30 is the number of the PRINT statement it was trying to execute when it discovered there was no room. Again,

CONT

will clear the screen & carry on - this time, CONT means GOTO 30.

Note that the screen is cleared not because this is a CONT statement, but because it is a command. All commands (except COPY, which appears in chapter 20) clear the screen first.

When you're tired of this, stop the program using STOP & get the listing by pressing NEWLINE.

Look at the PRINT statement on line 30. Each time the pair of numbers A & SQR A is printed, it is on a new line, & this is because the PRINT statement does not end with a comma or semicolon. Whenever this is the case, then the next PRINT statement starts printing on a new line. (Thus to put in a blank line, use a PRINT statement in which there is nothing to be printed - just PRINT on its own.)

However, a PRINT statement can end in a comma or semicolon, & then the next PRINT statement carries on printing as though the two had been one long statement.

For instance, with commas, replace the 30 by

30 PRINT A,

& run the program to see how successive PRINT statements can print on the same line but spread out in two columns.

With semicolons, on the other hand, with

30 PRINT A;

everything is jammed together.

Try also

30 PRINT A

Now type in these extra lines.

100 REM THIS PROGRAM MEASURES STRINGS

110 INPUT A$

120 PRINT A$,LEN A$

130 GOTO 110

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

RUN 100

This program inputs a string instead of a number, & prints it & its length. Type

CAT (& NEWLINE, as usual)

Because the computer is expecting a string, it prints out two string quotes - this is a reminder to you, & it usually saves you some typing as well. But you don't have to restrict yourself to string constants (explicit string with opening & closing quotes & all their characters in between); the computer will evaluate any string expression, such as one with string variables. In this case you might have to rub out the quotes that the computer has displayed. Try this. Rub them out (with [image] & RUBOUT twice), & type

A$

Since A$ still has the value "CAT", the answer is CAT 3 again.

Now input

A$

again, but this time without rubbing out the string quotes. Now A$ has the value "A$", & the answer is 2.

If you want to use STOP for string input, you must first move the cursor back to the beginning of the line, using [image].

Now look back at the RUN 100 we had earlier on. That jumps to line 100, so couldn't we have said GOTO 100 instead? In this case, it so happens that the answer is yes, byt there is a difference. RUN 100 first of all clears the variables (like CLEAR in chapter 6), & after that works just like GOTO 100. GOTO 100 doesn't clear anything. There may well be occasions when you want to run a program without clearing any variables. Here GOTO is necessary & RUN could be disastrous, so it is best to get into the habit of automatically typing RUN to run a program.

Another difference is that you can type RUN without a line number, & it starts off at the first line in the program. GOTO must always have a line number.

Both these programs stopped because you typed STOP in the INPUT line; but sometimes - by mistake - you write a program that you can't top & won't stop itself. Type

200 GOTO 200

RUN 200

This looks all set to go on for ever unless you pull the plug out; but there is a less drastic remedy. Press the SPACE key, which has 'BREAK' written above it. The program will stop, saying D/200.

At the end of every program line, the computer looks to see if this key is pressed; & if it is, then it stops. The BREAK key can also be used when you are in the middle of using the tape recorder or the printer.

You have now seen the statements PRINT, LET, INPUT, RUN, LIST, GOTO, CONT, CLEAR, NEW & REM, & most of them can be used either as commands or as program lines - this is true of almost all statements in BASIC. The only real exception is INPUT, which cannot be used as a command (you get report 8 if you try; the reason is that the same area inside the computer is used for both commands & for input data, & for an INPUT command there would be a muddle). RUN, LIST, CONT, CLEAR & NEW are not usually much use in a program, but they can be used.

Summary

Statements: GOTO, CONT, INPUT, NEW, REM, PRINT

STOP in input data

BREAK

Exercises

1. In the square root program, try replacing line 40 by GOTO 5, GOTO 10 or GOTO 15 - it should make no perceptible difference to the running of the program. If the line number in a GOTO statement refers to a non-existent line, then the jump is to the next line after. The same goes for RUN; in fact RUN on its own actually means RUN 0.

2. Run the string length program, & when it asks you for input type

X$ (after removing the quotes)

Of course, X$ is an undefined variable & you get report 2/110.

If you now type

LET X$="SOMETHING DEFINITE"

(which has its own report of 0/0) &

CONT

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

The point about this exercise is that CONT has the effect of GOTO 110. It disregards the report 0/0 because that had code 0, & takes its line number from the previous report, 2/110. This is intended to be useful. If a program stops over some error then you can do all sorts of things to fix it, & CONT will start work afterwards.

3. Try this program:

10 INPUT A$

20 PRINT A$;" = ";VAL A$

30 GOTO 10

(c.f. chapter 7, exercise 1).

Put in extra print statements so that the computer announces what it is going to do, & asks for the input string with extravagant politeness.

4. Write a program to input prices & print out the VAT due (at 15%). Again, put in PRINT statements so that it tells you what it's doing. Modify the program so that you can also input the VAT rate (to allow for zero rating or future budgets).

5. Write a program to print a running total of numbers you input. (Suggestion: have two variables TOTAL - set to 0 to begin with - & ITEM. Input ITEM, add it to TOTAL, print them both, & go round again.)

6. The automatic listings (the ones that are not the result of a LIST statement) may well have you puzzled. If you type in a program with 50 lines, all REM statements,

1 REM

2 REM

3 REM

: :

: :

49 REM

50 REM

then you will be able to experiment.

The first thing to remember is that the current line (with [image]) will always appear on the screen, & preferably near the middle.

Type

LIST (& NEWLINE, of course)

& then press NEWLINE again. You should get lines 1 to 22 on the screen. Now type

23 REM

& you should get lines 2 to 23 on the screen; type

28 REM

& you get lines 27 to 48. (In both cases, by typing in a new line you have moved the program cursor so that a new listing has to be made.)

Does this look a little arbitrary to you? It is actually trying to give you exactly what you want, although, humans being unpredictable creatures, it doesn't always guess right.

The computer keeps a record not only of the current line, the one that has to appear on the screen, but also the top line on the screen. When it tries to make a listing, the first thing it does is compare the top line with the current line.

If the top line comes after, then there is no point in starting there, so it uses the current line for a new top line & makes its listing.

Otherwise, it first tries to make the listing starting at the top line. If the current line gets on the screen then all is well; if the current line is only just off the bottom of the screen then it moves the top line down one & tries again; & if the current line is way off the bottom of the screen then it changes the top line to be the line before the current line.

Experiment with moving the current line about by typing

line number REM

LIST moves the cursor line but not the top line, so subsequent listings might be different. For instance, type

LIST

to get the LIST listing, & then press NEWLINE again to make line 0 the top line. You should have lines 1 to 22 on the screen. Type

LIST 22

which gives you lines 22 to 43; when you press NEWLINE again, you get back lines 1 to 22. This tends to be more useful for short programs than for long ones.

7. What would CONT, CLEAR & NEW do in a program? Can you think of any uses at all for this?

Previous: Chapter 8 Next: Chapter 10


Chapter 10: If...

 Chapter 10 - If...

All the program we've seen so far have been pretty predictable - they went straight through doing all the instructions, & then maybe went back to the beginning again. This is not all that useful. In practice the computer would be expected to make decisions & act accordingly; it does this using the IF statement.

Clear the computer (using NEW), & type in & run this terribly amusing little program:

10 PRINT "SHALL I TELL YOU A JOKE?"

20 INPUT A$

30 IF A$="GET LOST" THEN GOTO 200

40 PRINT "HOW MANY LEGS HAS A HORSE GOT?"

50 INPUT LEGS

60 IF LEGS=6 THEN GOTO 100

70 PRINT "NO, 6, FORE LEGS IN FRONT","AND TWO BEHIND."

80 STOP

100 PRINT "YES",,"SHALL I TELL YOU IT AGAIN?"

110 GOTO 20

200 PRINT "ALL RIGHT, THEN, I WONT."

Before we discuss the IF statement, you should first look at the STOP statement in line 80: a STOP statement stops the execution of the program, giving report 9.

Now as you can see, an IF statement takes the form

IF condition THEN statement

The statements here are GOTO statements, but they could be anything at all, even more IF statements. The condition is something that is going to be worked out as either true or false; if it comes out as true then the statement after THEN is executed, but otherwise it is skipped over.

The most useful conditions compare two numbers or two strings: they can test whether two numbers are equal, or whether one is bigger than the other; & can test whether two strings are equal, or whether one comes before the other in alphabetical order. They use the relations =, <, >, <=, >= and <>.

=, which we have used twice in the program (once for numbers & once for strings) means 'equals'. It is not the same as the = in a LET statement.

< means 'is less than', so that

1<2

-2<-1

& -3<1

are all true, but

1<0

& 0<-2

are false.

To see how this works, let us write a program to input numbers & display the biggest so far.

10 PRINT "NUMBER","BIGGEST SO FAR"

20 INPUT A

30 LET BIGGEST=A

40 PRINT A,BIGGEST

50 INPUT A

60 IF BIGGEST<A THEN LET BIGGEST=A

70 GOTO 40

The crucial part is line 60, which updates BIGGEST if its old value was smaller than the new input number A.

> (shifted M) means 'is greater than', & is just like < but the other way round. You can remember which is which, because the thin end points to the number that is supposed to be smaller.

<= (shifted R - do not type it as < followed by =) means 'is less than or equal to', so that it is like < except that it holds even if the two numbers are equal: this 2<=2 holds, but 2<2 does not.

>= (shifted Y) means 'is greater than or equal to' & is similarly like >.

<> (shifted T) means 'is not equal to' the opposite in meaning to =.

All six of these relational operations have priority 5.

Mathematicians usually write <=, >= and <> as [image], [image] and [image]. They also write things like '2<3<4' to mean '2<3 and 3<4', but this is not possible in BASIC.

These relations can be combined using the logical operations AND, OR & NOT.

one relation AND another relation

is true whenever both relations are true.

one relation OR another

is true whenever one of the two relations is true (or both are).

NOT relation

is true whenever the relation is false and is false whenever the relation is true.

Logical expressions can be made with relations & AND, OR & NOT just as numerical expressions can be made with numbers & +, - and so on; you can even put in brackets if necessary. NOT has priority 4, AND 3 & OR 2.

Since (unlike other functions) NOT has fairly low priority, its argument does not need brackets unless it contains AND or OR; so NOT A = B means NOT (A = B) (which is the same as A <> B).

To illustrate this, clear the computer & try this program.

10 INPUT F$

20 INPUT AGE

30 IF F$="X" AND AGE<18 OR F$="AA" AND AGE<14 THEN PRINT "DONT";

40 PRINT "LET IN."

50 GOTO 10

Here F$ is supposed to be the category if a film - X for 18 years old & over, AA for 14 & over, & A or U for anyone, & the program works out whether a person of a given age is to be allowed to see the film.

Lastly, we can compare not only numbers, but also strings. We have seen '=' used in 'F$="X"', & you can even use the other five, < & so on.

So what does 'less than' mean for strings? One thing it does not mean is 'shorter than', so don't make that mistake. We make the definition that one string is less than another if it comes first in alphabetical order: thus
"SMITH" | < "SMYTHE"
"SMYTHE" | > "SMITH"
"BLOGGS" | < "BLOGGS-BLACKBERRY"
"BILLION" | < "MILLION"
"TCHAIKOVSKY" | < "WAGNER"
"DOLLAR" | < "POUND"

all hold. <= means 'is less than or equal to', & so on, just as for numbers.

Note: In some versions of BASIC - but not on the ZX81 -, the IF statement can have the form

IF condition THEN line number

This means the same as

IF condition THEN GOTO line number

Summary

Statements: IF, STOP

Operations: =, <, >, <=, >=, <>, AND, OR

Function: NOT

Exercises

1. <> and = are opposites in the sense that NOT A=B is the same as A<>B

&

NOT A<>B is the same as A=B

Persuade yourself that >= is opposite to <, and <= is opposite to > so that you can always get rid of NOT from in front of a relation by changing the relation to its opposite.

Also,

NOT (a first logical expression AND a second)

is the same as

NOT (the first) OR NOT (the second),

&

NOT (a first logical expression OR a second)

is the same as

NOT (the first) AND NOT (the second).

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

2. BASIC can sometimes work along different lines from English. Consider, for instance, the English clause 'if A doesn't equal B or C'. How would you write this in BASIC? [The answer is not

'IF A<>B OR C' nor 'IF A<>B OR A<>C']

Don't worry if you don't understand exercises 3, 4 & 5, the points covered in them are rather refined.

3. (For experts.)

Try

PRINT 1=2,1<>2

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.

(i) =, <, >, <=, >=, and <> are all number valued binary operations, with priority 5. The result is 1 (for true) if the relation holds, & 0 (for false) if it does not.

(ii) In

IF condition THEN statement

the condition can actually be any numeric expression. If its value is 0, then it counts as false, & any other value counts as true. This the IF statement means exactly the same as

IF condition <>0 THEN statement

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

X AND Y has the value | { X if Y is non-zero (counting as true) { 0 if Y is zero (counting as false)
X OR Y has the value | { 1 if Y is non-zero { X if Y is zero
NOT X has the value | { 0 if X is non-zero { 1 if X is zero

Read through the chapter again, in the light of this revelation, making sure that it all works.

In the expressions X AND Y, X OR Y & NOT X, X and Y will each usually take the value 0 or 1, for false or true. Work out the ten different combinations & check that they do what you expect AND, OR & NOT to do.

4. Try this program:

10 INPUT A

20 INPUT B

30 PRINT (A AND A>=B)+(B AND A<B)

40 GOTO 10

Each time it prints the larger of the two numbers A & B - why?

Convince yourself that you can think of

X AND Y

as meaning

'X if Y (else the result is 0)'

& of

X OR Y

as meaning

'X unless Y (in which case the result is 1)'

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

LET RETAIL PRICE=PRICE LESS VAT*(1.15 OR V$="ZERO RATED")

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

5. You can also make string valued conditional expressions, but only using AND.

X$ AND Y$ has the value { X$ if Y is non-zero
{ if Y is zero

so it means 'X$ if Y (else the empty string)'.

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

10 INPUT A$

20 INPUT B$

30 IF A$<=B$ THEN GOTO 70

40 LET C$=A$

50 LET A$=B$

60 LET B$=C$

70 PRINT A$;" ";("<" AND A$<B$)+("=" AND A$=B$);" ";B$

80 GOTO 10

6. Try this program:

10 PRINT "X"

20 STOP

30 PRINT "Y"

When you run it, it will display "X" & stop with report 9/20. Now type

CONT

You might expect this to behave like 'GOTO 20', so that the computer would just stop again without displaying "Y"; but this would not be very useful, so things are arranged so that for reports with code (STOP statement executed), the line number is increased by 1 for a CONT statement. This in our example, 'CONT' behaves like 'GOTO 21' (which, since there are no lines between 20 & 30, behaves like 'GOTO 30').

7. Many versions of BASIC (but not the ZX81 BASIC) have an ON statement, which takes the form

ON numeric expression GOTO line number, line number,...,line number In this the numeric expression is evaluated; suppose its value is n then the effect is that of.

GOTO the nth line number

For instance

ON A GOTO 100, 200, 300, 400, 500

Here, if A has the value 2, then 'GOTO 200' is executed. In ZX81 BASIC this can be replaced by

GOTO 100*A

In case the line numbers don't go up neatly by hundreds like this, work out how you could use

GOTO a conditional expression

instead.

Previous: Chapter 9 Next: Chapter 11


Chapter 11: The character set

 Chapter 11 - The character set

The letters, digits, punctuation marks & so on that can appear in strings are called characters, & they make up the alphabet, or character set, that the ZX81 uses. Most of these characters are single symbols, but there are sone more, called tokens, that represent whole words, such as PRINT, STOP, **, & so on.

There are 256 characters altogether, & each one has a code between 0 & 255. There is a complete list of them in appendix A. To convert between codes & characters, there are two functions, CODE & CHR$.

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

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

This program prints out the entire character set.

10 LET A=0

20 PRINT CHR$ A;

30 LET A=A+1

40 IF A<256 THEN GOTO 20

At the top you can see the symbols ", £, $ and so on up to Z, which all appear on the keyboard & can be typed in when you have the [image] cursor. Further on, you can see the same characters, but in white on black (inverse video); these are also obtainable from the keyboard. If you press GRAPHICS (shifted 9) then the cursor will come up as [image]: this means graphics mode. If you type in a symbol it will appear in its inverse video form, & this will go on until you press GRAPHICS again or NEWLINE. RUBOUT will have its usual meaning. Be careful not to lose the cursor [image] amongst all the inverse video characters you've just typed in.

When you've experimented a bit, you should still have the character set at the top; if not, then run the program again. Right at the beginning are space & ten patterns of black, white & grey blobs; further on there are eleven more. These are called the graphics symbols & are used for drawing pictures. You can enter these from the keyboard, using graphics mode (except for space, which is an ordinary symbol using the [image] cursor; the black square is inverse space). You use the 20 keys that have graphics symbols written on them. For instance, suppose you want the symbol [image], which is on the T key. Press GRAPHICS to get the [image] cursor, & then press shifted T. From the previous description of the graphics mode, you would expect to get an inverse video symbol; but shifted T is normally <>, a token, & tokens have no inverses: so you get the graphics symbol [image] instead.

Here are the 22 graphics symbols.

Now look at the character set again. The tokens stand out quite clearly in two blocks: a small group of three (RND, INKEY$ & PI) after Z, & a larger group (starting with the quote image after [image], & carrying on from AT up to COPY).

The rest of the characters all seem to be ? This is actually just the way they get printed - the real question mark is between : and (. Of the spurious ones, some are for control characters like [image], EDIT & NEWLINE, & the rest are for characters that have no special meaning for the ZX81 at all.

Summary

Functions: CODE, CHR$

Exercises

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

2. Imagine the space for one symbol divided into two horizontally: . Then if each half can be black, white or grey, there are 3*3 = 9 possibilities. Find them all.

3. The characters in exercise 2 are designed to be used in horizontal bar charts, using two colours, grey & black. Write a program that inputs two numbers A & B (both between 0 & 32), & draws a bar chart for them:

You will need to start off printing " [image] ", & change to either " [image] " or " [image] ", according as A is more or less than B.

What does your program do if A & B are not whole numbers? Or if thet are not in the range 0 to 32? a good - 'user friendly' is the fashionable term - program will do something sensible & useful.

4. There are two different all grey characters on the keyboard, on A & H. If you look at them very close up, you will see that the one on H is like a miniature chessboard, while the one on A is like a sideways chessboard. Print them next to each other, & you will see that they don't join up properly. The one on A is used to join up neatly with [image] & [image] (on S & D), while the one on H joins up neatly with [image] & [image] (on F & G).

5. Run this program:

10 INPUT A

20 PRINT CHR$A;

30 GOTO 10

If you experiment with it, you will find that for CHR$, A is rounded to the nearest whole number; & if A is not in the range 0 to 255 then the program stops with report B.

6. Using the codes for the characters, we can extend the concept of 'alphabetical 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, these strings are in ZX81 alphabetical order.

" ZACHARY"

" [image] "

"(ASIDE)"

"123 TAXI SERVICE"

"AASVOGEL"

"AA [image] "

"ZACHARY"

" [image] RDVARK"

Here is the rule. First, compare the first characters in the two strings. If these are different, then one of them has its code less than the other, & the string of which it is the first character is the earlier (lesser) of the two strings. If they are the same, then go on to compare the next 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.

Type in again the program in exercise 4 of chapter 10 (the one that inputs two strings & prints them in order), & use it to experiment.

7. This program prints a screenful of random black & white graphics characters:

10 LET A=INT (16*RND)

20 IF A>=8 THEN LET A=A+120

30 PRINT CHR$ A;

40 GOTO 10

(How does it work?)

Previous: Chapter 10 Next: Chapter 12


Chapter 12: Looping

 Chapter 12 - Looping

Suppose you want to input five numbers & add them together. One way (don't type this in unless you're feeling dutiful) is to write

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 ten numbers would be, & a hundred would be just impossible.

Much better is to set up a variable to count up to five & 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 = 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 GOTO 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 counting is so useful that there are two special statements to make it easier: the FOR statement, & the NEXT statement. 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 = 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, 60 & 70. TO is shifted 4.)

Note that we have changed COUNT to C. The counting variable - or control variable - of a FOR-NEXT loop must have a single letter for its name.

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

An extra subtlety to this is that the control variable does not have to go up by 1 each time: you can change this 1 to anything else you like by using a STEP part in the FOR statement. The most general form for a FOR statement is

FOR control variable = initial value TO limit STEP step

where the control variable is a single letter, & the initial value, limit & step are all numeric expressions. So, if you replace line 20 in the program by

20 FOR C=1 TO 5 STEP 3/2

then C will run through the values 1, 2.5 & 4. Notice that you don't have to restrict yourself to whole numbers, & 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 (but see exercise 4).

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

10 FOR M=0 TO 6

20 FOR N=0 TO M

30 PRINT M;":";N;" ";

40 NEXT N

50 PRINT

60 NEXT M

N-loop

|

N-loop

M-loop

|

|

|

|

M-loop

You can see that the N-loop is entirely inside the M-loop - they are properly nested. What must be avoided is two FOR-NEXT loops that overlap without either being entirely inside the other, like this:

WRONG 10 FOR M=0 TO 6

20 FOR N=0 TO M

30 PRINT M;":";N;" ";

40 NEXT M

50 PRINT

60 NEXT N

M-loop

|

|

M-loop

N-loop

|

|

|

N-loop

The FOR-NEXT loops must either be one inside the other, or be 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, & if you miss this out the NEXT statement will confuse the computer. You might get error report 1 or 2 (meaning that a NEXT statement does not contain a recognised control variable) if you're lucky.

Summary

Statements: FOR, NEXT, TO, STEP

Exercises

1. Rewrite the program in chapter 11 that prints out the character set, using a FOR-NEXT loop (Answer in chapter 13.)

2. A control variable has not just a name & a value, like an ordinary variable, but also a limit, a step, & a line number for looping back to (the line after the FOR statement where it was set up). Persuade yourself first, that when the FOR statement is executed all this information is available (using the initial value as the first value it takes), & second, that (using as an example our second & third programs), this information is enough to

convert the one line.

NEXT C

into the two lines

LET C=C+1

IF C<=5 THEN GOTO 30

(Actually we have cheated slightly here: it should really be GOTO 21 instead of GOTO 30. This will have the same effect in our program.)

3. Run the program, & then type

PRINT C

Why is the answer 6, & not 5?

[Answer: the NEXT statement in line 60 is executed 5 times, and each time 1 is added to C.] What happens if you put STEP 2 in line 20?

4. Change the third program so that instead of automatically adding five numbers, it asks you to input how many numbers you want adding. When you run this program, what happens if you input 0, meaning that you want no numbers adding? Why might you expect this to cause problems to the computer, even though it is clear what you mean? (The computer has to make a search for the statement NEXT C, which is not usually necessary.) In fact this has all been taken care of.

5. Try this program, to print out the numbers from 1 to 10 in reverse order.

10 FOR N=10 TO 1 STEP -1

20 PRINT N

30 NEXT N

Convert this into a program that does not use FOR-NEXT loops in the same way that you would convert program 3 into program 2 (see exercise 2). Why does the negative step make is slightly different?

Previous: Chapter 11 Next: Chapter 13


Chapter 13: Slow & Fast

 Chapter 13 - Slow & fast

The ZX81 can run at two speeds - SLOW and FAST. When first switched on, the computer runs in the SLOW mode and can compute and display information on the screen simultaneously. This mode is ideal for animation displays.

However, it can go about four times as fast, & it does this by forgetting about the picture except when it has nothing else to do. To see this working, type

FAST

Now whenever you press a key, the screen will blink - this is because the computer stops displaying a picture while it works out what key you pressed.

Type in a program, say

10 FOR N=0 TO 255

20 PRINT CHR$ N;

30 NEXT N

When you run this, the whole screen will go an indeterminate grey until the end of the program, when the output from the PRINT statement will come up on the screen.

The picture is also displayed an INPUT statement, while the computer is waiting for you to type the INPUT data. Try this program:

10 INPUT A

20 PRINT A

30 GOTO 10

To get back into the normal (compute & display) mode, type

SLOW

It will often be just a matter of taste whether you want compute & display mode for neatness, or fast mode for speed, but in general you will use the fast mode when

(i) your program contains a lot of numerical calculation, especially if it doesn't print much but in compute and display mode time doesn't seem to linger quite as much is you can see output coming up on the screen fairly frequently, or

(ii) you are typing in a long program. You will already have noticed how the listing gets remade every time you enter a new program line, & this can get annoying.

You can use SLOW & FAST statements in programs without any problems.

For example,

10 SLOW

20 FOR N=1 TO 64

30 PRINT "A";

40 IF N=32 THEN FAST

50 NEXT N

60 GOTO 10

Summary

Statements: FAST, SLOW

Previous: Chapter 12 Next: Chapter 14


Chapter 14: Subroutines

 Chapter 14 - Subroutines

Sometimes different parts of your program will have rather similar jobs to do, & you will find yourself typing the same lines in twice or more; however this is not necessary. You can type the lines in once, in the form known as a subroutine, & then use, or call, them anywhere else in the program without having to type them in again.

To do this, you use the statements GOSUB (GO to SUBroutine) & RETURN.

GOSUB n

where n is the line number of the first line in the subroutine, is just like GOTO n except that the computer remembers the line number of the GOSUB statement so that it can come back again after doing the subroutine. It does this remembering by putting the line number (the return address) on top of a pie of them (the GOSUB stack).

RETURN

takes the top line number off the GOSUB stack, & goes to the line after it.

As a first example,

10 PRINT "THIS IS THE MAIN PROGRAM",

20 GOSUB 1000

30 PRINT "AND AGAIN";

40 GOSUB 1000

50 PRINT "AND THAT IS ALL."

60 STOP

1000 REM SUBROUTINE STARTS HERE

1010 PRINT "THIS IS THE SUBROUTINE,"

1020 RETURN

The STOP statement in line 60 is very important because otherwise the program will run on into the subroutine & cause error 7 when the RETURN statement is reached.

For a less trivial example, suppose you want to write a computer program to handle pounds, shillings and pence. Those with long memories will remember that before 1971 a pound was divided into twenty shillings - so a shilling is 5p - & a shilling was subdivided into twelve old pence; d was the abbreviation for an old penny.) You will have three variables L, S & D (any maybe others - L1, S1, D1 & so on), and arithmetic is dead easy. First you do it separately on the pounds, shillings and pence - for instance, to add two sums of money, you add the pence, add the shillings and add the pounds; to double a sum of money you double the pence, double the shillings and double the pounds; and so on. When all that is done, adjust it to the correct form so that the pence are between 0 & 11, and the shillings between 0 & 19. This last stage is common to all the operations, so we can make it into a subroutine.

Laying aside the notion of subroutines for a moment, it is worth your while trying to write the program yourself. Give the arbitrary numbers L, S & D, how do you convert them into proper pounds, shillings & pence? Part of the problem is that you will start thinking of odder & odder cases.

What first springs to mind will probably be something like 1..25s..17d, which you want to convert to 2..6s..5d. Not so difficult. But suppose you have negative numbers? A dept of 1..25s..17d, or -1..-25s..-17d, might well turn out as -3..13s..7d, which is rather an odd way of expressing it (as though people only ever lend each other whole pounds). And what about fractions? If you divide 1..25s..17d by two, you get 5..12.5s..8.5d, & although this has the pence, 8.5, between 0 & 11; the shillings, 12.5, between 0 & 19, it is certainly not as good as 1..3s..2.5d. Try & work out your own answers to all this - & use them in a computer program - before you read any further.

Here is one solution.

1000 REM SUBROUTINE TO ADJUST L.S.D. TO THE NORMAL FORM FOR POUNDS, SHILLINGS AND PENCE

1010 LET D=240*L+12*S+D

1020 REM NOW EVERYTHING IS IN PENCE

1030 LET E=SGN D

1040 LET D=ABS D

1050 REM WE WORK WITH D POSITIVE, HOLDING ITS SIGN IN E

1060 LET S=INT (D/12)

1070 LET D=(D-12*S)*E

1080 LET L=INT (S/20)*E

1090 LET S=S*E-20*L

1100 RETURN

On its own, this is not much use because there is no program to set up L, S & d beforehand, nor to do anything with them afterwards. Type in the main program, & also another subroutine to print out L, S & D.

10 INPUT L

20 INPUT S

30 INPUT D

40 GOSUB 2000

45 REM PRINT THE VALUES

50 PRINT

60 PRINT " [image] [image] [image] = ";

70 GOSUB 1000

75 REM THE ADJUSTMENT

80 GOSUB 2000

85 REM PRINT THE VALUES

90 PRINT

100 GOTO 10

2000 REM SUBROUTINE TO PRINT L,S AND D

2010 PRINT "£";L;"..";S;"S..";D;"D";

2020 RETURN

(Recall from chapter 9 that the empty PRINT statement in line 50 prints a black line.)

Clearly we have saved on program by using the printing subroutine at 2000, & this in itself is a very common use for subroutines: to shorten programs. However, the adjustment subroutine in fact makes the program longer - by a GOSUB & a RETURN; so program length is not the only consideration. Used with skill, subroutines can make programs easier to understand for the ones that matter, humans.

The main program is simplified by its using more powerful statements: each GOSUB represents some complicated BASIC, but you can forget that - only the net result matters. Because of this, it is much easier to grasp the main structure of the program.

The subroutines, on the other hand, are simplified for a very different reason, namely that they are shorter. They still use the same old plodding LET & PRINT statements, but they only have to do a part of the whole job & so are easier to write.

The skill lies in choosing the level - or levels - at which to write the subroutines. They must be big enough to have a significant impact on the main program, yet small enough to be significantly easier to write than a complete program without subroutines. These examples (not recommended) illustrate this.

First,

10 GOSUB 1000

20 GOTO 10

1000 INPUT L

1010 INPUT S

1020 INPUT D

1030 PRINT " ";L;"..";S;"S..";D;"D";TAB 8;"=";

1040 LET D=240*L+12*S+D

: :

: :

2000 RETURN

& second

10 GOSUB 1010

20 GOSUB 1020

30 GOSUB 1030

40 GOSUB 1040

50 GOSUB 1050

: :

: :

30 GOTO 10

1010 INPUT L

1015 RETURN

1020 INPUT S

1025 RETURN

1030 INPUT D

1035 RETURN

1040 PRINT " ";L;"..";S;"S..";D;"D";TAB 8; "=";

1045 RETURN

1050 LET D=240*L+12*S+D

1055 RETURN

: :

: :

The first, with its single powerful subroutine, & the second, with its many trivial ones, demonstrate quite opposite extremes, but with equal futility.

A subroutine can happily call another, or even itself (a subroutine that calls itself is recursive), so don't be afraid to having several layers.

Summary

Statements: GOSUB, RETURN

Exercises

1. The example program is virtually a universal LSD calculator. How would you use it.

(i) to convert pounds & new pence into pounds, shillings & pence?

(ii) to convert guineas into pounds & shillings? (1 guinea = 1..1s)

(iii) to find fractions of a pound? (e.g. a third of a pound, or a mark, is 6s..8d.

Put in a line to round the pence off to the nearest farthing (1/4d).

2. Add two statements to the program:

4 LET ADJUST=1000

7 LET LSDPRINT=2000

& change

GOSUB 1000 to GOSUB ADJUST

GOSUB 2000 to GOSUB LSDPRINT

This works exactly as you'd hope; in fact the line number in a GOSUB (or GOTO or RUN) statement can be any numerical expression. (Don't expect this to work on computers other than the ZX81, because it is not standard BASIC.)

This sort of stuff can work wonders for the clarity of your programs.

3. Rewrite the main program in the example to do something quite different, but still using the same subroutines.

4. ... GOSUB n

... RETURN

in consecutive lines can be replaced by

... GOTO n

Why?

5. A subroutine can have several entry points. For instance, because of the way our main program uses them, with GOSUB 1000 followed immediately by GOSUB 2000, we can replace our two subroutines by one big one that adjusts L, S & D & then prints them. It has two entry points: one at the beginning for the whole subroutine, & another further on for the printing part only.

Make the necessary rearrangements.

6. Run the program:

10 GOSUB 20

20 GOSUB 10

The return addresses are pushed on to the GOSUB stack in droves, but they never get taken off again & eventually there is no room for any more in the computer. The program then stops with error 4 (see appendix B).

You might have difficulty in clearing them out again without losing everything, but this will work.

(i) Delete the two GOSUB statements.

(ii) Insert two new lines

11 RETURN

21 RETURN

(iii) Type

RETURN

The return addresses will be stripped off until you get error 7.

(iv) Change your program so you don't get the same thing happening again.

How does this work?

Previous: Chapter 13 Next: Chapter 15


Chapter 15: Making your programs work

 Chapter 15 - Making your programs work

There is more to the art of programming computers than just knowing which statement does what. You will probably already have found that most of your programs have what are technically known as bugs when you first type them in: maybe just typing errors, or maybe mistakes in your own ideas of what the program should do. You might put this down to inexperience, but you would be deluding yourself.

EVERY PROGRAM STARTS OFF WITH BUGS.

Many programs finish up with bugs as well. There are two corollaries to this; first, you must test all your programs straight away; & second, there's no point in losing your temper every time they don't work. The general plan can be illustrated with a flowchart:

The idea is that you follow the arrows from box to box, doing what it says at each one. We have used different sorts of boxes for different sorts of instructions:

A rounded box | is start or finish.
A rectangular box | is a straightforward instruction.
A diamond | asks you to make some kind of decision before carrying on.

(These shapes are fairly widely used, but nothing earth-shattering depends on them.)

Of course, these flowcharts are ill-adapted for describing human activities; thinking along fixed straight lines like this is not good for creativeness or flexibility. For computers, however, they are just the job. They are best at describing the large-scale structure of programs, with a subordinate in almost every box, so a flowchart for our sterling example in the last chapter might be.

Conceptually, then, rectangular boxes correspond to GOSUBs; although in practice some boxes - like the one above that inputs L, S & D - are translated directly into BASIC statements, without a subroutine.

Anything - like flowcharts, subroutines, & also REM statements - that makes the program clearer gives you a better understanding of it; & then you are bound to write fewer bugs. But subroutines also help you get out the bugs you've written anyway, by making the program easier to test. You will find it much easier to test the subroutines individually & make sure that they fit together properly, than to test a whole unstructured program.

Subroutines, then, help with the box 'find the bugs' & this is the box where you need all the help you can get, for it is often the most exasperating. Other hints for finding bugs are

(i) Check that there are no typing errors. Always do this.

(ii) Try to work out what all the variables should be at each stage - & if possible explain this in REM statements. You can check the variables at a given point in the program by inserting a PRINT statement there.

(iii) If the effect of the program is to make the program stop with an error report, then use this information as thoroughly as you can. Look up the report code, & work out why it stopped on the line where it did. Print out the values of the variables, if necessary.

(iv) You might be able to step through a program line by line by typing in its lines as commands.

(v) Pretend to be the computer: run the program on yourself using pencil & paper to note down the values of the variables.

Once you've found the bugs, fixing them is much like writing the original program, but you must test the program again. It is surprisingly easy to fix one bug, only to introduce another.

Exercises

1. The flowchart for the LSD calculator has no 'finish' box. Does this matter? Where would you put one if you wanted to?

2. Write flowcharts for the looping programs in chapter 12.


Chapter 16: Tape storage

 Chapter 16 - Tape storage

As was mentioned in chapter 1, & you have no doubt found out from experience anyway, when you turn the ZX81 off you lose all the program & variables that were stored inside it. The only way to save these is to have the computer record them onto a cassette tape; & then later you can load them back in & the computer will be restored to practically the same state as it was in when it made the recording.

You will have found that with the ZX81 a pair of leads (article (v) in chapter 1) which connect the ZX81 to a cassette recorder. You must provide your own tape recorder, & some work better than others.

First, as far as the ZX81 is concerned, the cheap, portable mono cassette recorders are at least as good as expensive stereo ones, & give less trouble as well. You will find a tape counter very useful.

Second, the tape recorder must have an input socket for use with microphones, & an optput socket for use with earphones if there isn't one, try the external loudspeaker socket.) They should preferably be 3.5 mm jack sockets i.e. to fit the jack plugs on the leads provided), because other sorts often do not give a signal powerful enough for the ZX81.

Any cassette tape should work, although low noise tapes are preferable.

Now, having acquired a suitable cassette recorder, connect it to the computer: one lead should connect the microphone input socket on the recorder to the socket marked 'MIC' on the side of the ZX81, & the other connects the earphone output socket on the recorder to the 'EAR' socket on the ZX81. Make sure that the leads are not crossed over (although you won't damage the ZX81 if they are.)

Type some program into the computer, say the character set program in chapter 11. You are going to have to give the program a name when you save it, & it is a good idea to put this name into the program so that it appears in listings - the easiest way is with a REM statement. So type

5 REM "CHARACTERS"

Now - & this is just a dry run, so that you can see what happens, - type

SAVE "CHARACTERS"

& watch the television. For five seconds it will just be a greyish colour, then for about six seconds there will be a distinctive pattern of thin black & white stripes, & then the screen will go white with the report 0/0. The computer was sending a signal to the 'MIC' socket; but it was also sending the same signal to the television, producing the picture that you saw. The grey part was a silent lead-in, & the black & white part was the program.

What you want to do, of course, is catch that signal on tape, so let's do it properly this time.

Saving a program

1. Position the tape in a part either that is blank, or that you are prepared to overwrite.

2. Using a microphone, record yourself saying 'characters'. This is not essential, but it will make it easier to find the program afterwards. Reconnect the computer to the tape recorder.

3. Type

SAVE "CHARACTERS" (without NEWLINE)

4. Start the tape recorder recording.

5. Press NEWLINE.

6. Watch the television as before. When it has finished (with the report 0/0), stop the tape recorder.

To make sure that this has worked, you should now listen to the tape through the tape recorder's own loudspeaker. (You will probably have to unplug the lead from the earphone socket on the tape recorder.) Rewind the tape to where you started before, & play it back.

First, you will hear your own voice saying 'characters'.

After that, comes a soft, humming buzz. This is not really part of the recording, but the end of the signal for the television (before you pressed NEWLINE), which happens to have been sent to the tape recorder as well.

Next come five seconds of silence, the beginning of the proper tape signal. This corresponds to the period when the television screen went grey.

Next come about six seconds of a very harsh high-pitched buzz, & at full volume this should be very unpleasantly loud. This is a recording of the program, & corresponds to the black & white patterns on the television screen.

Finally, the soft humming buzz will return.

If you did not hear these various hums & buzzes, then check that you had the computer & tape recorder properly connected up. It happens with some tape recorders that the jack plug dies not make contact if it is pushed right in. Try pulling it out about a tenth of an inch - you can sometimes feel it settling down into a more natural position.

Now let us suppose that the recoding sounds all right to the human ear, & you want to try to load it back into the computer.

Loading a program with a name

1. Rewind the tape to the place where you started.

2. Make sure that the 'EAR' socket on the computer is connected to the earphone socket on the tape recorder.

3. Turn the volume control on the tape recorder to about three quarters of the maximum volume; if it has tone control then adjust them so that treble is high & bass is low (so that it sounds hissy).

4. Type

LOAD "CHARACTER" (again, without NEWLINE)

5. Start the tape recorder playing.

6. Press NEWLINE.

Again, you will be able to see pictures of the recording in the television, but they will look different this time, everything being a black & white pattern. The two parts, the silence & the program, will be less easily distinguished, but you should be able to see that the program part has much broader, more defined lines. (Try exercise 1 some time.)

After fifteen seconds it should have loaded & stopped with report 0/0. Otherwise, press the BREAK key (space), which should let it out of its misery.

The most likely thing to have been wrong is the volume level: this should be

(i) loud enough for the program part to be picked up by the computer,

(ii) not so loud that the program part is distorted (this is actually fairly rare),

& (iii) quiet enough for the silent part to be recognized as silent by the computer.

The best adjustment is to turn the volume up as loud as it will go without making the silent part at all noisy; you can do this while listening to the recording through the loudspeaker. If the silence is incorrigibly noisy, then you may have other problems:

Some tape recorders form a feedback loop with the ZX81. This can only happen when the EAR & MIC leads are both in at the same time, so the cure is to SAVE with the EAR lead disconnected.

Some tape recorders can record a mains hum. This is cured by operating them on batteries.

Some tape recorders - especially old, worn ones - are intrinsically noisy. This may be helped by using a better quality tape, although this should not be necessary.

Try cleaning the tape head in the cassette recorder, in case it is dirty.

Finally, there may be the same problem about pushing the plug right into the earphone socket as was mentioned for the microphone socket.

If you've got a program on tape & you can't remember its name, you can still load it. (Try this with the program "CHARACTERS" that you were using before.)

Loading a program without a name

1. Position the tape in the silent lead-in.

2. Check everything & adjust the controls as before. You might well find that you have to be more careful with the volume level than you did when you knew the name.

3. Type

LOAD "" (without NEWLINE)

4. Start the tape recorder playing.

5. Press NEWLINE.

6. The rest is as before.

The idea is that if the name of the program you ask to be loaded is the empty string, then the computer loads the first program it comes across. Note that when you save a program, you cannot make its name the empty string - if you try then you will get error F.

LOAD & SAVE can also be used in programs. With SAVE, the program will save itself in such a state then when loaded it will immediately carry on executing from the line after the SAVE statement.

For example, type in

5 REM "USELESS"

10 PRINT "THIS IS ALL IT DOES"

20 STOP

100 SAVE "USELESS"

110 GOTO 10

Connect up the tape recorder, type

RUN 100 (without NEWLINE),

start the tape recorder recording, & press NEWLINE. When the program has saved itself, it will continue running. You will discover afterwards that the last S in USELESS in line 100 has changed to inverse video, but this is nothing to worry about.

To load it, rewind the tape to somewhere before the beginning of the program, type

LOAD "USELESS" (without NEWLINE),

start playing back the tape into the computer, & press NEWLINE. When it has loaded, it will carry on with line 110 & execute itself without any effort on your part.

Note how putting the SAVE statement at the end of the program means that to run it without the SAVE you just type RUN - you don't have to jump round the SAVE statement.

Don't SAVE from within a GOSUB routine - it won't work properly.

Don't put inverse video characters in a program name. Any part of the name after the inverse video character gets lost.

The name should not contain more than 127 characters.

The name in a LOAD or SAVE does not have to be a string constant, it can be any string-valued expression, like A$ or CHR$ 100.

Summary

Saving a program on tape

Loading a named program from tape

Loading the first available program from tape

Saving a program so that it will load & then run itself

Statements: SAVE, LOAD

Note

You cannot load programs that were saved from any other kinds of computer or from the ZX80 with its own integer BASIC. Your saved programs cannot be loaded into other kinds of computer or the ZX80 with integer BASIC. The ZX80 with ZX81 BASIC, on the other hand is compatible with the ZX81; saved programs from either can be loaded to the other. After loading a ZX80 program, the ZX81 will be in fast mode.

Exercises

1. Make a tape with loads of short programs, start playing it back into the computer, & type

LOAD "NOT THE NAME OF A PROGRAM"

You should easily be able to see the difference on the television between the empty stretches on the tape (with a fairly unstructured black & white pattern) & the programs (with more definite lines). Both patterns are different from what you see when you save. If you turn the volume down while a program is going past, you can see the picture switching to the empty space pattern while the signal goes too quiet to look like program.

2. Make a tape on which the first program, when loaded, prints a menu (a list of the other programs on the tape), asks you to choose a program, & then loads it.

3. Type in the program "CHARACTERS" again, & then type

LET X=7

so that - although it doesn't appear in the program - the computer now contains a variable X with value 7. Now save the program, turn the computer off & on (to make sure there's no cheating), & load the program back again. Type

PRINT X

& you will get the answer 7. The SAVE statement saved not only the program, but also all the variables - including X.

If you want to keep these variables when you execute the program, you must remember to use GOTO & not RUN (as was mentioned in chapter 9). You can avoid having to remember this by making the program execute itself (using SAVE as a program line).

4. Type in a very long program, & them momentarily disconnect the power supply. This sort of thing sometimes happens spontaneously; it is not a bug, but a glitch. There is nothing you can do about it except cry. It if happens more often than you can bear then there is probably something wrong, but it would be worth saving the incomplete program on tape half-way through.

Previous: Chapter 15 Next: Chapter 17


Chapter 17: Printing with frills

 Chapter 17 - Printing with frills

You will recall that a PRINT statement has a list of items, each one an expression (or possibly nothing at all), & that they are separated by commas or semicolons. There are two more kinds of PRINT item which are used to tell the computer not what, but where to print. For example, PRINT AT 11,16; "*" prints a star in the middle of the screen.

AT line, column

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

TAB column

moves the PRINT position to the column specified. It stays on the same line, or, if this would invoke back-spacing, moves on to the next one. Note that the computer reduces the column number modulo 32 (it divides by 32 & takes the remainder); so TAB 33 means the same as TAB 1.

For example

PRINT TAB 30,1;TAB 12;"CONTENTS";AT 3,1;"CHAPTER";TAB 24;"PAGE"

(This is how you might print out the heading of a Contents page, with 1 as the page numbers.)

Some small points:

(i) These new 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 usually terribly useful.

(ii) Although AT & TAB are not functions, you have to type the function key (shifted NEWLINE) to get them.

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

(iv) You can use AT to put the PRINT position even where there is already something printed; the old stuff will be overwritten.

There are two more statements connected with PRINT, namely CLS & SCROLL.

CLS Clears the Screen (but nothing else).

SCROLL moves the whole display up one line (losing the top line) & moves the PRINT position to the beginning of the bottom line.

To see how this works, run this program:

10 SCROLL

20 INPUT A$

30 PRINT A$

40 GOTO 10

Summary

PRINT items: AT, TAB

Statements: CLS, SCROLL

Exercises

1. Try running this:

10 FOR I=0 TO 20

20 PRINT TAB 8*I;I;

30 NEXT I

This shows what is meant by the TAB number's being reduced modulo 32. For a more elegant example, change the 8 in line 20 to a 6.

Previous: Chapter 16 Next: Chapter 18


Chapter 18: Graphics

 Chapter 18 - Graphics

Here are some of the most elegant features of the ZX81; they use what are called pixels (picture elements). The screen you can display on has 22 lines & 32 columns, making 22*23 = 704 character positions, & each of these contains 4 pixels, divided up like a slice of Battenburg cake.

A pixel is specified by two numbers, its coordinates. The first, its x-coordinate, says how for it is across from the extreme left-hand column (remember, X is ACROSS), & the second, its y-coordinate, says how far if is up from the bottom. These coordinates are usually written as a pair in brackets, so (0,0), (63,0), (0,43) & (63,43) are the bottom left-, bottom right-, top left-, & top right-hand corners.

The statement

PLOT x-coordinate, y-coordinate

blacks in the pixel with these coordinates, while the statement

UNPLOT x-coordinate, y-coordinate

blanks it out.

Try this measles program:

10 PLOT INT (RND*64),INT (RND*44)

20 INPUT A$

30 GOTO 10

This plots a random point each time you press NEWLINE.

Here is a rather more useful program. It plots a graph of the function SIN (a sine wave) for values between 0 & 2 [image].

10 FOR N=0 TO 63

20 PLOT N, 22+20*SIN (N/32*PI)

30 NEXT N

This next one plots a graph of SQR (part of a parabola) between 0 & 4:

10 FOR N=0 TO 63

20 PLOT N,20*SQR (N/16)

30 NEXT N

Notice that pixel coordinates are rather different from the line & column in an AT item. At the end of this chapter is a diagram which you may find useful in working out pixel coordinates & line & column numbers.

Exercises

1. There are three differences between the numbers in an AT item & pixel coordinates; what are they?

Suppose that the PRINT position corresponds to AT L,C (for line & column). Prove to yourself that the four pixels in that position have x-coordinates 2*C or 2*C+1, & y-coordinates 2*(21-L) or 2*(21-L)+1. (Look at the diagram.)

2. Make a cheese nibbler by altering the measles program so that it first fills the screen with black (a black square is an inverse video space), & then unplots random points, if you have only 1K of memory - that is to say, the standard machine without any extra memory, - you will find yourself running out of store, so you will have to fix the program so that it uses only part of the screen.

3. Modify the SIN graph program so that before plotting the graph itself it prints a horizontal line of "-"s for an x-axis, & a vertical line of "/"s for a y-axis.

4. Write programs to plot graphs of more functions, e.g. COS, EXP, LN, ATN, INT & so on. For each one you will have to make sure that the graph fits the screen, so you will need to consider

(i) over what range you are going to take the functions (corresponding to the range 0 to 2 [image] for the SIN graph).

(ii) whereabouts on the screen to put the x-axis (corresponding to 22 in line 20 in the SIN graph program).

(iii) how to scale the y-axis of the graph (corresponding to 20 in line 20 of the SIN graph program).

You will find that COS is the easiest - it's just like SIN.

5. Run this:

10 PLOT 21,21

20 PRINT "HEAVY QUOTES"

30 PLOT 46,21

PLOT moves on the PRINT position. (UNPLOT does too.)

6. This subroutine draws a (fairly) straight line from the pixel (A,B) to the pixel (C,D).

Use it as part of some main program that supplies the value of A, B, C & D.

(If you have not got a memory expansion board then you'll probably need to omit the REM statements.)

1000 LET U=C-A

1005 REM U SHOWS HOW MANY STEPS ALONG WE NEED TO GO

1010 LET V=D-B

1015 REM V SHOWS HOW MANY STEPS UP

1020 LET D1X=SGN U

1030 LET D1Y=SGN V

1035 REM (D1X,D1Y) IS A SINGLE STEP IN A DIAGONAL DIRECTION

1040 LET D2X=SGN U

1050 LET D2Y=0

1055 REM (D2X,D2Y) IS A SINGLE STEP LEFT OR RIGHT

1060 LET M=ABS U

1070 LET N=ABS V

1080 IF M>N THEN GOTO 1130

1090 LET D2X=0

1100 LET D2Y=SGN V

1105 REM NOW (D2X,D2Y) IS A SINGLE STEP UP OR DOWN

1110 LET M=ABS V

1120 LET N=ABS U

1130 REM M IS THE LARGER OF ABS U & ABS V, N IS THE SMALLER

1140 LET S=INT (M/2)

1145 REM WE WANT TO MOVE FROM (A,B) TO (C,D) IN M STEPS USING N UP- DOWN OR RIGHT-LEFT STEPS D2, & M-N DIAGONAL STEPS D1, DISTRIBUTED AS EVENLY AS POSSIBLE

1150 FOR I=0 TO M

1160 PLOT A,B

1170 LET S=S+N

1180 IF S<M THEN GOTO 1230

1190 LET S=S-M

1200 LET A=A+D1X

1210 LET B=B+D1Y

1215 REM A DIAGONAL STEP

1220 GOTO 1250

1230 LET A=A+D2X

1240 LET B=B+D2Y

1245 REM AN UP-DOWN OR RIGHT-LEFT STEP

1250 NEXT I

1260 RETURN

The last part (lines 1150 on) mixes the M-N step D1 evenly with the N steps D2. Imagine a Monopoly board with M squares round the edge, numbered from 0 to M-1. The square you are on at any time is number S, starting at the corner opposite G0. Each move takes you N squares round the board, & in the straight line on the screen you make either a left-right/ up-down step (if you pass GO on the board), or a diagonal step otherwise. Since your total journey on the board is M*N steps, or right round N times, you pass GO N times & evenly spaced out in your M steps are N left-right/up-down steps.

Adjust the program so that if another parameter, E, is 1 then the line is drawn in black (as here), & if it is 0 then the line is drawn in white (using UNPLOT). You can then rub out a line you've just drawn by undrawing it.

Previous: Chapter 17 Next: Chapter 19


Chapter 19: Time & motion

 Chapter 19 - Time & motion

Quite often you will want to make the program take a specified length of time, & for this you will find the PAUSE statement useful (especially in fast mode):

PAUSE n

stops computing & displays the picture for n frames of the television (at 50 frames per second, or 60 in America). n can be up to 32767, which gives you just under 11 minutes; if n is any bigger then it means 'PAUSE for ever'.

A pause can always be cut short by pressing a key (note that a space, or £, will cause a break as well). You have to press the key down after the pause has started.

At the end of the pause, the screen will flash.

If a PAUSE statement is used in a program that will be run in FAST mode or on the old ZX80 with the new 8K ROM, then the PAUSE statement must be followed by POKE 16437,355. The PAUSE will appear to work without doing this, but it will probably result in your program being wiped out.

This program works the second hand (here just a single dot on the edge) of a clock.

5 REM FIRST WE DRAW THE CLOCK FACE

10 FOR N=1 TO 12

20 PRINT AT 10-10*COS (N/6*PI),10+10*SIN (N/6*PI);N

30 NEXT N

35 REM NOW WE START THE CLOCK

40 FOR T=0 TO 10000

45 REM T IS THE TIME IN SECONDS

50 LET A=T/30*PI

60 LET SX=21+18*SIN A

70 LET SY=22+18*COS A

200 PLOT SX,SY

300 PAUSE 42

310 POKE 16437,255

320 UNPLOT SX,SY

400 NEXT T

(Miss out the REM statements unless you have a memory expansion board.)

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

The function INKEY$ (which has no argument) reads the keyboard. If you are pressing exactly one key (or the shift key and one other key) then the result is the character that the key gives in [image] mode; otherwise the result is the empty string. The control characters do not have their usual effect, but give results like CHR$ 118 for newline - they are printed as "?".

Try this program, which works like a typewriter.

10 IF INKEY$<>"" THEN GOTO 10

20 IF INKEY$="" THEN GOTO 20

30 PRINT INKEY$;

40 GOTO 10

Here line 10 waits for you to lift your finger off the keyboard & line 20 waits for you to press a new key.

Remember that unlike INPUT, INKEY$ doesn't wait for you. So you don't type newline, but on the other hand if you don't type anything at all then you've missed your chance.

Exercises

1. What happens if you miss out line 10 in the typewriter program?

2. Why can you not type space or £ in the typewriter program?

Here is a modified program that gives you a space if you type cursor right (shifted 8).

10 IF INKEY$<>"" THEN GOTO 10

20 IF INKEY$="" THEN GOTO 20

30 LET A$=INKEY$

40 IF A$=CHR$ 115 THEN GOTO 110

90 PRINT A$;

100 GOTO 10

110 PRINT " ";

120 GOTO 10

Note how we read INKEY$ into A$ in line 30. It would be possible to miss this out & replace A$ by INKEY$ in lines 40 & 0, but there would always be a chance that INKEY$ could change between the lines.

Add some more programs so that if you type NEWLINE (CHR$ 118) it gives you a new line.

3. Another way of using INKEY$ is in conjunction with PAUSE, as in this alternative typewriter program.

10 PAUSE 40000

20 POKE 16437,255

30 PRINT INKEY$

40 GOTO 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?

This method has the disadvantage that the screen flashes, but in fast mode it is the only way of doing it. Run the program in fast mode, & notice that the computer takes the opportunity of a pause to display the television picture.

4. This one will drive you mad. The computer displays a number, which you (or an innocent victim) shall type back. To begin with you have a second to do it in, but if you get it wrong you get a longer time for the next number, while if you get it right you get less time for the next one. The idea is to get it going as fast as possible, & then press Q to see your score - the higher the better.

10 LET T=50

15 REM T=NUMBER OF FRAMES PER GO-INITIALLY 50 FOR 1 SECOND

20 SCROLL

30 LET A$=CHR$ INT (RND*10+CODE "0")

35 REM A$ IS A RANDOM DIGIT

40 PRINT A$

45 PAUSE T

50 POKE 16437,255

60 LET B$=INKEY$

70 IF B$="Q" THEN GOTO 200

80 IF A$=B$ THEN GOTO 150

90 PRINT "NO GOOD"

100 LET T=T*1.1

110 GOTO 20

150 PRINT "OK"

160 LET T=T*0.9

170 GOTO 20

200 SCROLL

210 PRINT "YOUR SCORE IS "; INT (500/T)

5. (Only for those with extra RAM.) Using the straight line routine in chapter 15, change the second hand program so that it also shows minute & hour hands, drawing them every minute. (Make the hour hand shorter.) If you're feeling ambitious, arrange so that every quarter of an hour it puts on some kind of a show.

6. (For fun.) Try this:

10 IF INKEY$ = "" THEN GOTO 10

20 PRINT AT 11.14; "OUCH"

30 IF INKEY$<>"" THEN GOTO 30

40 PRINT AT 11,14; " "

50 GOTO 10

Previous: Chapter 18 Next: Chapter 20


Chapter 20: The ZX81 printer

 Chapter 20 - The ZX81 Printer

If you have got a ZX81 printer, you will have some operating instructions with it. This chapter covers the BASIC statements needed to make it work.

The first two, LPRINT & LLIST, are just like PRINT and LIST, except that they use the printer instead of the television. (The L is a historical accident. When BASIC was invented it usually usually used an electronic typewriter instead of a television, so PRINT really did mean print. If you wanted messages of output you would use a very fast line printer attached to the computer, & an LPRINT statement meaning 'Line printer PRINT'.)

Try this program for example.

10 LPRINT "THIS PROGRAM:",,,,

20 LLIST

30 LPRINT ,,"PRINTS OUT THE CHARACTER SET.",,,

40 FOR N=0 TO 255

50 LPRINT CHR$ N;

60 NEXT N

The third statement, COPY, prints out a copy of the television screen. For instance, get a listing on the screen of the program above, & type

COPY

You can always stop the printer when it is running by pressing BREAK key (space).

If you execute these statements without the printer attached, it should just lose all the output & carry on with the next statement. However, sometimes it might get stuck, & when this happens the break key will bring it out.

Summary

Statements: LPRINT, LLIST, COPY

Note: None of these statements is standard BASIC, although LPRINT is used by some other computers.

Exercises

1. 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 letters working down diagonally from the top right-hand corner until it reaches the bottom of the screen, when the program stops with error report 5.

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 error 5, which should not occur with the printer, & the pattern will carry on an extra ten lines with the digits.

Now change 'TAB N' to 'AT 21-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 the LPRINT is not printed straight away, but arranged in a buffer store a picture one line long of what the computer will print when it gets round to it. The printing takes place

(i) when the buffer is full,

(ii) after an LPRINT statement that does not end in a comma or semicolon.

(iii) when a comma or TAB item requires a new line.

or (iv) at the end of a program, if there is anything left unprinted.

(iii) explains why our program with TAB works the way it does. As for AT, the line number is ignored & the LPRINT position (like the PRINT position, but for the printer instead of the television) is changed to the column number. An AT item can never cause a line to be sent to the printer. (Actually, the line number after AT is not completely ignored; it has to be between -21 & +21 or an error will result. For this reason it is safest always to specify line 0. The item 'AT 21-N,N' in the final version of our program would be much better albeit less illustrative if replaced by 'AT 0,N'.)

2. Make a printed graph of SIN by running the program in chapter 18 & then using COPY.

Previous: Chapter 19 Next: Chapter 21


Chapter 21: Substrings

 Chapter 21 - Substrings

Given a string, a substring of it consists of some consecutive characters from it, taken in sequence. Thus "STRING" is a substring of "BIGGER STRING", but "B STRING" & "BIG REG" are not.

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

string expression (start TO finish)

so that, for instance,

"ABCDEF" (2 TO 5) = "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) = "ABCDEF" (1 TO 5) = "ABCDE"

"ABCDEF" (2 TO ) = "ABCDEF" (2 TO 6) = "BCDEF"

&

"ABCDEF" ( TO ) = "ABCDEF" (1 TO 6) = "ABCDEF"

(you can also write this last one as "ABCDEF" (), for what it's worth.)

A slightly different for misses out the TO & just has one number:

"ABCDEF" (3) = "ABCDEF" (3 TO 3) = "C"

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

"ABCDEF" (5 TO 7)

gives error 3 (subscript error) because, the string only contains 6 characters, & 7 is too many, but

"ABCDEF" (8 TO 7) = ""

&

"ABCDEF" (1 TO 0) = ""

The start & finish must not be negative, or you get error B.

This next program makes B$ equal to A$, but omitting any trailing spaces.

10 INPUT A$

20 FOR N=LEN A$ TO 1 STEP -1

30 IF A$(N)<>"" THEN GOTO 50

40 NEXT N

50 LET B$=A$( TO N)

60 PRINT """";A$;"""","""";B$;""""

70 GOTO 10

Note how if A$ is entirely spaces, then in line 50 we have N = 0 & A$( TO N) = A$(1 TO 0) = "".

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

LET A$="LOR LOVE A DUCK"

& then

LET A$(5 TO 8)="******"

&

PRINT A$

Notice how since the substring A$(5 TO 8) is only 4 characters long, only the first four stars have been used. 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 the bed by either stretching them out on a rack or cutting their feet off.

If you now try

LET A$()="COR BLIMEY"

&

PRINT A$;"."

you will see that the same thing has happened again (this time with spaces put in) because A$() counts as a substring.

LET A$="COR BLIMEY"

will do it properly

Slicing may be considered as having priority 12, so, for instance

LEN "ABCDEF"(2 TO 5) = LEN("ABCDEF"(2 TO 5)) = 4

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

"ABC"+"DEF"(1 TO 2) = "ABCDE"

("ABC"+"DEF")(1 TO 2) = "AB"

Summary

Slicing, using TO. Note that this notation is non-standard.

Exercises

1. Some BASICs (not the ZX81 BASIC) have functions called LEFT$, RIGHT$, MID$ & 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 characters from the Nth on.

MID$(A$,N1,N2) gives the substring of A$ consisting of N2 characters starting at the N1th.

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

How would you write these in ZX81 BASIC? Would your answers work with strings of length 0 or 1?

2. Try this sequence of commands:

LET A$="X*+*Y"

LET A$(2)=CHR$ 11 [the string quote character]

LET A$(4)=CHR$ 11

PRINT A$

A$ is now a string with string quotes inside it! So there is nothing to stop you doing this if you are persevering enough, but clearly if you had originally typed

LET A$="X"+"Y"

the part to the right of the equals sign would have been treated as an expression, giving A$ the value "XY".

Now type

LET B$="X""+""Y"

You will find that although A$ & B$ look the same when printed out, they are not equal - try

PRINT A$=B$

Whereas B$ contains mere quote image characters (with code 192), A$ contains genuine string quote characters (with code 11).

3. Run this program:

10 LET A$="LEN ""ABDC"""

100 PRINT A$;" = ";VAL A$

This will fail because VAL does not treat the quote image "" as a string quote.

Insert some extra lines between 10 & 100 to replace the quote images in A$ by string quotes (which you must call CHR$ 11), & try again.

Make the same modifications to the program in chapter 9, exercise 3, & experiment with it.

4. This subroutine deletes every occurrence of the string "CARTHAGO" from A$.

1000 FOR N=1 TO LEN A$-7

1020 IF A$(N TO N+7)="CARTHAGO" THEN LET A$(N TO N+7)="********"

1030 NEXT N

1040 RETURN

Write a program that gives A$ various values (e.g. "DELENDA EST CARTHAGO.") & applies the subroutine.

Previous: Chapter 20 Next: Chapter 22


Chapter 22: Arrays

 Chapter 22 - Arrays

Suppose you have a list of numbers, for instance the number of income tax collectors that have died each month in the current financial year. To store them in a computer you could set up a single variable for each month, but you would find this very awkward. You might decide to call the variables ALAS NO MORE 1, ALAS NO MORE 2, & so on up to ALAS NO MORE 12, but the program to print out these twelve numbers would be rather long & boring to type in.

How much nicer it would be if you could type this:

5 REM THIS PROGRAM WILL NOT WORK

10 FOR N=1 TO 12

20 PRINT ALAS NO MORE N

30 NEXT N

Well, you can't.

However, there is a mechanism by which you can apply this idea, & it uses arrays. An array is a set of variables, or elements, all with the same name, & distinguished only by a number (the subscript) written in brackets after the name. In our example the name would be A (like control variables for FOR-NEXT loops, the name of an array must be a single letter), & the twelve variables would then be A(1), A(2), & so on up to A(12).

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 inside the computer, & you do this using a DIM (for dimension) statement.

DIM A(12)

sets up an array called A with dimension 12 (i.e. there are 12 subscripted variables A(1),...,A(12)), & initializes the 12 values to 0. It also deletes any array called A that existed previously. (But not a simple variable. An array & a simple variable with the same name can coexist, & there shouldn't be any confusion between them because the array variable always has a subscript.)

The subscript can be an arbitrary numerical expression, so now you can write

10 FOR N=1 TO 12

20 PRINT A(N)

30 NEXT N

You can also set up arrays with more than one dimension. In a two- dimensional array you need two numbers to specify one of the elements - rather like the line & column numbers to specify a character position on the television screen - so it has the form of a table. Alternatively, if you imagine the line & column numbers (two dimensional) as referring to a page printed, you could have an extra dimension for the page numbers. Of course, we are talking about numeric arrays; so the elements would not be printed characters as in a book, but numbers. Think of the elements of a three-dimensional array C as being specified by C (page number, line number, column number).

For example, to set up a two-dimensional array B with dimensions 3 & 6, you use a DIM statement

DIM B(3,6)

This then gives you 3*6 = 18 subscripted variables

B(1,1), B(1,2),..., B(1,6)

B(2,1), B(2,2),..., B(2,6)

B(3,1), B(3,2),..., B(3,6)

The same principal works for any number of dimensions.

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

There are also string arrays. The strings in an array differ from simple strings in that they are of fixed length & assignment to them is always

Procrustean - another way of thinking of them is as arrays (with one extra dimension) of single characters. The name of a string array is a single letter followed by $, & a string array & a simple string variable cannot have the same name (unlike the case for numbers).

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 each is long enough. You then say

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

This sets up a 5*10 array of characters, but you can also think of each row as being a string:

A$(1)=A$(1,1) A$(1,2) ... A$(1,10)

A$(2)=A$(2,1) A$(2,2) ... A$(2,10)

: : : : : :

A$(5)=A$(5,1) A$(5,2) ... 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 slice, so that for instance

A$(2,4 TO 8) = A$(2)(4 TO 8) = "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, or a slicer, to correspond with the extra number in the DIM statement.

Summary

Arrays (the way the ZX81 handles string arrays is slightly non-standard.)

Statements: DIM

Exercises

1. 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 M$(N) (use a loop). Type

PRINT "NOW IS THE MONTH OF ";M$(5);"ING";"WHEN MERRY LADS ARE PLAYING"

What can you do about all those spaces?

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

DIM A$(10)

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

3. READ, DATA & RESTORE; who needs them?

Most BASICs (but not the ZX81 BASIC) have three statements called READ, DATA & RESTORE.

A DATA statement is a list of expressions, & taking all the DATA statements in the program gives one long list of expressions, the DATA list.

READ statements are used to assign these expressions, one by one, to variables:

READ X

for instance, assigns the current expression in the DATA list to the variable X, & moves on to the next expression for the next READ statement.

[RESTORE moves back to the beginning of the DATA list.]

In theory, you can always replace READ & DATA statements by LET statements; however, one of their major uses is in initializing arrays, as in this program:

5 REM THIS PROGRAM WILL NOT WORK IN ZX81 BASIC

10 DIM M$(12,3)

20 FOR N=1 TO 12

30 READ M$(N)

40 NEXT N

50 DATA "JAN","FEB","MAR","APR"

60 DATA "MAY","JUN","JUL","AUG"

70 DATA "SEP","OCT","NOV","DEC"

If you only want to run this program once, you might as well replace line 30 with an INPUT statement thus:

10 DIM M$(12,3)

20 FOR N=1 TO 12

30 INPUT M$(N)

40 NEXT N

& you will have no extra typing to do. However, if you want to save the program, you will certainly not want to type the months in every time you

run it.

We suggest that you use this method:

(i) Initialize the array using a program like the one above.

(ii) Edit out the initialization program. (Don't use NEW, because you want to preserve the array.)

(iii) Type in the rest of the program, & save it. This will save the variables as well, including the array.

(iv) When you load the program back, you will also load the array.

(v) When you execute the program, do not use RUN, which clears the variables. Use GOTO with a line number instead.

You may alternatively be able to use the LOAD & execute technique of chapter 16, & its exercise 3. Then in stage (iii) above you will use a SAVE statement in the program, & stage (v) will be omitted altogether.

Previous: Chapter 21 Next: Chapter 23


Chapter 23: When the computer gets full

 Chapter 23 - When the computer gets full

The ZX81 has a limited amount of internal storage, and it is not hard to fill it up. The best sign of this happening is usually an error report 4, but other things can happen and some of them are rather strange. The exact behaviour depends on whether you have a memory expansion board attached, so first let us assume that you have not. If you have, take it off (after first switching off the computer).

The display file, that is to say the area inside the computer where it stores the television picture, is cunningly designed so that it only takes up space for what has been printed so far: a line in the display consists of up to 32 characters and then a NEWLINE character. This means that you can run out of memory by printing something, and the most obvious place is while making a listing. Type

NEW

DIM A(150)

10 FOR N=1 TO 15

20 PRINT N

Here comes the first surprise: line 10 disappears from the listing. The listing is bound to include the current line, 20, and there is not room for both lines. Now type

30 NEXT N

Again, there is only room for line 30 in the listing. Now type

40 REM X (without NEWLINE)

and you will see line 30 disappear and line 40 jump to the top of the screen. It has not been entered in the program - you still have the [image] cursor and can move it about. All you have seen is some obscure mechanism that gives the bottom half of the screen 24 lines to give it priority over the top half. Now type

XXXXXX (still without NEWLINE)

and the cursor will disappear - there is no room to display it. Type another X, without NEWLINE, and one of the Xs will disappear. Now type NEWLINE. Everything will disappear, but the program is still in the computer, as you can prove by deleting line 10 and using [image] & [image]. Now type

10 FOR N=1 TO 15

again - it will move up to the top of the screen as line 40 did. But when you press NEWLINE, it will not be entered, although there is no error message or [image] marker to say that anything is wrong. This is the result of there being no room to check the syntax of a line, and usually happens only for lines that contain numbers (other than the line number at the beginning).

The only cure is to make some space somehow, but first delete the line 10 that won't go in. Press EDIT: the screen will go blank, because there is no room to bring the line down.

When EDIT does not work it is sometimes possible to make space by typing a number of spaces until the cursor moves up the screen.

Press NEWLINE, and you will get part of the listing back. Now delete the line 40 (which you didn't really want anyway) by typig

40 (& NEWLINE)

Now try typing in line 10 again - and it still won't go. Rub it out again. You must still find some extra space somewhere. Bear in mind that the reason that line 10 was rejected was probably that there was no room to check the syntax of the two numbers, 1 & 15: so if you delete line 20 in the program you might have room to enter line 10, and still have room to re-enter line 20 (which contains no number) afterwards. Try this. Type

20

10 FOR N=1 TO 15

20 PRINT N

and the program is entered properly.

Type

GOTO 10

and again you will find that this line is rejected because its syntax cannot be checked; however, of you rub it out and type

RUN

it will work. (RUN clears out the array, making plenty of space.)

Now type in the same as before from NEW up to line 30, and then

40 REM XXXXXXXXXXXX

(12 Xs), which will end up looking like 40 RE. When you press NEWLINE, the listing will just consist of line 30, and in fact line 40 has been completely lost. This is because it was simply too long to fit in the program. The effect is a bit worse when the line is a lengthened version of a line that is already in the program, for you will lose both the old line from the program and the new line that was to replace it.

The ultimate cure for this is to buy a RAM pack, which fits on the back of the computer. The Sinclair 16K RAM pack gives the computer sixteen times as much memory as it has in its unexpanded form.

If you have an old ZX80 3K RAM pack, it will not work on the ZX81.

The behaviour with the RAM pack is rather different, because the display file is filled out with spaces to make each line 32 characters long (note that SCROLL upsets this - see chapter 27). Now printing and listing will not make the computer run out of memory, and you will not see all these shortened listings, and jumping around; but you will see the lines sticking or getting lost, and again the only cure is to find some spare space.

If you have a memory expansion board, put it on and go through the typing in this chapter, using

DIM A(3069)

to replace DIM A(150).

To summarize, this is a tangled tale and the moral is to avoid getting an absolutely jam-packed computer if you can. However, the second moral is that things are not usually as bad as they look.

1. If the listing starts shortening or things start jumping around, then the space is getting tight.

2. If NEWLINE seems to have no effect at the end of a line, then there is probably no room to deal with a number. Rub out the line using EDIT-NEWLINE or RUBOUT.

3. NEWLINE might lose a line altogether.

For all these oddities, the cure is the same. Don't panic, and look for some spare space.

The first thing to consider is CLEAR. If you have some variables and you do not mind losing any of them, then this is the thing to do.

Failing this, look for unnecessary statements in the program, such as REM statements, and delete some of those.

Summary

When the memory fills up odd things can happen; but they are not usually fatal.

Previous: Chapter 22 Next: Chapter 24


Chapter 24: Counting on your fingers

 Chapter 24 - Counting on your fingers

The next chapter digs inside the computer a bit, but before we look at that it would be as well to describe how computers count: they do it using the binary system, which means that they have no fingers - they are all thumbs.

Most European languages count using a more or less regular pattern of tens - in English, for example, although it starts off a bit erratically, it soon settles down into regular groups:

twenty, twenty one, twenty two,...,twenty nine

thirty, thirty one, thirty two,...,thirty nine

forty, forty one, forty two, ...,forty nine

& so on, & this is made even more systematic with the Arabic numerals that we use. However, the only reason for using ten is that we happen to have ten fingers & thumbs.

Now suppose Martians have three extra fingers on each hand (in so far as one can call them fingers): so instead of using our decimal system, with ten as its base, they use a hexadecimal (or hex, for short) system, based on sixteen. They need six extra hex digits in addition to the ten that we use, & they happen to write them as A, B, C, D, E & F. And what comes after F? Just as we, with ten fingers, write 10 for ten, so they, with sixteen, write 10 for sixteen. Their number system starts off:
Hex | English
0 | nought
1 | one
2 | two
: | :
: | :
9 | nine

just as ours does, but then it carries on
A | ten
B | eleven
C | twelve
D | thirteen
E | fourteen
F | fifteen
10 | sixteen
11 | seventeen
: | :
: | :
19 | twenty five
1A | twenty six
1B | twenty seven
: | :
: | :
1F | thirty one
20 | thirty two
21 | thirty three
: | :
: | :
9E | a hundred & fifty eight
9F | a hundred & fifty nine
A0 | a hundred & sixty
A1 | a hundred & sixty one
: | :
: | :
FE | two hundred & fifty four
FF | two hundred & fifty five
100 | two hundred & fifty six

If you are using hex notation & you want to make the fact quite plain, then write 'h' at the end of the number, & say 'hex'. For instance, for a hundred & fifty eight, write '9Eh' & say 'nine E hex'.

You will 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 (0), & a high voltage, or on (1). This is called the binary system, & the two binary digits are called bits: so a bit is either 0 or

1.

In the various systems, counting starts off

English | Decimal | Hexadecimal | Binary
nought | 0 | 0 | 0 or 0000
one | 1 | 1 | 1 or 0001
two | 2 | 2 | 10 or 0010
three | 3 | 3 | 11 or 0011
four | 4 | 4 | 100 or 0100
five | 5 | 5 | 101 or 0101
six | 6 | 6 | 110 or 0110
seven | 7 | 7 | 111 or 0111
eight | 8 | 8 | 1000
nine | 9 | 9 | 1001
ten | 10 | A | 1010
eleven | 11 | B | 1011
twelve | 12 | C | 1100
thirteen | 13 | D | 1101
fourteen | 14 | E | 1110
fiveteen | 15 | F | 1111
sixteen | 16 | 10 | 10000

The important point is that sixteen is equal to two raised to the fourth power, & this makes converting between hex & binary very easy.

To convert hex to binary, change each hex digit into four bits, using the table above.

To convert binary to hex, divide the binary number into groups of four bits, starting on the right, & then change each group into the corresponding hex digit.

For this reason, although strictly speaking computers use a pure binary system, humans often write the numbers stored inside a computer using hex notation.

The bits inside the computer are mostly grouped into sets of eight, or bytes. A single byte can represent any number from nought to two hundred & fifty five (11111111 binary or FF hex), or alternatively any character in the ZX81 character set. Its value can be written with two hex digits.

Two bytes can be grouped together to make what is technically called a word. A word can be written using sixteen bits of hex digits, & represents a number from 0 to (in decimal) 216-1 = 65535.

A byte is always eight bits, but words vary from computer to computer.

Summary

Decimal, hexadecimal & binary systems.

Bits & bytes (don't confuse them) & words.

Exercises

1. The Martian unit of currency is the pound, & it is divided into sixteen ounces. How would you convert from pounds & ounces to ounces & back again

(i) when all the numbers are written in decimal?

(ii) when all the numbers are written in hex?

2. How would you convert between decimal & hex? (Hint: exercise 1.)

When programs on the ZX81 to convert numerical values into the strings giving their hex representation, & vice versa. (This is what STR$ & VAL do with decimal representations.)

3. Suppose people from Venus have a total of eight fingers, without thumbs, how would their octal (base eight) counting be useful with computers?

Previous: Chapter 23 Next: Chapter 25


Chapter 25: How the computer works

 Chapter 25 - How the computer works

The illustration overleaf shows the inside of the ZX81 (but don't take it apart yourself because it can be a tricky business putting it together again).

As you can see, everything has a three letter abbreviation (TLA).

The pieces of plastic with lots of metal legs are the wondrous silicon chips, which have brought you not only digital watches, but also the Sinclair ZX81. Inside each piece of plastic is a piece of silicon about the size of the [image] cursor, joined by wires to the metal legs.

The brains behind the operation is the processor chip, often called the CPU (Central Processor Unit). This particular one is a Z80 processor

(actually a Z80A, which goes faster).

The processor controls the whole computer, does the arithmetic, considers what keys you've pressed, decides what to do as a result, & coordinates the television picture. However, for all its cleverness, it could not do all this on its own. Left to itself, it knows nothing about BASIC, floating point arithmetic, or televisions, & it has to get all its instructions from another chip, the ROM (Read Only Memory). The ROM is just a long list of instructions that make a complete computer program telling the processor what to do under all foreseeable circumstances. This program is written not in BASIC, but in what is called Z80 machine code, & takes the form of a long sequence of bytes. (Remember that a byte is just a number between 0 & 255.) Each byte has an address showing whereabouts in the ROM it is; the first one has address 0, the second has address 1, & so on up to 8191. That makes altogether 8192 = 8*1024 bytes, which is why this ZX81 BASIC is sometimes called an 8K BASIC. 1K is 1024, or 210.

Although there are similar chips in many different machines, this particular sequence of instructions is unique to the ZX81 & was written specially for it by a small firm of Cambridge mathematicians.

You can see what byte is at a given address using the function PEEK. For example, this program prints out the first 21 bytes in the ROM (& their addresses).

10 PRINT "ADDRESS";TAB 8;"BYTE"

20 FOR A = 0 TO 20

30 PRINT A;TAB 8;PEEK A

40 NEXT A

The next chip to consider is the memory, or RAM (Random Access Memory) chip. This is where the processor stores the information that it wants to keep - your BASIC program, variables, the picture for the television, & various notes (the system variables) of what sort of state the computer is in.

Like the ROM, the memory is arranged into bytes, each with an address: the addresses range from 16384 to 17407 (or possibly up to 32767 if you have a 16K RAM pack.) Again as with the ROM you can find the values of these bytes using PEEK, but the big difference from the ROM is that you can also change them. (The ROM, of course, is fixed & unalterable.)

Type

POKE 17300,57

This makes the byte at address 17300 have the value 57. If you now type

PRINT PEEK 17300

you get your number 57 back. (Try poking in other values, to prove that there's no cheating.)

Note that the address has to be between 0 & 65535; & most of these will refer to bytes in ROM or nowhere at all, & so have no effect. The value must be between -255 & +255, & if it is negative it gets 256 added to it.

The ability to poke gives you immense power over the computer if you know how to use it; however, the necessary knowledge is rather more than can be imparted in an introductory manual like this.

The last big chip is the logic chip, or SCL (Sinclair Computer Logic) chip. Again, this was specially designed & made for the ZX81, & it connects the other chips together in rather a clever way to make them do more than they normally would.

The modulator converts the computer's television output into a form suitable for the television, & the regulator converts the smoothed, but unregulated 9 volts of the power supply to a regulated 5 volts.

Summary

Chips

Statements: POKE

Functions: PEEK

Previous: Chapter 24 Next: Chapter 26


Chapter 26: Using machine code

 Chapter 26 - Using machine code

This chapter is written for those that understand Z80 machine code, the set of instructions that the Z80 processor chip uses. If you do not, but you would like to, there are books about it; two introductory ones are 'Programming the Z80' by Rodnay Zaks, published by Sybex at about £10 and 'Z80 and 8080 Assembly language programming' by Rathe Spracklen, published by Hayden at £5.25.

The ultimate authority is the 'Z80 Assembly Language Programming Manual' together with the 'Z80-CPU, Z80A-CPU Technical Manual', published by Zilog at about £6 for the pair, but these could hardly be recommended for beginners.

Machine code routines can be executed from within a BASIC program using the function USR. The argument of USR is the starting address of the routine, and its result is a two byte unsigned integer, the contents of the bc register pair on return. The return address to the BASIC is tacked in the usual way, so return is by a Z80 ret instruction.

There are certain restrictions on USR routines:

(i) On return, the iy & i registers must have the values 4000h & 1 Eh.

(ii) The display routine uses the a', f', ix, iy & r registers, so a USR routine should not use these if compute & display is operating. (It is not even sade to read the af' pair.)

The control, data & address busses are all exposed at the back of the ZX81, so you can do almost anything with a ZX81 that you can with a Z80. The ZX81 hardware might sometimes get in the way, though, especially in compute and display. Here is a diagram of the exposed connections at the back.

A piece of machine code in the middle of memory runs the risk of being overwritten by the BASIC system. Some safer places are

(i) In a REM statement: type in a REM statement with enough characters to hold your machine code, which you then poke in. Make this the first line in the program, or it might move about. Avoid halt instructions, since these will be recognized as the end of the REM statement.

(ii) In a string: set up a long enough string, and then assign a machine code byte to each character. Strings are always liable to move about in the memory.

In appendix A, the character set, you will find the characters and Z80 instructions written down side by side in order, & you may well find this useful when entering code.

(iii) At the top of the memory. When the ZX81 is switched on, it tests to see how much memory there is and puts the machine stack right at the top so that there is no space for USR routines there. It stores the address of the first non-existent byte (e.g. 17K, or 17408, if you have 1K of memory) in a system variable known as RAMTOP, in the two bytes with addresses 16388 & 16389. NEW on the other hand, does not do a full memory test, but only checks up as far as just before the address in RAMTOP. Thus if you poke the address of an existing byte into RAMTOP, for NEW all the memory from that byte on is outside the BASIC system and left alone. For instance, suppose you have 1K of memory and you have just switched on the computer.

PRINT PEEK 16388+256*PEEK 16389

tells you the address (17408) of the first non-existent byte.

Now suppose you have a USR routine 20 bytes long. You want to change RAMTOP to 17388 = 236 + 256*67 (how would you work this out on the computer?), so type

POKE 16388,236

POKE 16389,67

and then NEW. The twenty bytes of memory from address 17388 to 17407 are now yours to do what you like with. If you then type NEW again it will not affect these twenty bytes.

The top of memory is a good place for USR routunes, safe (even from NEW) and immobile. Its main disadvantage is that it is not saved by SAVE.

Summary

Functions: USR

Statements: NEW

Exercises

1. Make RAMTOP equal to 16700 and then execute NEW. You will get an idea of what happens when the memory gets full.

Previous: Chapter 25 Next: Chapter 27


Chapter 27: Organization of memory

 Chapter 27 - Organization of memory

The memory is sorted into different areas for storing different kinds of information. The areas are only large enough for the information that they actually contain, & if you insert some more at a given point (for instance by adding a program line or variable) space is made by shifting up everything above that point. Conversely, if you delete information then everything above it is shifted down.

The system variables contain various pieces of information that tell the computer what sort of state the computer is in. They are listed fully in the next chapter, but for the moment note that there are some (called D_FILE, VARS, E_LINE & so on) that contain the addresses of the boundaries between the various areas in the memory. These are not BASIC variables, & their names will not be recognized by the computer.

Each line in the program is stored as:

Note that, in contrast with all other cases of two-byte numbers in the Z80, the line number here (& also in a FOR-NEXT control variable) is stored with its most significant byte first: that is to say, in the order that you would write them down in.

A numerical constant in the program is followed by its binary form, using the character CHR$ 126 followed by five bytes for the number itself.

The display file is the memory copy of the television picture. It begins with a NEWLINE character, & then has the twenty four lines of text, each finishing with a NEWLINE. The system is so designed that a line of text does not need space a full thirty two characters: final spaces can be omitted. This is used to save space when the memory is small.

When the total amount of memory (according to the system variable RAMTOP) is less than 3 1/4 K, then a clear screen - as set up at the start or by CLS - consists of just twenty five NEWLINEs. When the memory is bigger than a clear screen is padded out with 24*32 spaces & on the whole it stays at its full size; SCROLL, however, & certain conditions where the lower part of the screen expands to more than two lines, can upset this by introducing short lines at the bottom.

The variables have different formats according to their different natures.

Number whose name is one letter only:

Number whose name is longer than one letter:

Array of numbers:

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

& 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, & so on down to the last.

As an example, the elements of the 3 x 6 array B in chapter 22 are stored in the order

B(1,1),B(1,2),B(1,3),B(1,4),B(1,5),B(1,6),B(2,1),B(2,2),...,B(2,6),B(3,1),B(3,2),...,B(3,6).

Control variable of a FOR-NEXT loop:

String:

Array of characters:

The part string at E_LINE contains the line being typed (as a command, a program line, or INPUT data) & also some work space.

The calculator is the part of the BASIC system that deals with arithmetic, & the numbers on which it is operating are held mostly in the calculator stack.

The spare part contains the space so far unused.

The machine stack is the stack used by the Z80 chip to hold return addresses & so on.

The GOSUB stack was mentioned in chapter 14.

The space for USR routines has to be set aside by you, using NEW as described in the last chapter.

Previous: Chapter 26 Next: Chapter 28


Chapter 28: The system variables

 Chapter 28 - The system variables

The bytes in memory from 16384 to 16508 are set aside for specific uses by the system. You can peek them to find out various things about the system, & some of them can be usefully poked. They are listed here with their uses.

These are called system variables, & have names, but do not confuse them with the variables used by BASIC. The computer will not recognize the names as referring to system variables, & they are given solely as mnemonics for you humans.

The abbreviations in column 1 have the following meanings:

X The variable should not be poked because the system might crash.

N Poking the variable will have no lasting effect.

S The variable is saved by SAVE.

The number in column 1 is the number of bytes in the variable. For two bytes, the first one is the less significant byte - the reverse of what you might expect. So to poke a value v to a two-byte variable at address n, use

POKE n,v-256*INT (v/256)

POKE n+1,INT (v/256)

& to peek its value, use the expression

PEEK n + 256*PEEK (n+1)

Notes | Address | Name | Contents
1 | 16384 | ERR_NR | 1 less than the report code. Starts off at 255 (for - 1), so PEEK 16384, if it works at all, gives 255. POKE 16384,n can be used to force an error halt: 0 [image] n [image] 14 gives one of the usual reports, 15 [image] n [image] 34 or 99 [image] n [image] 127 gives a non-standard report, and 35 [image] n [image] 98 is liable to mess up the display file.
X1 | 16385 | FLAGS | Various flags to control the BASIC system.
X2 | 16386 | ERR_SP | Address of first item on machine stack (after GOSUB returns).
2 | 16388 | RAMTOP | Address of first byte above BASIC system area. You can poke this to make NEW reserve space above that area (see chapter 26) or to fool CLS into setting up a minimal display file (chapter 27). Poking RAMTOP has no effect until one of these two is executed.
N1 | 16390 | MODE | Specified K, L, F or G cursor.
N2 | 16391 | PPC | Line number of statement currently being executed. Poking this has no lasting effect except in the last line of the program.
S1 | 16393 | VERSN | 0 Identifies ZX81 BASIC in saved programs.
S2 | 16394 | E_PPC | Number of current line (with program cursor).
SX2 | 16396 | D_FILE | See chapter 27.
S2 | 16398 | DF_CC | Address of PRINT position in display file. Can be poked so that PRINT output is sent elsewhere.
SX2 | 16400 | VARS | See chapter 27.
SN2 | 16402 | DEST | Address of variable in assignment.
SX2 | 16404 | E_LINE | See chapter 27.
SX2 | 16406 | 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.
S2 | 16408 | X_PTR | Address of the character preceding the [image] marker.
SX2 | 16410 | STKBOT | See chapter 27.
SX2 | 16412 | STKEND | See chapter 27.
SN1 | 16414 | BERG | Calculator's b register.
SN2 | 16415 | MEM | Address of area used for calculator's memory. (Usually MEMBOT, but not always.)
S1 | 16417 | not used |
SX1 | 16418 | DF_SZ | The number of lines (including one blank line) in the lower part of the screen.
S2 | 16419 | S_TOP | The number of the top program line in automatic listings.
SN2 | 16421 | LAST_K | Shows which keys pressed.
SN1 | 16423 |  | Debounce status of keyboard.
SN1 | 16424 | MARGIN | Number of blank lines above or below picture: 55 in Britain, 31 in America.
SX2 | 16425 | NXTLIN | Address of next program line to be executed.
S2 | 16427 | OLDPPC | Line number of which CONT jumps.
SN1 | 16429 | FLAGX | Various flags.
SN2 | 16430 | STRLEN | Length of string type destination in assignment.
SN2 | 16432 | T_ADDR | Address of next item in syntax table (very unlikely to be useful).
S2 | 16434 | SEED | The seed for RND. This is the variable that is set by RAND.
S2 | 16436 | FRAMES | Counts the frames displayed on the television. Bit 15 is 1. Bits 0 to 14 are decremented for each frame set to the television. This can be used for timing, but PAUSE also uses it. PAUSE resets to 0 bit 15, & puts in bits 0 to 14 the length of the pause. When these have been counted down to zero, the pause stops. If the pause stops because of a key depression, bit 15 is set to 1 again.
S1 | 16438 | COORDS | x-coordinate of last point PLOTted.
S1 | 16439 |  | y-coordinate of last point PLOTted.
S1 | 16440 | PR_CC | Less significant byte of address of next position for LPRINT to print as (in PRBUFF).
SX1 | 16441 | S_POSN | Column number for PRINT position.
SX1 | 16442 |  | Line number for PRINT position.
S1 | 16443 | CDFLAG | Various flags. Bit 7 is on (1) during compute & display mode.
S33 | 16444 | PRBUFF | Printer buffer (33rd character is NEWLINE).
SN30 | 16477 | MEMBOT | Calculator's memory area; used to store numbers that cannot conveniently be put on the calculator stack.
S2 | 16507 | not used |

Exercises

1. Try this program

10 FOR N=0 TO 21

20 PRINT PEEK (PEEK 16400+256*PEEK 16401+N)

30 NEXT N

This tells you the first 22 bytes of the variables area: try to match up the control variable N with the description in chapter 27.

2. In the program above, change line 20 to

20 PRINT PEEK (16509+N)

This tells you the fist 22 bytes of the program area. Match these up with the program itself.

Previous: Chapter 27 Next: Appendix A


Appendix A: The character set

 Appendix A - The character set

This is the complete ZX80 character set, with codes in decimal & 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 are probably aware if you understand these things, certain Z80 instructions are compounds starting with CBh or EDh; the two right hand columns give these.

Code | Character | Hex | Z80 assembler | - after CBh | - after EDh
0 | space | 00 | nop | rlc b |
1 |  | 01 | ld bc,NN | rlc c |
2 |  | 02 | ld (bc),a | rlc d |
3 |  | 03 | inc bc | rlc e |
4 |  | 04 | inc b | rlc h |
5 |  | 05 | dec b | rlc l |
6 |  | 06 | ld b,N | rlc (hl) |
7 |  | 07 | rlca | rlc a |
8 |  | 08 | ex a,af' | rrc b |
9 |  | 09 | add hl,bc | rrc c |
10 |  | 0A | ld a,(bc) | rrc d |
11 | " | 0B | dec bc | rrc e |
12 | £ | 0C | inc c | rrc h |
13 | $ | 0D | dec c | rrc l |
14 | : | 0E | ld c,N | rrc (hl) |
15 | ? | 0F | rcca | rrc a |
16 | ( | 10 | djnz DIS | rl b |
17 | ) | 11 | ld de,NN | rl c |
18 | > | 12 | ld (de),a | rl d |
19 | < | 13 | inc de | rl e |
20 | = | 14 | inc d | rl h |
21 | + | 15 | dec d | rl l |
22 | - | 16 | ld d,N | rl (hl) |
23 | * | 17 | rla | rl a |
24 | / | 18 | jr DIS | rr b |
25 | ; | 19 | add hl,de | rr c |
26 | , | 1A | la a,(de) | rr d |
27 | . | 1B | dec de | rr e |
28 | 0 | 1C | inc e | rr h |
29 | 1 | 1D | dec e | rr l |
30 | 2 | 1E | ld e,N | rr (hl) |
31 | 3 | 1F | rra | rr a |
32 | 4 | 20 | jr nz,DIS | sla b |
33 | 5 | 21 | ld hl,N | sla c |
34 | 6 | 22 | ld (NN),hl | sla d |
35 | 7 | 23 | inc hl | sla e |
36 | 8 | 24 | inc h | sla h |
37 | 9 | 25 | dec h | sla l |
38 | A | 26 | ld h,N | sla (hl) |
39 | B | 27 | daa | la a |
40 | C | 28 | jr z,DIS | sra b |
41 | D | 29 | add hl,hl | sra c |
42 | E | 2A | ld hl,(NN) | sra d |
43 | F | 2B | dec hl | sra e |
44 | G | 2C | inc l | sra h |
45 | H | 2D | dec l | sra l |
46 | I | 2E | ld l,N | sra (hl) |
47 | J | 2F | cpl | sra a |
48 | K | 30 | jr nc,DIS |  |
49 | L | 31 | ld sp,NN |  |
50 | M | 32 | ld (NN),a |  |
51 | N | 33 | inc sp |  |
52 | O | 34 | inc (hl) |  |
53 | P | 35 | dec(hl) |  |
54 | Q | 36 | ld (hl),N |  |
55 | R | 37 | scf |  |
56 | S | 38 | jr c,DIS | srl b |
57 | T | 39 | add hl,sp | srl c |
58 | U | 3A | ld a,(NN) | srl d |
59 | V | 3B | dec sp | srl e |
60 | W | 3C | inc a | srl h |
61 | X | 3D | dec a | srl l |
62 | Y | 3E | ld a,N | srl (hl) |
63 | Z | 3F | ccf | srl a |
64 | RND | 40 | ld b,b | bit 0,b | in b,(c)
65 | INKEY$ | 41 | ld b,c | bit 0,c | out (c),b
66 | PI | 42 | ld b,d | bit 0,d | sbc hl,bc
67 | not used | 43 | ld b,e | bit 0,e | ld (NN),bc
68 | not used | 44 | ld b,h | bit 0,h | neg
69 | not used | 45 | ld b,l | bit 0,l | retn
70 | not used | 46 | ld b,(hl) | bit 0,(hl) | im 0
71 | not used | 47 | ld b,a | bit 0,a | ld i,a
72 | not used | 48 | ld c,b | bit 1,b | i c,(c)
73 | not used | 49 | ld c,c | bit 1,c | out (c),c
74 | not used | 4A | ld c,d | bit 1,d | adc hl,bc
75 | not used | 4B | ld c,e | bit 1,e | ld bc,(NN)
76 | not used | 4C | ld c,h | bit 1,h |
77 | not used | 4D | ld c,l | bit 1,l | reti
78 | not used | 4E | ld c,(hl) | bit 1,(hl) |
79 | not used | 4F | ld c,a | bit 1,a | ld r,a
80 | not used | 50 | ld d,b | bit 2,b | ld d,(c)
81 | not used | 51 | ld d,c | bit 2,c | out (c),d
82 | not used | 52 | ld d,d | bit 2,d | sbc hl,de
83 | not used | 53 | ld d,e | bit 2,e | ld (NN),de
84 | not used | 54 | ld d,h | bit 2,h |
85 | not used | 55 | ld d,l | bit 2,l |
86 | not used | 56 | ld d,(hl) | bit 2,(hl) | im 1
87 | not used | 57 | ld d,a | bit 2,a | ld a,i
88 | not used | 58 | ld e,b | bit 3,b | in e,(c)
89 | not used | 59 | ld e,c | bit 3,c | out (c),e
90 | not used | 5A | ld e,d | bit 3,d | adc hl,de
91 | not used | 5B | ld e,e | bit 3,e | ld de,(NN)
92 | not used | 5C | ld e,h | bit 3,h |
93 | not used | 5D | ld e,l | bit 3,l |
94 | not used | 5E | ld e,(hl) | bit 3,(hl) | im 2
95 | not used | 5F | ld e,a | bit 3,a | ld a,r
96 | not used | 60 | ld h,b | bit 4,b | in h,(c)
97 | not used | 61 | ld h,c | bit 4,c | out (c),h
98 | not used | 62 | ld h,d | bit 4,d | sbc hl,hl
99 | not used | 63 | ld h,e | bit 4,e | ld (NN),hl
100 | not used | 64 | ld h,h | bit 4,h |
101 | not used | 65 | ld h,l | bit 4,l |
102 | not used | 66 | ld h,(hl) | bit 4,(hl) |
103 | not used | 67 | ld h,a | bit 4,a | rrd
104 | not used | 68 | ld l,b | bit 5,b | in l,(c)
105 | not used | 69 | ld l,c | bit 5,c | out (c),l
106 | not used | 6A | ld l,d | bit 5,d | adc hl,hl
107 | not used | 6B | ld l,e | bit 5,e | ld de.(NN)
108 | not used | 6C | ld l,h | bit 5,h |
109 | not used | 6D | ld l,l | bit 5,l |
110 | not used | 6E | ld l,(hl) | bit 5,(hl) |
111 | not used | 6F | ld l,a | bit 5,a | rld
112 | cursor up | 70 | ld (hl),b | bit 6,b |
113 | cursor down | 71 | ld (hl),c | bit 6,c |
114 | cursor left | 72 | ld (hl),d | bit 6,d | sbc hl,sp
115 | cursor right | 73 | ld (hl),e | bit 6,e | ld (NN),sp
116 | GRAPHICS | 74 | ld (hl),h | bit 6,h |
117 | EDIT | 75 | ld (hl),l | bit 6,l |
118 | NEWLINE | 76 | halt | bit 6,(hl) |
119 | RUBOUT | 77 | ld (hl),a | bit 6,a |
120 | / [image] mode | 78 | ld a,b | bit 7,b | in a,(c)
121 | FUNCTION | 79 | ld a,c | bit 7,c | out (c),a
122 | not used | 7A | ld a,d | bit 7,d | adc hl,sp
123 | not used | 7B | ld a,e | bit 7,e | ld sp,(NN)
124 | not used | 7C | ld a,h | bit 7,h |
125 | not used | 7D | ld a,l | bit 7,l |
126 | number | 7E | la d,(hl) | bit 7,(hl) |
127 | cursor | 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 | add a,b | res 1,b |
137 |  | 89 | add a,c | res 1,c |
138 |  | 8A | add a,d | res 1,d |
139 | inverse " | 8B | adc a,e | res 1,e |
140 | inverse £ | 8C | adc a,h | res 1,h |
141 | inverse $ | 8D | adc a,l | res 1,l |
142 | inverse : | 8E | adc a,(hl) | res 1,(hl) |
143 | inverse ? | 8F | adc a,a | res 1,a |
144 | inverse ( | 90 | sub b | res 2,b |
145 | inverse ) | 91 | aub c | res 2,c |
146 | inverse > | 92 | sub d | res 2,d |
147 | inverse < | 93 | sub e | res 2,e |
148 | inverse = | 94 | sub h | res 2,h |
149 | inverse + | 95 | sub l | res 2,l |
150 | inverse - | 96 | sub (hl) | res 2,(hl) |
151 | inverse * | 97 | sub a | res 2,a |
152 | inverse / | 98 | sbc a,b | res 3,b |
153 | inverse ; | 99 | sbc a,c | res 3,c |
154 | inverse , | 9A | sbc a,d | res 3,d |
155 | inverse . | 9B | abc a,e | res 3,e |
156 | inverse 0 | 9C | abc a,h | res 3,h |
157 | inverse 1 | 9D | abc a,l | res 3,l |
158 | inverse 2 | 9E | abc a,(hl) | res 3,(hl) |
159 | inverse 3 | 9F | abc a,a | res 3,a |
160 | inverse 4 | A0 | and b | res 4,b | ldi
161 | inverse 5 | A1 | and c | res 4,c | cpi
162 | inverse 6 | A2 | and d | res 4,d | ini
163 | inverse 7 | A3 | and e | res 4,e | outi
164 | inverse 8 | A4 | and h | res 4,h |
165 | inverse 9 | A5 | and l | res 4,l |
166 | inverse A | A6 | and (hl) | res 4,(hl) |
167 | inverse B | A7 | and a | res 4,a |
168 | inverse C | A8 | xor b | res 5,b | ldd
169 | inverse D | A9 | xor c | res 5,c | cpd
170 | inverse E | AA | xor d | res 5,d | ind
171 | inverse F | AB | xor e | res 5,e | outd
172 | inverse G | AC | xor h | res 5,h |
173 | inverse H | AD | xor l | res 5,l |
174 | inverse I | AE | xor (hl) | res 5,(hl) |
175 | inverse J | AF | xor a | res 5,a |
176 | inverse K | B0 | or b | res 6,b | ldir
177 | inverse L | B1 | or c | res 6,c | cpir
178 | inverse M | B2 | or d | res 6,d | inir
179 | inverse N | B3 | or e | res 6,e | otir
180 | inverse O | B4 | or h | res 6,h |
181 | inverse P | B5 | or l | res 6,l |
182 | inverse Q | B6 | or (hl) | res 6,(hl) |
183 | inverse R | B7 | or a | res 6,a |
184 | inverse S | B8 | cp b | res 7,b | lddr
185 | inverse T | B9 | cp c | res 7,c | cpdr
186 | inverse U | BA | cp d | res 7,d | indr
187 | inverse V | BB | cp e | res 7,e | otdr
188 | inverse W | BC | cp h | res 7,h |
189 | inverse X | BD | cp l | res 7,l |
190 | inverse Y | BE | cp (hl) | res 7,(hl) |
191 | inverse Z | BF | cp a | res 7,a |
192 | "" | C0 | ret nz | set 0,b |
193 | AT | C1 | pop bc | set 0,c |
194 | TAB | C2 | jp nz,NN | set 0,d |
195 | not used | C3 | jp NN | set 0,e |
196 | CODE | C4 | call nz,NN | set 0,h |
197 | VAL | C5 | push bc | sel 0,l |
198 | LEN | C6 | add a,N | set 0,(hl) |
199 | SIN | C7 | rst 0 | set 0,a |
200 | COS | C8 | ret z | set 1,b |
201 | TAN | C9 | ret | set 1,c |
202 | ASN | CA | jp z,NN | set 1,d |
203 | ACS | CB |  | set 1,e |
204 | ATN | CC | call z,NN | set 1,h |
205 | LN | CD | call NN | set 1,l |
206 | EXP | CE | adc a,N | set 1,(hl) |
207 | INT | CF | rst 8 | set 1,a |
208 | SQR | D0 | ret nc | set 2,b |
209 | SGN | D1 | pop de | set 2,c |
210 | ABS | D2 | jp nc,NN | set 2,d |
211 | PEEK | D3 | out N,a | set 2,e |
212 | USR | D4 | call nc,NN | set 2,h |
213 | STR$ | D5 | push de | set 2,l |
214 | CHR$ | D6 | sub N | set 2,(hl) |
215 | NOT | D7 | rst 16 | set 2,a |
216 | ** | D8 | ret c | set 3,b |
217 | OR | D9 | exx | set 3,c |
218 | AND | DA | jp c,NN | set 3,d |
219 | <= | DB | in a,N | set 3,e |
220 | >= | DC | call c,NN | set 3,h |
221 | <> | DD | prefixes instructions using ix | set 3,l |
222 | THEN | DE | sbc a,N | set 3,(hl) |
223 | TO | DF | rst 24 | set 3,a |
224 | STEP | E0 | ret po | set 4,b |
225 | LPRINT | E1 | pop hl | set 4,c |
226 | LLIST | E2 | jp po,NN | set 4,d |
227 | STOP | E3 | ex (sp),hl | set 4,e |
228 | SLOW | E4 | call po,NN | set 4,h |
229 | FAST | E5 | push hl | set 4,l |
230 | NEW | E6 | and N | set 4,(hl) |
231 | SCROLL | E7 | rst 32 | set 4,a |
232 | CONT | 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 | GOTO | EC | call pe,NN | set 5,h |
237 | GOSUB | ED |  | set 5,l |
238 | INPUT | EE | xor N | set 5,(hl) |
239 | LOAD | EF | rst 40 | set 5,a |
240 | LIST | F0 | ret p | set 6,b |
241 | LET | F1 | pop af | set 6,c |
242 | PAUSE | F2 | jp p,NN | set 6,d |
243 | NEXT | F3 | di | set 6,e |
244 | POKE | F4 | call p,NN | set 6,h |
245 | PRINT | F5 | push af | set 6,l |
246 | PLOT | F6 | or N | set 6,(hl) |
247 | RUN | F7 | rst 48 | set 6,a |
248 | SAVE | F8 | ret m | set 7,b |
249 | RAND | F9 | ld sp,hl | set 7,c |
250 | IF | FA | jp m,NN | set 7,d |
251 | CLS | FB | ei | set 7,e |
252 | UNPLOT | FC | call m,NN | set 7,h |
253 | CLEAR | FD | prefixes instructions using iy | set 7,l |
254 | RETURN | FE | cp N | set 7,(hl) |
255 | COPY | FF | rst 56 | set 7,a |


Appendix B: Report codes

 Appendix B - Report codes

This table gives each report code with a general description & a list of the situations where it can occur. In appendix C, a more detailed description of what error reports mean is given under each statement or function.

Code | Meaning | Situations
0 | Successful completion, or jump to line number bigger than any existing. A report with code 0 does not change the line number used by CONT. | Any
1 | The control variable does not exist (has not been set up by a FOR statement) but there is an ordinary variable with the same name. | NEXT
2 An undefined variable has been used.

For a simple variable this will happen if the variable is used before it has been assigned to in a LET statement.

For a subscripted variable it will happen if the variable is used before it has been dimensioned in a DIM statement.

For a control variable this will happen if the variable is used before it has been set up as a control variable in a FOR statement, when there is no ordinary simple variable with the same name.

Any
3 Subscript out of range.

If the subscript is hopelessly out of range (negative, or bigger than 65535) then error B will result.

Subscripted variables
4 | Not enough room in memory. Note that the line number in the report (after the /) may be incomplete on the screen, because of the shortage of memory: for instance 4/20 may appear as 4/2. See chapter 23. For GOSUB see exercise 6 of chapter 14. | LET, INPUT, DIM, PRINT, LIST, PLOT, UNPLOT, FOR, GOSUB. Sometimes during function evaluation.
5 | No more room on the screen. CONT will make room by clearing the screen. | PRINT, LIST.
6 | Arithmetic overflow: calculations have led to a number greater than about 1038. | Any arithmetic
7 | No corresponding GOSUB for a RETURN statement. | RETURN
8 | You have attempted INPUT as a command (not allowed). | INPUT
9 | STOP statement executed. CONT will not try to re-execute the STOP statement. | STOP
A | Invalid argument to certain functions. | SQR, LN, ASN, ACS
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 error B results.

For array access, see also report 3.

RUN, RAND, POKE, DIM, GOTO, GOSUB, LIST, LLIST, PAUSE, PLOT, UNPLOT, CHR$, PEEK, USR

Array access

C | The text of the (string) argument of VAL does not form a valid numerical expression. | VAL
D (i) Program interrupted by BREAK.

(ii) The INPUT line starts with STOP.

At end of any statement, or in LOAD, SAVE, LPRINT, LLIST or COPY.

INPUT

E | Not used
F | The program name provided is the empty string. | SAVE


Appendix C: The ZX81 for those that understand BASIC

 Appendix C - The ZX81 for those that understand BASIC

General

If you already know BASIC then you should not have much trouble using the ZX81; but it has one or two idiosyncrasies.

(i) Words are not spelled out, but have keys of their own - this is dealt with in chapter 2 (for keywords & shifted keys) & chapter 5 (for function names). In the text, these words are printed in BOLD TYPE.

(ii) ZX81 BASIC lacks READ, DATA & RESTORE (but see exercise 3 of chapter 22 concerning this), user-defined functions (FN & DEF; but VAL can sometimes be used), & multi-statement lines.

(iii) The string handling facilities are comprehensive but non-standard - see chapter 21, & also chapter 22 (for string arrays).

(iv) The ZX81 character set is completely its own.

(v) The television display is not in general memory-mapped.

(vi) If you are accustomed to using PEEK & POKE on a different machine, remember that all the addresses will be different on the ZX81.

Speed

The machine works at two speeds, called compute & display mode, & fast mode.

In compute & display, the television picture is generated continuously & computing is done during the blank parts at the top & bottom.

In fast mode, the television picture is turned off during computing, & is only displayed at the end of the program, while waiting for INPUT data, or during a pause (see PAUSE).

Fast mode runs about four times as fast, & should be used for programs with a lot of computing as opposed to output, or when typing in long programs.

Switching between speeds is done with the FAST & SLOW statements (q.v.).

The keyboard

ZX81 characters comprise not only the single symbols (letters, digits, etc.), but also the compound tokens (keywords, function names, etc.; these are printed here in BOLD TYPE) & all these are entered from the keyboard rather than being spelled out. To fit this in, some keys have up to five distinct meanings, given partly by shifting the keys (i.e. pressing the SHIFT key at the same time as the required one) & partly by having the machine in different modes.

The mode is indicated by the cursor, an inverse video letter that shows where the next character from the keyboard will be inserted.

mode (for keywords) occurs automatically when the machine is expecting a command or program line (rather than INPUT data), & from its position on the line it knows it should expect a line number or a keyword. This is at the beginning of the line, or just after some digits at the beginning of the line, or just after THEN. If unshifted, the next key will be interpreted as either a keyword (these are mostly written above the keys), or a digit.

mode (for letters) normally occurs at all other times. If unshifted, the next key will be interpreted as the main symbol on that key.

In both [image] & [image] modes, shifted keys will be interpreted as the subsidiary red character in the top right-hand corner of the key.

mode (for functions) occurs after FUNCTION (shifted NEWLINE) is pressed, & lasts for one key depression only. That key will be interpreted as a function name, these appearing under the keys.

mode for graphics occurs after GRAPHICS (shifted 9) is pressed, and lasts until it is pressed again. An unshifted key will give the inverse video of its [image] mode interpretation; a shifted key will as well, provided that it is a symbol, but if the shifted key would normally give a token, in graphics mode it gives the graphics symbol that appears in the bottom right hand corner of the key.

The screen

This has 24 lines, each 32 characters long, and is divided into two parts. The top part is at most 22 lines, and displays either a listing or program output. The bottom part, at least two lines, is used for inputting commands, program lines and INPUT data, and also for displaying reports.

Keyboard input: this 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 with [image] (shifted 5) or right with [image] (shifted 8). The character before the cursor can be deleted with RUBOUT (shifted 0). (Note:- the whole line can be deleted by typing EDIT (shifted 1) followed by NEWLINE; or, if it is INPUT data, just by typing EDIT.)

When NEWLINE is pressed, the line is executed, entered into the program, or used as INPUT data as appropriate, unless it contains a syntax error. In this case the symbol [image] appears just before the error.

As program lines are entered, a listing is displayed in the top half of the screen. The manner in which the listing is produced is rather complicated, and explained more fully in chapter 9, exercise 6. The last line to be entered is called the current line and indicated by the symbol [image], but this can be changed using the keys [image] (shifted 6) and [image] (shifted 7). If EDIT (shifted 1) is pressed, the current line is brought down to the bottom part of the screen and can be edited.

When a command is executed or a program run, the screen is first of all cleared, & then output is displayed in the top half of the screen and remains until a program line is entered, or NEWLINE is pressed with an empty line, or [image] or [image] is pressed. In the bottom part appears a report of the form m/n where m is a code showing what happened (see appendix B), & n is the number of the last line executed - or 0 for a command. The report remains until a key is pressed (and indicates [image] mode).

In certain circumstances, the SPACE key acts as a BREAK, stopping the computer with report D. This is recognized

(i) at the end of a statement while a program is running,

(ii) while the computer is looking for a program on tape,

or (iii) while the computer is using the printer (or by accident trying to use it when it is not there).

The BASIC

Numbers are stored to an accuracy of 9 or 10 digits. The largest number you can get is about 1038, & the smallest (positive) number is about 4 * 10-39.

A number is stored in the ZX81 in floating point binary with one exponent byte e (1 [image] e [image] 255), & four mantissa bytes m (½ [image] m [image] 1). This represents the number m * 2e-128.

Since ½ [image] m [image] 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.

Zero has a special representation in which all 5 bytes are 0.

Numeric variables have names of arbitrary length, starting with a letter and continuing with letters and digits. All these are significant, so that for instance LONGNAME & LONGNAMETOO are distinct names. Spaces are ignored.

Control variables for 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 arbitrarily many dimensions of arbitrary size. Subscripts 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 arbitrarily many dimensions of arbitrary size. The name is a single letter followed by $ and may not be the same as the name of a string. All the strings in a given array have the same fixed length, which is specified as an extra, final dimension in the DIM statement. Subscripts start at 1.

Slicing: Substrings of strings may be specified using slicers.

A slicer can be

(i) empty

or

(ii) numerical expression

or

(iii) optional numerical expression TO optional numerical expression

& is used in expressing a substring either by

(a) string expression (slicer)

or by

(b) string array variable (subscript,...,subscript, slicer)

which means the same as

string array variable (subscript,...,subscript)(slicer)

In (a), suppose the string expression has the value s$.

If the slicer is empty, then 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 mth 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), & the second, n (the default value is the length of s$).

If 1 [image] m [image] n [image] the length of s$ then the result is the substring of s$ starting with the mth character & ending with the nth.

If 0 [image] n [image] 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).

The argument of a function does not need brackets if it is a constant or a (possibly subscripted or sliced) variable.

Function | Type of operand (x) | Result
ABS | number | Absolute magnitude.
ACS | number | Arccosine in radians. Error A if x not in the range -1 to +1.
AND | binary operation, right operand always a number | Numeric left operand: A AND B = A if B [image] 0, 0 if B = 0 String left operand: A$ AND B = A$ if B [image] 0, "" if B = 0
ASN | number | Arcsine in radians. Error A if x not in the range -1 to +1.
ATN | number | Arctangent in radians.
CHR$ | number | The character whose code is x, rounded to the nearest integer. Error B if x not in the range 0 to 255.
CODE | string | The code of the first character in x (or 0 if x is the empty string).
COS | number (in radians) | Cosine
EXP | number | ex
INKEY$ | none | Reads the keyboard. The result is the character representing (in [image] mode) 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 [image] 0
NOT | number | 0 if x [image] 0, 1 if x = 0. NOT has priority 4.
OR | binary operation, both operands numbers | A OR B = 1 if B [image] 0, 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 not in the range 0 to 65535.
PI | none | (3.14159265..)
RND | none | The next pseudo-random number y in a sequence generated by taking the powers of 75 modulo 65537, subtracting 1 & dividing by 65536. 0 [image] y [image] 1.
SGN | number | Signum: the sign (-1, 0 or +1) of x.
SIN | number (in radians) | Sine
SQR | number | Square root Error B 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 (rounded to the nearest integer). On return, the result is the contents of the bc register pair. Error B if x is not in the range 0 to 65535.
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.
- | number | Negation

The following are binary operations:
+ | Additional (on numbers), or concatenation (on strings).
- | Subtraction
* | Multiplication
/ | Division
** | Raising to a power. Error B if the left operand is negative.
= | Equals*
> | Greater than*
< | Less than*
<= | Less than or equal to*
>= | Greater than or equal to*
<> | Not equal to*
* Both operands must be of the same type. The result is a number, 1 if the comparison holds & 0 if it does not.

Functions & operations have the following priorities:
Operation | Priority
Subscripting & slicing | 12
All functions except NOT and unary minus | 11
** | 10
Unary minus | 9
* , / | 8
+ , - (binary -) | 6
= , > , < , <= , >=, <> | 5
NOT | 4
AND | 3
OR | 2

Statements

In this list,
&alpha; | represents a single letter
v | represents a variable
x,y,z | represent numerical expressions
m,n | represent numerical expressions that are rounded to the nearest integer
e | represents an expression
f | represents a string valued expression
s | represents a statement

Note that arbitrary expressions are allowed everywhere (except for the line numbers at the beginning of a statement).

All statements except INPUT can be used either as commands or in programs (although they may be more sensible in one than the other).

CLEAR | Deletes all variables, freeing the space they occupied.
CLS | (Clear Screen) Clears the display file. See chapter 27 concerning the display file.
CONT | Suppose p/q was the last report with a non-zero. Then CONT has the effect GOTO q if p [image] 9, GOTO q+1 if p = 9 (STOP statement)
COPY Sends a copy of the display to the printer, if attached; otherwise does nothing.

Unlike all other commands, a COPY command does not clear the screen first. There must be no spaces before COPY.

Report D if BREAK pressed.

DIM &alpha;(n1,...,nk) Deletes any array with the name &alpha;, & sets up an array &alpha; of numbers with k dimensions n1,...,nk. Initializes all the values to 0.

Error 4 occurs if there is no room to fit the array in. An array is undefined until it is dimensioned in a DIM statement.

DIM &alpha;$(n1,...,nk) Deletes any array or string with the name &alpha;$, & sets up an array &alpha;$ of characters with k dimensions n1,...,nk. Initializes all the values to "". This can be considered as an array of strings of fixed length nk, with k-1 dimensions n1,...,nk-1.

Error 4 occurs if there is no room to fit the array in. An array is undefined until it is dimensioned in a DIM statement.

FAST | Starts fast mode, in which the display file is displayed only at the end of the program, while INPUT data is being typed in, or during a pause.
FOR &alpha;=x TO y | FOR &alpha;=x TO y STEP 1
FOR &alpha;=x TO y STEP z Deletes any simple variable &alpha;, & sets up a control variable with value x, limit y, step z, & looping address 1 more than the line number of the FOR statement (-1 if it is a command). Checks if the initial value is greater (if step [image] 0) or less (if step < 0) than the limit, & if so then skips to statement NEXT &alpha; at the beginning of a line.

See NEXT &alpha;.

Error 4 occurs if there is no room for the control variable.

GOSUB n Pushes the line number of the GOSUB statement onto a stack; then as GOTO n

Error 4 can occur if there are not enough RETURNs.

GOTO 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. The form 'IF x THEN line number' is not allowed.
INPUT v Stops (with no special prompt) & waits for the user to type in an expression; the value of this is assigned to v. In fast mode, the display file is displayed. INPUT cannot be used as a command; error 8 occurs if you try.

If the first character in the INPUT line is STOP, the program stops with report D.

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 a LET or INPUT statement.

If v is a subscripted string variable, or a sliced string variable (substring), then the assignment is Procrustean: the string value of e is either truncated or filled out with spaces on the right, to make it the same length as the variable v.

LIST | LIST 0
LIST n Lists the program to the television, starting at line n, & makes n the current line.

Error 4 or 5 if the listing is too long to fit on the screen; CONT will do exactly the same again.

LLIST | LLIST 0
LLIST n Like LIST, but using the printer instead of the television.

Should do nothing if the printer is not attached.

Stops with report D if BREAK pressed.

LOAD f Looks for a program called f on tape, & loads it & its variables.

If f = "", then loads the first program available.

If BREAK is pressed or a tape error is detected, then

(i) if no program has yet been read from tape, stops with report D & old program;

(ii) if part of a program has been read in, then executes NEW.

LPRINT ... Like PRINT, but using the printer instead of the television. A line of text is sent to the printer.

(i) when printing spills over from one line to the next,

(ii) after an LPRINT statement that does not end in a comma or a semicolon,

(iii) when a comma or TAB item requires a new line, or

(iv) at the end of the program, if there is anything left unprinted.

In an AT item, only the column number has any effect; the line number is ignored (except that the same error conditions arise as for PRINT if it is out of range). An AT item never sends a line of text to the printer.

There should be no effect if the printer is absent. Stops with report D if BREAK is pressed.

NEW | Starts the BASIC system off anew, deleting program & variables, & using the memory up to but not including the byte whose address is in the system variable RAMTOP (bytes 16388 & 16389).
NEXT &alpha; (i) Finds the control variable &alpha;.

(ii) Adds its step to its value.

(iii) If the step [image] 0 & the value > the limit; or if the step < 0 & the value < the limit, then jumps to the looping line.

Error 1 if there is a simple variable &alpha;.

Error 2 if there is no simple or control variable &alpha;.

PAUSE n Stops computing & displays the display file for n frames (at 50 frames per second) or until a key is pressed.

0 [image] n [image] 65535, else error B. If n [image] 32767 then the pause is not timed, but lasts until a key is pressed.

PLOT m,n Blacks in the pixel ( | m | , | n | ); moves the PRINT position to just after that pixel.

0 [image] | m | [image] 63, 0 [image] | n | [image] 43, else error B.

POKE m,n Writes the value n to the byte in store with address m.

0 [image] m [image] 65535, -255 [image] n [image] 255, else error B.

PRINT ... The '...' is a sequence of PRINT items, separated by commas or semicolons, & they are written to the display file for display on the television. The position (line & column) where the next character is to be printed is called the PRINT position.

A PRINT item can be

(i) empty, i.e. nothing

(ii) a numerical expression.

First, a minus sign is printed if the value is negative. Now let x be the modulus of the value.

If x [image] 10-5 or x [image] 1013, then it is printed using scientific notation. The mantissa part has up to eight digits (with no trailing zeros), & 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, & no trailing zeros after the decimal point. A decimal point right at the beginning is always followed by a zero, so for instance .03 & 0.3 are printed as such.

0 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.

The quote image character prints as ".

Unused characters & control characters print as ?.

(iv) AT m,n

The PRINT position is changed to line |m| (counting from the top, column n (counting from the left).

0 [image] | m | [image] 21, else error 5 if | m | = 22 or 23, error B otherwise.

0 [image] | n | [image] 31, else error B.

(v) TAB n

n is reduced modulo 32. Then, the PRINT position is moved to column n, staying on the same line unless this would involve backspacing, in which case it moves on to the next line.

0 [image] n [image] 255, else error B.

A semicolon between two items leaves the PRINT position unchanged, so that the second item follows on immediately after the first. A comma, on the other hand, moves the PRINT position on at least one place, & after that, however many as are necessary to leave it in column 0 or 16, throwing a new line if necessary.

At the end of the PRINT statement, if it does not end in a semicolon or comma, a new line is thrown.

Error 4 (out of memory) can occur with 3K or less of memory.

Error 5 means that the screen is filled.

In both cases, the cure is CONT, which will clear the screen & carry on.

RAND | RAND 0
RAND n Sets the system variable (called SEED) used to generate the next value of RND. In n [image] 0, then SEED is given the value n; if n = 0 then it is given the value of another system variable (called FRAMES) that counts the frames so far displayed on the television, & so should be fairly random.

Error B occurs if n is not in the range 0 to 65535.

REM ... | No effect. '...' can be any sequence of characters except NEWLINE.
RETURN Pops a line number from the GOSUB stack, & jumps to the line after it.

Error 7 occurs when there is no line number on the stack. There is some mistake in your program; GOSUBs are not properly balanced by RETURNs.

RUN | RUN 0
RUN n | CLEAR, & then GOTO n.
SAVE f Records the program & variables on tape, & calls it f. SAVE should not be used inside a GOSUB routine.

Error F occurs if f is the empty string, which is not allowed.

SCROLL Scrolls the display file up one line, losing the top line & making an empty line at the bottom.

NB the new line is genuinely empty with just a NEWLINE character & no spaces. (See chapter 27).

SLOW | Puts the computer into compute & display mode, in which the display file is displayed continuously, & computing is done during the spaces at the top & bottom of the picture.
STOP | Stops the program with report 9. CONT will resume with the following line.
UNPLOT m,n | Like PLOT, but blanks out a pixel instead of blacking it in.

Previous: Appendix B


A Course in BASIC Programming

CHAPTER 1

INTRODUCTION - READ CHAPTER TWO FIRST!

This book is the user's manual for the ZX-80 personal computer. In it is everything you need to know in order to set up the ZX-80 hardware and to use the ZX-80 BASIC language for writing your own programs.

For most of the book the chapters are grouped in pairs. The first. (odd-numbered) chapter of a pair is purely descriptive and prepares the reader for what is covered in the second (even-numbered) chapter of the pair. The second chapter of a pair is intended to take you through the use of ZX-80 BASIC as painlessly as possible while you're actually sitting at the keyboard.

If you are an experienced BASIC user, you won't need to read very much - probably only chapter 2, the ZX-80 BASIC language summary, and the Index.

If you're less experienced and patient, it's probably best to read through the whole book, chapter by chapter. If you're less experienced but impatient you can skip the odd numbered chapters 3, 5, 7, and 9 (and probably will!).

OK. NOW READ CHAPTER TWO - AGAIN!


A Course in BASIC Programming

CHAPTER 2

GETTING STARTED

This is the most important chapter in the book. It tells you how to connect up and switch on your ZX-80.

The ZX-80 consists of two units:

(1) The computer

(2) The power supply

The power supply used should be 9 volts DC @ 600 mA unregulated, terminated with a 3.5 mm jack plug. The tip of the jack plug must be positive.

DON'T PLUG IN TO THE MAINS SUPPLY YET

Look at the back of the ZX-80 computer. You will see four sockets. Three of these are 3.5 mm jack sockets marked MIC, EAR and POWER. The fourth is a phono socket for the video cable.

The connection diagram shows how to connect up the ZX-80 to the power supply and to a domestic television which will be used to display the output for the ZX-80.

A video cable with a coaxial plug at each end is provided to connect the TV to the computer.

A twin cable with 3.5 mm jack plugs at both ends is provided to connect the ZX-80 to a cassette recorder. Don't worry about this for the moment.

Connect the power supply to the ZX-80 by plugging the 3.5 mm jack plug into the socket marked 9V DC IN (if you do get it in the wrong jack socket you won't damage your ZX-80 even if you switch on the power. It won't work until you get the plug in the right socket, though!)

SEE DIAGRAM

Connect the TV using the coax lead provided. You will have to tune the TV to the ZX-80 frequency, approximately channel 36 on UHF, so check that you can do this - most TV sets either have a continuously variable tuning control or, if they select channels with push-buttons, have separate tuning controls for each channel. If your set is a push-button set select an unused channel (ITV 2, perhaps). Turn down the volume control.

OK - we can't put off the moment of truth any longer!

Switch on the TV.

When it has warmed up...

SWITCH ON THE ZX-80.

Connecting the ZX80

You will be disappointed to see a horrible grey mess on the screen!!

Try tuning in the TV set. At some position of the tuning control the screen will suddenly clear. At the bottom left hand corner of the screen you will see a curious symbol - a black square with a white letter K in it.

If you can't see the K, turn the brightness control up until you can see it; you may find that adjusting the contrast control improves legibility. You may be planning to use your ZX-80 a lot. If so it may be worth considering buying a second-hand black-and-white TV to use with the ZX-80, They can be bought cheaply - in the UK, at least.

STORING PROGRAMS ON TAPE

Before you can store programs on tape you'll have to write a program, The rest of this book is all about writing programs, so the first thing to do is to read on until you've got a program to store...

...and now that you have we can start.

The twin coax cable with 3.5 mm jack plugs is used to connect the tape recorder to the ZX-80. Most cassette recorders have 3.5 mm jack sockets

for MICROPHONE and EARPIECE. If you have one of those, just connect the 3,5 mm jack plugs as shown in the diagram. On other recorders DIN sockets are used. DIN plug to 3.5 mm jack plug connecting leads are available from most Hi-Fi shops. Consult the handbook to find out how to connect up the plug or plugs.

Once you have done this, connect up the cassette recorder to the ZX-80. Set the tone control (if any) to MAX IMUM. Some recorders have separate TREBLE and BASS control. In this case set TREBLE to MAXIMUM, BASS to MINIMUM. Set the volume control to MAXIMUM.

Have you got that program?

Unplug the MIC plug or DIN plug from the recorder and use the recorder's microphone to record the program's title; if you haven't recorded your voice saying the program's title, you will have trouble in finding programs when you've got a lot of them on tape. Stop the recorder. Reconnect the plug to the recorder. Get into command mode. Start recording and then type SAVE (E key) and NEWLINE.

The screen will go grey for about 5 seconds, then you'll see a series of horizontal streaks

across the screen. After a few seconds the screen will clear and will show the program listing.

You will want to check that the program has been SAVED. Unplug the EAR plug. Rewind the tape until you get back to your voice. Now play back. You will hear your title, then you may (or may not) hear a short buzz followed by about 5 seconds of silence. You will then hear a peculiar sound, rather like a supercharged bumble bee. This is the program being played back via the loudspeaker. After a while the sound will change to a loud buzz. Rewind until you are at the beginning of the 5 second silence. Reconnect the EAR plug. Start playing back and then type LOAD (W key) NEWLINE. The screen will go grey or black and after a few seconds it may start looking grey but agitated. After a few more seconds the screen should clear to show a listing of the program.

Note: when you SAVE a program y.ou also SAVE all the data and variables. You can avoid deleting these (RUN clears them) by using the command GO TO 1.

If it doesn't, use BREAK (SHIFT SPACE) to stop LOADING. If this doesn't work, unplug the power from the ZX-80 for a few seconds. Try repeating the procedure using different

volume control settings. If this doesn't work, are you using the cassette recorder on mains power? Try again using battery power. If this fails, check the wiring to MIC and EAR.

On the ZX-80 some cassette recorders will not work properly with both jacks plugged in at the same time. You can usually tell if yours is one of these by observing that there is a signal (self oscillation) during the 5 second "silence". To SAVE on these recorders you should connect only from the computer to the cassette recorder external MIC socket. To LOAD connect only from the computer to the cassette recorder EAR socket.

Good luck!


A Course in BASIC Programming

CHAPTER 3

NOT SO BASIC

Nearly all digital computers (such as the ZX-80) talk to themselves in binary codes. We talk to each other in English. This means that either we have to learn binary codes, or we have to teach the computer English. Binary codes are about as difficult to learn as Chinese, but it can be done. Forty years ago you had to learn them if you wanted to use a digital computer at all. But why should we do the work when we‘ve got a computer to do it for us?

So we teach the computer English. There is a snag, though. Computers, so far, aren’t bright enough to learn English, something which a child of two does relatively easily. This is mainly because we have so many words and ways of saying things in English. A computer would have to learn every single one. We have to compromise half-way between binary and English. Sometimes we compromise at a low level by using assembly codes which are more like binary than English. Sometimes we compromise at a high level by using languages such as ALGOL, PL/1, PASCAL, FORTRAN, and BASIC. These languages are much closer to English than binary. The ZX-80 uses BASIC because it is easy to learn and more than adequate for most purposes. BASIC stands

for Beginner's All-purpose Symbolic Instruction Code and was devised at Dartmouth College, New Hampshire in 1964 as a simple beginners' programming language. Although it was intended just for beginners, it has since become one of the most widespread and popular high level languages. This isn't very surprising when you think about it, because even scientists and engineers prefer to concentrate on science and engineering instead of trying to talk to computers in complex and difficult languages.

Like English, BASIC has a variety of dialects, depending on which computer is being used. The ZX-80 BASIC differs from other BASIC's in some respects. These differences are listed in the appendix "Summary of ZX-80 BASIC" at the end of this book.

As we said before, computers aren't that bright. We have to tell them exactly what to do by giving them a step-by-step list of instructions. This is called a program. Each instruction must be given in a clear and un-ambiguous way - the syntax must be right (in ZX-80 BASIC the computer will tell you if it thinks that the syntax is wrong before you can run the program. Some BASIC'S wait until you’ve tried to run the program before they say "nuts!"), Even if the

syntax is right, the computer will be confused if you give it a badly thought out list of instruc-tions. Chapters 5 and 7 give some ideas for making sure that you’re telling the computer to do the right things in the right order.

STATEMENTS AND COMMANDS

ZX-80 BASIC allows you to use 22 instructions or statements.

These are divided into several categories.

1. System commands:

NEW - Clears ZX-80 ready for a new

program

RUN - Runs the current program

LIST - Lists the current program

LOAD - Loads a program from tape

SAVE - Saves a program on tape

2. Control statements:

GOTO

IF... THEN...

GOSUB

STOP

RETURN

FOR... TO

NEXT

CONTINUE

These statements allow the programmer to control the order in which instructions are carried out. They are described in detail in chapters 7 - 10.

3. Input/Output statements;

PRINT - allows computer to output data

INPUT - allows user to enter data

I/0 statements provide a means for getting data into and out from BASIC programs.

4. Assignment statement;

LET...=...

This versatile statement is used whenever an arithmetic operation is to be performed.

5. Other statements:

CLEAR - clears the stored values of

variables

CLS - clears the screen

DIM - sets the size of an array

REM - indicates that what follows is a

remark

RANDOMISE - sets up random number

generator

POKE - allows user to talk to the com-

puter in binary code

There are some normal BASIC statements which are not included in ZX-80 BASIC. These are:

READ

DATA

RESTORE

END

ON

Nearly everything that can be done by using these statements can be done in ZX-80 BASIC by using other statements. (The END statement is not needed at all in ZX-80 BASIC).

In a BASIC program all statements or lines are preceded by a statement number or line number which labels that particular line. Line numbers can vary between 1 and 9999. The computer carries out, or executes, statements in the order in which they are numbered. It makes life easier by always displaying programs in order of increasing statement numbers, so that the order in which the program is listed is also the order in which it would be executed.

VARIABLES

All the pieces of information stored in the computer for use in a program are labelled so that the computer can keep track of them, Each piece of information, or variable, has a name.

There are two sorts of variable:

1. Numbers (integer variables) which can take

any whole number value from - 32768 to

32767 inclusive. Example: 142

2. Strings which can be any sequence of any

characters (except " ) of any length.

Example: "AROUND THE WORLD IN 80

DAYS"

Integer variables have names which must always start with a letter and only contain letters and digits.

Integer variable names can be any length, so if you wish the name could be a mnemonic for the variable.

Some allowable variable names for integer variables are:

A A2 AB AB3 ANSWER A4X

Y Y8 YZ YZ9 FREDBLOGGS (N.B. no

space).

AAAA Z123ABC QTOTAL

Some illegal names are:

4 4 4AD (name must start with a

letter)

FRED BLOGGS (space not allowed)

A.B(other characters not

allowed)

FRED-BLOGGS (not a variable, but two

variables, one subtracted from the other)

String variables have names of the form: letter $

The dollar sign tells you (and the computer) that the variable is a string variable. Because only one letter is allowed, this means that you can only have up to 26 string variables in a program.

Some allowable names for string variables:

A$ P$ X$

Some illegal names:

2$ (name must start with letter)

A2$ (too many characters)

AC$ (too many characters)

All this may seem a little daunting at first. The good news is that, like so many things, it's easier than it sounds.

Notes: (1) Arrays must have a name consisting

of a single letter.

(2) Control variables (see Chapter 10)

must have a name consisting of a

single letter.


A Course in BASIC Programming

CHAPTER 4

TALKING TO THE ZX-80

ZX80 keyboard layout

The Keyboard

LET'S TALK

Set up the computer as described in chapter 2 and switch on. You will see a [image] sign appear at the bottom left hand corner of the screen. This is the cursor and shows you where you are on the screen.

THE KEYBOARD

If you look at the keyboard you will see that it looks quite like a typewriter keyboard but there are some differences. There is no carriage return key (instead there's a key called NEW LINE) and the space bar is replaced by a key labelled SPACE. All the letters are upper case (capitals) so that if you use the SHIFT key you get the symbol printed on the top right hand corner of the key. You'll also notice that quite a lot of keys have labels above them - such as NEW above the Q key. These will save you a lot of time from now on.

One vital point: it is very important to dis-tinguish between the letter 0 and figure 0 or Zero. In the book we will use 0 to mean letter 0 and Ø to mean zero. On the screen the com-puter uses' a square O [ [image]] for letter O and a

hexagonal 0 [ [image]] for zero. (The reason that we've used Ø in the book is because it is easier for printing and because all other books on programming use it).

SINGLE-KEY KEYWORD SYSTEM

Hit the Q key. Amazing! The computer writes NEW on the screen. Now hit NEWLINE. You have cleared the computer ready to accept a new program. This illustrates the single-key keyword system. Most of the words you'll have to use with ZX-80 BASIC can be typed with only one keystroke in this way. In all this may save you up to 40% of the typing you'd otherwise have to do. Some BASIC's allow you to use single key-strokes to input words like NEW, PRINT, RUN etc but only the ZX-80 prints out the word in full. This makes it much easier to keep track of what's going on in programs. You'll see how it works as you go along.

The labels above the numeral keys - NOT, AND etc - are not keywords. They are called tokens and, when needed, are obtained by using the SHIFT key. This also applies to EDIT on the NEWLINE key.

Getting data in and out of the ZX-80 computer.

The PRINT. statement allows you to get data out of the computer. This can be done while a program is running - or afterwards.

Type exactly: 100 "THIS IS A STRING"

using SHIFT Y for"

That should have come out as

10 PRINT "THIS IS A STRING"

The computer provided the word PRINT, as well as the space between 10 and PRINT. Did you notice what happened to the [image] cursor? First of all, it followed what you were typing in, appearing just after the last character typed. After PRINT it changed to a [image] sign - this showed that the computer was not expecting any more single-key keywords just then. After you typed " you may have noticed that another character appeared as well - a [image] sign. What was actually on the screen was

10 PRINT "

This S is the syntax error marker and occurs if there is a syntax error in the line being typed in. In this case it came up because the line needs the closing quotation marks if it is to be

correct. The [image] followed the cursor as you typed in THIS IS A STRING and vanished when you typed the second ". Now erase the " by using the RUBOUT key. The [image] reappears. Try hitting the NEWLINE key - nothing happens because the computer won't accept a line containing a syntax error.

Type " and hit the NEWLINE key.

The computer accepts the line and displays it at the top of the screen together with a [image] cursor which shows that it is the last (and in this case the first) line entered. The [image] points to the current line.

Although there is only one line entered it is a program consisting of only one instruction. Type R (RUN) and NEWLINE and the program will run - after a brief flicker on the screen the words

THIS IS A STRING

appear at the top of the screen. At the bottom you'll see 0/10 which tells you that the program ran successfully with no errors.

Type any key to get back into command mode.

What the computer did was to print all the -characters between the quotation marks. Any

character (except for quotation marks) is legal when PRINT is used in this way.

In general this form of the PRINT statement is useful for things like titles which only have to be printed once in a program. There are other forms which allow more complicated things to be done; you'll come across these the whole way through this book.

Now let's try getting some data into the com-puter. This is done by using the INPUT statement, which is basically of the form:

INPUT variable name.

Hit NEW (key Q) and NEWLINE. This tells the computer that a new program is being entered.

Type in the following program, using NEWLINE at the end of each line. (If you make a mistake, use SHIFT 0 (RUBOUT) to delete the mistake; every time you hit RUBOUT the character, keyword, or token to the left of the cursor is deleted).

10 PRINT "ENTER YOUR STRING"
20 INPUT A$            (A$ is the name of a
                              string variable)
30' PRINT A$           (You can use PRINT to
                              print out a variable)

Now run the program by typing RUN (key R) and NEWLINE.

The computer responds with

ENTER YOUR STRING

" [image] "

and waits. The "L" means that it is waiting for you to do something; in this case the quotation marks show that is is expecting you to enter a string variable.

Type in a short message or random string of letters (don't use quote marks) and press NEWLINE, The computer prints out what you have just put in, which was a string variable called A$.

Get back into command mode by pressing any key. Try running the program several times using more and more characters in your string. Keep an eye on the cursor. On the 15th line it will vanish. RUBOUT (shift 0) - the cursor will reappear. Now carry on adding characters - the display will gradually get SMALLER as you use up the storage capacity of the processor. Now hit NEWLINE - a 4/20 error message appears. The 4 tells you that the ZX-80 ran out of space to put the string variable into, and the 20 tells you that this happened at line 20 of the program.

Get back into command mode.

You may have wondered why the line numbers have been 10, 20, 30 instead of (say) 1, 2, 3.

This is because you may want to add bits to the middle of your program.

For instance, enter

22 PRINT "ENTER A NUMBER"
24 INPUT A
40 PRINT A

The program displayed at the top of the screen now reads

10 PRINT "ENTER YOUR STRING"
20 INPUT A$
22 PRINT "ENTER A NUMBER"
24 INPUT A
30 PRINT A$
40 PRINT A

because the computer always sorts out the lines in numerical order. By leaving gaps between line numbers you can always do this. It also makes it easy to see how you've altered the program since the original lines will have line numbers in multiples of 10 (unless the lines were added at the end of the program, like statement 40). Now try running the program again.

FIRST it asks you for a string, Enter a string.

THEN it asks you for a number. Notice that when the ZX-80 is waiting for you to enter a number it displays [image] [image] and not " [image] ". Enter a number.

FINALLY it prints out what you put in.

In chapter 3 the difference between string variables and integer variables is mentioned. The program has two variables in it - a string variable A$ and an integer variable A. How does the computer react when you give it a different sort of variable to the one that it's expecting?

Easy enough to find out - just run the program again. When the computer asks you for a string, give it a number. What happened? It was accepted - numbers are acceptable inside strings. Now - when it asks you for a number, type in a letter. Nothing much happened except that 2/24 appeared at the lower left hand corner of the screen. This is another error code. The 2 stands for the type of error - VARIABLE NAME NOT FOUND - because the computer knew that the letter was the name of an integer variable and you hadn't assigned a value to it. The 24 stands for the line number at which the error was found.

EDITING PROGRAMS

Suppose that you want to alter something in a program that you've already entered. (This is called editing a program.)

It's easy on a ZX-80.

Get into command mode.

Look at the listing at the top of the screen. The cursor (current line pointer) is at line 40. Now see what happens when you hit SHIFT 7 ( [image]) a few times - the cursor moves up line by

line. SHIFT 6 ( [image]) moves it down line by line.

These keys allow you to select any line in your

program to edit.

A further key, HOME (SHIFT 9) sets the line pointer to line 0. Because there isn't a line 0 the cursor will vanish if you use HOME - but when you hit SHIFT 6 the cursor will jump to the next line -,in this case line 10 - and reappear.

Select a line - line 22 for example.

Now hit SHIFT NEWLINE, Line 22 (or any other one you might have selected) appears at the bottom of the screen.

Try SHIFT 8 ( [image]) - you'll see the cursor jump past PRINT. SHIFT 5 ( [image]) moves the cursor left,

to where it was before. Try moving the cursor right a few times - say to the position after ENTER. Now type a few A's - they are inserted into the string to the immediate left of the cursor. A few RUBOUTS and you can erase them again.

This editing facility is very useful if you want to alter individual characters within lines. However, if you want to delete a whole line it would be rather tedious to go through the procedure mentioned above. There is a simpler way to delete lines, though.

Type the line number, then NEWLINE - and you'll see the line vanish from the listing at the top of the screen. The cursor > will also vanish. It will not reappear until you type a new line, use the control keys Ø and g, or use the LIST command.

THE LIST COMMAND

As you get more experienced with the ZX-80 you'll want to write programs longer than the 24 lines which will fit onto the screen. This could pose a problem - or could it? We can find out by writing a really long program.

Type NEW then NEWLINE.

Enter the following program (which prints a large number of blank lines).

  10 PRINT
  20 PRINT
  30 PRINT
  40 PRINT
...and so on to...
230 PRINT (keep an eye on the listing in
              the upper part of the screen)
240 PRINT
250 PRINT
260 PRINT

We seem to have lost the first few lines. Or have we?

Hit LIST (key A) fallowed by NEWLINE - the program is now displayed from line 10 down.

Now try LIST 200 - the program is displayed from line 200. You can list the program starting from any line you want in this way. Notice that the current line cursor is altered to the line you selected.

Try using the up/down cursor control keys - go on hitting the [image] key and see what happens.

In this way you can display any part of the program you want.

By now you will have realised that the ZX-80 has some powerful (and very convenient) facilities to help you write programs.

From now on we can concentrate on how to write programs which actually do something - like solving arithmetic problems, for instance.


A Course in BASIC Programming

CHAPTER 5

SO YOU’VE GOT PROBLEMS

People are very good at disentangling confused instructions and solving complex problems. A computer isn't - all it can do is to follow a list of instructions and carry out the instructions as it comes to them.

As an example, take the following instructions which a mother might give to her child:

"Could you run down to the shop and buy some bread? Take 50p which is in my purse on the kitchen table. And for goodness sake get dressed!"

It all seems quite clear; the child knows where to go, what to buy and where the money is.

A computer controlled robot would take the first instruction:

run down the shop, and do that.

The second instruction: buy some bread. It can't do that (no money) and at this stage would probably just stop, baffled.

The third instruction: take 50p from the purse, it can't do that.

The fourth instruction: go to the kitchen table. It returns home and goes to the kitchen table.

Then the fifth instruction: get dressed. It gets dressed.

A child would instinctively carry out the instruc-tions in the following order:

1. Get dressed

2. Go to the kitchen table

3. Take 50p from the purse

4. Go to the shop

5. Buy some bread

He or she would come back home!

The mother in this example missed out one vital instruction ("come home") as well as putting the instructions in an illogical order. Children use commonsense to interpret complex instructions, but computers can't do this. You have to do all the thinking in advance when you use a computer. So remember:

One way of making sure that you are thinking straight is by drawing a flow diagram before you start to do any actual programming. This helps you get things,in the right order to begin with.

The flow diagram for the example above would look like this:

Each box contains an instruction, and the arrows show the order in which the instructions are executed. Well, that looks pretty simple and neat. Now that the flow diagram is drawn on paper we can check it by going through the boxes one by one and asking ourselves: Can the child (or the computer) do this?

Starting with the first box (get dressed) we might think that it's pretty basic. On the other hand, the child may not be able to find his clothes because his naughty sister has thrown them out of the bedroom window. Perhaps we should add

an instruction (find clothes) at the beginning of the program.

Go to the kitchen table: well, that looks OK.

Take 50p from purse: what happens if the purse is empty?

Go to the shop: does the child know where the shop is?

Buy some bread: what sort?

Return home: nothing much wrong with that!

Maybe the flow diagram wasn't as good as we thought. Even simple tasks can turn out to be more complicated than we think.

Most of the problems which we've spotted are due to a lack of information and this can be coped with by adding extra instructions at the beginning of the program. These could include:

1. Ask where the shop is 2. Find clothes

When you are writing programs for the ZX-80 it is particularly important to give the computer all the information it needs before it has to carry out a task. For instance, if you ask it to PRINT a variable the computer must know the value of the variable.

Now for some arithmetic.


A Course in BASIC Programming

CHAPTER 6

FINDING THE ANSWERS

Up to now you've just been getting used to the feel of the computer. Now we‘ll actually use the computer to do a few sums.

THE LET STATEMENT

Nearly all arithmetic operations are done by using the LET statement. It is of the form

LET variable = expression.

In this case the variable (which can have any name you assign to it) is what you want to find out. The expression describes how you want to define the variable.

For instance

LET A = 2+4

variable expression

means "add 2 to 4 and set A equal to the result

(6) ".

You can use other variables: LET A =2+ B

Or

LET A= B+C

One condition: the computer must already know what the values of B and C are before it comes to the LET statement.

The equal sign (=) isn't used in quite the same way it is in ordinary arithmetic or algebra. For instance:

LET J = J+1

Obviously J isn't equal to J + 1. What the LET statement means is:

"Take the existing value of J, add one to it and then set J to this value."

The + sign is called an operator and defines the

operation you wish to be performed. The other

arithmetic operators are:

- (minus)

* (multiply - there is no x sign to avoid

confusion with letter x)

/ (divide)

** (raise to the power)

For the moment we'll leave / and ** out of it.

Here is a program for multiplying two numbers together

10 PRINT "MULTIPLICATION"
20 PRINT "ENTER FIRST NUMBER"
30 INPUT A
40 PRINT "ENTER SECOND NUMBER"
50 INPUT B
60 LETC=A B
70 PRINT "THE ANSWER IS", C

Notice line 70. It's a PRINT statement with a string between inverted commas, but it's got a C added to it. This form allows you to economize on PRINT statements.

Enter the program and try running it, using two quite small numbers - such as 17 and 25.

The computer will come up with the answer:

THE ANSWER IS 425

Run the program a few more times, increasing the size of the input variables. At about 255 x 129 or just a bit larger you will get another error message - 6/60. The 6 is the code for arithmetic overflow because the answer is larger than 32767, which is the largest number the computer can hold as an integer variable.

Now try editing the program so that it does addition instead - just change the " to a + in line 60, You can also try subtraction and check that you get negative numbers when A is less than B.

All fairly straightforward so far.

Now let's try division. Alter line 60 to

60 LET C = A/B

Run the program for A (first number) = 24

B (second number) = 12

The computer will come up with:

THE ANSWER IS 2

Run the program again, this time for A=18 and B=12

THE ANSWER IS 1

??!!

Shouldn't that be 1.5? Well, yes, but the ZX-80 uses integer arithmetic - only whole numbers can be expressed. What the computer does is to do a division normally and the truncate the result towards ZERO. As examples:

ANSWER

2.58       would     become    2
-0.01           "         "           0
212.1          "         "          212
-5941.98      "         "       -5941

This means that you may have to be careful when you use division - it's always fairly accurate when you're dividing a large number by a small number, but may be less accurate when the two numbers are closer together in size.

Luckily there are ways of getting round this problem. For instance, here is a program which will give quotients to 3 decimal places using integer arithmetic only.

10 PRINT "DIVISION PROGRAM"
20 PRINT "DIVIDEND =?"
30 INPUT X
40 PRINT "DIVISOR =?"
50 INPUT Y
60 LET Z = X/Y            Divides X by Y
70 LET R 1 = X - Z * Y      Calculates
                                    remainder
80 LET D1 = 10 * R1/Y       Divides 10 * re-
                                    mainder by Y to
                                    give 1st decimal
90 LET R2 = 10 * R1 - D1 * Y     Calculates 2nd
                                    remainder -
100 LET D2= 10 * R2/Y Divides to give
                                    2nd decimal
                                    place
110 LET R3 = 10 * R2 - D2" Y C‘alculates 3rd
                                    remainder
120 LET D3 = 10 * R3/Y Last decimal
                                    place
130 PRINT "THE ANSWER IS ";Z;".";
D1;D2; D3

This program does a long division in exactly the same way as we would do it on paper.

Try running it!

Notice the PRINT list in line 130 - it contains several literal strings and variables separated by semicolons. The semicolons tell the ZX-80 that each thing to be printed must be printed immediately after the preceding item, without spaces between them.

Also notice the LET statements from line 70 on. There's no fiddle - you can use more than one operator per statement. There is a snag, though.

Operations are not necessarily carried out in order from left-to-right.

The order in which they are carried out depends on what sort of operations are present in the statement.

Here is a list of priorities for arithmetic operations:

First    A**B  (A to the power B)
Second   -A   (Negation, or multiplication
               by -1)
Third    A*B
Fourth   A/B
Fifth    A+B or A-B

Now for some experiments

10 REM TEST PROGRAM (REM is a key-
word - key Y)
20 PRINT "ENTER A"
30 INPUT A
40 PRINT "ENTER B"
50 INPUT B
60 PRINT "ENTER C"
70 INPUT C
80 LET Z=A+B*C
90 PRINT Z

Try running this with A = 1, B = 2, C = 3 but before you start, use the priority rules to predict what answer the ZX-80 will give: 7 or 9? ‘

0.K. - run it now.

The answer was 7. First the computer multiplied 2 by 3 to get 6, th'en it added 1 to get the final answer.

Try a few other combinations by editing state-ment 80 - like

A BIG

A/B"C (watch out for truncation! )

A"'B (A to the power B - try using small

numbers with C = 0)

-A**B

A* - B

Here's a golden rule: when in doubt either use more than one LET statement and build up that way, or use brackets.

Brackets make life much easier when it comes to complex arithmetic operations.

Take example Z = A/B *C

The normal sequence would be for the computer to evaluate B times C and then divide A by the result.

If we put brackets round A/B thus: 80 LET Z = (A/B)*C

then the computer will carry out the operation within the brackets first, even though it has a lower priority.

A more subtle example is:

Z = A*(B/C)

and

Z = A* B/C

At first sight you would think that these would give the same answer.

Well, they do - sometimes!

Try them both using A = 100, B = 25, C = 5 (the answer is 500) -

Now try it both ways using A = 100, B = 3, C = 5 (the answer should be 60).

What happened when you used the brackets?

Think about it.

The phantom truncator has struck again!

The computer evaluated 3/5 first and truncated it to ZERO - then it multiplied 10 by ZERO and naturally got ZERO as a result.

All this emphasizes that you have to be very much on the alert when you use integer arith-metic for multiplication and division. Multi-plications can cause arithmetic overflow problems (which will cause the program to stop), whilst small numbers used in division may give rise to funny answers which don't give error codes.

If you think that you're going to run into truncation then do multiplications first - on the other hand it may be better to do divisions first to avoid overflow.

That's probably enough arithmetic for now. Let's move on to more interesting things.


A Course in BASIC Programming

CHAPTER 7

DECISIONS, DECISIONS

So far we have only considered problems which can be solved by carrying out a list of instructions, starting at the beginning of the list and working steadily down the list until the last instruction is carried out.

The next four chapters deal with ways in which you can make the ZX-80 (or any computer using BASIC) carry out much more complex programs which can perform many tedious tasks.

In chapter 5 we talked briefly of the use of flowcharts for checking that the program steps were in a logical sequence. This can be useful even for simple programs. When it comes to complex programs flowcharts are vital.

Let's consider a problem we face every day - getting up in the morning. There is a flowchart for getting up on the next page.

The program is said to branch at each decision diamond. As you can see, one feature of branches is that they allow some parts of the program to be skipped if they are not neccessary.

Programs can get difficult to understand if there are a lot of branches, and this is where flow diagrams help.

It is a good idea to keep a pad or notebook handy when you are writing programs and an even better one to draw a flow diagram of your program before you start writing it!

Turn to the next chapter to find out how the ZX-80 can take decisions.


A Course in BASIC Programming

CHAPTER 8

BRANCHING OUT

Before we go on to real decisions lets have a look at the GO TO statement.

This is of the form

GO TO n where n is normally a line number. It can be a variable, though only the ZX-80 BASIC has the power to do this.

When the ZX-80 comes to a GO TO statement it jumps straight to statement number n and executes that statement. If n is a variable - X, say - the computer will look at the value of X and jump to the statement with that number - assuming that there is a statement with that number in your program.

A further refinement of the GO TO statement is that n can be any integer expression such as A/10. Here again, this is possible with the ZX-80.

Here is a program which illustrates the use of GO TO.

10 PRINT "THIS IS STATEMENT 10"
20 GO TO 40
30 PRINT "THIS IS STATEMENT 30"
40 PRINT "END OF PROGRAM"

Now run the program.

The computer responded with

THIS IS STATEMENT 10

END OF PROGRAM

It skipped statement 30. "That's not much use", you must be saying, "what's the point of .including a perfectly good statement which will never be executed?"

OK

Get back into command mode.

Now, type GO TO 30, and then NEWLINE.

The ZX-80 came back with

THIS IS STATEMENT 30

END OF PROGRAM

This demonstrates two uses of GO TO - first to jump unconditionally to an arbitary statement (in this case statement 40); second as a command which causes the computer to jump to the desired statement (in this case 30) and start executing the program from there.

THE IF STATEMENT

This is the most powerful control statement in BASIC. It allows the user to incorporate decision-making into his programs.

Here is a program for calculating square roots approximately. It does this by multiplying, a number by itself, starting with 0 and compar-ing the result with the number whose square root is to be found. If the product is less than the number to be rooted it increases the number by 1 and tries again.

10 PRINT "SQUARE ROOT ROUTINE"

20 PRINT "ENTER THE NUMBER TO BE

ROOTED"
30 INPUT X
40 LET J=0
50 LET K = J*J
60 LETD=X - K
70 IF D = 0 THEN GO (Use SHIFT 3 to
TO 110         get THEN)
80 IF D < 0 THEN GO (< is SHIFT N)
TO 130
90 LET J = J+1
100 GO TO 50
110 PRINT "THE ROOT IS";
120 GO TO 140
130 PRINT " THE ROOT LIES BETWEEN
(J - 1); "AND"; J
140 STOP

See the diagram on the next page.

The form of the IF statement is:

IF (CONDITION TO BE MET) THEN (DOTHIS) 70 IF D = 0 THEN GO TO 110

In line 70 the condition to be met was D = 0 and if this is so then J is exactly the square root of X, so we want to print THE ROOT IS J. In this case (DO THIS) is GO TO 110 which is the number of the PRINT statement we want.

In most BASIC's the only thing you can do in a IF statement is to GO TO a line number. The ZX-80 lets you do other things as well.

In fact it lets you do almost anything!

Some examples:

70 IF D = 0 THEN PRINT "NUTS"

70 IF D = 0 THEN INPUT G

70 IF D = 0 THEN LET A = 10

Any keyword can follow THEN in an IF state-ment - even things like LIST or RUN. The results can be rather peculiar if you use commands such as LIST. The examples listed above can be useful, though.

The condition to be met is (in its simplest version) of the form:

(Expression) (relational operator) (expression) This sounds rather a mouthful!

A relational operator can be:

equal to

less than

greater than

Examples

A = 2 A equal to 2

A< 10 A less than 10

A+B>C+D A+B greater than C+D

In these cases, A, 2, 10, A+B and C+D are the expressions.

The expressions need not be a simple integer or integer variable.

The statement IF A=Z - (Z/B) B THEN GO

TO 10 expression

is quite valid, and so is IF A+B ) C+D THEN GO TO 20

The condition to be met can be even more complex because logical operators can be used.

For example

10 IF NOT A=2 THEN GO TO 100

logical operator

(use SHIFT 1 for NOT)

This NOT operator negates the succeeding condition, so that the ZX-80 will jump to 100 if A does not equal 2.

This program illustrates the use of the AND operator.

10 INPUT A
20 INPUT B
30 INPUT C
40 IF A=1 AND B=1 AND C=1 THEN PRINT

"OK"

Another logical operator

(Use SHIFT 2 for AND)

The condition to be met is that ALL three variables must be 1; if this is so it will print OK. You can chain together as many conditions as you like in this way. Try running this program

page 50

and see if you can make it print OK in any way other than by entering three 1’s.

The other logical operator is the OR operator.

Edit the program by changing the AND'S to OR's (OR is SHIFT B).

When you run the program now you will find that it prints OK as long as one of the numbers entered is a 1.

You can use brackets to group things together.

Consider the following statements:

(a) 40 IF A=1 OR B=l AND C=l THEN

PRINT "OK"

(b) 40 IF (A=1 OR B=1) AND C=l THEN

PRINT "OK"

If you remember, in chapter 6 we said that some operators had priority over others - multiplications were carried out before divisions or additions, for instance. The same applies to logical operators.

Their priority (in descending order) is

NOT

AND

OR

Thus, in (a) B=1 AND C=1 is taken first, so that the computer will print OK if B AND C are 1 'but will also print OK if A=1. The brackets in (b) work in the same way as they did for arith-metic operators. Thus the ZX-80 will print OK if C=1 and either B=l or A=1.

The operators NOT, AND and OR also allow you to produce conditional expressions. For example, if you require

X=3 if A>B

X=Q+R if A=B

X=P if A<8

The obvious way is:

110 IF A>B THEN LET X=3
120 IF A=B THEN LET X=Q+R
130 IF A<B THEN LET X=P

However you could instead write:

110 LET X=A>B AND 3 or A=B AND Q+R

OR A<B AND P

To round off this chapter on branching, here is a program which throws a die. The program uses a useful facility, the function

RND(X)

This generates a random number in the range 1

to X. It occurs in line 120 of the program - in this case X = 6

10 PRINT "DIE THROWING"
20 LET A$ = "  ...  "       is SHIFT A
30 LET B$ = ". .    . ."
40 LET C$ = "   . . . ."
50 LET D$=". . . .   "
60 LET E$=". . . . ."
120 LET X = RND (6)
130 PRINT "YOU THREW..."
140 IF X = 1 THEN G 0 TO 200
150 IF X = 2 THEN GO TO 300
160 IF X = 3 THEN GO TO 400
170 IF X = 4 THEN GO TO 500
180 IF X = 5 THEN GO TO 600
190 IF X = 6 THEN GO TO 700
195 GO TO 1000
200 PRINT E$
205 PRINT E$
210 PRINT B$
215 PRINT E$
220 PRINT E$
230 GO TO 1000
300 PRINT C$
305 PRINT E$
310 PRINT E$
315 PRINT E$
320 PRINT D$
330 GO TO 1000
400 PRINT D$
405 PRINT E$
410 PRINT B$
415 PRINT E$
420 PRINT C$
430 GO TO 1000
500 PRINT A$
505 PRINT E$
510 PRINT E$
515 PRINT E$
520 PRINT A$
530 GO TO 1000
600 PRINT A$
605 PRINT E$
610 PRINT B$
615 PRINT E$
620 PRINT A$
630 GO TO 1000
700 PRINT A$
705 PRINT E$
710 PRINT A$
715 PRINT E$
720 PRINT A$
1000 STOP

It's a bit of a strain to enter this program but it's quite fun to run.

Note that lines 140 to 190 could have been replaced by

140 GO TO (X+1) * 100

If you want to make the program restart itself try editing the program:

1000 PRINT "HIT NEWLINE TO THROW

AGAIN"

1100 INPUT X$
1200 CLS    (CLS is on key C)

1300 IF X$ = "" THEN GO TO 120

Two points: CLS clears the screen. If you didn't put this in the screen would fill up after 3 goes and the program would stop, giving an error message such as 5/305 (run out of screen at line 305).

Secondly, the use of a INPUT statement to halt program execution is a useful trick. The string variable X$ is used in statement 1300 when it is tested to see that only NEWLINE has been pressed; any other entry will stop the program (There is nothing between the quotation marks in 1300.)

The reason that there is a IF statement at 1300 rather than a GO TO statement is that, while the ZX-80 is waiting for a string variable to be entered, the BREAK key (SHIFT SPACE) doesn't work, As a result it is difficult to get out of the program except by entering a very long string variable, a variable so long, in fact, that it makes the computer run out of storage space. This is very tedious, so it's better to use the IF statement. Then if you enter any character the program will stop.

(If you do ever get into a situation when nothing you do seems to have any useful effect on the computer, try the BREAK key first. If this has no effect, give in and switch the ZX-80 off for a few seconds. You lose the current program, but

this may be inevitable if you really have got yourself into a fix.)


A Course in BASIC Programming

CHAPTER 9

ITER - WHAT?

Very often we come up against problems which involve repeated operations. The square rooting program in chapter 8 was one example of such a problem, and the program was written so that the computer jumped back to line 50, if the test conditions in statements 70 or 80 were not met, and tried again - and again - until the conditions were met.

Programs of this sort are called iterative. By using iterative techniques it's possible to get the computer to do a lot of work with a very short program.

It's easy to make a program iterative - all you have to do is to put a GO TO statement at the end of the program to jump the computer back to the first statement (or any other suitable statement). One snag is that such iterative programs can get stuck in endless loops.

One way to avoid this is to allow the computer to go round only a set number of times. One way of doing this would be to use IF and GO TO statements.

Consider the following program which prints $ 152 times.

10 LET J= 1
20 PRINT "$";
30 IF J = 152 THEN GO TO 60
40 LET J = J+1
50 GO TO 20
60 STOP

First the program sets J (the loop control variable) to 1. Then it prints $. Then it tests to see if J = 152. It isn't and so the computer goes on to line 40 which increments the value of J by 1 to 2. The computer passes on to 50 which tells it to jump back to 20. This process goes on until J = 152 when the IF statement is satisfied and the computer jumps out of the loop to line

60.

The arrows on the program help you to see where the program is going; for short programs this is quicker than drawing a flow diagram and does make it easier to see what the program is doing.

The program took 5 lines (if you don't count the STOP statement, which doesn't actually do anything - it just serves as a target for the GO TO in line 30.

Loops are so useful that you'd have thought that there was an easier way of writing programs using them. Well there is. Turn to chapter 10.


A Course in BASIC Programming

CHAPTER 10

LOOPING THE LOOP

Because loops are so useful some special state-ments have been devised to make it easy to use them.

Program for printing $:

10 FOR J = 1 TO 152 (use SHIFT 4 for TO)

20 P R I NT "$";

60 NEXT J

In chapter 9 it took 5 lines of program to get the same result using IF and GO TO statements.

Note the; after the PRINT statement. This tells the computer to print each $ immediately after its predecessor. Try running this program. It's a pity that one can’t have a dollar bill for each $ sign printed.

In BASIC these loops are normally called FOR loops. They are also widely known as DO loops (because other languages,. such as FORTRAN, use DO instead of FOR).

There is nothing to stop us from putting a loop inside another loop - or putting several loops in:

Add the following lines to the program:

30 FOR I =1TO3
40 PRINT "£"
50 NEXT I

The flowchart for this program is:

You can jump out of a loop at any time. If you do this the loop control variable, will remain at whatever value if had got to when you jumped out. In our case the loop control variables were J for the major loop and I for the minor loop.

Try jumping out of the major loop at J = 100 add:

15 IF J = 100 THEN GO TO 1000

1000 STOP

Run this. You'll see that you get fewer $'s and £'s. Get into command mode.

Now type PRINT J NEWLINE

The computer responds with 100

This shows two things

1. J was l00 when the program jumped out of the loop and stopped.

2. You can use PRINT to find out what state the control variables (or other variable) were in when the program stopped. This is especially useful when you are debugging programs.

If the loop is completed successfully for all values of J up to 152 (in this case) the control variable will be left at 153. This is because the NEXT J statement not only tests the value of J

but also increments J by 1. Some BASIC's allow you to increment the control variable by other amounts, but this isn't possible on the ZX-80 (It’s not a very useful feature anyway.)

All this is quite straightforward.

control variable starting value finis ing value defines what variable you want to use, what value it should start at and at what value of control variable you want to leave the loop.

NEXT J reminds the computer that it is in a loop and tells it what variable it should be testing and (in fact) where it should jump back to if the loop isn't finished.

You can start at any value you like - try starting at J = 100. The computer will go round the loop M - N + 1 times.

DON'T EVER jump into a loop unless you have just jumped out of it - if you do the computer will skip the FOR statement and will get very confused because it won't know what the control variable is, what it should start at and what it should finish at. It will do the best it can but it will probably stop when it gets to the NEXT statement. The error message will be of the form

1/LINE No. where 1 means "no FOR statement to match this NEXT statement", or 2/LINE No. where 2 means "variable name not found".

You can try this by adding to the program:

5 GO T0 20

and running, and then adding

4 LET J = 4

and running (you must say RUN, not GO TO 4).

This will jump the ZX-80 into the major loop and it will stop when it gets to statement 60 (NEXT J) giving the error message 2/60 or 1/60.

In chapter 6 there was a program to divide one number by another to give a quotient to 3 decimal places.

Here is a program to give any number of decimal places. Statement 10 is a remark. The computer disregards REM ‘statements when it executes programs. It's often useful to put comments and remarks into programs so that you can remind yourself what the program does when you look at it, often months later!

10 REM HIGH PRECISION DIVISION 20 PRINT "HOW MANY DECIMAL

PLACES?"

30 INPUT D
40 PRINT "DIVIDEND?"
50 INPUT R
60 PRINT "DIVISOR?"
70 INPUT Y
80 LET Z = R/Y
90 LET R = R - Z"Y
100 PRINT "QUOTIENT IS "; Z; ".";
110 FOR J = 1 TO D
120 LET Z = 10 R/Y
130 LET R = 10*R-Z*Y
140 PRINT Z;
150 NEXT J
(110 to 150 evalu-
 ate successive
 decimal places un-
 til the program has
 produced D decimal
 places

Try running this, first of all with dividend = 1, divisor = 3, D = 100 (say).

Note line 110

110 FOR J =1 to D

The starting and finishing values can be variables. This means that you can control the starting value and finishing value of the loop variable as you wish. The starting and finishing values can also be expressions of the form D/2, (D+1)*5 or indeed any other arithmetic expression.

110 FOR J = D*10 TO D*200 would be quite legal. However, the name of the control variable must be a single letter.

If you do decide to use several FOR loops, one inside the other, be very careful in the way you go about it.

is definitely not all right and could cause major problems. Another good reason for using flowcharts!

One final point: because the control variable is effectively tested and incremented by the NEXT statement the main part of the loop will always be executed at least once regardless of the value of the control variable even if you have jumped into the loop.

SUBROUTINES

A subroutine is a sub-program which may be used once or many times by the program (or main program).

Example:

10 FOR J =1 TO 10

20 GO SUB 1000 (GO SUB is on key V)

30 NEXT J

40 PRINT "END"

900 GO TO 1200

1000 PRINT "SUBROUTINE EXECUTED"

1100 RETURN (RETURN is on key B)

1200 STOP

Statement 20 tells the computer to GO TO the subroutine at line 1000.

This prints:

SUBROUTINE EXECUTED

Statement 1100 tells the computer that the subroutine is finished and that it should return to the main program. The computer then jumps to the line immediately following the GO SUB statement and executes that (in this case: NEXT J).

An example of the use of subroutines is given below: The Chinese Ring Puzzle.

As you will see, one subroutine can call another, or even call itself (this is called recursion),

THE CHINESE RINGS PUZZLE

This is a program which will say what moves are required to remove N rings from the T-shaped loop.

The mechanics of this wire puzzle are not important - roughly speaking one manipulates the rings until they all come off the loop.

For an arbitrary number of rings the rules are as follows:

1. Each ring can be either on the loop or off it.

2. Only one ring may be moved (from on to off

or vice versa) at a time.

3. The first ring may be moved at any time.

4. The ith ring (i>1) may be moved if and only if:

(a) All the rings numbered i-2 or lower are

off.

(b) R ing i-1 is on.

...the rings higher up the loop (number )i) may

be in any state, so:

To remove the first i rings:

1. Remove the first i-Z rings

2. Remove the ith ring

3. Replace the first i-2 rings

4. Remove the first i-1 rings

To replace the first i rings:

1. Replace the first i-1 rings

2. Remove the first i-2 rings

3. Replace the ith ring

4. Replace the first 1-2 rings

CHINESE RINGS (Recursive procedure)

10 INPUT N

20 GO SUB 100

30 STOP

Chinese Ring Puzzle

100 IF N<1 THEN RETURN

120 LET N=N - 2

130 GO SUB 100

140 PRINT N+2; "OFF",

150 GO SUB 500

160 LET N = N+1

170 GO SUB 100

180 LET N = N+1

190 RETURN

500 IF N<1 THEN RETURN 520 LETN=N - 1

530 GO SUB 500

540 LET N=N - 1

550 GO SUB 100

560 PRINT N + 2; " ON",

570 GO SUB 500

575 LET N = N+2

580 RETURN

Your output for the case N = 4 should look like:

2 OFF 1 OFF 4 OFF 1 ON
2 ON 1 OFF 3 OFF 1 ON
2 OFF 1 OFF

The GO SUB statement can be used in conjunction with a variable, e.g.

10 GO SUB G whereupon the computer

will jump to the subroutine at line whose number is the value of G (if there is such a line).

As before, an expression can also be used.

In general it is not a very good idea to use variables or expressions in this way because the program may alter the variable in a way you hadn't foreseen and thus cause problems.


A Course in BASIC Programming

CHAPTER 11

HOW TO PRINT

Up to now we have used the PRINT statement as and when it was needed to print out headings and variables. In fact PRINT is a very versatile statement indeed.

The general form of the PRINT statement is PRINT expression ch expression ch expression ch... and so on.

ch stands for control character and this can be , or ; or nothing at all (at the end of the statement only).

Expressions can be literal strings in quotes, e.g.

"THIS IS A LITERAL STRING"

or string variables such as A$

Alternatively they can be integer variables or arithmetic expressions, e.g.

A2 or B*2/C

The object of using control characters is to be able to control the spacing of the line to be printed. We've already come across the use of; in PRINT statements.

The program

10 LET X=4

20 PRINT "THE ANSWER IS"; X; "UNITS"

expression expression

control

characters

expression

Would print:

THE ANSWER IS4UNITS

The semi-colon (;) makes the computer print out the expressions without any spaces between them. If you want spaces you have to include then in the literal strings to be printed.

The comma (,) is used as a tab. Each display line of 32 characters on the screen is divided into 4 fields each of which is 8 characters in length. Each time the computer comes across a comma in a PRINT statement, it starts printing the next expression at the beginning of the next available field.

The effect of this is to provide a display on the screen in 4 columns. If a string variable or literal string is more than 7 characters long and is followed by a comma the computer uses two or more fields in which to print the string and starts the next expression at the beginning of the third field.

You can add extra commas to skip fields:

PRINT "FIELD 1", "FIELD 2", "FIELD 3"

would produce the output

FIELD 1 FIELD 2 FIELD 3

but

PRINT "FIELD 1",,"FIELD 2", "FIELD 3"

extra comma

would produce

FIELD 1 FIELD 2 FIELD 3

this field skipped

The statement

PRINT "THIS IS A FIELD",,"FIELD1", "FIELD 2"

would produce

THIS IS A FIELD FIELD 1

FIELD 2

The computer used 2 fields for the first string, skipped a field and then continued. It runs out of fields on the first line and has to continue in the first field of the second line.

There is no limit to the number of fields you may skip using commas, (Unless you run out of display area, of course.)

If you use a control character right at the end of a PRINT statement the next PRI.NT statement will obey the control character. For instance

10 X = 4

20 PRINT "THE ANSWER IS ";

30 PRINT X

will produce the output

THE ANSWER IS 4

If no control character occurs at the end of a line the next PRINT statement will start printing on a new line.

The best way of finding out about PRINT is to experiment with it.


A Course in BASIC Programming

CHAPTER 12

COPING WITH CHARACTERS

You will have noticed that, in addition to the normal typewriter characters there are several other characters not usually found on a typewriter. In addition there are some usable characters not written on the keyboard.

Before we go on to investigate what characters can be printed, meet an interesting function:

CHR$(X) where X is a number, integer variable

or expression.

It is used mainly in conjunction with the PRINT statement.

CHR$(X) means "the character whose code is x"

Try this:

10 INPUT X

20 PRINT CHR$(X)

30 GO TO 10

What this program does is to ask for a number and then to print out the character whose code is the number entered. The codes lie between 0 and 255.

A useful program for listing the symbols is given below.

10 PRINT "ENTER CODE VALUE"

20 INPUT X

30 PRINT X; "..."; CHR$(X)

40 PRINT

50 LET X = X+1

60 GO TO 30

This lists 11 symbols together with their codes, starting with the code entered at the start of the program.

Table of characters corresponding to different codes:

Code | Character | Code | Character
0 | space | 14 | :
1 | null string | 15 | ?
2 |  | 16 | (
3 |  | 17 | )
4 |  | 18 | -
5 | graphics | 19 | +
6 |  | 20 | *
7 |  | 21 | /
8 |  | 22 | =
9 |  | 23 | <
10 |  | 24 | >
11 |  | 25 |
12 | £ | 26
13 | $ | 27 |
Code | Character | Code | Character
28 | Ø | 55 | R
29 | 1 | 56 | S
30 | 2 | 57 | T
31 | 3 | 58 | U
32 | 4 | 59 | V
33 | 5 | 60 | W
34 | 6 | 61 | X
35 | 7 | 62 | Y
36 | 8 | 63 | Z
37 | 9 | 64 to 127 | ?
38 | A | 128 | Inverse space
39 | B | 129 | Inverse quote
40 | C | 130 |
41 | D | 131 |
42 | E | 132 |
43 | F | 133 |
44 | G | 134 |
45 | H | 135 |
46 | I | 136 |
47 | J | 137
48 | K | 138
49 | L | 139
50 | M | 140 | INVERSE £
51 | N | 141 | " $
52 | O | 142 | " :
53 | P | 143 | " ?
54 | Q | 144 | " (
Code | Character | Code | Character
145 | Inverse ) | 172 | Inverse G
146 | " - | 173 | " H
147 | " + | 174 | " I
148 | " * | 175 | " J
149 | " / | 176 | " K
150 | " = | 177 | " L
151 | " > | 178 | " M
152 | " < | 179 | " N
153 | " ; | 180 | " 0
154 | " , | 181 | " P
155 | " . | 182 | " Q
156 | " 0 | 183 | " R
157 | " 1 | 184 | " S
158 | " 2 | 185 | " T
159 | " 3 | 186 | " U
160 | " 4 | 187 | " V
161 | " 5 | 188 | " W
162 | " 6 | 189 | " X
163 | " 7 | 190 | " Y
164 | " 8 | 191 | " Z
165 | " 9 | 192 to 211 | ?
166 | " A | 212 | "
167 | " B | 213 | THEN
168 | " C | 214 | TO
169 | " D | 215 | ;
170 | " E | 216 | ,
171 | " F | 217 | )
Code | Character | Code | Character
218 | ( | 237 | POKE
219 | NOT | 238 | INPUT
220 | - | 239 | RANDOMISE
221 | + | 240 | LET
222 | * | 241 | ?
223 | / | 242 | ?
224 | AND | 243 | NEXT
225 | OR | 244 | PRINT
226 | ** | 245 | ?
227 | = | 246 | NEW
228 | < | 247 | RUN
229 | > | 248 | STOP
230 | LIST | 249 | CONTINUE
231 | RETURN | 250 | IF
232 | CLS | 251 | GO SUB
233 | DIM | 252 | LOAD
234 | SAVE | 253 | CLEAR
235 | FOR | 254 | REM
236 | GO TO | 255 | ?

Inverse means that the character appears white on a black background.

Inverse space is a black square, for instance.

The graphics characters are shown on the next page:

CHR$ (X) allows us to print any character we want.

There is a further group of facilities which enables us to handle characters;

These are

(a) TL$ (string)

- this gives the string minus its first character.

The string can be a literal string inside quotes or a string variable.

10 PRINT TL$ ("ABC") would give

BC

10 PRINT TL$(G$) will cut off the first character of string G$

(b) CODE (string)

- this gives the code corresponding to the first character in a string (either a string variable or a literal string)

10 PRINT CODE("ABC")

would print 38 which is the code for A,

An example of the way in which these can be used is the following program which accepts a string and prints it out in inverse video.

10 PRINT "ENTER YOUR STRING"

20 INPUT G$

30 PRINT G$

Table of Graphic Symbols

40 LET X = CODE (G$)

50 LET X = X + 128

60 IF G$ = CHR$ (1) THEN GO TO 100

70 PRINT CHR$ (X);

80 LET G$ = TL$ (G$)

90 GO TO 40

100 STOP

Statement:

40 sets X = code of the first character of G$.

50 adds 128 to the code (this gives inverse of the letters, digits and graphics).

60 test the string to see if it is a null string, i.e. has no characters in it. If it is a null string either the input string was a null string to begin with or all the characters have been converted to inverse video and printed.

70 prints the inverse video character.

80 chops off the character which has just been printed and the program then jumps back to 40 and the code for the next character is extracted. The program goes on until the string has been shortened to the null string.

There is a further function which can be useful. This is:

STR$ (variable or number).

This allows an integer number or variable to be treated as a string variable

10 LET G$ = STR$(1234)

sets G$ = "1234"

10 LET G$ = STR$(X)

does the same thing for an integer variable - if X = 4852 then G$ = "4852".

So far we've not said very much about the graphics symbols. These have been designed so as to double the effective resolution of the display, which gives 23 lines of 32 characters each.

Here is a program which plots TWO bar charts on the same display.

BAR CHART PLOTTER

10 LET X =0

20 PRINT "YZ-AXIS"

30 PRINT "X ="

40 FOR I = 1 TO 21

50 LETY=X

60 LETZ=24 - X

70 PRINT X,

80 FOR J=1TO20

85 IF J)Y AND J=Z THEN PRINT CHR$ (3);

90 IF J>Y AND J>Z THEN GO TO 135

95 IF J=Y AND J>Z THEN PRINT CHR$ (11);

100 IF J<Y AND J<Z THEN PRINT CHR$ (139);

105 IF J<Y AND J=Z THEN PRINT CHR$ (139);

110 IF J<Y AND J>Z THEN PRINT CHR$ (11);

115 IF J=Y AND J<Z THEN PRINT CHR$ (139);

Comment 10-70:

Defines Vari-
ables and
prints titles;
generates Y
and Z

120 IF J>Y AND J<Z THEN PRINT CHR$ (3);

125 IF J=Y AND J=Z THEN PRINT CHR$ (139);

130 NEXT J

135 PRINT

140 LET X = X+1 150 NEXT I

The program prints Z as black bars, Y as grey bars. Statements 80 to 130 determine what graphic symbol is to be used: , [image], [image] or nothing at all.

This program calculates the graphs of Y = X and Z = 24 - X and plots them in bar chart form. As you will see if you run the program it produces a very clear, unambiguous display You can use the same sort of trick to achieve greater resolution along the l inc as well as from I inc to line.

Lines 85 to 125 decide what character will be printed, depending on the relative size of J, Z and Y.

These examples are only scratching the surface when it comes to character manipulation and graphics, The possibilities are almost literally endless.


A Course in BASIC Programming

CHAPTER 13

HELP! OR, WHAT TO DO WHEN DESPERATE

You may occasionally get into difficulties.

These can be divided into two sorts: (a) Problems with the system (b) Problems with your programs.

Most problems with the system are likely to occur when you're entering string variables into your programs. One favourite is deleting the quotation marks round the string by accident. When the computer is waiting for you to enter a string variable it prints " [image] ".

If you enter the wrong string and then use RUBOUT to delete it you may delete one or other of the quotation marks. This will give rise to a [image] syntax error symbol. If you see this check to see that both quotes are there.

If you have written a program which calls for a null string to be entered, and the program is recursive, you may find it very difficult to get out of the program back into command mode, Whatever you enter seems to have no effect! When (or if) this happens delete the quotes using RUBOUT [image] RUBOUT and enter (say) CHR$ (10**6) which causes arithmetic overflow, giving a 6/N error message (when N is the line

number of the INPUT statement reading the string).

Generally speaking the BREAIC key (SHIFT SPACE) is the first thing to resort to, If the program is caught in an endless loop, or if it is LOADing unsuccessfully, the screen will go grey or black for an indefinite period. BREAK will get you back under these conditions.

If BREAK does not work in this situation there is nothing left to do but switch the ZX-80 off for a few seconds and then switch on. You do lose whatever program was in the ZX-80 if you do this.

When it comes to faults in the program it is difficult to offer such specific advice.

Some problems arise if you type an O instead of a 0.

LET J = O would be accepted as a valid program line but would give a 2/N error code (variable not found) when the program was run. This sort of thing can be very difficult to spot. Similarly S and $ do get confused.

When a program stops unexpectedly or does something peculiar it may be difficult to work out exactly what went wrong. It is possible to carry out a post-mortem by using the immediate

PRINT statement to find out what the value of variables (especially loop control variables) was at the time the program stopped.

If you type

PRINT J (or whatever variable you want)

the ZX-80 will print it even after the program has stopped running.

Sometimes there is not room to print the whole of the line number in an error message, particu-larly with error numbers 4 and 5. In this case usually only the first digit of the line number is printed. For example, error 4 on line 250 may cause the message
4/2

Another useful technique is to put STOP statements into programs at key points. When the program reaches the STOP statement it will stop (of course) and you will be able to see how it has performed up to that point, You can then get back into command mode, type CONTINUE (key T) NEWLINE and the program will continue from the STOP statement.

Luckily the ZX-80 is quite choosy about the program lines it will accept and this eliminates many of the problems which can happen with other BASIC's.


A Course in BASIC Programming

CHAPTER 14

A RAGBAG OF FUNCTIONS

This chapter covers all those statements and functions that haven't already been dealt with elsewhere.

RND(X) provides a random number in the

range 1 to X

Typical statement using RND: 10 LET J = RND(X)

sets J equal to a random number

Every time the ZX-80 executes the function RND it uses a random number generator to generate a pseudo-random number. It is called pseudo-random because the numbers occur in a fixed sequence, However, the sequence is very long and hence appears random.

RANDOMISE - sets the starting point of the

sequence to a number equal to the number of frames supplied to the TV since the machine was turned on (unless POKE is used to alter the count, see below).

RANDOMISE n - sets the starting point of the

sequence to n unless n is 0,

when it behaves as RANDOM-ISE.

The RANDOMISE statement allows the random

sequence to be initialised at any time in the program. Typical forms:

10 RANDOMISE 6

10 RANDOMISE

RANDOMISE n (n =/= o) generates a sequence

depending only on the value of n (which will be thesamefromrun to run if n is unchanged).

RANDOMISE generates a different sequence

each time.

One highly useful statement is POKE,

This is of the form

POKE A,B where A is the ADDRESS of a

location in store and B is an expression (the value of which should be less than 256 for sensible results).

Typically A might be the address of one of the two bytes which form the variable which acts as the frame counter. This is demonstrated in the next example program.

Thus:

LET X = PEEK (A) sets X equal to the contents

of address A

PEEK (A) is always less than 256

(in range 0 to 255)

The reason that the variables associated with PEEK and POKE should always be less than 256 (255 is maximum) is that everything in the ZX-80 is stored in 8 bit bytes. Bit is short for Binary digit. The maximum which can be stored in 8 bits is 255, and so all the integer variables use up 2 bytes, which allows numbers up to 32,767 to be stored.

Each half of a variable is stored in one byte, and every byte has an address of its own.

Here is a program which uses PEEIC and POKE to gain access to the TV frame counter.

PEEK/POKE REACTION TIMER

10 FOR I = 1 to 20 RND(100)

20 NEXT I

POKE 16414,0

40 POKE 16415,0

50 PRINT "HIT RETURN"

60 INPUT C$

70 LET A = PEEK (16414)

80 LET B = PEEK (16415)

90 PRINT "YOUR REACTION TIME WAS";

(B*256 + A - 4) *20; "MILLISECS"

16414 and 16415 are the addresses of the two halves of a 16 bit number which counts the frames on the TV - increasing by 1 every 1/50th of a second. Lines 30 to 40 set the count to zero, and the count is stopped when a null string is input to C$. There is a delay on all operations (mainly between pressing the return key and this signal getting to the CPU) of around 80 mS, hence the 4 subtracted from the expression in line 90.

This could have a repeat mechanism tacked on the end, for example:

100 PRINT "DO YOU WANT ANOTHER GO?"

110 PRINT "TYPE Y OR N"

120 INPUT C$

130 IF C$ = "Y" THEN GO TO 10

140 STOP

Another function which allows the user to communicate directly with the ZX-80 is

USR(A) - this calls a machine-code subroutine

at the address A. The value is what-ever the routine leaves in HL (a storage register within the central processor of the ZX-80) or, if the subroutine has not altered HL, the result is A

Typical form: LET J = USR(A)

PEEK, POKE and USR(A) are really facilities provided for very experienced users who under-stand the detailed working of the ZX-80.

CLEAR is a statement which resets all the variables in the program.

Typical form: 10 CLEAR

{RUN automatically clears the variables every-time a program is run.)

And now, last' but not least, DIM. This is of the form

10 DIM A(B) - sets up an array A which

contains B+1 variables.

Each variable is called an element of array A.

Arrays can have any single-letter name and can have any number of elements (providing that there is enough room to store all the elements).

It is possible, though not a good idea, to have a variable and an array with the same name example:

10 LET A =4

20 DIM A(A)

Each element is referred to by its subscript. For instance

B(0) is the first element of array B

B(2) is the third element of array B

B(N) is the (N+1)th element of array B.

Because you can use any integer expression as a subscript it is possible to process array elements easily and quickly.

Here is an example of the use of arrays for character manipulation.

CHEESE NIBBLER

10 DIM A(10)

20 DIM B(10)

30 DIM C(10)

100 FOR J = 1 TO 10

110 LET A(J) = 1

120 LET B(J) = 1

130 LET C(J) = 1

140 NEXT J

200 FOR J = 1 TO 10

205 IF NOT A(J) = 1 THEN GO TO 220

210 PRINT " [image] ";

215 GO TO 230

220 PRINT" ";

230 NEXT J

240 PRINT

300 FOR J=1 TO 10

305 IF NOT B(J) = 1 THEN GO TO 320

310 PRINT " [image] "

315 GO TO 330

320 PRINT" ";

330 NEXT J

340 PRINT

400 FOR J=1 TO 10

405 IF NOT C(J)=1 THEN GO TO 420

410 PRINT " [image] "

415 GO TO 430

420 PRINT" ";

430 NEXT J

440 PRINT

445 PRINT "HIT NEWLINE TO NIBBLE THE

CHEESE"

450 INPUT Y$

460 IF NOT Y$ = " "THEN GO TO 1000

470 CLS

500 LET I = RND(10)

510 LET K = RND(3)

520 IF K = 1 THEN LET A(I) = 0

530 IF K = 2 THEN LET B(l) = 0

540 IF K = 3 THEN LET C(l) = 0

550 GO TO 200

1000 STOP

When typing in a program like this where there are several similar lines the EDIT facility is very useful, because you can edit line numbers.

For example; after entering line 210, type:

EDIT

RUBOUT

3

NEW LINE

Statements 10 to 30 set up 3 arrays, A, B, and C of 10 elements each.

Statements 100 to 140 set all the elements of all arrays to 1.

200 to 240 examine each element of the array A in turn. If an element is equal to 1 a [image] is printed. If an element is not 1 a space is printed.

Similarly for 300 to 340 and 400 to 430.

On the first pass all the elements are set to 1 and

is printed all the way through.

445 to 470 print the instruction and if the user then hits NEWLINE the screen is cleared.

500 to 540 select a random element of a random array to be set to 0.

At 550 the program jumps back to print out all

the arrays. The element which has been set to 0 is printed as a space - or nibble.

As more nibbles are taken there is a greater chance that the element selected will already be 0 and thus the effective nibble rate slows down as the game progresses.

ABS(n) this function gives n if n>=0, and -n if

n<0. n is any integer expression.

e.g. ABS(5) = 5

ABS( - 5) = 5


A Course in BASIC Programming

CHAPTER 15

OVER TO YOU

If you have read all the way through this book, running the programs in it and writing your own, you should be well on the way to becoming a fluent BASIC programmer. Remember, though, that there are many things you can do with ZX-80 BASIC which you can't do using other BASIC's. Equally, some BASIC's have features which are not present in ZX-80 BASIC.

The appendices present a concise summary of the error codes and the ZX-80 BASIC. Section 2 of Appendix 2 is written with experienced users in mind, but most of it does not require a detailed knowlege of the working of the central processor.

From now on it's up to you!


A Course in BASIC Programming

APPENDIX I

ERROR CODES

When results are displayed, a code

n/m

is displayed also: n is the error number, m is a line number in the program

statement | code | meaning
 | 0 | (m = next line that would have been executed) BREAK pressed. (m = - 1 or - 2) Command successfully completed. (m < 0 or ) largest line number in program) GO TO m was executed. (m = largest line number in program) end of program.
NEXT | 1 | * NEXT <id> where <id> is not the control variable of an active FOR loop.
any | 2 | * variable name not found (any variable being used, or array name of an array element being assigned to).
any | 3 | * subscript out of range, or error of any kind while evaluating a subscript.
LET INPUT DIM PRINT | 4 | * no room to add new variable or to assign a longer string to a string variable or to screen.
PRINT | 5 | * no more room on screen.
any | 6 | arithmetic overflow (result > 32767 or < - 32768, also result = - 32768 in some circumstances.
RETURN | 7 | * RETURN with no corresponding GOSUB.
INPUT | 8 | INPUT can only be used in a program, not directly.
STOP | 9 | STOP statement executed. * m = line number of offending statement. CONTINUE is the same as GO TO m, except after code 9 when it is GO TO m+l.


A Course in BASIC Programming

APPENDIX II

4K BASIC FOR ZX-80

1. ZX-80 user's view.
(a) Program Listing

The user inputs via the keyboard, lines of BASIC for insertion into the program and commands for immediate execution. While he is doing this he sees a display which is divided into two parts: the upper part is a "window" on the program listing, while the lower part displays the line or command he is currently outputting. Normally, the lower part is large enough to hold the whole line (which will take more than one screen line if it contains more than 32 characters), there is a blank line between the two parts, and the upper part occupies the remainder of the screen. If, however, there is insufficient RAM to hold a display of this size (each character on screen occupies 1 byte of RAM* ) the upper part of the display will be shrunk line by line until the display file is small enough. When the upper part has disappeared altogether the lower part shrinks character by character.

The computer maintains a "current line number"

* RAM stands for random access memory, or store.

for editing the program and the display is always organised so that the line with that number, or the preceding line if no line with that number exists, is on the screen if at all possible. If there is a line with the current number, it is displayed with a symbol consisting of a reverse video [image] between its line number and the text of the line; if there is none then the reverse video [image] will not appear.

Three keys are provided for changing the current line number: " [image] " changes it to the line number of the preceding line, " [image] " changes it to the line number of the following line, and "HOME" resets it to zero. If there is no preceding line [image] sets it to the line number of the first line in the program; similarly " [image] " will set it to the last line.

There are two other ways which the current line number can change: inserting a line into the program sets it to the line number of that line, and the command "LIST n" will set it to n.

When the current line is off the top of the screen, the window maves up so that it becomes the first line. When it is at or just off th.e bottom the window moves down a line. If it is well beyond the bottom of the window, the window moves down so that it becomes the second line on the screen.

(b) Input area

The lower part of the screen contains the line the user is currently typing in. This line may be a command or a line of program; in the latter case it will begin with a line number (in the range 1 to 9999) and in the former case there should be no number, although zero in practice counts as "no number" here.

Somewhere in the line a "cursor" is displayed. This indicates two things: the position in the line where symbols will be inserted, and whether an unshifted alphabetic key will be treated as a keyword (eg "LIST") or a letter leg "A"). The cursor is in the form of an inverse video [image] for keywords or [image] for letters.

Note that this cursor, although displayed in the line and occupying a character position on the screen, does not form part of the line and is ignored by anything interpreting the line.

A second symbol, similar in principle to the cursor, may also be displayed: this is in the form of an inverse video [image] and indicates that the line is not a syntactically correct BASIC state-ment. It is positioned such that the part to the left of it could be the beginning (or the whole) of a syntactically correct BASIC statement eg if "20 LET A = B + 5"

is input from left to right then. symbol will be displayed at the end of

20 LET and be absent from 2

20 LET A 20

20 LET A= 20 LET A=B

20 LET A=B+ 20 LET A=B+5

In most cases the symbol is displayed as far to the right as is consistent with the above descrip-tion; however there are a few circumstances where this is not quite so, for instance in

LET A=ASC("X")

although "LET A=ASC" is a syntactically correct statement (ASC here being an integer variable) the [image] is not displayed after "ASC" but rather before it. This is because "ASC(...)" has already been identified as a function call, but as no built-in function with the name "ASC" is available it is faulted. Having identified it as a function call, however, the computer does not then consider other possible parses.

The following keys are available to alter the

input line:

(i) single-character symbols: letters, digits,

punctuation, etc the symbol is inserted to

the left of the cursor.

(ii) multi-character "tokens": "**", "AND",

"OR", "NOT", "TO", "THEN" keywords.

Each of these is stored in the computer as a single byte, which, as in (i), is inserted to the left of the cursor. However, they appear on the screen as more than one character. Those that are alphanumeric (ie all except "'") are preceded and followed by a space, the preceding space being omitted (a) at the beginning of the line (b) where it follows another alphanumeric token. (This rule means that programs appear well-laid- out on the screen without using up scarce RAM space for explicit space characters. Inserting an explicit space character before or after an alphanumeric token always inserts one extra space in the displayed form.)

"RUBOUT" deletes the symbol or token

to the left of the cursor,

(iv) cursor control keys " [image] " and " [image] " skip the

cursor past the next symbol or token to the right and left respectively.

(v) "EDIT" replaces the input line with a copy

of the current line from the program. If no line has the current line number, the first line after it is used. If the current line is after the last line in the program, the last line is used. If there are n,o lines of program

at all, then an empty line is used. Note that any existing input line is lost; "EDIT" followed by "NEWLINE" is in fact the quickest way to get rid of an unwanted line, but beware typing "EDIT" in mistake for "NEWLINE"!

(vi) "NEWLINE" is ignored if the inverse video

symbol is present. Otherwise it marks the end of input and the line or command is submitted to the system (see next section). Note that the whole line is sub- mitted, not just the part to the left of the Cursor.

(c) After input

When a line with a nonzero line number is sub-mitted to the system, it is inserted into the program, any existing line with the same number being first deleted. The input area is then cleared. A special case is where the new line consists only of a line number, possibly preceded by spaces: the existing line (if any) is deleted but nothing replaces it and it therefore simply disappears from the listing. The "current line number" is still set to its number, however, so the inverse video [image] disappears also (see (a) above). If the line being inserted has one or more spaces after the line number but no other symbols or tokens,

it is still inserted in the program and appears in the listing as a line which is blank except for its number; when the program is run such lines are ignored.

A line which has no line number, or which has line number zero, is a "command" and is obeyed immediately. For as long as it takes to obey the command (which for most commands is very brief) the screen is blank, then on completion the upper part of the display contains any output generated and the lower part contains a display of the form

m/n

where m is a single digit and n is "-2" for most commands.

If m = 0, execution was successful; if m = 9 a STOP command was executed; otherwise m is an error code (see Appendix I).

Where a command (RUN, GO TO, GOSUB, CONTINUE) has caused the program to be entered, n is the line number of the offending instruction if m is an error code (exception: if the error is in a GO TO or GOSUB then n may be the target of the jump), the line number of the STOP if m = 9, and the line number of the last line in the program if m = 0. Except in the case of m = 0 or m = 9, CONTINUE is a jump to

line number n (but see3(c)). If m=9, CONTINUE is a jump to line number n+1.

Sometimes only the first digit of n is displayed because there is no room in the RAM for any more display file. For example beware confusing line number 240, of which only the first digit is displayed, with line number 2.

A jump to a line number which is beyond the end of the program, or greater than 9999, or negative, gives m=0, n= the line number jumped to.

The commands are described individually in section 3.

2. Computer's view

N.B. 35h means Hexadecimal 35 (35h=3*16+5 =53. 0Ah to 0Fh are the decimal numbers 10 to 15.

(a) RAM

The contents of the RAM are:

The first area is fixed in size and contains various "system variables" which store various items of information such as the current line number, the line number to which CONTINUE jumps, the seed for the random number generator, etc etc. Those that could possibly be useful with PEEK etc have been documented elsewhere (Appendix 3).

An important subset of the system variables are the five contiguous words labelled VARS to DF_END which hold pointers into the RAM and define the extent of the remaining areas (apart from the stack).

The program consists of zero or more lines, each of the form

ie beginning with the line number (stored ms byte first contary to the usual practice on Z80's) and ending with a newline. The line number is in the range 1 to 9999 so that the ms 2 bits of the first byte are zeroes. The ms 2 bits of the byte pointed to by (VARS) will not both be zeroes; this gives a simple test for end-of-program.

The program lines are stored in ascending order of line number. The text consists of ordinary characters (codes 0 to 3Fh) and tokens (codes C0h to FFh), although reverse video characters (codes 80h to BFh) have also been allowed for.

The variables take the forms shown on the next page.

They are not stored in any particular order; in practice each new variable is added onto the end. When a string variable is assigned to, the old copy is deleted and a new one created at the end. (Created first - "LET A$ = A$" does work!) Note that apart from the ms bit of the first byte a single-character integer is the same as the controlled variable of a FOR loop. The characters in a name, being al! alphanumeric, have 6-bit codes as in the character code table. The first character in a name, being perforce alphabetic (ie in the range 26h to 3Fh) effectively has a 5-bit code.

The "variables" area is terminated by a single byte holding 80h (which can't be the name of a string! ).

The working space holds the line being input (or edited, hence "E_LINE") except when statements are being obeyed when it is used for

temporary strings (e.g. the results of CHR$ and STR$) and any other similar requirements. The subroutine X_TEMP is called after each state-ment to clear it out, so there is no need to explicitly release space used for these purposes.

The display file always contains 25 newline characters (hex 76); the first and last bytes are always 76h and in between are 24 lines each of

from 0 to 32 (inclusive) characters. (DF_EA) points to the start of the lower part of the screen.

The stack (pointed to by register SP) has at the bottom (high-address end) a stack of 2-byte records. GOSUB adds a record to this stack consisting of 1+ its own line number; RETURN removes a record and jumps to the line number

stored therein. The last 2 bytes of RAM contain a value which RETURN recognises as not being a line number.

The expression evaluator (which is also used to check the syntax of expressions) pushes 4 bytes onto the top of the stack for each intermediate result and pops them again when the appropriate operator is found, eg,

A+B*C**D*E+F*G                  X=B*CD
                                Y=A+X*E

stack  A+   B*   C**  X*   Y+   F*
            A+   B*   A+        Y+
                 A+

Thus the above expression uses a maximum of 12 bytes of stack.

Parentheses use an additional 6 bytes each, eg.

A + (B * C ** D) * E + F * G

would use 12 + 2 x 6 = 24 bytes

Apart from these two cases, the stack is only used for subroutine calls and for saving registers.

(b) Actions

The actions taken by the computer in response to the user's keystrokes are as follows.

Each time a symbol or token is inserted into or deleted from the input line, also each time the cursor is moved, this change is put into effect in the input line held in working-space after deleting the lower part of the display file (viz that part from (DF_EA to DF_END) - note that during this period the display file may be incomplete in that less than 25 newline characters are present, although the display file is never allowed to become large enough that there will not be room to add the remaining newline characters). Then the input line is checked to see if it is syntactically correct. The input line contains an inverse video [image] at the point where the cursor is; the syntax checker notes the address of the cursor in the variable (P_PTR) and sets variable (X_PTR) to point to the first wrong symbol or to zero if there is none, It also notes whether the cursor should be displayed as [image] or an [image]. Finally the lower part of the display file is rebuilt, inserting the [image] symbol and changing the cursor from [image] to [image] if required, as well as converting tokens into characters.

If there is now insufficient room for the display file the display file area is cleared and the upper part is remade with fewer lines by re-copying from the program stored in the area RAMBOT to (VARS), again converting tokens into characters

as part of this process, and the lower part is then output afresh.

When a line is to be inserted into the program, its line number is converted into binary, space is made at the appropriate place by copying every-thing else up, and the text of the line (from which the cursor has already been deleted) is copied in. The working-space and display file are then re-made, the former now containing just the cursor and a newline.

When a command is executed, it is interpreted in situ in the working-space area. Program lines are of course interpreted in their place in the program.

3. Statements

(a) expressions

Throughout section 3, "n" will be used to represent any space integer expression and "s" to represent any string expression.

String expressions are:

(i) string variable: a$ where a is any letter

(no intervening space allowed). Example: A$.

May be used as "dest" for INPUT (see 3(b)).

(ii) literal string: delimited by quotes, any

symbols or tokens other than quote permitted inside the string. Examples: "ABC" "++"

(iii) CHR$(n) the character with code n,

or the null string if n = 1. (Note: code 212 is a token which is represented by the quote character, and this code may be supplied as the parameter to CHR$ to get something which prints as a quote.)

(iv) TL$(s) the string s minus its first

character, or the null string if s is null or contains only one character.

(v) STR$(n) the decimal representation

of n: from 1 to 5 digits, leading minus sign if negative, no spaces - hence from 1 to 6 characters in all.

(vi) (s) parenthesised string expres-

sion.

Integer expressions are:

integer variable: first character alphabetic,

subsequent characters alphanumeric, no em-bedded spaces, no limit on length of name, May be used as "dest" for INPUT (see 3(b)).

Examples: J AB37Q,

literal number: decimal, unsigned, value

must be <32768 (syntax error otherwise), as many leading zeroes as you like. Examples: 23 32767

0000032767.

(iii) prefix and

infix operations:

form   priority  notes

n**n   10         "to the power"
-n      9
n*n     8
n/n     7
n+n     6
n-n     6        n - n behaves
                 identically to
         n+ - n

form    priority  notes
n=n     5
n>n     5
n<n     5         value is - 1 if
s=s     5         "true", 0 if
s>s     5         "false".
s<s     5
NOT n   4
n AND n 3         bitwise Boolean
n OR n  2         operations

Ambiguities in parsing operations are resolved by considering the priority of the operators in question: higher priorities bind tighter, equal priorities associate from the left. Example:

-A**B+C*D/E*F-G-H

is the same as

(((-(A**B))+((C*D)/(E*F)))-G)-H

(iv) PEEK(n) the value at address n, being

a single byte in the range 0 to 255.

(v) CODE(s) the code for the first

character in strings.

(vi) RND(n) a pseudo-random number in

the range 1 to n if n>0, in the range 1 to 32767 or -32768 to n-1 if n<0. If n=0 returns 1 always.

(vii) USR(n) call machine-code sub-rou-

tine at address n. Value is whatever the subroutine leaves in HL, or n if it doesn't alter HL.

(viii) ABS(n) if n<0 then - n else n.

(ix) array element: a(n) Example: A(I+1).

May be used as "dest" for INPUT (see 3(b)).

(x) (n) parenthesized integer expression.

Values of string expressions can be of any length and can contain any codes except 1 (the closing quote). Values of integer expressions must be in the range - 32768 to +32767; any value outside this range causes a run-time error (number 6).

Note that relations yield - 1 for "true" and 0 for "false" and that

-1 AND n is the same as n.

0 AND n is the same as 0

-1 OR n is the same as - 1.

0 OR n is the same as n.

also

NOT n is the same as - n - 1.

so that for instance

I AND I>0 OR - I AND I<0.

is the same as ABS (I),

However constructions such as A>B>C do not have the obvious effect, being parsed as

(A>B)>C ie as

(A>B) AND C<-1 OR (NOT A>B) AND C<0.

(b) Statements

The statements available are:

NEW re-initialise the computer to the

state it has at initial switch-on. Loses all program, variables, etc.

LOAD read system variables, program,

and variables, from tape, and re-initialise input line and remake display file. Does not affect any GOSUB blocks that may be on the stack (although the effect of doing a RETURN is unlikely to be sensible). BREAK after data has been found on the

tape does the same as NEW: BR EA K during the lead-in preserves the current program and variables.

SAVE Write system variables, program,

and variables to tape for sub-sequent reading by LOAD. Precedes data with 5 secs of silence; starting the tape before executing SAVE (which is recommended, practice) writes frame sync pulses to the tape.

The above can all be used in programs, but are intended to be used as commands, and use in programs is not particularly sensible.

RUN n is the same as CLEAR followed

by GO TO n.

RUN is the same as RUN 1.

CONTINUE is the same as GO TO n, where n

is the last number in an end-of-program message m/n with m>0 (see 1(c) and 3(c). However, after message 9/n, CONTINUE is the same as GO TO n+1.

REM any text no effect (ie is comment).

IF n THEN executes the statement unless n statement is zero. (ie unless n is "false"),

INPUT dest where "dest" can take any of

the forms marked above (see 3(a)). Returns to the input mode with any output so far produced by the PRINT state-ment in the upper part of the screen, and the input line initialised to contain the cursor alone if "dest" is an integer and the cursor inside a pair of quotes if "dest" is a string. These quotes can, however, be deleted as the input can be any expression (not necessarily a literal). The expression is checked for correct syntax and "NEWLINE" is ignored if the [SS marker is present. The upper part of the screen consists of as many lines as have been written by PRINT and the lower part follows on rather than being placed at the bottom of the screen. It is possible for the upper part to contain 24 lines, in which case the lower part is not

visible although the keys all function normally, and, pro-vided the user is able to work blind, the input can still be submitted.

The keys " [image] " and " [image] " have no effect; the effect of "EDIT" is rather comical and not very helpful, although it doesn't actually crash the system.

The INPUT statement cannot be used as a command because of the conflict in use of the working-space; however, in this situation LET can be used instead. Using INPUT as a command causes error code 8/ - 2.

If "dest" is an array element and there is an error in evaluating the subscript or the subscript is out of bounds the error is not reported until after the input value has been submitted.

PRINT <list>

in which <list> may be:

<empty>

or <expr>

or <list>, <list>

or <list>; <list>

and <expr> may be s or n.

writes the value of each <expr> to the upper part of the screen, ie in the case of "s" writes the body of the string, converting tokens into characters, and in the case of "n" writes STR$(n). Each comma causes the output to tab to the 9th, 17th, or 25th column on the line of to the 1st column on the next line. A new line is output unless the <list> ends with a comma or semicolon.

LIST n sets the "current line number"

to n and enters "program input" mode without waiting to display any printed output error code (even if there is an error in evaluating n!) It is therefore only really suitable for use as a command.

LIST is equivalent to LIST 0.

STOP causes "error" code 9, so that

CONTINUE will carry on from the following statement. Useful for displaying results when no input is required.

DIM a(n) creates an array with name a and

subscript range 0 to n inclusive. If one already exists, the new space will be reserved but the old array will continue to be used for all accesses. If a variable a already exists, it can still be used.

FOR a = n TO n assigns to a (ie an integer with a

single-character name) a FOR block as described in section 2(a). The effect' is that a sub-sequent "NEXT a will incre-ment n and if it is not now greater than the TO value jump to the statement following the FOR. Note that we always enter the body of the loop at least once, and that the association between FOR and NEXT is entirely dynamic, ie not lexical.

GO TO n jumps to line number n, or to

the next line with a line number greater than n, or if neither exists stops showing code 0/n.

POKE n,n the first n is an address to which

the value of the second (modulo 256) is written as a single byte.

RANDOMISE n set the seed of the pseudo random number generator to n.

RANDOMISE as above with n = number of frames displayed on the TV since initialisation (modulo 256).

CLEAR delete all variables.

CLS clear the upper part of the

screen, eg to get rid of a message appropriate to an INPUT as in

20 PRINT "TYPE THE VALUE FOR A".

30 INPUT A.

40 cps.

GOSUB n as GO TO n, but also push a

GOSUB block on the stack so that RETURN will jump to the line following this one.

RETURN pop a GOSUB block off the

stack and jump to the line number contained in it.

NEXT a equivalent to LET n = a + 1.

IF NOT a > (value supplied with

TO) THEN

GO TO (line following FOR a).

The combined effect of

m FOR ,I>a = n12 (m is the line number).

and

NEXT a

is of

rn LETa= n2

LET LIMIT a = np (assuming LIMITa isn't used elsewhere in the program).

and

LET'a =a+1.

IF NOT a>LIMITa THEN GO

TO m+1.

Note that this does not preclude (i) assignment to a (ii) several NEXTs matching one FOR, or one NEXT matching several FORs.

Note also that FOR - GOSUB - NEXT - RETURN, and FOR I - FOR J - NEXT I - NEXT J are possible, though not very useful.

(c) BREAK

If the BREAK key is found to be pressed at the end of execution of a line, execution does not

follow on to the next line but stops showing 0/n where n is the line number of the next line that would have been executed but for the break-in.

4 Character set

0 | space | †23 | >
1 | " | †24 | <
2 |  | †25 | ;
3 |  | †26 | ,
4 |  | 27 | .
5 |  | 28 | 0
6 |  | 29 | 1
7 | GRAPHICS | 30 | 2
8 |  | 31 | 3
9 |  | 32 | 4
10 |  | 33 | 5
11 |  | 34 | 6
12 | £ | 35 | 7
13 | $ | 36 | 8
14 | : | 37 | 9
15 | ? | 38 | A
†16 | ( | 39 | B
†17 | ) | 40 | C
†l8 | - | 41 | D
†19 | + | 42 | E
†20 | * | 43 | F
†21 | / | 44 | G
†22 | = | 45 | H
46 | I
47 | J
48 | K
49 | L
50 | M
51 | N
52 | O
53 | P
54 | Q
55 | R
56 | S
57 | T
58 | U
59 | V
60 | W
61 | X
62 | Y
63 | Z
† 64 | - 127 print as ?
† 128 | - 191 inverse video of 0 to 63
† 192 | - 211 print as ?
† 212 | "
213 | THEN
214 | TO
215 | ,
216 | ,
217 | )
218 | (
219 | NOT | 238 | INPUT
220 | - | 239 | RANDOMISE
221 | + | 248 | LET
222 |  | 241 | ?
223 | / | 242 | ?
224 | AND | 243 | NEXT
225 | OR | 244 | PRINT
226 | ** | 245 | ?
227 | = | 246 | NEW
228 | < | 247 | RUN
229 | > | 288 | STOP
230 | LIST | 249 | CONTINUE
231 | RETURN | 250 | IF
232 | CLS | 251 | GOSUB
233 | DIM | 252 | LOAD
234 | SAVE | 253 | CLEAR
235 | FOR | 254 | REM
236 | GO TO | 255 | ?
237 | POKE

† not available from the keyboard. Codes 38 - 63 only available when cursor is [image], codes 230 - 255 only when cursor is [image].


A Course in BASIC Programming

APPENDIX III

SYSTEM VARIABLES

The contents of the first 40 bytes of RAM are as follows. Some of the variables are 1 byte, and can be POKEd and PEEKed directly. The others are each 2 bytes, and have the low order byte at the given address (n, say) and the high order byte at the next address. Thus to poke value v at address n do

POKE n,v

POKE n+1, v/256

and to PEEK at the value in address n use the expression

PEEK(n) + PEEK(n+1) "256

if the value is known to be in the range 0 to 32767, and something like

LET MSB = PEEK(n+1)

IF MSB>127 THEN LET MSB = MSB - 256.

LET VALUE = PEEK(n) + MSB "256

if it may be negative, ie. if n is 16412 or 16414. The notes at the lefthand side of the table have the following meanings:

X | The variable should not be altered by POKE as this could cause the BASIC to hang up.
N | POKE will have no lasting effect, as the variable will be rewritten either at the end of the POKE statement or the next time "edit" mode is entered (either at the end of the run or to get some input).
1 or 2 | Number of bytes in variable.
U | "unsigned" number in the range 0 to 65535; the BASIC will treat values in the range 32768 to 65535 as - 32768 to - 1 respectively. These are the only variables likely to yield negative values.
notes | address | contents
1 | 16384 | 1 less than the "run-time errornumber": PEEK yields 255 normally, 1 less than the error code if an error has already occurred in this statement, eg PRINT (10**6 AND 0) OR PEEK (16384) prints 5 because 10**6 overflows. Do not POKE any value other than 255 or 0 to 8. POKE 16384,255 does nothing; POKE 16384, n (n in the range 0 to 8) causes error n+1, Thus POKE 16384, 8 is the same as STOP.
X1 | 16385 | sundry flags which control the BASIC system.
2 | 16386 | Statement number of current statement: POKE has no effect unless this is the last line in the program.
N2 | 16388 | position in RAM of [image] or [image] cursor last line any input or edit-ing was done.
2 | 16390 | Statement number of [image] cursor.
X2 | 16392 | VAR S
X2 | 16394 | E-LINE See section 2a of Appendix 2.
X2 | 16396 | D-FILE See section 2a of Appendix 2.
X2 | 16398 | DF-EA See section 2a of Appendix 2
X2 | 16400 | DF-END See section 2a of Appendix 2
X1 | 16402 | Number of lines in lower part of screen, including blank line separating the two parts.
2 | 16403 | Statement number of first line on screen. The LIST statement sets this, and scrolling alters it.
2 | 16405 | Address of character or token preceding the [image] marker.
2 | 16407 | Statement number to which CONTINUE jumps.
N1 | 16409 | Sundry flags which control the syntax analysis.
N2 | 16410 | Address of next item in syntax table (very unlikely to be useful).
U2 | 16412 | "seed" for the random number generator. This is set by the RANDOMISE statement, q.v., and updated each time RND is called: see note below.
U2 | 16414 | Number of frames displayed since the ZX-80 was switched on (more exactly, the remainder when this is divided by 65536). While a picture is on the screen, this number is incremented 50 times per second in the UK version, 60 times per second in the US version.
N2 | 16416 | Address of 1st character of 1st variable name in last LET, INPUT, FOR, NEXT, or DIM statement. Thus in LET ABC=PEEK(16416) ABC is assigned the remainder when the address of the A is divided by 256. (Not likely to be very useful).
N2 | 16418 | Value of the last expression or variable: in practice this is the parameter of PEEK so that PEEK(16418) yields 34 and PEEK(16419) yields 64 always.
X1 | 16420 | Position on line of next line character to be written to screen: 33 = lefthand column, 32 second from left, etc, up to 2 = righthand column. Also, 1 = 1st column in next line because current line is full, 0 = 1st column on next line because end-of-line has been signalled. Thus after a PRINT not ending in a comma or a semi-colon PEEK(16420) always yields 0. It only yields 33 if the screen is empty (eg after CLS).
X1 | 16421 | Position of current line on screen: 23 = top line, 22 = second line down, etc.
X2 | 16422 | Address of the character after the closing bracket of the call of PEEK, or of the newline at the end of the POKE statement.

The first line of program begins at address 16424.

The function RND generates a pseudo-random number from the current "seed" as follows:

let n be the seed.

if n is zero, take n = 65536 instead.

let m be the remainder when n*77 is divided by 65537.

if m is 65536, take m = o instead.

the result of RND(x) is now x*m/65536.

the new seed is m.

The TAB function in printing can be implemented as follows:

1000 REM GO SUB 1050 TABS TO

1001 REM COLUMN I

1010 REM GO SUB 1040 TABS TO

1011 R EM CO LUMN I OUTPUTTING

1012 REM AT LEAST ONE SPACE

1030

1040 PRINT" ";

1050 IF I+PEEK(16420) = 33 THEN RETURN

1060 IF 1=0THEN IF PEEK(16420)<2

THEN RETURN

1070 GO TO 1040


Credits

ZX80 User Manual

Copyright 1980 Science of Cambridge. OCR'd by F.J. Kraan

ZX81 User Manual

Copyright 1980 Sinclair Research. HTML'd by Robin Stuart

Memotech User Manuals

Taken from http://www.zx81.de/ with permission

G007 Hi-Res Graphics by Gary Keall

Manual taken from http://www.howell1964.freeserve.co.uk/ZX81/ZX81.htm with permission by K Howell