.png)
Every loop you can write so far runs forever.
That is one instruction short of being useful. A game needs to draw twenty sprites, print a five-digit score, step through a level one tile at a time - all of which mean doing something a particular number of times and then carrying on.
The missing piece is a jump that only sometimes jumps.
You have been looking at the answer since S3. On the end of every register line there is a column you have had no use for:
A BC DE HL PC SZ-H-PNC
41 3D00 1EFF FB3E 0769 01000010
SZ-H-PNC is a heading for eight single bits, and together they are the
flag register. The processor sets them automatically after most
instructions, as a record of how the last result turned out. They are how a
program knows anything about what it just did.
| Flag | Name | Means |
|---|---|---|
| S | Sign | The result was negative. |
| Z | Zero | The result was zero. |
| H | Half-carry | A carry happened inside the byte. Specialised; ignore it for now. |
| P | Parity / overflow | Depends on the instruction. Later. |
| N | Subtract | The last operation was a subtraction rather than an addition. |
| C | Carry | An addition carried out of the byte, or a subtraction borrowed. |
The two gaps in the heading are positions the Z80 does not use.
This section needs exactly one of them.
A word of warning about names. The C at the end of that heading is the
carry flag. The C in BC is the C register. They have nothing to do
with each other, they are used in completely different places, and confusing
them will cost you an hour one day. The instruction DEC C decrements the
register. The condition NC means "no carry" and does not mention the
register at all.
Z is set when the last result came out as zero, and clear when it did not.
That is the whole rule.
You can watch it happen. Two programs, differing in one digit:
ORG 256
LD A,1
DEC A ; 1 - 1 = 0
RET
A BC DE HL PC SZ-H-PNC
00 3D41 1EFF FB3E 0769 01000010
ORG 256
LD A,2
DEC A ; 2 - 1 = 1
RET
A BC DE HL PC SZ-H-PNC
01 3D41 1EFF FB3E 0769 00000010
Line the two flag bytes up against the heading. Every bit is the same except
the second - Z - which reads 1 where the answer was zero and 0 where it was
not.
Run both. It is the fastest way to make the flags stop feeling abstract.
DEC subtracts one:
DEC A
DEC C
It works on A, B, C, D, E, H and L, and it sets the flags
according to the result - which is the part that matters here. DEC a
register holding 1 and Z comes up set. DEC a register holding anything
else and it does not.
There is an INC that adds one, and it sets the flags the same way.
Now the piece that has been missing:
JR NZ,loop
Read it as three parts. JR is the relative jump from S5. NZ is the
condition - not zero, meaning "only if Z is clear". loop is where to
go.
In plain English: jump back to loop if the last result was not zero.
If the last result was zero, the jump does not happen and the processor carries straight on to the next instruction. That is the way out of the loop.
Put those together and you can repeat something a fixed number of times:
ORG 256
LD C,10 ; how many times
LD A,'A' ; what to print
loop: RST 8
DEFB 158 ; ZOUTC
DEC C ; one fewer to go
JR NZ,loop ; not finished? go round again
RET
What you should see
>AAAAAAAAAA
A BC DE HL PC SZ-H-PNC
41 3D00 1EFF FB3E 0769 01000010
Ten A's - count them. And the register line tells you the rest of the story:
C reads 00, so the counter ran out, and Z reads 1, which is exactly what
stopped the jump being taken.
Follow one lap. C is 10. Print an A. DEC C makes it 9, which is not
zero, so Z is clear, so JR NZ jumps. Round again. On the tenth lap DEC C
makes it 0, Z is set, the jump is not taken, and the RET underneath
finally runs.
Because the print call leaves C alone.
That is not a style preference. RST 8 / DEFB 158 is somebody else's code,
and you have no say in what it does with the processor while it runs. It
happens to give you back A - which is why A still holds your character on
the next lap - and it gives you back C. So C is a safe place to keep a
count across a print, and the loop above works.
A could not be the counter here anyway: it is carrying the character. Any
loop that both prints and counts needs the count somewhere else, and C is
the register known to survive.
Nothing stops you changing A as well as counting. Here is the alphabet
backwards:
ORG 256
LD C,26 ; 26 letters
LD A,'Z' ; starting from the end
loop: RST 8
DEFB 158 ; ZOUTC
DEC A ; previous letter
DEC C ; one fewer to go
JR NZ,loop
RET
What you should see
>ZYXWVUTSRQPONMLKJIHGFEDCBA
A BC DE HL PC SZ-H-PNC
40 3D00 1EFF FB3E 0769 01000010
There is one thing in here worth being careful about. DEC A and DEC C
both set the flags, and JR NZ only ever looks at the most recent result.
DEC C is the last one before the jump, so the loop counts laps and not
letters. Swap those two lines and the loop would end when a letter hit zero,
which is not what you want and is a mistake that reads perfectly innocently.
The rule: put the thing you are testing immediately before the jump.
A finishing at 40 is the proof it ran the right number of times - one
below 'A', which is 65, because the final DEC A happened after the last
letter printed.
LD C,10 to LD C,1. How many characters, and why not none?LD C,10 to LD C,0 and predict what happens before you run it.
This one is worth thinking through: what does DEC C do to a register
holding zero, and how many laps will it take to come back to zero?DEC A and DEC C. Predict the output, then
run it.JR NZ,loop to JR Z,loop - jump if zero. What should happen on
the very first lap?DEC A with INC A, starting fromZ come up set? What does that tell you about what Z actually
measures?6.1 - Count the alphabet forwards. Print A to Z in order. Use C for
the count and INC A for the letter.
6.2 - A row of anything. Write a program that prints a chosen character a chosen number of times, where changing the character and the count means editing exactly one number each. Use it to draw a line of 40 dashes.
6.3 - Two loops. Print five rows of ten asterisks, with a line break
between rows. You will need a count for the row and a count for the columns -
which means finding a second register that survives a print. Try B, check
the register line to see whether it did, and if it did not, work out another
way.
6.4 - Read the flags. Write three short programs that end with Z set,
Z clear, and C set. Check each against the register line. For the carry
one you will need to look up an instruction this section has not covered -
that is the exercise.
| What you see | What it means |
|---|---|
| One character instead of many | The counter was already zero, or the register you counted in was not the one you loaded. |
| The screen fills and the program never returns | The jump is always taken. Usually the flags are being set by something after the DEC, so the jump never sees the zero. Put the DEC immediately before the jump. |
| A screenful of characters when you asked for none | DEC on a register holding zero wraps round to 255 rather than stopping, so the loop runs a full cycle before Z comes up again. |
| The right number of laps but the wrong characters | Two DECs, and the jump is testing the wrong one. Check which is last. |
error: unable to resolve reference: loop |
The label and the jump do not match, or the colon is missing from the label. |
SZ-H-PNC column you have been seeing since S3.Z is set when the last result was zero.DEC subtracts one and sets the flags. INC adds one and does the same.JR NZ,label jumps only if the last result was not zero, so a loop can end.C. The print call is known to give A and C back, and A is
usually busy carrying the character.DEC immediately before the JR.S7. Doing the same job from several places. The two lines that print a
character have appeared in every program you have written. Next you write them
once and call them from anywhere - which introduces the stack, and explains
the RET you have been typing since S3.