Introduction
The opcodes that have been examined and used in the preceding chapters may be thought of as action codes. Each instruction performs a single operation on hytes of data.
The jumps and calls discussed in this chapter are decision codes that alter the flow of the program by examining the results of the action codes and changing the contents of the program counter. A jump permanently changes the contents of the program counter if certain program conditions exist. A call temporarily changes the program counter to allow another part of the program to run. These decision codes make it possible for the programmer to let the program adapt itself, as it runs, to the conditions that exist at the time.
While it is true that computers can’t "think" (at least as of this writing), they can make decisions about events that the programmer can foresee, using the following decision opcodes:
Jump on bit conditions
Compare bytes and jump if not equal
Decrement byte and jump if zero
Jump unconditionally
Call a subroutine
Return from a subroutine
Jumps and calls may also be generically referred to as "branches," which emphasizes that two divergent paths are made possible by this type of instruction.
The Jump and Call Program Range
A jump or call instruction can replace the contents of the program counter with a new program address number that causes program execution to begin at the code located at the new address. The difference, in bytes, of this new address from the address in the program where the jump or call is located is called the range of the jump or call. For example, if a jump instruction is located at program address 0100h, and the jump causes the program counter to become 0 I 20h, then the range of the jump is 20h bytes.
Jump or call instructions may have one of three ranges: a relative range of +I 27d, -128d bytes from the instruction following the jump or call instruction; an absolute range on the same 2K byte page as the instruction following the jump or call; or a long range of any address from 0000h to FFFFh, anywhere in program memory. Figure 6.1 shows the relative range of all the jump instructions.
FIGURE 6.1 Jump Instruction Ranges
Relative Range
Jumps that replace the program counter contents with a new address that is greater than the address of the instruction following the jump by I 27d or less than the address of the instruction following the jump by I 28d are called relative jumps. They are so named because the address that is placed in the program counter is relative to the address where the jump occurs. If the absolute address of the jump instruction changes, then the jump address changes also hut remains the same distance away from the jump instruction. The address following the jump is used to calculate the relative jump because of the action of the PC. The PC is incremented to point to the next instruction before the current instruction is executed. Thus, the PC is set to the following address before the jump instruction is executed, or in the vernacular: "before the jump is taken."
Relative jumping has two advantages. First, only one byte of data need be specified, either in positive format for jumps ahead in the program or in 2’s complement negative format for jumps behind. The jump address displacement byte can then be added to the PC to get the absolute address. Specifying only one byte saves program bytes and speeds up program execution. Second. the program that is written using relative jumps can be located anywhere in the program address space without re-assembling the code to generate absolute addresses.
The disadvantage of using relative addressing is the requirement that all addresses jumped be within a range of+ 127d, -128d bytes of the jump instruction. This range is not a serious problem. Most jumps form program loops over short code ranges that are within the relative address capability. Jumps are the only branch instructions that can use the relative range.
If jumps beyond the relative range are needed, then a relative jump can be done to another relative jump until the desired address is reached. This need is better handled, however. by the jumps that are covered in the next sections.
Short Absolute Range
Absolute range makes use of the concept of dividing memory into logical divisions called "pages." Program memory may be regarded as one continuous stretch of addresses from 0000h to FFFFh. Or, it may be divided into a series of pages of any convenient binary size. such as 256 bytes, 2K bytes, 4K bytes, and so on.
The 805 I program memory is arranged as 2K byte pages, giving a total of 32d (20h) pages. The hexadecimal address of each page is shown in the following table:
PAGE |
ADDRESS(HEX) |
PAGE |
ADDRESS(HEX) |
PAGE |
ADDRESS(HEX) |
00 |
0000-07FF |
0B |
5800-5FFF |
16 |
B000-B7FF |
01 |
0800-0FFF |
oc |
6000-67FF |
17 |
8800-BFFF |
02 |
1000-17FF |
0D |
6800-6FFF |
18 |
C000-C7FF |
03 |
1800-lFFF |
0E |
7000-77FF |
19 |
C800-CFFF |
04 |
2000-27FF |
0F |
7800-7FFF |
lA |
0000-07FF |
05 |
2800-2FFF |
10 |
8000-87FF |
1B |
0800-0FFF |
06 |
3000-37FF |
11 |
8800-8FFF |
lC |
E000-E7FF |
07 |
3800-3FFF |
12 |
9000–97FF |
10 |
E800-EFFF |
08 |
4000-47FF |
13 |
9800-9FFF |
lE |
F0000-F7FF |
09 |
4800-4FFF |
14 |
A000-A7FF |
1 F |
F800-FFFF |
0A |
5000-57FF |
15 |
A800-AFFF |
|
|
Inspection of the page numbers shows that the upper five bits of the program counter hold the page number, and the lower eleven bits hold the address within each page. An absolute address is formed by taking the page number of the instruction following the branch and attaching the absolute page range address of eleven bits to it to form the 16-bit address.
Branches on page boundaries occur when the jump or call instruction finishes at X7FFh or XFFFh. The next instruction starts at X800h or X000h, which places the jump or call address on the same page as the next instruction after the jump or call. The page change presents no problem when branching ahead but could be troublesome if the branch is backwards in the program. The assembler should flag such problems as errors, so adjustments can be made by the programmer to use a different type of range.
Absolute range addressing has the same advantages as relative addressing; fewer bytes are needed and the code is relocatable as long as the relocated code begins at the start of a page. Absolute addressing has the advantage of allowing jumps or calls over longer programming distances than does relative addressing.
long Absolute Range
Addresses that can access the entire program space from 0000h to FFFFh use long range addressing. Long-range addresses require more bytes of code to specify and are relocatable only at the beginning of 64K byte pages. Since we are limited to a nominal ROM address range of 64K bytes, the program must be re-assembled every time a long-range address changes and these branches are not generally relocatable.
Long-range addressing has the advantage of using the entire program address space available to the 8051. It is most likely to be used in large programs.
Jumps
The ability of a program to respond quickly to changes in conditions depends largely upon the number and types of jump instructions available to the programmer. The 8051 has a rich set of jumps that can operate at the bit and byte levels. These jump opcodes are one reason the 8051 is such a powerful microcontroller.
Jumps operate by testing for conditions that are specified in the jump mnemonic. If the condition is true, then the jump is taken-that is, the program counter is altered to the address that is part of the jump instruction. If the condition is false, then the instruction immediately following the jump instruction is executed because the program counter is not altered. Keep in mind that the condition of true does not mean a binary I and that false does not mean binary 0. The condition specified by the mnemonic is either true or false.
Bit Jumps
Bit jumps all operate according to the status of the carry flag in the PSW or the status of any bit-addressable location. All bit jumps are relative to the program counter.
Jump instructions that test for bit conditions are shown in the following table:
Mnemonic |
Operation |
JC radd |
Jump relative if the carry flag is set to 1 |
JNC radd |
Jump relative if the carry flag is reset to 0 |
JB b,radd |
Jump relative if addressable bit is set to 1 |
JNB b,radd |
Jump relative if addressable bit is reset to 0 |
JBC b.radd |
Jump relative if addressable bit is set, and clear the addressable bit to 0 |
Note that no flags are affected unless the bit in JBC is a flag bit in the PSW. When the bit used in a JBC instruction is a port bit, the SFR latch for that port is read, tested, and altered.
The following program example makes use of bit jumps:
ADDRESS
|
MNEMONIC |
COMMENT |
LOOP: |
MOV A,#l0h
|
; A = l0h |
|
MOV R0, A |
;R0 = l0h |
ADDA: |
ADD A.R0
|
;add R0 to A |
|
JNC ADDA |
;if the carry flag is 0. then no carry is |
|
|
; true; jump to address ADDA; jump until A |
|
|
;is F0h; the C flag is set to |
|
|
;l on the next ADD and no carry is |
|
|
; false: do the next instruction |
|
MOV A,#l0h |
;A = l0h; do program again using JNB |
ADDR: |
ADD A.R0 |
;add R0 to A (R0 already equals !0h) |
|
JNB 0D7h.ADDR |
;D7h is the bit address of the carry flag |
|
JBC 0D7h,L00P |
;the carry bit is l; the jump to L00P |
|
|
;is taken. and the carry flag is cleared |
|
|
;to 0 |
CAUTION
All jump addresses, such as ADDA and ADDR, must be within + 127d, -128d of the instruction following the jump opcode.
If the addressable bit is a flag bit and JBC is used, the flag bit will be cleared.
Do not use any label names that are also the names of registers in the 8051. These are called "reserved" words and will cause great agitation in the assembler.
Byte Jumps
Byte jumps-jump instructions that test bytes of data-behave as bit jumps. If the condition that is tested is true, the jump is taken; if the condition is false.the instruction after the jump is executed. All byte jumps are relative to the program counter.
The following table lists examples of byte jumps:
Mnemonic |
Operation |
CJNE A,add,radd |
Compare the contents of the A register with the contents of the direct address; if they are not equal, then jump to the relative address; set the carry flag to I if A is less than the contents of the direct address; otherwise, set the carry flag to 0 |
CJNE A,#n,radd |
Compare the contents of the A register with the immediate number n; if they are not equal, then jump to the relative address; set the carry flag to I if A is less than the number; otherwise, set the carry flag to 0 |
CJNE Rn,#n,radd |
Compare the contents of register Rn with the immediate number n; if they are not equal, then jump to the relative address; set the carry flag to I if Rn is less than the number; otherwise, set the carry flag to 0 |
CJNE @Rp,#n,radd |
Compare the contents of the address contained in register Rp to the number n; if they are not equal, then jump to the relative address; set the carry flag to I if the contents of the address in Rp are less than the number; otherwise, set the carry flag to 0 |
DJNZ Rn.radd |
Decrement register Rn by I and jump to the relative address if the result is not zero; no flags are affected |
DJNZ add.radd |
Decrement the direct address by I and jump to the relative address if the result is not O; no flags are affected unless the direct address is the PSW |
JZ radd |
Jump to the relative address if A is 0; the flags and the A register are not changed |
JNZ radd |
Jump to the relative address if A is not O; the flags and the A register are not changed |
Note that if the direct address used in a DJNZ is a port, the port SFR is decremented and tested for 0.
Unconditional Jumps
Unconditional jumps do not test any bit or byte to determine whether the jump should be taken. The jump is always taken. All jump ranges are found in this group of jumps. and these are the only jumps that can jump to any location in memory.
The following table shows examples of unconditional jumps:
Mnemonic |
Operation |
JMP@A+DPTR |
Jump to the address formed by adding A to the DPTR; this is an unconditional jump and will always be done; the address can be anywhere in program memory; A, the DPTR, and the flags are unchanged |
AJMP sadd |
Jump to absolute short range address sadd; this is an unconditional jump and is always taken; no flags are affected |
LJMP !add |
Jump to absolute long range address ladd; this is an unconditional jump and is always taken; no flags are affected |
SJMP radd |
Jump to relative address radd; this is an unconditional jump and is always taken; no flags are affected |
NOP |
Do nothing and go to the next instruction; NOP (no operation) is used to waste time in a software timing loop; or to leave room in a program for later additions; no flags are affected |
The following program example uses byte and unconditional jumps:
ADDRESS |
MNEMONIC |
COMMENT |
|
.0RG 0100h |
;begin program at 0100h |
BGN: |
MOV A,#30h |
;A = 30h |
|
MOV 50h,#00h |
;RAM location 50h = 00h |
AGN: |
CJNE A,50h,AEQ |
;compare A and the contents of 50h in RAM |
|
SJMP NXT |
;SJMP will be executed if (50h) = 30h |
AEQ: |
DJNZ 50h.AGN |
;count RAM location 50h down until (50h) |
|
NOP |
;A; (50h) will reach 30h before 00h |
NXT: |
MOV R0,#0FFh |
;R0 = FFh |
DWN: |
DJNZ R0.0WN |
;count R0 to 00h; l00p here until done |
|
MOV A.R0 |
;A = R0 = 00h |
|
JNZ ABIG |
;the jump will not be taken |
|
JZ AZR0 |
;the jump will be taken |
HERE: |
NOP |
;this address will not be reached |
|
ORG l000h |
;start this segment of program code at |
|
|
;l000h |
AZRO: |
MOV A,#08h |
;A = 0Bh (code at 1000.lh) |
|
MOV DPTR, #l000h |
;DPTR = l000h (code at 1002,3,4h) |
|
JMP @A+DPTR |
;jump to location 1008h (code at 1005h) |
|
NOP |
; ( code at 1006h) |
|
NOP |
; (code at 1007h) |
ABIG: |
AJMP AZRO |
; (code at 1008h, all code on page 2) |
CAUTION
DJNZ decrements first, then checks for 0. A location set to 00h and then decremented goes to FFh, then FEh, and so on, down to 00h.
CJNE does not change the contents of any register or RAM location. It can change the carry flag to 1 if the destination byte is less than the source byte.
There is no zero flag; the JZ and JNZ instructions check the contents of the A register for 0. JMP @A+ DPTR does not change A, DPTR, or any flags.