In the sequence of instructions to be executed, it is often necessary to transfer program control to a different location. There are many instructions in the 8051 to achieve this. This chapter covers the control transfer instructions available in 8051 Assembly language. In the first section we discuss instructions used for looping, as well as instructions for conditional and unconditional jumps. In the second section we examine CALL instructions and their uses. In the third section, time delay subroutines are described for both the traditional 8051 and its newer generation.
SECTION 3.1: LOOP AND JUMP INSTRUCTIONS
In this section we first discuss how to perform a looping action in the 8051 and then talk about jump instructions, both conditional and unconditional.
Looping in the 8051
Repeating a sequence of instructions a certain number of times is called a loop. The loop is one of most widely used actions that any microprocessor performs. In the 8051, the loop action is performed by the instruction “DJNZ reg, label”. In this instruction, the register is decremented; if it is not zero, it jumps to the target address referred to by the label. Prior to the start of the loop the register is loaded with the counter for the number of repetitions. Notice that in this instruction both the register decrement and the decision to jump are combined into a single instruction.
In the program in Example 3-1, the R2 register is used as a counter. The counter is first set to 10. In each iteration the instruction DJNZ decrements R2 and checks its value. If R2 is not zero, it jumps to the target address associated with the label “AGAIN”. This.looping action continues until R2 becomes zero. After R2 becomes zero, it falls through the loop and executes the instruction immediately below it, in this case the “MOV R5 , A” instruction.
Notice in the DJNZ instruction that the registers can be any of RO – R7. The counter can also be a RAM location as we will see in Chapter 5.
What is the maximum number of times that the loop in Example 3-1 can be repeated?
Since R2 holds the count and R2 is an 8-bit register, it can hold a maximum of FFH (255 decimal); therefore, the loop can be repeated a maximum of 256 times.
Loop inside a loop
As shown in Example 3-2, the maximum count is 256. What happens if we want to repeat an action more times than 256? To do that, we use a loop inside a loop, which is called a nested loop. In a nested loop, we use two registers to hold the count. See Example 3-3.
Write a program to (a) load the accumulator with the value 55H, and (b) complement the ACC 700 times.
Since 700 is larger than 255 (the maximum capacity of any register), we use two registers to hold the count. The following code shows how to use R2 and R3 for the count.
In this program, R2 is used to keep the inner loop count. In the instruction “DJNZ R2 , AGAIN”, whenever R2 becomes 0 it falls through and “DJNZ R3 , NEXT” is executed. This instruction forces the CPU to load R2 with the count 70 and the inner loop starts again. This process will continue until R3 becomes zero and the outer loop is finished.
Other conditional jumps
Conditional jumps for the 8051 are summarized in Table 3-1. More details of each instruction are provided in Appendix A. In Table 3-1, notice that some of the instructions, such as JZ (jump if A = zero) and JC (jump if carry), jump only if a certain condition is met. Next we examine some conditional jump instructions with examples.
JZ (jump if A = 0)
In this instruction the content of register A is checked. If it is zero, it jumps to the target address. For example, look at the following code.
Table 3-1: 8051 Conditional Jump Instructions
In this program,. if either RO or Rl is zero, it jumps to the label OVER. Notice that the JZ instruction can be used only for register A. It can only check to see whether the accumulator is zero, and it does not apply to any other register. More importantly, you don’t have to perform an arithmetic instruction such as decrement to use the JNZ instruction. See Example 3-4.
JNC (jump if no carry, jumps if CY = 0)
In this instruction, the carry flag bit in the flag (PSW) register is used to make the decision whether to jump. In executing “JNC label”, the processor looks at the carry flag to see if it is raised (CY =1). If it is not, the CPU starts to fetch and execute instructions from the address of the label. If CY = 1, it will not jump but will execute the next instruction below JNC.
Note that there is also a “JC label” instruction. In the JC instruction, if CY = 1 it jumps to the target address. We will give more examples of these instructions in the context of applications in future chapters.
There are also JB (jump if bit is high) and JNB (jump if bit is low) instructions. These are discussed in Chapters 4 and 8 when bit manipulation instructions are discussed.
All conditional jumps are short jumps
It must be noted that all conditional jumps are short jumps, meaning that the address of the target must be within -128 to +127 bytes of the contents of the program counter (PC). This very important concept is discussed at the end of this section.
Unconditional jump instructions
The unconditional jump is a jump in which control is transferred unconditionally to the target location. In the 8051 there are two unconditional jumps: LJMP (long jump) and SJMP (short jump). Each is discussed below.
LJMP (long jump)
LJMP is an unconditional long jump. It is a 3-byte instruction in which the first byte is the opcode, and the second and third bytes represent the 16-bit address of the target location. The 2-byte target address allows a jump to any memory location from 0000 to FFFFH.
Remember that although the program counter in the 8051 is 16-bit, thereby giving a ROM address space of 64K bytes, not all 8051 family members have that much on-chip program ROM. The original 8051 had only 4K bytes of on-chip ROM for program space; consequently, every byte was precious. For this reason there is also an SJMP (short jump) instruction, which is a 2-byte instruction as opposed to the 3-byte LJMP instruction. This can save some bytes of memory in many applications where memory space is in short supply. SJMP is discussed next.
SJMP (short jump)
In this 2-byte instruction, the first byte is the opcode and the second byte is the relative address of the target location. The relative address range of 00 – FFH
is divided into forward and backward jumps; that is, within -128 to +127 bytes of memory relative to the address of the current PC (program counter). If the jump is forward, the target address can be within a space of 127 bytes from the current PC. If the target address is backward, the target address can be within -128 bytes from the current PC. This is explained in detail next.
Calculating the short jump address
In addition to the SJMP instruction, all conditional jumps such as JNC, JZ, and DJNZ are also short jumps due to the fact that they are all two-byte instructions. In these instructions the first byte is the opcode and the second byte is the relative address. The target address is relative to the value of the program counter. To calculate the target address, the second byte is added to the PC of the instruction immediately below the jump. To understand this, look at Example 3-6.
Using the following list file, verify the jump forward address calculation.
First notice that the JZ and JNC instructions both jump forward. The target address for a forward jump is calculated by adding the PC of the following instruction to the second byte of the short jump instruction, which is called the relative address. In line 4 the instruction “JZ NEXT” has opcode of 60 and operand of 03 at the addresses of 0004 and 0005. The 03 is the relative address, relative to the address of the next instruction INC RO, which is 0006. By adding 0006 to 3, the target address of the label NEXT, which is 0009, is generated. In the same way for line 9, the “JNC OVER” instruction has opcode and operand of 50 and 05 where 50 is the opcode and 05 the relative address. Therefore, 05 is added to GOOD, the address of instruction “CLR A”, giving 12H, the address of label OVER.
Verify the calculation of backward jumps in Example 3-6.
In that program list, “JNC AGAIN” has opcode 50 and relative address F2H. When the relative address of F2H is added to 15H, the address of the instruction below the jump, we have 15H + F2H = 07 (the carry is dropped). Notice that 07 is the address of label AGAIN. Look also at ‘.’SJMP HERE”, which has 80 and FE for the opcode and relative address, respectively. The PC of the following instruction, 0017H, is added to FEH, the relative address, to get 0015H, address of the HERE label (17H + FEH = 15H). Notice that FEH is -2 and 17H + (-2) = 15H. For further discussion of the addition of negative numbers, see Chapter 6.
Jump backward target address calculation
While in the case of a forward jump, the displacement value is a positive number between 0 to 127 (00 to 7F in hex), for the backward jump the displacement is a negative value of 0 to -128 as explained in Example 3-7.
It must be emphasized that regardless of whether the SJMP is a forward or backward jump, for any short jump the address of the target address can never be more than -128 to +127 bytes from the address associated with the instruction below the SJMP. If any attempt is made to violate this rule, the assembler will generate an error stating the jump is out of range.