LET A= …
This installment will teach you how to enter an actual program in machine code. But first, a “fun” program – a rather lengthy one, this time.
You’ll notice that we have changed the loader program again, as shown in Figure 4-1. After the experience you’ve had in the first three chapters, you should be able to combine the operations of POKEing the vacancies and proofreading the program.
1000 LET F=16513
1010 LET F=F+1
1020 PRINT F;" ";
1030 IF PEEK F<>27 THEN GOTO 1060
1040 INPUT A
1050 POKE F,A
1060 PRINT PEEK F,CHR$ PEEK F
1065 IF PEEK F=118 THEN STOP
1070 GOTO 1010
FIGURE 4-1. LOADER/PROOFREAD
PROGRAM
The program we’re giving you this time will enable you to delete blocks of program material in a single operation. All you do is mark the beginning of the section to be deleted with
N1 REM >
and the end with
N2 REM <
where N1 and N2 are line numbers. Then RAND USR 16514 will lump all the material between the markers into one line which can be deleted at one go.
The rough draft of the 1 REM statement is shown in Figure 4-2, and the final listing in Figure 4-3. While you’re proofreading the statement, the display will stop for you wherever you have included a period, and wait for you to INPUT the final number (which may, of course, actually be 27). When the screen is full, just CONTINUE to get the following bytes.
1 REM <>5.RNDY.W<>7<>▒ TAB ▒R
ND<>▒▒COS Y.<>▒▒TAB ▒RNDY><>▒▒TA
B ▒RND<> FAST AT W<>▒▒TAB ▒RND<>
FAST LPRINT .PI777VAL <> LPRINT
<>.▒<>.▒TAN
HOW IT LOOKS
1 REM <> 5 . RND Y . W <> 7
<> ▒ (SPACE) TAB (GR G) RND <> ▒
(GR 1) COS Y . <> ▒ (GR 5) TAB
(GR Y) RND Y > <> ▒ (GR T) TAB ▒
RND <> FAST AT W <> ▒ (GR T)
TAB (GR Y) RND <> FAST LPRINT .
PI 7 7 7 VAL <> LPRINT <> .
(GR 4) <> . (GR 7) TAN
HOW IT IS DONE
FIGURE 4-2. ROUGH DRAFT OF 1 REM
As before, the mnemonics, which are included for the information of more experienced programmers, will not appear on your listing.
16514 221 <> LD IX,
16515 33 5 16509
16516 125 ?
16517 64 RND
16518 62 Y LD A,
16519 117 ? 117
16520 60 W INC A
16521 221 <> INC IX
16522 35 7
16523 221 <> CP(IX+0)
16524 190 ▒
16525 0
16526 194 TAB JP NZ,
16527 137 ▒ 16521
16528 64 RND
16529 221 <> CP(IX+1)
16530 190 ▒
16531 1
16532 200 COS RET Z
16533 62 Y LD A,
16534 234 REM 234
16535 221 <> CP(IX+5)
16536 190 ▒
16537 5
16538 194 TAB JP NZ,
16539 134 ▒ 16518
16540 64 RND
16541 62 Y LD A,
16542 18 > 18
16543 221 <> CP(IX+6)
16544 190 ▒
16545 6
16546 194 TAB JP NZ,
16547 168 ▒ 16552
16548 64 RND
16549 221 <> PUSH IX
16550 229 FAST
16551 193 AT POP BC
16552 60 W INC A
16553 221 <> CP(IX+6)
16554 190 ▒
16555 6
16556 194 TAB JP NZ,
16557 134 ▒ 16518
16558 64 RND
16559 221 <> PUSH IX
16560 229 FAST
16561 225 LPRINT POP HL
16562 237 GOSUB SBC HL,BC
16563 66 PI
16564 35 7 INC HL
16565 35 7 INC HL
16566 35 7 INC HL
16567 197 VAL PUSH BC
16568 221 <> POP IX
16569 225 LPRINT
16570 221 <> LD(IX+4),H
16571 116 ?
16572 4 ▒
16573 221 <> LD(IX+3),L
16574 117 ?
16575 3 ▒
16576 201 TAN RET
FIGURE 4-3. FINAL LISTING OF
1 REM
One word of caution: DON’T use this program in the SLOW mode. It’s very likely to crash if you do, since this program pre-empts some of the the computer’s capabilities that are required to make the SLOW mode work.
Now back to lessons.
You’ve carved out some turf for yourself – so what do you do with it? You may remember an earlier declaration that the output of a machine language routine is what the computer calls BC; i.e.
C+256*B
So how do we make B and C reflect any value that we can use?
For the moment, think of B and C as simple variables. What we want to do is to assign values to them. The Z80 machine code instructions that we want are:
LET B=m is 6,m
and LET C=n is 14,n
And RETURN, which we must not forget, is 201.
Note that the instructions (6,14) and the data (m,n) are mixed into the program. There is no difference between them, as far as mortal eye can see. The computer knows, though, from the context. If it receives an instruction of 6 or 14, for instance, it’ll interpret the next byte as data, whether you mean it to or not.
Now we’re ready for our first, very simple, program. After reserving at least 5 nulls in a 1 REM statement (see the previous chapter, if you’ve forgotten how), POKE in the sequence shown in Figure 4-4. Give the command PRINT (not RAND) USR 16514, and there’s your answer: 256.
MEANING
POKE 16514,6 LET B =
POKE 16515,1 1
POKE 16516,14 LET C =
POKE 16517,0 0
PRINT USR 16514 PRINT 256*B+C
FIGURE 4-4. SETTING B AND C
Now another one, as in Figure 4-5. Note that you don’t have to delete the previous material – the new entries will overwrite the old bytes. Before printing the output, what do you expect it to be? Enter PRINT USR 16514, and check your prediction.
MEANING
POKE 16514,6 LET B =
POKE 16515,0 0
POKE 16516,14 LET C =
POKE 16517,1 1
PRINT USR 16514 PRINT 256*B+C
FIGURE 4-5. SETTING B AND C
It should have been
256*B(=0)+C(=1)=1
But all this POKEing is getting to be a bit tedious, isn’t it? (You’ll notice that I stalwartly resist the temptation to make a pun on poking fun.) Plus the danger of losing your place and skipping a byte. With the further disadvantage that you can’t proofread the program.
It has probably already occurred to you that this is an appropriate place to use a loop. So let’s build a very simple loader program, like the one in Figure 4-6.
1 REM ...........
1000 FOR M=16514 TO 17000 ***
1010 PRINT M;" ";
1020 INPUT A
1030 POKE M,A
1040 PRINT PEEK M
1050 NEXT M
*** DON/T WORRY; WE WON/T USE
ALL 487 BYTES. SEE THE TEXT
ON THIS POINT.
FIGURE 4-6. A SIMPLE LOADER
To try it out, let’s go through the two programs we wrote above. First, RUN the program of Figure 4-6, and then INPUT in succession:
6,1,14,0,201,Z
The Z, or any other letter that the computer will not interpret as a number (NOT M or A, which have already been assigned values by the computer), will cause the program to STOP, with an error report of 2/1120, meaning “I don’t recognize that as a defined value for A”. And that’s the way you get out of the loop without having to go through all 487 INPUTs.
16514 6
16515 1
16516 14
16517 0
16518 201
FIGURE 4-7. PROOFREADING
Now you have the contents of the whole 1 REM statement displayed on the screen, as shown in Figure 4-7, so you can proofread it – including making sure that it includes the all-important 201, for RETURN. If it’s the way you want it, PRINT USR 16514. And there’s the 256, just as before.
If you do find an error in the program, POKE in the proper value, as, for instance, POKE 16516,14. If your program is to be more than 22 bytes long, use CONTINUE when the screen is filled. Or you can add 1005 SCROLL, if you prefer.
If you want to proofread a program after POKEing in a correction, use the following procedure:
1. Disable lines 1030 and 1040. You can do this either by deleting the lines or by inserting a REM at the beginning of each line, right after the line number.
2. If you have included a SCROLL, either disable it or put the computer into SLOW mode.
3. RUN the program.
El Minimo
The following experiment will help you to understand what goes on when you store your machine code in REM. It’ll also give you a clue to the way we’ve been writing those “fun” programs at the head of each chapter.
I call this loading technique “EL MINIMO” because it’s just about the most compact program loading system possible.
Enter
1 REM (Gr T) (space) : (Gr1) TAN
If you’ll look at the listing of the character set in your manual, or if you’ll check each character by PRINT CODE “…”, you’ll find that the codes of these respective characters are, to nobody’s surprise, 6,0,14,1, and 201.
This is in fact the series of numbers that has been entered into memory, starting at 16514.
Try PRINT USR 16514 for this program, and again after you have exchanged the places of the 0 and the 1.
You may find it more convenient to use this technique for building up your 1 REM statement, as we have been doing in the “fun” programs. If so, you’ll find it useful to add a little more information to your ZX81 manual. You’ll notice that the table of the character set as listed in the manual shows the graphics symbols for Codes 1-10 and 128-138 (with an error in the entry for 135, at least in my copy). However, it’s not too easy to find these symbols on the keyboard, so I wrote into the manual the keystroke needed to produce each of these symbols. They’re listed in Figure 4-8.
CODE CHR$ KEYSTROKE
0 SPACE
1 ▒ GR 1
2 ▒ GR 2
3 ▒ GR 7
4 ▒ GR 4
5 ▒ GR 5
6 ▒ GR T
7 ▒ GR E
8 ▒ GR A
9 ▒ GR D
10 ▒ GR S
128 ▒ INV SPACE
129 ▒ GR Q
130 ▒ GR W
131 ▒ GR 6
132 ▒ GR R
133 ▒ GR 8
134 ▒ GR Y
135 ▒ GR 3
136 ▒ GR H
137 ▒ GR G
138 ▒ GR F
FIGURE 4-8. KEYING THE GRAPHICS
SYMBOLS
Incidentally, if you want to enter keywords, like RUN (CHR$ 247), REM (234), FOR (235), and the like directly from the keyboard, you can do it by preceding the character with THEN, which conditions the ZX81 to interpret the next keystroke as a command. You’ll have to delete the THENs from the final program, of course.
And that’s it for now. There will be more.
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.