This chapter will review the operation of the ZX81 memory, it will discuss PEEK and POKE and it will introduce the USR command.
First, let’s take a look at another utility program on a “play-by-ear” basis, just to keep up the interest. This one is the classic line renumber program. (Fred Nachbaur would call it a half-program, since it does not make appropriate adjustments in GOTO and GOSUB destinations, but it’s still pretty impressive–especially when you remember that it is only 34 bytes long.)
Now, enter the “rough draft” 1 REM line shown in Figure 2-1, and proof read it via the rudimentary loader program of Figure 2-2. (Keep in mind that it will not run until all the periods (.) have been poked with the data in table 2-4. The first column is the address+ 16500 and the second column is the data to be poked.-ed.) You’ll find the loader a little different from the one in the last issue, in that only one column of figures is displayed now. There’s nothing sinister in this change–it’s just that the new form is easier to work with when it has to handle a number of different programs. The number of bytes has also been changed, of course, to fit the length of the new program.
After you’ve proofread the line (Figure 2-3), POKE in the vacancies, as shown in Figure 2-4, and proofread the final version as per Figure 2-5. Now you’ll find that the command, RAND USR 16514, changes all your program lines into a neat sequence. It probably louses up your whole program if it has any GOSUBs or GOTOs in it though
If you want a different line number sequence, you can change the interval between line numbers by POKEing the desired number into 16539. You can change the number of the second line by POKEing your desires to 16515. (All line numbers must be less than 256, of course.) Line number one will remain unchanged, no matter what you do with the program. Now, back to our general discussion.
FIGURE 2-1. 1 REM FOR RENUMBER -FIRST DRAFT-
1 REM ▒▒ 5▒RNDY.W7▒4.7▒COS Y5▒..7. FAST 5▒ ▒.. LPRINT .▒RND
HOW IT LOOKS
1 REM (GR 1) (GR 5) (SPACE) 5 (GR Q) RND Y . W 7 ▒ 4 . 7 ▒ COS Y 5 ▒ . . 7 . FAST 5 (GR S) (SPACE) (GR D) . . LPRINT . (GR H) RND
HOW IT IS DONE
FIGURE 2-2. THE RUDIMENTARY LOADER
10>REM PROOFREADING THE PROGRAM
20 FOR F=16514 TO 16547
30 PRINT F;TAB 6;PEEK F;TAB 10;CHR$ PEEK F
40 NEXT F
50 STOP
100 REM POKEING THE VACANCIES
110 INPUT A
120 PRINT A;TAB 6;
130 LET A=A+16500
140 INPUT B
150 POKE A,B
160 PRINT PEEK A
170 GOTO 110
ZX/TS Memory
You will remember that your computer stores information in the form of “bytes,” each of which is an integer between 0 and 255, inclusive. Every time you press a key (except for SHIFT, DELETE, and such), that keystroke is translated into the appropriate byte, and stored in memory. (Sometimes the computer volunteers a few extra bytes that you didn’t ask for. We’ll call them “housekeeping” bytes, and discuss them later on.)
To see what these bytes look like, enter and RUN the mini-program shown in Figure 2-6. Note that 16509 is the address of the first byte of the program.
16509 is the address of the first program byte. That’s a number worth remembering!
What you see on the screen is the contents of the first 50 bytes in the program area of the RAM. With a few exceptions, these bytes correspond to the keystrokes that you entered. These exceptions, the housekeeping bytes that we mentioned above, are very important to the writer of machine code. Don’t worry, we’ll get around to them before too long.
The PEEK command lets you look at the contents of any memory location. POKE, on the other hand, lets you change the contents of any RAM location you choose, to any number you specify (0 to 255 inclusive).
To watch POKE at work, leave the program of Figure 2-6 in the computer, and enter the command:
POKE 16518,35
You’ll find that line ten has been changed to read:
10 FOR M=16709 TO 16558
To see the significance of the bytes stored in memory, restore line 10 to its original form, and change line 20 to read:
20 PRINT CHR$ PEEK M;
RUN the program. Do you see the words and characters that you recognize from the program? The apparently meaningless stuff represents those “housekeeping” bytes.
FIGURE 2-3. PROOFREADING THE PROVISIONAL 1 REM
16514 1 ▒ 16531 33 5
16515 5 ▒ 16532 190 ▒
16516 0 16533 27 .
16517 33 5 16534 27 .
16518 129 ▒ 16535 35 7
16519 64 RND 16536 27 .
16520 62 Y 16537 229 FAST
16521 27 . 16538 33 5
16522 60 W 16539 10 ▒
16523 35 7 16540 0
16524 190 ▒ 16541 9 ▒
16525 32 4 16542 27 .
16526 27 . 16543 27 .
16527 35 7 16544 225 LPRINT
16528 190 ▒ 16545 27 .
16529 200 COS 16546 136 ▒
16530 62 Y 16547 64 RND
ZX/TS Character Set
If your going to use the El Minimo Loader, described later on (which we have been using with our demonstration programs, without telling you about it), it will be useful for you to understand the computer’s character set.
The entire set is printed in your instruction book. Alternatively, you can look at the character corresponding to any number N (always 0 to 255, inclusive) by using the command:
PRINT CHR$ N
You can print out the whole set by the program in Figure 2-7, if you prefer.
To understand the POKE exercise you just went through, enter the command:
PRINT CHR$ 35
The computer will return the symbol 7. Maybe you have deduced that 16518 is the address of the digit that you just changed from 5 to 7.
FIGURE 2-4. POKING THE VACANCIES
ADDRESS VALUE +16500 21 117 26 252 33 248 34 112 36 113 42 68 43 77 45 195
The USR Command
The trigger for a machine code routine is the symbol USR (under the L key). USR must always be followed by a memory location telling the computer where to start executing the machine code. For the moment, let’s represent that address by LL.
Whenever the computer senses this trigger, as in PRINT USR LL, RAND USR LL, LET A =USR LL or the like, it reacts like a Pavlovian dog, jumping into the memory at LL, and scooting through the program like a mad fiend, at a speed of tens of thousands of operations per second. If there are no instructions to the contrary, the sequence of operations will follow the program bytes in the order in which they occur.
FIGURE 2-5. PROOFREADING THE FINAL 1 REM
16514 1 ▒ LD BC,5
16515 5 ▒
16516 0
16517 33 5 LD HL,16513
16518 129 ▒
16519 64 RND
16520 62 Y LD A,117
16521 117 ?
16522 60 W INC A
16523 35 7 INC HL
16524 190 ▒ CP (HL)
16525 32 4 JR NZ,-4
16526 252 UNPLOT
16527 35 7 INC HL
16528 190 ▒ CP (HL)
16529 200 COS RET Z
16530 62 Y LD A,33
16531 33 5
16532 190 ▒ CP (HL)
16533 248 SAVE RET M
16534 112 ? LD(HL),B
16535 35 7 INC HL
16536 113 ? LD(HL),C
16537 229 FAST PUSH HL
16538 33 5 LD HL,10
16539 10 ▒
16540 0
16541 9 ▒ ADD HL,BC
16542 68 ? LD B,H
16543 77 ? LD C,L
16544 225 LPRINT POP HL
16545 195 ? JP,16520
16546 136 ▒
16547 64 RND
If the program (as per listing) encounters the RETurn instruction (address 16529 or 16533), the computer will RETurn to BASIC. If there are no valid RETurn addresses (the Stack Pointer, SP, will contain the address that the computer will RETurn to), well, you are on your own. Stand by to pull the plug. At this point, of course, you have lost everything in memory. Believe me, it’s easier to include RETurn (extra, well placed RETurns won’t hurt you).
FIGURE 2-6. A PEEK AT THE MEMORY
200>FOR M=16509 TO 16558
210 PRINT PEEK M;" ";
220 NEXT M
If the trigger command is PRINT USR LL, the machine code routine will end by printing the value of a variable (register) known as BC. More precisely, it will print:
C + 256 * B
based on the values that the registers B and C have taken at the time the program RETurns to BASIC. If the USR command does not include PRINT, the output may be in the form of some other action based on the value of BC. For instance, GOTO USR LL and LIST USR LL are both perfectly valid commands, as long as LL has a value that can be handled by the computer.
In all cases, the computer will enter the machine code at LL, execute the machine code until it meets a RETurn, and then try to execute the BASIC command, substituting the final value of BC for USR LL.
That’s all for now, but there will be more.
FIGURE 2-7. THE ZX81/TS1000 CHARACTER SET
300>FOR M=0 TO 255
310 PRINT CHR$ M;" ";
320 NEXT M
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.