This technique is based on a suggestion from Dennis Clinton, of Sunland, CA. Dennis modestly says that practically all the veterans know it already, but it was sure a new one on me. He gives credit, by the way, to David Nowotnik, who published it in “ZX Computing” Magazine, under “First Steps in Machine Code”.
There are many times when you’re writing machine code routines with loops in them. A few commands, like LDIR, LDDR, CPIR, CPDR, and DJNZ, automatically take care of keeping count of the number of times the loop is repeated: you just set BC (B, in the case of DJNZ) to the required number of iterations, and the loop stops when it has counted this number down to zero.
However, you sometimes want to do something to the data while you’re moving it, so you use LDI, CPI, etc., and decrement BC after the entire operation has been completed. Or you may want to do something with the data without moving it at all. (DJNZ is a powerful command in this sort of application, as it combines DEC B, compare B with zero, and JR in one instruction. You still have to include the number of bytes to jump, of course.)
If you’re counting to 255 or less, you have a choice of many ways to keep count: for instance, you can use DJNZ, you can CP the count variable, or you can just DEC the count, and use the status of the plus/minus, carry, or zero flag to steer your program in the right direction. However, it gets a little stickier if you want to iterate more than 255 times–DJNZ won’t work, and I don’t know of any easy operation on a two-byte register that will do the trick. You might think to SBC 1 each time, and use the carry flag as your test, but it’s not all that easy to SBC a number from a two-register variable. And the flags tend to ignore INC or DEC operations on a two-byte register. Perhaps the most obvious way to determine when the loop is finished is to CP both B and C with zero, and branch (or whatever else you want to do) when BOTH B and C are at zero.
And that’s essentially what Dennis’s technique does; but it does it in a very easy way. Try this:
. . . . .
(Loop)
DEC BC
LD A,B
OR C
JR NZ, Loop
. . . . .
If you don’t remember, the command OR gives a NON-ZERO reading on the zero flag if the content of either the A register or the register tested (C in this case) is not equal to zero. Since you have set A=B, then OR C gives non-zero if either B or C is not zero.
Of course, you then have to re-assign a value to A if you’re going to use A somewhere else in the program. PUSH AF. . .POP AF is one way to do this–or sometimes you can define the loop so it includes the LDA,x command.
Dennis says that he prefers to preserve the value of A via EX AF,AF’ (8d or 08h)–once before the test sequence, and once afterwards. You pay your money and you take your choice.