Authors
Publication
Pub Details
Date
Pages
If you’ve examined some of your programs for any of the Sinclair computers containing machine code, you’ve probably seen machine code routines called in a variety of ways. The most common calls are:
- RANDOMIZE USR r
- LET A = USR n
where “n” represents the address where the machine code is located.
How do you know which way to call a USR routine? The purpose of this article is to explain why USR routines are called in the ways that they are, and to suggest some alternate ways of calling USR routines.
THE BASICS
As you probably know, the heart of Sinclair computers (QLs excepted) is the Z80 microprocessor. When using BASIC in our programs, we are communicating with Z80 in an indirect way. Our commands are “interpreted” by the ROM into instructions that are meaningful to the Z80 microprocessor. The extra step of interpreting the BASIC program takes times and means that BASIC programs run slower. Sinclair computers allow us to execute programs that are directly executable by the Z80 microprocessor by use of the USR function. The USR function removes us of the USR from the safety of BASIC, since you can easily cause the computer to crash. Don’t worry, you can’t hurt the computer, but you can easily lose a program painstakingly entered into the computer. You are working without a net when you run machine code program. The results are breathtaking when the program works, but until your program is fully debugged, you are only a step away from disaster. For this reason, SAVE your machine code programs before running them.
When invoking the USR function, we are telling the computer to execute a machine code program at a specific address. Inside the Z8O that can microprocessors, there are three “register pairs” that can hold any integer between 0 and 65535. These resister pairs are called the HL, DE, and BC registers. (There are some other registers, but they are more difficult to use.) When we write machine code programs, we manipulate the contents of these registers, and the contents of RAM to some useful purpose.
WHAT HAPPENS ON RETURNING TO BASIC FROM A USR ROUTINE?
In most cases, after finishing a USR routine, we return to BASIC. On returning to BASIC, THE CONTENTS OF THE BC REGISTER PAIR ARE INTERPRETED AS A NUMBER. This fact allows us to pass information from our machine language routines back to BASIC. Let’s write a program that does nothing but load the BC register pair with the number 50 decimal, and return to BASIC. (This will work on any Sinclair computer. ) Enter:
POKE 30000,1
POKE 30001,50
POKE 30002,0
POKE 30003,201
To the Z80 microprocessor, this program means load the BC register with 00 then return. In Z80 mnemonics this is abbreviated as:
LD BC, 32 (that's 50 in hexadecimal)
RET
Now let’s prove that the contents of the BC register are interpreted as a number on return to BASIC. Enter:
PRINT USR 30000
The computer will print 50. Try entering:
LET A=USR 30000
PRINT A
Again the computer prints 50, but this time the contents of the BC register has been assigned to the variable A.
A common USR call is:
RANDOMIZE USR n
The effect of this call is to put the contents of the BC resister in the system variable SEED. SEED is used to provide a number for random numbers. To see the results of RANDOMIZE USR 30000 enter:
TS 1000, TS 1500, ZX-31 version
PRINT PEEK 16434 + PEEK 16435 * 256
TS 2068, SPECTRUM version
PRINT PEEK 23670 + PEEK 23671 * 256
Again, the computer prints 50, the number that has been stored in SEED. (You can find the system variables by looking in the appendix of your manual.) You should be careful when using the RANDOMIZE USR n command. If you are using random numbers somewhere in your program as in a same, the RANDOMIZE USR n command may keep putting the same number in SEED time and time again. This will mean that you will keep setting the same random numbers again and again. After using RANDOMIZE USR n, you should have another line that says RANDOMIZE or RANDOMIZE 0. This will cause the number of TV frames shown since you turned your computer on to be deposited in SEED. This number should be fairly random.
In the preceding examples we have seen three common ways of calling USR routines. Now let’s examine a couple more advanced methods.
ADVANCED USR CALL TECHNIQUES
Since we have seen that the BC resister pair is interpreted as a number on return to BASIC, it is possible to use USR calls in any way that a numeric argument is valid. For example you could have a line that said:
IF USR n = 10 THEN GOTO 1000
and it would be perfectly legal. You could execute multiple USR routines with statement such as:
LET A = (USR n OR USR m OR USR p)
and all three USR routines would be executed.
I enjoy storing data in strings. String storage of data has the advantage of being compact, and the Sinclair computers handle strings especially well. My favorite USR cali is:
LET A$(1) = CHR$ USR n
It has the advantage of setting the system variable DEST to contain the address of A$(1). This means that you can store data in strings and easily find the location of that string for your machine code routine. (DEST will also point to numeric variables, but there are quite a bit more difficult to use.) The one thing you have to remember when using DEST is that you must restore a$(1) to some legal character code between 0 and 255. This is easily done by ending your routine with:
LD HL, (DEST)
LD C, (HL)
LD B, O
RET
This loads the BC register with the character that is pointed to by DEST. It is much like saying:
LET A$ (1)=A$(1)
One final tip on calling USR routines. If you need to set a value to a USR routine from BASIC you can always POKE it to some unused location in memory, but here is a bit more elegant way. Pass the number to memory with the RANDOMIZE function. Suppose you want to set the number 3 to the routine. Just enter RANDOMIZE 3 and the number three will be put in SEED. Then call your USR routine and have it read SEED. It’s simple, and will even put two byte numbers in SEED. The one number it won’t work for is zero.
Once you have learned that the BC register is the key to returnins to BASIC, you will find that your machine code routines will be more imaginative.