Basil’s Compendium

Publication: SyncWare News
Pub Details: SyncWare News v5 n1 (Volume 5, Issue 1)
Date: September/October 1987
Pages: 22-24

Input Output PEEK & POKE

So far, the Z80 chip must impress you as being a singularly inflexible device. It will do what you ask it to, and do that very well–so long as you ask it to tell you the value of B+256*C. And as long as you include enough information in the program to define B and C. And, once you have defined them, there seems to be no way to change their values, short of rewriting the program.

It seems a little like the remark ascribed to Henry Ford: people could have any color car they wanted–as long as they wanted black.

Well, there’s no way to get around that ultimate inflexibility. We can tell the computer to do much more than compute BC, but it still won’t do any more than we tell it to. (Although some times you can’t be sure what you’ve told it to do, until it’s done it.) Once we’ve written that program, we have committed ourselves. Just as in BASIC.

There’s no reason, though, that we can’t write a number of programs, and send the computer to one or another, as conditions demand. That’s what the Sinclair people did when they designed the ZX81’s ROM. Those 8K are packed with machine code routines which, taken all together, contain the entire repertoire of amazing things that your computer can do.

But there’s still the question of communicating with your computer. In BASIC, you have INPUT. And you have PRINT (or LPRINT) for an output. And you can PRINT a lot more than one variable. Whereas in machine code…

Well, you just wrote a program that would compute the fifth power of 2, for instance. Wouldn’t it be nice to be able to compute the sixth power of 2, without rewriting the whole program? Or the fifth power of 3? Or maybe to compute a whole series of the Nth power of 2 from N=1 to N=6, and see the series of answers?

INPUT and OUTPUT in machine code are accomplished by PEEK and POKE. You INPUT data, you store that data in the computer’s memory, and tell the chip to PEEK it at the proper time. For an output, you tell the computer to POKE the information into the memory at some place you specify.

PEEK with Register A…

PEEK and POKE are identified in the mnemonic lists by parentheses. For instance, LD A,(HL) means to load register A with the data found at the address defined by the contents of HL. Notice that it doesn’t mean to load A with the data held in HL itself–it couldn’t, anyway, because HL contains two bytes, while A has room for only one.

LD A,(NN) is a little more complicated, but still perfectly logical. First of all, NN represents a number that is made up of two bytes, Least Significant Byte first. This number, when it appears in parentheses, represents a memory address. And LD A,(NN) means to load register A with the data found in the memory byte at that address.

Let’s try an example to help us to understand that one. Look at Figure 14-1. The data at 16515 and 16516 are 256-imal for 16513 (i. e., 129+256*64). Byte 16514 tells us to PEEK that location, and to LD A with the number it finds there. The rest of the program moves that number into BC, where we’ll be able to read it.

16514   58 U       LD A,(16513)
16515 129 Gr Q
16516 64 RND
16517 6 Gr T LD B,0
16518 0 space
16519 79 ? LD C,A
16520 201 TAN RET

PRINT USR 16514 gives
PEEK 16513=234

Figure 14-1. LD A,(NN)

Before you go any further, what is that number? If you can’t figure it out, try PRINT PEEK 16513.

Now PRINT USR 16514, and check your prediction. You should get 234, the CODE for “REM”.

LD A,     (BC) (DE) (HL)  (NN)
           10   26  126*  58

  * NOTE that 126 is a minor
  no-no (see Chapter 7)

LD(HL),     A    B    C    D
          119  112  113  114

LD(HL),     E    H    L    N
          115  116  117   54

LD B,(HL)     70
LD C,(HL)     78
LD D,(HL)     86
LD E,(HL)     94
LD BC,(NN)   *75
LD DE,(NN)   *91
LD HL,(NN)    42 or *107**

   *NOTE: preceded by 237
  **NOTE: mistake in ZX81 manual

LD(NN),     A   BC   DE   HL
           50  *67  *83  34 or
                         *99

   *NOTE: preceded by 237

Table 14-1. Some PEEKs and POKEs

Try another. POKE 16515,130. What does PRINT USR 16514 give you now? Since you are asking to PEEK 16514, your output should be 58.

A collection of instructions involving PEEK and POKE is shown in Table 14-1.

…or 2-Byte Registers

You will notice that there are instructions in the table for loading BC, DE, or HL with (NN)–that is, with the data in the byte at memory location N1+256*N2. However, you will remember that register pairs must be loaded with two bytes of data. Accordingly, a PEEK on their behalf must PEEk two consecutive bytes. We only have to specify the address of the first of the two.

So LD HL,(NN) tells the computer:

1. Compute the address represented by N1+256*N2, where N1 is the first of the NN pair, and N2 is the second.

2. Load H with the data in that address.

3. Load L with the data found in the very next byte.

So let’s have a go at it. Follow Figure 14-2. PRINT USR 16514 should give you:

PEEK 16513+256*PEEK 16514, or

234+256*42=10986

16514   42 E       LD HL,(16513)
16515 129 Gr Q
16516 64 RND
16517 68 ? LD B,H
16518 77 ? LD C,L
16519 201 TAN RET

PRINT USR 16514 gives
PEEK 16513+256*PEEK 16514
=234+256*42=10986

Figure 14-2. LD HL,(NN)

Oddly enough, there is also a two-byte instruction, 237:107, that has the same meaning as 42. Even more oddly, my ZX81 handbook has it mislabeled as LD DE,(NN). It should be LD HL,(NN). (The TS 2068 handbook has it right.)

Try again, with LD DE,(NN) (=237:91), and then again with LD BC,(NN) (=237:75). In the DE case, you’ll have to replace bytes 16517 amd 16518 with LD B,D (=66) and LD C,E (=75). (Not necessarily in that order, by the way–it doesn’t matter which you do first, as long as you do both.) And when you LD BC,(NN) those two bytes can be deleted.

NOP

Or they can be replaced with zeroes. A zero instruction is a do-nothing. Its mnemonic is NOP (no operation). It is sometimes used to delay a program for a few microseconds (like the PAUSE in BASIC, but with much, much shorter delays) while events in the real world catch up. If you want a longer delay, you can insert a loop of NOP’s, just as you might use

100 FOR X=1 TO 17
110 NEXT F

in BASIC. Except for the delay, which you will never notice in these elementary applications, the NOP has no effect whatsoever.

You can use it in practice sessions to reserve a byte or a number of bytes, which will be given significant numbers later on. Or to null out a byte of instruction that you no longer want. Just be sure that the byte you’re replacing with zero actually IS AN INSTRUCTION. If you replace a data byte with a zero, the computer will take the zero as bona fide data, and may give you rather unforeseen results.

One other caution (two, actually). If you null out an instruction, be sure that you also null out all the data bytes associated with it. And if you are zeroing out a two-byte instruction, be sure that you replace BOTH bytes with zeroes. If you violate either of these rules, the computer will be almost sure to misinterpret the bytes that you neglected to null out.

POKE

In the POKE case, the destination address is sure to be greater than 255. After all, the bytes at addresses lower than 256 are all in ROM, and can’t be POKEd. Therefore, all addresses you will ever POKE will be expressed as two bytes. For example, your POKE instruction might take the form of

LD(NN),A    or
LD(NN),L

In the first case, the contents of register A (one byte, less than 256) will be POKEd into the address given by NN (=N1+256*N2). If you are POKEing the contents of a two-byte register, then the contents of the low-byte register (L, C, or E) will be POKEd into the memory at address N1+256*N2, and the contents of the high-byter will be POKEd into the following byte of memory. In other words, data storage will follow the pattern that you are used to: Least Significant Byte first.

16514    1 Gr 1    LD BC,69
16515 69 ?
16516 0 space
16517 237 GOSUB LD(16522),BC
16518 67 ?
16519 138 Gr F
16520 64 RND
16521 201 TAN RET
16522 27 . null
16523 27 . null

After RAND USR 16514, PRINT
(PEEK 16522+256*PEEK 16523)
should give 69

Figure 14-3. LD(NN),BC

16514   62 Y       LD A,69
16515 69 ?
16516 50 M LD(16520),A
16517 136 Gr H
16518 64 RND
16519 201 TAN RET
16520 27 . null
16521 27 . null

After RAND USR 16514, PRINT
PEEK 16520 should give 69

Figure 14-4. LD(NN),A

For practice, try the exercises in Figures 14-3 to 14-5. Remember to provide nulls at the end of the REM statement to furnish a destination for the POKEd data. In these cases, don’t PRINT USR 16514, as you did before. Use RAND USR 16514, followed by the PRINT statement given with each exercise.

That’s all for now. There will be more.

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.