.........1.........2.........3.........4.........5.........6.........7.........8

FIRST STEPS IN MACHINE CODE
An introduction to Z80 machine code by David Nowotnik
part 3 of 6 - Using Flags
from ZX Computing Apr/May'85


One of the essential features of all computer programming
languages is the ability to test a condition, and take
different courses of action according to the result of that
test (IF ... THEN ... in BASIC). Machine code is no
exception, and in this article I shall be examining how the
Z80 processor makes decisions. There will also be a little
on simple arithmetic, and one of the Z80's powerful load
instructions, which enables large chunks of memory to be
moved with a few bytes of code.


1. The flags

In part 1 of this series, I described how a register in the
Z80 CPU, or a byte of memory, is made up. If you recall,
there are eight bits within a register or byte, each bit has
two states, 0 or 1. It is the combination of values of bits
within a byte that makes up the value held by the register
or byte.

The F register in the CPU is a special purpose register in
which the individual bit values are far more important than
the total byte value. 'F' stands for 'flag'; it is the bits
of the F register which 'flag' messages to the processor,
and to the machine code program. Following almost every
single instruction carried out by the Z80 processor, the
flag register is automatically modified according to the
nature and result of the operation performed. In effect, the
CPU tests the result of the operation, and the results of
the test are recorded as yes/no answers (1 or 0) by certain
bits (flags) within the F register. Not all the flags are of
value to the machine code programmer; those that can be used
are described below:

The Carry (C) Flag - This tests whether an addition or
subtraction operation remained within the limits of a byte
value (0-255), or if carry or borrow occurred. Other
applications will be demonstrated later in the series.

The Parity/Overflow (P/V) Flag - Tests the parity of the
result of an operation. This involves counting the '1's in
the bits which form the result byte. If the parity sum is
odd, then the P/V flag is set to 0. The flag is also used to
demonstrate a 'carry' in two's complement arithmetic (also
dealt with later on).

The Zero (Z) Flag - Set to 1 if the result of an operation
is zero, otherwise this flag is set to 0.

The Sign (S) Flag - This takes the value of the highest bit
(bit 7) of a register following an operation on that
register. Don't worry if most of what I have described isn't
too clear yet, it should become clear later on in the
series.

A programmer can set (flag value=1) or reset (flag value=0)
any of these flags (either directly, with a specific machine
code instruction, or indirectly with a 'dummy' operation).
More often, the programmer will want to test whether a flag
has a value of 1 or 0, and respond accordingly. That
response usually means moving (or not moving) to another
part of the program. In BASIC, this could be GOTO, or GOSUB
(or RETurn from subroutine) if the condition is, or is not,
met. The same choices are available in machine code. These
are shown in table 2.

There are two machine code instructions which are equivalent
to BASIC's GOTO. These are JP and JR. JP stands for jump
absolute, and JR for jump relative. JP instructions are
usually three bytes long; the first is the opcode, the
second and third contain the address in memory to which the
program will jump. The address is calculated as the value in
the second byte plus 256 times the value in the third byte.
JR instructions are two bytes long; the first is the opcode,
and the second is the distance (and direction) of the
relative jump. The jump is calculated in exactly the same
way as DJNZ, described last time. That is, the jump can be
anywhere from - 128 to + 127 from the address of the opcode
immediately following the JR instruction.

JR has the advantages that it uses two instead of three
bytes, and the jump is independent of the position of the
machine code in memory, so should be used in preference to
JP. If the jump is greater than the limits set on JR, then
JP is easier to use (it is not impossible to use JR for
large jumps, but it could be tricky to program).

The equivalent of GOSUB in assembly language is CALL. It
works in just the same way. The argument of CALL is an
address in memory, so the instruction is three bytes long
(the first for the opcode, the second and third the address
in memory). Unfortunately, the Z80 processor does not allow
relative CALLs. The subroutine is terminated with the RET
instruction, which, like the RETurn command in BASIC,
returns the operation of the program to the instruction
immediately following the CALL instruction which initiated
the subroutine.

JP, JR, CALL, and RET all have unconditional (i.e. not
dependent on a test of any flag) as well as conditional
options. Most of these are shown in Table 1.


2. Comparisons

A simple example of using flags is in conjunction with the
assembly language instruction CP (compare). This allows the
contents of the A register to be compared with the contents
of any other register, or the contents of a byte in memory
(indexed by HL). In effect, with CP, the CPU carries out a
subtraction between the A register contents, and the
register or byte with which it is being compared. The result
is not stored anywhere, but the result effects the values of
the flags. For example, here is a typical assembly language
sequence involving CP:

	CP E
	JR NZ,next

Having compared the value in the A register with that in the
E register, the CPU sets or resets the zero (Z) flag
according to the result. If A = E, then the Z flag = 1, and
if A does not equal E, then the flag is reset to 0. The
instruction 'JR NZ,next' tests the value of the Z flag. If
the flag is not zero (NZ), then a relative jump to the
position in the program labelled 'next' will occur; if the
flag is set, then the program continues with the instruction
immediately following 'JR NZ, next'. Other flags are set or
reset according to the relative values of the two registers
being compared. It is possible to test whether one is
greater or less than the other. Rather than tell you all of
these, I have given you a program which will show the effect
of certain comparisons; this is the first example given
later on in the article. By setting different values in the
registers, you should be able to determine for yourself the
flag settings for 'less than' or greater than' using this
program. Why not try it!


Addition and subtraction

Like it or not, computer programs almost invariably involve
some arithmetic, and machine code is no exception. The
facilities for arithmetic on the Z80 processor are quite
simple; addition, subtraction, and instructions (which I'll
cover in a later issue) to effectively multiply and divide
by two. All other mathematical operations are made up from
these basic operations. Last time, I described the simple
cases of adding or subtracting one (INC and DEC) from a
register, or register pair. There are a number of machine
code instructions which allow more complex addition and
subtraction. For these, the choice of register is more
limited than with INC and DEC. A single register addition or
subtraction must always involve the 'A' register. Addition
takes the form of adding the contents of the A register to
another register or byte in memory (addressed by the HL
pair), or a number (operand) in the program, and placing the
result in the A register. Similarly, subtraction involves
taking the value of a register, memory byte, or operand from
the value in 'A' and placing the result back in the A
register.

Two byte arithmetic is more restricted. Addition involves
taking the contents of the HL register pair, adding the
contents of another register, and placing the result in HL.
Subtraction involves subtracting a register pair value from
the value in HL, and placing the result in HL. In single
byte arithmetic, numbers are restricted to the range 0 to
255, whilst the range for two byte arithmetic is 0 to 65535.

A further complication is the carry flag. It is possible to
add two numbers, then add the value of carry (0 or 1) to the
result just before storing the final value. And it is
possible to subtract the complement (1 minus the value) of
the carry flag from the result of subtracting two values,
before storing the result. This gives two forms of add (ADD
and ADC) and two forms of subtract (SUB and SBC); without
and with the carry flag. Confused? I'll try and explain.

For simple arithmetic, it's easier to use the forms of add
or subtract which do not use the carry flag value (ADD and
SUB). So, if you are adding two registers or two register
pairs, or subtracting two registers, use ADD or SUB. That
way there is little chance of a mistake being made by an
incorrect setting of the carry flag. The carry flag will, of
course, be set (or reset) by the result of the addition /
subtraction. For more complicated arithmetic, involving
numbers held in several bytes, you'll want to use ADC or
SBC. The purpose of involving the carry flag is that you can
register whether or not there has been an addition or
subtraction which has resulted in a value greater or smaller
than that allowed by the restrictions on the register size.
In this way you can carry a value to the next addition /
subtraction, as you would carry one into the 'tens' column,
having added 6 and 5 in the 'units'. Before using ADC or SBC
it is usual to reset (for ADC) or set (for SBC) the carry
flag before carrying out the calculation. The assembly
language instruction to set the carry flag is SCF. There is
no direct instruction to reset the carry flag, but this can
be carried out by first setting the carry flag with SCF
followed by the instruction CCF (complement carry flag),
which inverts the value of the carry flag (0 to 1, or 1 to
0). The two instructions are one byte each (opcodes are 37
(SCF) and 3F (CCF), hex). The carry flag can be reset in one
byte; I'll show you how next time.

You'll see all the opcodes for the add and subtract in Table
2. Note that for two byte subtraction, only SBC is
available, so be sure to set the carry flag when using it
for simple arithmetic. Fig 2 in the examples section, later
on, provides a BASIC program which should help to clarify
any doubts about the different add and subtract
instructions.


Block loading

The final piece of theory for this issue is the Z80's
powerful block load instruction. It allows the values in a
block of bytes (of any size) in memory to be moved to
another location. It works like this:

The starting address of the source block is loaded into the
HL register pair, the starting address of the destination
block is moved into DE, and the number of bytes to be moved
goes into BC. Then one instruction LDIR performs the move.
LDIR stands for LoaD Increment Repeat. The value in BC acts
as a counter. The value in the byte addressed by HL is
transferred to the byte addressed by DE; HL and DE are
incremented, while BC is decremented, then the instruction
repeats itself automatically until BC gets down to zero.
There is a non-repeat alternative, LDI, where the byte value
transfer takes place, and registers HL and DE are
incremented, BC decremented, but the instruction is not
repeated automatically. Beginners to machine code would
normally use LDIR, and this is shown in the examples.

The Z80 offers an almost identical instruction called LDDR.
To use this, the END addresses of the source and destination
blocks are loaded into HL and DE, respectively, while BC
still holds the number of bytes to be transferred. Each
cycle of the instruction involves transfer from (HL) to
(DE), and all three register pairs decremented. LDD is the
non- automatic repeat version of LDDR. It doesn't really
matter whether you use LDIR or LDDR unless there is some
overlap bet- ween the source and destination blocks of
memory. Then, the choice is critical if bytes are not going
to be corrupted. I'll leave you to sort out which should be
used, depending on whether the overlap is at the beginning
or end of the source block! The block move opcodes are shown
in Table 2.


Examples

The first two examples given this time are written in such a
way that they will work on both the ZX81 and Spectrum.
Example 1 is the flag demonstration program, and all details
appear in fig. 1. Example 2 demonstrates add and subtract,
and should help explain any questions you might have on all
the arithmetic instructions mentioned earlier. Fig.2
contains the details of this.

The final example carries out similar block move operations
on both ZX81 and Spectrum; copying the display file to a
safe area of RAM, then returning it 'instantly'. Machine
differences prevent the same code working on both machines,
so ZX81 users should refer to fig.3, while Spectrum owners
go to fig.4.

Next time we'll be looking at a stack which has little to do
with chimneys, and some bit operations!


- Table 1. Testing flags  - - - - - - - - - - - - - - - - - - - - - - - - -

a) Symbols and flag values

Flag    Flag=1          Flag=0
C       C (Carry)       NC (No Carry)
Z       Z (Zero)        NZ (Not Zero)
P/V     PO (Parity Odd) PE (Parity Even)
S       P (Positive)    M (Negative)

b) Valid operations and their opcodes

Unconditional   ----------------------- Conditional -----------------------
Operation                               Operations
                Flag: C         P/V             Z               S
JP   (C3)       JP C    (DA)    JP PO   (E2)    JP Z    (CA)    JP P    (F2)
                JP NC   (D2)    JP PE   (EA)    JP NZ   (C2)    JP M    (FA)
JR   (18)       JR C    (38)    -               JR Z    (28)    -
                JR NC   (30)    -               JR NZ   (20)    -
CALL (CD)       CALL C  (DC)    CALL PO (E4)    CALL Z  (CC)    CALL P  (F4)
                CALL NC (D4)    CALL PE (EC)    CALL NZ (C4)    CALL M  (FC)
RET  (C9)       RET  C  (D8)    RET  PO (E0)    RET  Z  (C8)    RET  P  (F0)
                RET  NC (D0)    RET  PE (E8)    RET  NZ (C0)    RET  M  (F8)


- Table 2. Aritmetic and block move opcodes - - - - - - - - - - - - - - - -

a) Arithmetic

Instruction             Register (r)
                A   B   C   D   E   H   L   (HL)n
ADD A,r         87  80  81  82  83  84  85  86  C6
ADC A,r         8F  88  89  8A  8B  8C  8D  8E  CE
SUB A,r         97  90  91  92  93  94  95  96  D6
SBC A,r         9F  98  99  9A  9B  9C  9D  9E  DE

Instruction     Register Pair (rr)
                HL      DE      BC
ADD HL,rr       29      19      09
ADC HL,rr       ED6A    ED5A    ED4A
SBC HL,rr       ED62    ED52    ED42

b) Block Moves

Instruction     Opcode

LDI             EDA0
LDIR            EDB0
LDD             EDA8
LDDR            EDB8


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Spectrum users should type in the following listing as shown
(Figure 1). A minor change should be made by ZX81 users.
Instead of line 60 type in the following two lines:

	60 POKE 16388,47
	70 POKE 16389,117

Once you have completed entry of the listing, go to the
explanation at the end of the listing.


- Fig.1. Demonstration of flags - - - - - - - - - - - - - - - - - - - - - -

  10 REM FLAG DEMO
  20 REM ZX COMPUTING, 1985
  30 REM
  40 REM INITIALISE
  60 CLEAR 29999
 100 DIM f$(8,3)
 110 LET f$(1)=" S "
 120 LET f$(2)=" Z "
 130 LET f$(6)="P/V"
 140 LET f$(8)=" C "
 200 REM ENTER MACHINE CODE
 210 LET x=30000
 220 LET t=0
 230 INPUT y
 240 IF y=-1 THEN GO TO 300
 250 POKE x,y
 260 LET x=x+1
 270 LET t=t+y
 280 GO TO 230
 300 IF t=2100 THEN GO TO 500
 310 PRINT "CHECKSUM ERROR (";t;")"
 320 STOP
 500 CLS
 510 PRINT AT 21,0;"ENTER 'A' REGISTER VALUE"
 520 INPUT a
 530 PRINT AT 21,0;"ENTER THE COMPARISON VALUE"
 540 INPUT c
 550 POKE 32500,a
 560 POKE 32501,c
 570 IF USR 30000 THEN
 580 CLS
 590 PRINT
 600 PRINT "VALUE IN 'A' REGISTER IS ";a
 610 PRINT
 620 PRINT "COMPARISON VALUE = ";c
 630 PRINT
 640 PRINT "FLAGS ARE SET AS:"
 650 LET x=32502
 660 FOR i=1 TO 8
 670 PRINT
 680 IF i=3 OR i=4 OR i=5 OR i=7 THEN GO TO 700
 690 PRINT f$(i);"    ";PEEK x
 700 LET x=x+1
 710 NEXT i
 720 PRINT AT 20,2;"PRESS ANY KEY TO CONTINUE"
 730 IF INKEY$="" THEN GO TO 730
 740 GO TO 500

---

Once you have typed in the listing, SAVE the program, then
RUN it. You'll get an INPUT request on the screen. This is
the first part of the program, and you're expected to enter
the machine code routine as a series of decimal numbers.
Refer to the assembly language listing below, and enter the
numbers on the left hand side, in the order shown. Once you
have entered the 22 numbers, enter -1, which informs the
program that you have come to the end. If you made a mistake
on the entry then a checksum should detect it, and stop the
program going any further. Once you enter the main routine,
on-screen instructions and display should be clear enough to
make a further description unnecessary.

There are three new machine code commands in the routine
outlined below. They'll be covered in the next two parts of
the series.

---

33,244,126       LD HL,32500  Start of data store
126              LD A,(HL)    Load A register
35               INC HL       Move to next byte
190              CP (HL)        & compare its value to A
245              PUSH AF      Copy   the F register
209              POP DE         into the E register
6,8              LD B,8       Lood loop counter
35          LOOP INC HL       Move to next byte
54,0             LD (HL),0      & place 0 into it
203,19           RL E         Move 1 bit of E into Carry
48,2             JR NC,NEXT   Jump to NEXT if bit is 0
54,1             LD (HL),1    Place 1 into byte
16,245      NEXT DJNZ,LOOP    Loop back to LOOP, unless
201              RET            all 8 done, then return.


- Fig.2. Demonstration of Z80 arithmetic instructions - - - - - - - - - - -

  10 REM MACHINE CODE ARITHMETIC
  20 REM ZX COMPUTING, 1985
  30 REM
  40 DIM a$(4,3)
  50 LET a$(1)="ADD"
  60 LET a$(2)="ADC"
  70 LET a$(3)="SUB"
  80 LET a$(4)="SBC"
  90 DIM n(2,2)
 200 LET x=0
 210 GO SUB 500
 220 LET x=7
 230 GO SUB 500
 240 GO SUB 560
 250 PRINT AT 21,0;"PLACE A VALUE IN UPPER TWO BYTES"
 260 INPUT u
 270 LET s=u
 280 LET p=2
 290 GO SUB 1000
 300 PRINT AT 21,0;"PLACE A VALUE IN LOWER TWO BYTES"
 310 INPUT l
 320 LET s=l
 330 LET p=9
 340 GO SUB 1000
 350 PRINT AT 21,0;"PLACE A VALUE IN THE CARRY FLAG "
 360 INPUT c
 370 IF c=1 OR c=0 THEN GO TO 5000
 380 GO TO 360
 500 PRINT AT x,5;"**********************"
 510 FOR i=1 TO 4
 520 PRINT "     *        *           *"
 530 NEXT i
 540 PRINT "     **********************"
 550 RETURN
 560 PRINT AT 14,10;"*****      *****"
 570 FOR i=15 TO 17
 580 PRINT AT i,10;"*   *      *   *"
 590 NEXT i
 600 PRINT AT 18,10;"*****      *****"
 610 PRINT AT 19,12;"A        CARRY"
 620 PRINT AT 6,10;"LO         HI"
 630 PRINT AT 4,0;"(HL)";AT 9,0;"(DE)"
 640 RETURN
 680 PRINT AT 21,0;"                                "
 690 RETURN
 750 FOR q=1 TO 20
 760 GO SUB 800
 770 NEXT q
 780 RETURN
 800 FOR l=1 TO 2
 810 NEXT l
 820 RETURN
 900 FOR t=1 TO 10
 910 PRINT AT -5+r*7,x*10-1;"   "
 920 GO SUB 800
 930 PRINT AT -5+r*7,X*10-1;n(r,x)
 940 GO SUB 800
 950 NEXT t
 960 RETURN
1000 LET ss=INT (s/256)
1010 LET st=s-ss*256
1020 PRINT AT p,9;st;AT p,19;ss
1030 LET p=INT (p/9)+1
1040 LET n(p,1)=st
1050 LET n(p,2)=ss
1060 RETURN
2000 PRINT AT 21,0;"LD (DE),A "
2010 GO SUB 750
2020 LET r=2
2030 GO SUB 900
2040 PRINT AT 16,11;"   ";AT 16,11;n(2,x)
2050 RETURN
2100 IF w>255 THEN GO TO 2150
2110 LET c=0
2120 LET n(2,x)=w
2130 GO TO 2170
2150 LET c=1
2160 LET n(2,x)=w-256
2170 FOR t=1 TO 10
2180 PRINT AT 16,11;"   ";AT 16,22;" "
2190 GO SUB 800
2200 PRINT AT 16,11;n(2,x);AT 16,22;c
2210 GO SUB 800
2220 NEXT t
2230 RETURN
2300 PRINT AT 21,0;"LD (DE),A "
2310 LET r=2
2320 GO SUB 900
2330 RETURN
2400 IF w<0 THEN GO TO 2450
2410 LET c=1
2420 LET n(2,x)=w
2430 GO TO 2470
2450 LET c=0
2460 LET n(2,x)=256+w
2470 GO TO 2170
3000 PRINT AT 21,0;"INC HL    INC DE"
3010 GO SUB 750
3020 GO SUB 680
3030 RETURN
5000 PRINT AT 16,22;c
5010 PRINT AT 21,0;" 1=ADD, 2=ADC, 3=SUB, 4=SBC",
5020 INPUT m
5030 IF m<>INT m THEN GO TO 5020
5040 IF m<1 OR m>4 THEN GO TO 5020
5050 GO SUB 680
5060 PRINT AT 4,28;a$(m)
5070 GO SUB 5000+m*1000
5080 PRINT AT 21,0;"PRESS ANY KEY TO CONTINUE"
5090 IF INKEY$="" THEN GO TO 5090
5100 RUN
6000 FOR x=1 TO 2
6010 GO SUB 2000
6020 PRINT AT 21,0;"ADD A,(HL)"
6030 GO SUB 750
6040 LET w=n(1,x)+n(2,x)
6050 LET r=1
6060 GO SUB 900
6070 GO SUB 2100
6080 GO SUB 750
6090 GO SUB 2300
6100 GO SUB 750
6110 IF x=2 THEN GO TO 6150
6120 GO SUB 3000
6150 NEXT x
6160 RETURN
7000 FOR x=1 TO 2
7010 GO SUB 2000
7020 PRINT AT 21,0;"ADC A,(HL)"
7030 GO SUB 750
7040 LET w=n(1,x)+n(2,x)+c
7050 LET r=1
7060 GO SUB 900
7070 GO SUB 2100
7080 GO SUB 750
7090 GO SUB 2300
7100 GO SUB 750
7110 IF x=2 THEN GO TO 7150
7120 GO SUB 3000
7150 NEXT x
7160 RETURN
8000 FOR x=1 TO 2
8010 GO SUB 2000
8020 PRINT AT 21,0;"SUB A,(HL)"
8030 GO SUB 750
8040 LET w=n(2,x)-n(1,x)
8050 LET r=1
8060 GO SUB 900
8070 GO SUB 2400
8080 GO SUB 750
8090 GO SUB 2300
8100 GO SUB 750
8110 IF x=2 THEN GO TO 8150
8120 GO SUB 3000
8150 NEXT x
8160 RETURN
9000 FOR x=1 TO 2
9010 GO SUB 2000
9020 PRINT AT 21,0;"SBC A,(HL)"
9030 GO SUB 750
9040 LET w=n(2,x)-(n(1,x)+(1-c))
9050 LET r=1
9060 GO SUB 900
9070 GO SUB 2400
9080 GO SUB 750
9090 GO SUB 2300
9100 GO SUB 750
9110 IF x=2 THEN GO TO 9150
9120 GO SUB 3000
9150 NEXT x
9160 RETURN

---

When this program is RUN, there is on the screen a
diagrammatic representation of the two pairs of bytes in
memory (addressed by HL and DE), the 'A' register and the
Carry flag. The program asks you to insert two values
(0-65535) into the pairs of bytes. The value is
automatically split into low and high byte values, and
placed in the appropriate box. You then select 1 or 0 for
the Carry flag, and the arithmetic operation (ADD, ADC, SUB,
or SBC). A slow motion display then shows you what happens
when you conduct two byte arithmetic using one byte
instructions. The assembly language instruction appropriate
to the operation being carried out will be shown at the
bottom left of the screen. You should be able to see the
effect on the carry flag and result of using the four
different operations.


- Fig.3. ZX81 block move demonstration  - - - - - - - - - - - - - - - - - -

Type in the following listing, SAVE it. Before RUNning the
program, lower RAMTOP with two direct commands:

	POKE 16388,231
	POKE 16389,124
	NEW		
[This NEW was omitted, but is required to actually reposition RAMTOP. JG.]

The hex loader places the machine code (shown below) into
RAM. A screen message is then generated, and saved (line
140) to a safe section of RAM. The screen is cleared, and
the display restored instantly by another machine code block
load routine (line 180).

---

  10 REM ..................................
  20 LET X=16514
  30 LET A$="2A0C4011E77C011903EDB0C921E77CED5B0C40011903EDB0C9"
  40 FOR I=1 TO LEN A$/2
  50 LET J=16*(CODE A$-28)+CODE A$(2)-28
  60 IF PEEK X=27 THEN POKE X,J
  70 LET X=X+1
  80 LET A$=A$(3 TO)
  90 NEXT I
 100 CLS
 110 FOR I=1 TO 20
 120 PRINT "1234567890ABCDEFGHI"
 130 NEXT I
 140 RAND USR 16514
 150 CLS
 160 PRINT AT 20,0;"PRESS A KEY TO RESTORE DISPLAY"
 170 IF INKEY$="" THEN GOTO 170
 180 RAND USR 16526

---

Assembly language listing:

SAVE     LD HL,(16396)    2A0C40    Load D_FILE into HL
         LD DE,31975      11E77C    Load RAMTOP into DE
         LD BC,793        011903    Length of the display file
         LDIR             EDB0      Block load
         RET              C9        Return to BASIC
RESTORE  LD HL,31975      21E77C    Load RAMTOP into HL
         LD DE,(16396)    ED5B0C40  Load D_FILE into DE
         LD BC,793        011903    Length of the display file
         LDIR             EDB0      Block load
         RET              C9        Return to BASIC


- Fig.4. Spectrum block move example  - - - - - - - - - - - - - - - - - - -

Type in the following listing, SAVE it, then RUN it. After
the machine code has been placed in position above RAMTOP
(lines 10 to 80), a screen display is generated, and saved,
then the screen cleared, and the display restored by another
machine code block move.

---

  10 CLEAR 24999
  20 FOR i=25000 TO 25023
  30 READ x: POKE i,x
  40 NEXT i
  50 DATA 33,0,64,17,112,98
  60 DATA 1,0,27,237,176,201
  70 DATA 33,112,98,17,0,64
  80 DATA 1,0,27,237,176,201
  90 CLS
 100 FOR i=1 TO 20
 110 PRINT INK i/3; PAPER 8-i/3;"  111122223333444455556666777788"
 120 NEXT i
 130 RANDOMIZE USR 25000
 140 CLS
 150 PRINT AT 12,0;"Press any key "
 160 IF INKEY$="" THEN GO TO 160
 170 RANDOMIZE USR 25012

---

Assembly language listing:

25000    LD HL,16384      210040    Start of display file
         LD DE,25200      117062    Start of storage area
         LD BC,6912       01001B    Number of bytes moved
         LDIR             EDB0      Move them
         RET              C9          and return to BASIC
25012    LD HL,25200      217062    Start of storage area
         LD DE,16384      110040    Start of display file
         LD BC,6912       01001B    Number of bytes moved file
         LDIR             EDB0      Move them
         RET              C9          and return to BASIC


--
Another Fine Product transcribed by:
Jim Grimwood (jimg@globalnet.co.uk), Weardale, England
--
