OK, so your ZX80/81 is all fired up and ready, and that ominous is sitting there glaring at you from its little corner and waiting for you to type something in. What do you do?
Well the first thing is to set up the machine so that it can accept programs in machine code instead of in BASIC. This is not difficult, but unfortunately for us, when Sinclair designed his machine he forgot to include a button saying GO-INTO-MACHINE-CODE-MODE, so the routine for doing this is going to have to be a BASIC program.
If you have a NEW ROM machine type one of the following sequences, depending on how much memory you have:
POKE 16388,173 POKE 16388,32 POKE 16388,48
POKE 16389,67 POKE 16389,78 POKE 16389,117
NEW NEW NEW
[Download available for 16K ZX81 -> chapter02-setramtop.p. Well you don't need me to supply you with BASIC 3 line programs, but I do know that from here on in you'll be asked to set RAMTOP to various decimal or hexadecimal addresses and so this heavily modified version of the author's listing will save you a lot of typing (I'm assuming you're using an emulator and are NOT going to load this from tape). I recommend you rename it to something like "s.p" so that you can LOAD "S", select decimal or hex, enter an address and then LOAD "your-program".]
The effect of this is quite straightforward. The addresses 16388 and 16389 together hold a system variable called RAMTOP. It contains the address of the first byte which the computer cannot use - at least not for BASIC. Under normal circumstances this address is the one immediately after the last byte in memory, so that the whole of the memory is available for BASIC programming. What we have done is to alter that address, so that some of the memory is unavailable for BASIC, and becomes a safe place in which to store machine code.
If you have an OLD ROM machine, don't worry - you can still store machine code in spare areas of the memory, but you MUST NOT type NEW, or you will lose it all.
The best addresses in which to store machine code are best found by trial and error. We shall adopt the following standard addresses, which should work perfectly for all of the routines in this book:
OLD ROM 1K: 17225
NEW ROM 1K: 17325
Throughout the remainder of this book I shall use the address 30000. Please read this as one of the alternatives above if you have less than 16K.
OK:- Now we're ready to start. Type in the following BASIC program:
10 LET X=30000
When you have 20 LET A$=""
typed this program 30 IF A$="" THEN INPUT A$
in name it 40 IF A$="S" THEN STOP
"HEXLD" and don't 50 POKE X,16*CODE A$+CODE A$(2)-476
forget to SAVE 60 LET X=X+1
it. 70 LET A$=A$(3 TO )
80 GOTO 30
(For the OLD ROM you must replace lines 50 and 70 as follows:)
50 POKE X,16*CODE (A$)+CODE (TL$(A$))+36
70 LET A$=TL$(TL$(A$))
Can you see how the program works? Or at least what it does? In brief - it will accept a machine code program, and will store it at addresses 30000 onwards. (Or 20000, or whatever.) The program will stop when you input an "S". Note that although it will enter machine code, it will NOT attempt to run it.
Now for the big question you've all been dying to ask - what exactly IS machine code? Well machine code, or machine language as it's otherwise known, is another computer language - much like BASIC is - only at a much lower level, which means that very complicated instructions, such as FOR/NEXT loops, are simply not available. However this also makes it quite an easy language to learn. Like BASIC it consists of a set of instructions, each of which tells the computer to do a different, and quite specific, task. One such instruction is RET, which is more or less equivalent to BASIC's RETURN.
Unlike BASIC, however, the computer isn't programmed to understand all of the various instructions as we do. If you were to RUN the above program and enter "RET" then this simply would not make sense to the poor old ZX81 (or '80). To make life easier for it, every instruction has a numerical code, which it DOES understand directly. For example the code for RET is 201. Every code lies somewhere in the range 0-255, and it is usually more convenient to write these codes in a system called HEXADECIMAL.
COUNTING IN HEXADECIMAL
Our friend Mr. Sinclair briefly covers this obscure system of counting in the ZX81 instruction manual by describing an imaginary race of sixteen fingered "Martians" who would regard counting in tens as being equally absurd. In these modern days of science we know enough about Mars to realise that it is extremely unlikely to host sixteen fingered people, but the principle of counting in sixteens is still very sound.
Briefly, for those who have not read the ZX81 manual, hexadecimal, or hex for short, is a means of counting which uses sixteen symbols instead of ten. The first ten sysmbols are the same as the ones we're used to. These are:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
There are six new symbols which represent the numbers 10 to 15. These are:
A, B, C, D, E, F.
The fun really starts when we want to represent numbers bigger than fifteen, for believe it or not, sixteen is written as 10! Worse still, seventeen is written 11. This continues up as far as twenty-five, written 19, and then when we come to twenty-six we have to start using the new symbols again; twenty-six becomes 1A.
A complete table of all of the numbers from 0 to 255 is shown here. This is intended to help you understand the hexadecimal system of counting. You should try to refer to it as little as possible, but don't worry if you find yourself using it all the time at first, you'll find you get used to it much quicker than you expect.
The symbols down the left hand side are the first hex digit, the symbols along the top are the second digit. The leading zeros may of course be ommitted if there are any, but it is sometimes more convenient to leave hex codes as two digits rather than one.
If there is ever any confusion about whether a number is written in hex or not, you should make it clear by writing a small letter h (standing for hex) or a small letter d (for decimal) after the number, so that 19h means twenty-five, and 19d means nineteen. Usually you won't need to do this because numbers like CD can only possibly be hexadecimal, and number like 118, which are three digits long, can only be decimal. (Computing does not use hex numbers which are three digits long, though it does uses ones which are FOUR digits long).
Knowing at least the fundamentals of counting in hex is virtually paramount as far as machine code is concerned, so don't be afraid to keep coming back to this section, or to keep refering to the table - that's what it's there for.
There are fundamental differences between machine code programming and BASIC programming. One of the most fundamental differences is that of LINE NUMBERS.
As you know, every BASIC instruction in a program must be preceded by a line number, so that the computer knows in which order to execute them. If no line number is given the computer will interpret the instruction as a COMMAND and will execute it immediately.
In machine code, there are no line numbers. Also, the ZX80/81 will not allow you to use machine code instructions as commands, they MUST form part of a program. The instructions are executed in the order that they are stored. For example, if the computer had just finished executing the instruction which was stored in location 30000, it would then go on to execute the instruction held in location 30001. It will continue in this way until it recieved an instruction telling it to do otherwise.
Unlike BASIC, it will NOT automatically stop when it reaches the end of the program. It will plough right on through the addresses, and every time it finds a number which is not zero it will simply treat that number as a code for some instruction and try to execute it. Usually this will result in what is called a CRASH.
Crashing is the name we give to what happens when your (up until now at least moderately well-behaved) Sinclair machine unwittingly tries to execute something it shouldn't, or if there is a drastic mistake in your machine-coding which will confuse the poor machine and give it a rather nasty headache. The effect of a crash is very unmistakable - The screen will either go blank or will go in to its "LET'S-PRODUCE-SOME-MODERN-ART" mode. If this happens you will get pretty (or otherwise) patterns on your TV not unlike those produced during SAVE.
When this happens you will undoubtedly try to break out, by using the BREAK key, and discover to your horror that the BREAK key doesn't work! In fact NONE of the keys will work after a crash, except possibly to produce slight variations in the TV picture. This is the prime reason why we dislike crashes, for THE ONLY WAY TO THEN GET BACK TO NORMAL IS TO DISCONNECT THE POWER SUPPLY! When you reconnect you will of course have lost all of your program and will have to reLOAD it.
If a BASIC program contains a mistake it will usually NOT WORK.
If a machine-code program contains a mistake it will usually CRASH!
HOW TO PREVENT CRASHES
We have already stated that a machine code program will not automatically stop at the end of a program - it must be told to do so by a specific instruction. For the ZX80/81, that instruction is RET. (Return - i.e. return to BASIC).
There is an instruction similar to STOP in BASIC, that instruction is HALT. DO NOT USE THIS INSTRUCTION! On other computers you can use HALT to end a program, but not on the ZXs. HALT produces a condition similar to a crash, for it means "Do nothing whatsoever until somebody breaks out." The problem is of course that you CAN'T break out because you'll find that the keyboard no longer works. To summarise: To end a machine code program ALWAYS use RET. NEVER use HALT.
A program must have at least one return instruction in it somewhere, otherwise it will never return to BASIC, unless you actually disconnect the power supply, and this is not usually a desirable thing to do.
This chapter has dealt with how to reserve space for machine code programs, and has given you a program with which to load it. It has not told you how to make use of this program, nor has it explained how to run machine code programs once they have been loaded. The fundamentals of counting in hex have been introduced, and the notion of a crash has been mentioned.
Once you have understood this chapter, you may turn to chapter three for your first lesson in machine language programming.