A loop is a control structure which allows a block of instructions, the loop body, to be executed repeatedly in succession. In this article we investigate loop control structures and how they are constructed in assembly language. There are two categories of loops:
1) Counted Loops - Loops in which the iteration number, the number of times the loop should be executed, is known before the loop is entered.
2) Conditional Loops - Loops which will be continually iterated until a prescribed condition occurs.
Creating Counted Loops
The most commonly used instruction for creating a counted loop is the Branch On Count instruction, which has mnemonic BCT. The iteration number is first loaded into a register which is subsequently manipulated by BCT. Each time the BCT is executed, the iteration number in the register is decremented by one. After the register is decremented, the register is tested. If the result in the register is not zero, a branch is taken to the address specified in Operand 2. If the test reveals that the result in the register is zero, the loop is terminated and execution continues with the instruction following the BCT. Here is a sample loop that would be iterated 10 times.
LA R5,10 PUT THE ITERATION NO. IN R5
LOOPTOP EQU *
...LOOP BODY GOES HERE
BCT R5,LOOPTOP DECREMENT R5,IF NOT 0, BRANCH BACK
In the code above, the register that will control the loop is initialized at 10 and then the statements in the loop body are executed. At the end of the first iteration, BCT subtracts 1 from register 5, leaving it set to 9. The register is tested and since it does not contain zero, a branch is taken back to LOOPTOP. The loop body is executed a second time, and again BCT subtracts 1 from register 5, leaving it set at 8. BCT tests the content of R5, which is now 8 , and not finding it zero, branches back to LOOPTOP. This process continues through 10 iterations of the loop body. On the tenth iteration, BCT decrements the register and the result becomes zero. Testing R5 reveals it to be zero. This time the branch is not taken and control returns to the statement following the branch on count instruction.
There are two other instructions which are occasionally used to implement a counted loop. The first instruction that we consider is called “Branch on Index Less Than or Equal”. The mnemonic for this instruction is BXLE. When coded it has three operands:
1) Operand 1 is a register containing a count or an address.
2) Operand 2 is typically an even register of an even-odd consecutive pair of registers. The even register contains a value which is used to increment or decrement the value in Operand 1.
The odd register, which is not coded in the instruction, contains a limit or address against which Operand 1 is compared.
3) Operand 3 represents an address to which the instruction will branch if the Operand 1 value is less than or equal to the limit in the odd register.
For example, consider the following instruction.
The diagram below illustrates the relationships among the registers used by the instruction.
Each time the instruction is executed, the value in the even register, R4, is added to the value in the Operand 1 register, R3. If the result is less than or equal to the value in the odd register, R5, a branch occurs to the address in Operand 3, LOOPTOP. The code listed below uses BXLE to implement a loop.
SR R3,R3 PUT 0 IN R3
LA R4,10 PUT INCREMENT INTO EVEN REG
LA R5,100 PUT LIMIT VALUE IN ODD REG
LOOPTOP EQU *
BXLE R3,R4,LOOPTOP EXECUTE THE LOOP
First, the count in R3 is initialized to 0, the increment is set to 10, and the limit is set at 100. Each time the BXLE is executed, the increment in R4 is added to the count in R3 and the result is compared to the limit in R5. If the new count is less than or equal to the limit, a branch occurs back to LOOPTOP. The effect of the statement is to execute the loop 11 times. ( The loop is executed once on the equal condition.)
BXLE has a companion instruction called “Branch on Index High”. The mnemonic is BXH and the instruction is similar in execution to BXLE except the branch occurs on a “high” condition instead of “less than or equal”. The following code gives an example of this instruction.
LA R3,5 SET THE COUNT TO 5
L R4,=F’-1’ SET THE DECREMENT TO -1
SR R5,R5 SET THE LIMIT VALUE AT 0
LOOPTOP EQU *
BXH R3,R4,LOOPTOP EXECUTE THE LOOP
In the example above, the count is set at 5, the decrement is -1, and the limit is 0. Each time the BXH is executed, the decrement is added to the count, reducing it by 1. As long as the result is higher than the limit 0, a branch occurs to LOOPTOP. The effect is to execute the loop body 5 times.
The main drawback to using BXLE and BXH is that both instructions require 3 registers. Since registers are usually at a premium in most programs, loops are often implemented using BCT.
While the instructions discussed above were specifically designed for the construction of loops, comparisons of any type, as well as other instructions that set the condition code, can be used to create “home-made” loop structures. In the code below we use a packed decimal instruction in combination with a branch to implement a counted loop.
ZAP COUNT,=P’100’ LOOP 100 TIMES
LOOPTOP EQU *
SP COUNT,=P’1’ DECREMENT ON EACH ITERATION
BNZ LOOPTOP BRANCH IF NOT ZERO
In this case, we have decided to loop 100 times. Each time through the loop the count is decremented by 1. We take advantage of the fact that SP sets the condition code based on the result of the subtraction. If the result is not zero, we loop back to LOOPTOP.
Creating Conditional Loops
Conditional loops are characterized by the property that we cannot predetermine the number of times the loop will be iterated. In other words, the loop will continue to be executed until a prescribed condition occurs. The condition is tested “by hand” using one of the compare instructions; CP for packed data, CLC or CLI for character data, and C or CH for binary data. The following code implements a conditional loop that continues to be executed until a field, called “FLAG”, is equal to “Y”.
LOOPTOP EQU *
CLI FLAG,C’Y’ IS THE FLAG SET?
BNE LOOPTOP NO... BRANCH BACK
When creating loops of this type, the loop body must contain logic that will eventually cause termination of the loop. Otherwise an infinite loop results.
One common use of a conditional loop is for processing all the records in a sequential file. This is illustrated with the code below.
GETREC EQU *
GET MYFILE,MYRECORD READ A RECORD
...PROCESS THE RECORD
B GETREC LOOP BACK FOR NEXT RECORD
NEXTSTEP EQU *
At first glance, the loop above appears to be an “infinite” loop. In other words, there does not appear to be logic present that would allow the program to escape the loop body once it is entered. This problem is resolved when we execute the GET macro and there are no more records in the file. At this point, a branch would occur to NEXTSTEP if we have specified EODAD=NEXTSTEP in the DCB of MYFILE. The EODAD parameter causes an unconditional branch to the address we specify in the parameter when “end of file” is detected. So, in fact, the loop above is conditional, and continues to execute until “end of file” occurs.
Occasionally you may code an infinite loop by mistake. When this happens, your program will continue to execute the loop until it has used up the time allocated to the job by the operating system. At that point, the program will be interrupted with a “322” abend.