Block Transfers: Horizontal Scrolling on your 1K ZX81

See all articles from SYNC v2 n5
Author(s): John Scher
Publication: SYNC
Pub Details: SYNC v2 n5 (Volume 2, Issue 5)
Date: September/October 1982
Pages: 70-72

A programming technique called block transfers of memory adds new possibilities for your programming and for taking advantage of your computer’s capabilities. Although the technique involves the use of machine language, this article assumes only that you are familiar with the Sinclair manual ZX81 BASIC Programming and that you are willing to work with hexadecimal. Dr. Ian Logan’s article, “An Introduction to Machine Language” (SYNC 1:6) is helpful, but not essential.

For some readers learning may be its own reward. For those who want a more concrete incentive, this article will show how to modify Douglass D. Sharp’s LSCROLL routine (SYNC 2:2) for a 1K machine. Using this routine, you will be able to launch a fleet of jets, in formation, across your TV screen . . . that is, after a little homework.

What is a Block Transfer?

We must begin by defining a block of memory. This is the information held in a set of sequential addresses in the memory of the computer. The contents of a REM statement, for example, constitute such a block. A block transfer of this information would write the contents of the block into a different area of memory. That is, the sequence is reproduced at a new starting address. Furthermore, the original sequence is not disturbed unless the “source” and “destination” areas overlap.

RAMTOP

To use this programming technique, we must first understand the systems variable called RAMTOP. Reviewing the information on RAMTOP in ZX81 Basic Programming, Chapter 26, would be helpful at this point. The discussion below draws on this chapter and supplements it.

When you turn on the ZX81, it tests to see how much memory it has to work with and then stores the address of the first non-existent byte for future reference. This address is called RAMTOP. It is stored at addresses 16388 and 16389. For example, if you have 1K RAM, type:

PRINT PEEK 16388+256*PEEK 16389

and ENTER. This will tell you that the address of the first non-existent byte is 17408. This is RAMTOP.

You can change RAMTOP by POKEing the appropriate values into addresses 16388 and 16389 then typing NEW and ENTER. For example, suppose that you want to establish RAMTOP at 17388. You would type POKE 16388,236 and ENTER; then POKE 16389,67 and ENTER, and then NEW and ENTER. These values produce the new RAMTOP address by the following calculation:

236+256*67=17388

This POKEing will fool the machine into thinking that there is no usable memory above RAMTOP (17388).

As a result nothing above that address will be disturbed by the Basic system. The area above RAMTOP is also undisturbed by LOADing a new program into the machine. The usefulness of this area cannot be overemphasized because it gives the user a place to store machine code, Basic data arrays, and other memory blocks. These are then available for use in multiple Basic programs without having to type in the machine code or data each time you want to use it.

The only disadvantage of this area is that it is not saved by SAVE. This is why block transfers are so useful. They allow the transfer of information from a SAVEable area of memory to one that is undisturbed during program LOADing.

A Basic Program for a Block Transfer

Figure 1 shows a block transfer program in Basic. This program locates the bytes, in this case X’s, in the REM statement and transfers them to a new starting address. The address of the first X in the REM statement is 16514. Before using such a program to place machine code bytes above RAMTOP, you must first reserve space above RAMTOP as we have already discussed.

The bytes in Figure 1 could just as easily be in an array or another Basic variable. Either of these would be similarly SAVEable, although locating the starting address for a block transfer would be a bit more difficult.

Figure 1. A Basic Program for Block Transfer.

 1 REM XXXXXXXXXX
10 FOR N=0 TO 9
20 POKE 17398+N,PEEK (16514+N)
30 NEXT N

The LDIR Instruction

Given that much of the work of a computer is moving things from one address to another, it is not surprising that the Z80(A) microprocessor has a command that can accomplish a block transfer much more quickly and efficently than a Basic program like that in Figure 1. This is the “Repeating Block Load With Increment” instruction, LDIR. The LDIR instruction makes use of three register pairs: BC, DE, and HL. Initially, the BC register pair must hold the number of bytes that you want to transfer, just like the FOR-NEXT loop in Figure 1. The DE pair holds the first address in the “destination” block of memory, and the HL pair holds the first address in the “source” block of memory. The LDIR instruction transfers the contents of the address held in the HL pair to the address held in the DE pair. Then it increments HL and DE (i.e., adds 1) and decrements BC (i.e., subtracts 1). It then compares the BC pair to zero, and, if BC is not equal to zero, the instruction is repeated, otherwise the next instruction is executed.

Although we will use LDIR in the sample programs in this article, you should know that LDIR has a cousin, LDDR, which is similar except that it decrements all three registers. You might think about which of these two you would use to transfer overlapping memory blocks.

An Overview of the Process

At this point let me summarize what we are going to do. We will enter a machine code block transfer program along with a sample machine code routine to be transferred into the space above RAMTOP. Then we will transfer this block of memory to a SAVEable REM statement. At this point, a few modifications will be made, and then we will try out LSCROLL with a sample Basic program. There are slightly easier ways to achieve the same end result, but this sequence will teach you the most.

A Machine Language Block Transfer

The first step in entering the machine language block transfer program is to reserve 184 bytes above RAMTOP by typing POKE 16388,72 and ENTER, then POKE 16389,67, and ENTER, and then NEW and ENTER. Now that you have reserved the necessary space above RAMTOP, enter the hex loading program shown in Figure 2 (from Booth, “The Game of Life Revisited,” SYNC 2:1, p. 20).

Figure 2. Hex Loading Program.

200 LET V=-1
210 LET V=V+1
220 IF INT (V/50)*50=V THEN CLS
230 IF INT (V/10)*10=V THEN PRI
NT
240 INPUT H$
250 IF H$="" THEN GOTO 240
260 PRINT H$;"#"
270 IF H$="END" THEN STOP
280 IF H$="/" THEN GOTO 310
290 POKE 17224+V,16*CODE (H$)+C
ODE (H$(2))-476
300 GOTO 210
310 LET V=V-1
320 GOTO 240

When you RUN this program, the screen will prompt you for a byte in hexadecimal. Refer now to Figure 3, which lists the block transfer machine code. Note that the first nine bytes (contained in addresses 17224-17232) set up the BC, DE, and HL register pairs (LD stands for load) as discussed above. The next two bytes perform the transfer, and the last returns the computer to Basic. Note that all addresses within an LD instruction, for example, 4082h = 16514d, are entered lower-order-byte first, higher-order-byte second, in the same manner used to change RAMTOP. Remember that a 0 in a hexadecimal listing such as in Figure 3, column 2, is always a zero and never the letter O.

Figure 3. The Block Transfer Machine Code.

Decimal Hex  Instructions
Address Code
17224 01 LD BC,#of bytes
17225 B8 00B8h=184d
17226 00
17227 11 LD DE,destination
17228 82 4082h=16514d
17229 40
17230 21 LD HL,source
17231 48 4348h=17224d
17232 43
17233 ED LDIR(transfer)
17234 B0
17235 C9 RET(return)

Now that the screen is prompting you for an entry, enter the bytes in Figure 3, column 2 (i.e., type 01 and ENTER, then B8 and ENTER, etc.). Then go directly to Figure 4 without typing RUN and continue by entering the LSCROLL sequence. The parentheses and asterisks will be explained later. For now just ignore them (i.e., type 3A and ENTER, then FE and ENTER, then 43 and ENTER, etc.). If you make a mistake while entering this machine code, note that line 280 in Figure 2 gives you a backspace key, “/”. When you are done entering the machine code in Figure 4, type END and ENTER, and the loading program will STOP. At this point you should check to be sure that you did not leave out a byte or two accidently by typing PRINT PEEK 17405 and ENTER. The number 201 should appear at the top of your screen (201d = C9h). Congratulations if you have come this far without leaving anything out!

Figure 4. The LSCROLL Sequence.

17236-17407  ENTER the LSCROLL
sequence: 3A(FE.43)FE.16.DA(61
.43)3E.00.32(FE.43)3A(FF.43)D6.0
0.CA(71.43)FE.15.D2(71.43)C3(76.
43)3E.16.32(FF.43)F5.3A(FF.43)47
.F1.3A(FE.43)80.FE.16.DA(95.43)2
6.00.2E.16.3A(FE.43)4F.06.00.ED.
42.7D.32(FF.43)ED.5B.0C.40.0E.FF
.F5.3A(FE.43)6F.F1.26.00.06.00.1
A.FE.76.CA(AF.43)13.C3(A5.43)0C.
A7.E5.ED.42.E1.CA(BC.43)13.C3(A5
.43)06.00.F5.3A(FF.43)4F.F1.C5.D
5.E1.23.7E.FE.76.C2(C7.43)E5.A7.
ED.52.2B.7D.4D.D6.00.E1.C2(E0.43
)E5.D1.C3(F5.43)3D.C2(E8.43)13.C
3(F1.43)06.00.0B.13.D5.E1.23.ED.
B0.3E.00*12.13.C1.0B.79.D6.00.C2
(C4.43)C9.00*00*

Next, SAVE the hex loading program for future use. Then type NEW and ENTER to clear out the memory for the REM statement that we will use as the destination block of memory. Put the computer into FAST mode to enter the REM statement, otherwise it will take forever. Type 1 REM and then 184 X’s, as in Figure 1, and ENTER. You can change back to SLOW mode now.

Transferring LSCROLL

Now you are ready for the block transfer. Type RAND USR 17224 and ENTER. The transfer will occur so fast that you will think that you made a mistake. Type ENTER again and you will see the first few bytes of machine code in the REM statement. If this does not occur you had better PEEK a few addresses between 17224 and 17235 to look for mistakes.

Before you SAVE the REM statement, a few changes must be made so that in the future, when you LOAD the program, the block transfer will work in the other direction, that is, it will transfer LSCROLL from the REM statement to above RAMTOP. Also, the first twelve bytes need not be transferred because they make up the block transfer routine, not the LSCROLL routine. Figure 5 shows the changes you must make. Column 1 lists the addresses that the block transfer machine code routine occupies in the REM statement, and column 2 is identical to column 2 in Figure 3 for comparison. Column 3 gives the decimal values which must be POKEd in. Type POKE 16515,172 and ENTER, then POKE 16518,84 and ENTER, etc. until you have POKEd all five changes in. Now SAVE “LSCROLL”.

Figure 5. Changes for Transfers from REM to above RAMTOP.

Decimal Hex  Code         Instructions
Address Code Changes
16514 01
16515 B8-->AC=172d,change #bytes
16516 00-->00 ,no change
16517 11
16518 82-->54= 84d,change dest.
16519 40-->43= 67d,4354h=17236d
16520 21
16521 48-->8E=142d,change source
16522 43-->40= 64d,408Eh=16526d
16523 ED
16524 B0
16525 C9

In the future, when you want to use LSCROLL, reserve 172 bytes above RAMTOP (POKE 16388,84; POKE 16389,67; NEW), then LOAD “LSCROLL” and transfer it to the space above RAMTOP by typing RAND 16514. In fact, you should do this now to reclaim the twelve bytes of memory above RAMTOP that were needed before to make the block transfer to the REM statement. You will need all the memory available for the sample Basic program in Figure 6.

Using LSCROLL from above RAMTOP

Once you have LSCROLL above RAMTOP, type NEW and ENTER to get rid of the REM statement. Now you have enough space to enter the Rockets program in Figure 6. Note that the Rockets program POKES three addresses in the LSCROLL routine, 17394, 17406, and 17407. These addresses correspond to the bytes in Figure 4 that are followed by asterisks. The function of these addresses is as follows:

Figure 6. Rockets Program Listing.

 1 REM ROCKETS
4 POKE 17394,14
5 FOR H=6 TO 14
10 PRINT AT H,31;"[inverse graphic, illegible]"
15 NEXT H
17 FOR M=0 TO 4
20 POKE 17406,10-M
30 POKE 17407,1+2*M
35 FOR N=0 TO 32
40 RAND USR 17236
45 NEXT N
50 NEXT M
60 CLS
70 GOTO 5

17394 specifies the code for the character which will occupy the new spaces created by LSCROLLing.

17406 specifies the line number at which to begin LSCROLLing; POKE in a number from 0 to 21; see ZX81 BASIC Programming, p. 89.

17404 specifies the number of lines to be LSCROLLed, including the first one; POKE in a number from 1 to 22.

Add 1024 to these addresses if you have 2K RAM (see below). Rockets calls the LSCROLL routine with the line 80 RAND USR 17236 since the starting address of the LSCROLL routine is 17236.

Now comes the moment of truth. RUN Rockets. If you have come this far without making a mistake, you will see a line of jets form on the right side of the screen and take off across the screen in formation, leaving their contrails behind.

For More Than 1K RAM

Those with more than 1K RAM may want to locate LSCROLL at a higher starting address. For instance, if you have added 1K for a total of 2K RAM, you have an additional 1024 bytes. Therefore you could move RAMTOP to 18260 (17236 + 1024) for the final run which only requires 172 bytes. Do not forget that the hex loading program requires 184 bytes above RAMTOP. You will have to make these changes to move RAMTOP.

First, add 1024 to the following addresses in the figures:

Figure 2: Line 290.

Figure 3: all addresses in column 1.

Figure 6: Rockets Program: all addresses.

Next you must change some of the machine code.

Figure 3, column 2: change the 9th byte from 43 to 47.

Figure 5, column 3: 43 = 67d to 47 = 71d. Note that we have been adding 4 to the higher-order-byte of a series of addresses because 1024/256 = 4.

Figure 4: The parentheses contain addresses of information or routines within the LSCROLL program. For instance, the first parenthesis (FE.43) contains address 43FEh = 17406d. Add 4 to the higher-order-byte, 43, in all the parentheses. Thus the first parenthesis should read (FE.47). The program is ready for use at the starting address, 18260.

If you have more than 2K, make sure that you understand the changes suggested for 2K users, then give the changes best for your machine a try. One last word of caution: look over the article and write in the changes you will want to make in the addresses in the text, as well as the addresses referred to in the figures.

As you can see, LSCROLL is a superb program in that it allows the user to chose exactly which part of the screen to scroll. You are now ready to try some of your own programs with the LSCROLL routine. The program has many other virtues that are detailed by the author, and I give it the highest rating of any machine code program that I have seen in SYNC.

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