Part Seven:
Recursion

    Recursion is the process of looping over a certain area of code repeatedly, until the loop is "broken" out of when a certain condition is met.  For instance, if you wanted some code to perform a certain action eight times, you could write a recursive algorithm to execute the same code that many times, rather than writing out the code segment eight seperate times.
    This next block of code will use the b register as a counter.  When B becomes 0, the loop will terminate.

 ld b,8                               ;let's run the loop 8 times
add_hl_de_loop:               ;label the place where you want the recursion to begin
 add hl,de                         ;the action of the loop ... we want to perform this action 8 times
 dec b                               ;decrement b; set the zero flag if it becomes zero, reset it otherwise
 jr nz,add_hl_de_loop       ;continue the until B becomes zero

    The result of this is that DE is added to HL eight times.  From there it continues executing on the next line of code.  But a recursive loop can also be structured as call; as a call it will be capable of inputting the number of recursions.  Here, for instance, is a call that will do the same as above, only it will additionally input the number of recursions in B:

add_hl_de:                       ;the name of this call
 add hl,de                         ;the recursive action
 dec b                              ;decrement the counter (inputted -- at most 255)
 ret z                                ;return from the call when B reaches 0
 jr add_hl_de                   ;if B is not 0, keep looping

    Now DE was added to HL B number of times.  If HL was initially zero, then the effect of this call was to multiply DE by B, storing the result to HL.  Since the Z80 has no multiplication instruction, recursion of this kind is employed often, even though in most cases it is very slow.  Later on, I may show you a faster algorithm for multiplication.

    Two instructions that are useful in manipulating counters: inc and dec, or increment and decrement.  The operand of this instruction can be a register or indirect address (<inc a>, <dec (hl)>) or a register pair (<inc de>, <dec ix>).  Incrementing and decrementing of the first kind will set the zero and sign flags according to the result of the active operand.  The carry flag will always be reset.  For example, with 0 in E, <dec e> will reset the zero flag, reset the carry, and set the sign flag.  Inc and dec of a register pair, however, has no affect on any of the flags.
    Now that you understand two important instructions that I've so far neglected, we can move one step further, combining the decrement instruction into another instruction specialized for recursion called djnz.  Djnz (decrement, jump if not zero) will decrement the B register and then make an absolute jump to the provided label unless B becomes zero.  djnz label  Here's the first loop again, modified to use djnz:

 ld b,8                               ;initialize counter to loop 8 times
add_hl_de_loop:
 add hl,de
 djnz add_hl_de_loop       ;decrement B, continue once B is zero

    This is an obviously useful instruction, and it shows why B should be the primary register to use as a counter.

    A counter is one method of controlling recursion, but really anything that sets a flag can be checked and used to break a recursive loop.  If you want to break the loop when A becomes $3c, then <sub $3c> will set the zero flag and break the loop.  There is one fundamental problem with this, however; <sub $3c> destroys the content of the A register, making it impossible to do any recursion of this kind, bringing us into the depths of contact with yet another extremely important instruction: cp, or the compare instruction.  It does the same as the sub instruction -- subtract the operand from the A register and set the approiate flags -- but with one important difference: it doesn't affect the contents of the A register, but it does set the flags as though a subtraction took place.  If A is 22 when <cp 22> is executed, then the zero flag will be set and the sign and carry flags reset.  If A is 21 when <cp 22> is executed, then the zero flag will be reset and the sign and carry flags will be set.  If A is 23 when <cp 22> is executed, then all flags will be reset.  In this way, cp can be used to test greater than and less than operations.  If A is greater than the operand, all flags are reset; if A is equal to the operand, only the sign flag is set; if A is less than the operand, the sign and carry flags are set and the zero flag reset.  Here is an example:

 cp d                                 ;compare A to D
 jr z,d_equal_to_a             ;z is only set when D is equal to A
 jr c,d_greater_than_a       ;c is only set when D is greater than A
 jr nc,d_less_than_a          ;nc means D is less than or equal to A, but we already checked z

    You could use the P and M conditions in the place of NC and C, but you would have to change the relative jump to an absolute jump.
    So, as an example, here is the chess square problem from the last section solved using recursion and the compare instruction.  This method is slower because it has to loop several times.

square_info:
 and %111111                ;the square can't be more than 63
 ld b,0                             ;intialize the number of accumulated rows as 0
sub_loop:
 sub 8                             ;subtract 1 row
 inc b                              ;the number of times the loop is run will represent the row
 cp 8                              ;when A becomes less than 8, break the loop
 jr nc,sub_loop               ;is A still greater than or equal to 8? then continue looping
 ld c,a                             ;the remainder in A is the column; put it into C
 xor b                             ;is the square black?
 and %1
 ret

    Loops can also be nested within each other; one loop, the inner loop, will execute as many times as required times the number of times as the outer loop is required to execute.  Here is an example of a nested loop (in the form of a call) that delays the processor for exactly five seconds:

timer5:
 ld e,$35                       ;outer loop to run $35 times
j60:
 ld b,$ff                        ;first inner loop to run $ff times
j61:
 ld d,$ff                        ;second inner loop to run $ff times
j62:
 dec d                          ;dec second inner counter
 jp nz,j62                     ;check it for zero
 dec b                         ;dec first inner counter
 jp nz,j61                     ;check for zero
 dec e                          ;dec outer counter
 jp nz,j60                     ;check for zero
 ret

    This routine uses a nested loop within a nested loop, using three counters -- B,D and E -- to keep track of current number of loops.  The effect of this routine is that the elapsed time from <ld e,$35> to <ret> will be exactly five seconds.  Adjusting the value put into E in the first instruction will vary the number of seconds that the processor delays -- the greater the number, the longer it will delay.

    Here are some more instructions that you might not find useful right away, except in a few circumstances.  These are the shift and rotate instructions.  As you saw in the previous section, I used <srl b> to divide B by two.  Shift right logically (srl) shifts all the bits in the operand one to the right, copying bit 0 into the carry flag; in binary this produces the same result as dividing the operand by two, with any remainder recorded by the carry flag.  So then, any division by the power of two can quickly be done using srl.  It would take four srl instructions to divide by 16.
    The only problem with this, however, is that you can't shift negative numbers to a negative result because of how the sign bits are set up.  There is another instruction you can use, though, called sra (shift right arthmeticly).  Sra will not change the sign bit as it shifts right, nor will it shift the sign bit; so, when C is -44 <sra c> will have the result of -22 in C with the carry flag reset (-45 in C followed by <sra c> will result in -22 in C with the carry flag set).  Both srl and sra will set the zero flag if the result is zero and set the sign flag if the result is negative.
    Shifting left is similar and can be accomplished using the instruction sla (shift left arithmeticly).  As you would expect, this multiplies the operand by two, by shifting all bits of the operand left and moving bit 7 into the carry flag.  When multiplying the A register by two, though, you should always use <add a,a> because it does the same and is one byte shorter.  If the byte addressed by IX contains 3, then <sla (ix)> will change that byte to 6, resetting the carry, zero and sign flags.

    Rotation instructions rotate the operand: rather than destroying bit 0 as when shifting right, rotating right will move that lost bit around into bit 7.  A second type of rotate can also occur, called rotating through the carry: rotating right through the carry will move bit 0 only to the carry flag, also moving the old carry flag into bit 7.  Here's a short sumarry of rotate instructions:

 rl operand - rotate operand left through the carry flag; 2 bytes
 rla  - rotate the accumulator (register A) left through the carry flag; 1 byte
 rlc operand - rotate operand left through bit 7; 2 bytes
 rlca  - rotate the accumulator left through bit 7; 1 byte
 rr operand - rotate operand right through the carry flag; 2 bytes
 rra  - rotate the accumulator right through the carry flag; 1 byte
 rrc operand - rotate operand right through bit 7; 2 bytes
 rrca  - rotate the accumulator right through bit 7; 1 byte

    All rotation instructions only affect the carry flag.