9.5.1 Unconditional Transfer Instructions
Unconditional transfer instructions transfer control to a location either in the current executing memory segment (intrasegment) or in a different code segment (intersegment). Table 9.5 lists the unconditional transfer instructions.
The 8086 CALL instructions provide the mechanism to call a subroutine into operation while the RET instruction placed at the end of the subroutine transfers control back to the main program. There are two types of 8086 CALL instruction. These are intrasegment CALL (IP changes, CS is fixed), and intersegment CALL (both IP and CS are changed). Intrasegment or Intersegment CALL is defined by the various operands of the CALL instruction. For example, the three operands NEAR PROC, meml6, and regl6 define intrasegment CALLs to a subroutine. Upon execution of the intrasegment CALL with any of the three operands, the 8086 pushes the current contents of IP onto the stack; the SP is then decremented by 2. The saved IP value is the offset that contains the next instruction to be executed in the main program. The 8086 then places a new I 6-bit value ( Offset of the first instruction in the subroutine) into IP. The three types of operands of the intrasegment CALL will be discussed next.
Consider CALL NEAR PROC. The assembler directive NEAR specifies the CALL instruction with relative addressing mode. This means that NEAR determines a I 6- bit displacement, and the offset is computed relative to the address of the CALL instruction. With 16-bit displacement, the range of the CALL instruction is limited to -32766 to+ 32765 (0 being positive). As an example, consider the following 8086 instruction sequence:
In the above, the main program is located in a segment named CODE. A subroutine called MULTI is also resident in the same code segment named CODE. Since this subroutine is in the same code segment as the main program containing the CALL instruction, the contents of CS are not altered to access it. Use of the assembler directive NEAR in the statement MULTI PROC NEAR tells the 8086 assembler that the main program and the subroutine are located in the same code segment.
The instructions CALL me m 16 and CALL re g 16 specify a memory location or a 16-bit register such as BX to hold the offset to be loaded into IP. Thus, these two CALL instructions use indirect addressing mode. An example of CALL me m 16 is CALL [BX] which loads the 16-bit value stored in the memory location pointed to by BX into IP. The physical address of the offset is calculated from the current DS and the contents of BX. The first instruction of the subroutine is contained in the address computed from new IP value and current CS. Next, typical examples of CALL regl6 are CALL BX and CALL BP; these instructions load the 16-bit contents of BX or BP into IP. The starting address (physical address) of the subroutine is computed from the new value of iP and the current CS contents. Note that intrasegment CALL instructions are used when the main program and the subroutine are located in the same code segment.
Intersegment CALL instructions are used when the main program and the subroutine are located in two different code segments. The two intersegment CALL instructions are CALL FAR PROC and CALL mem32. These instructions define a new offset for IP and a new value for CS. Upon execution of these two instructions, the 8086 pushes the current contents of IP and CS onto the stack, the new values of IP and CS are then loaded. For example consider CALL FAR PROC which loads the new value of IP from the next two bytes, and the new value of CS from the following two bytes. As an example, consider the following 8086 instruction sequence:
In the above, the main program is located in a segment named CODE. A subroutine called MULTI is in a segment named SUBR. Since this subroutine is in a different code segment from the CALL instruction, the contents of CS must be altered to access it. Use of the assembler directive FAR in the statement MULTI PROC FAR tells the 8086 assembler that the main program and the subroutine are located in different code segments. When the assembler translates the CALL instruction, it will assign the value of SUBR to CS, and will place the offset of the first instruction of the subroutine in SUBR as the IP value in the instruction.
CALL FAR [SI] stores the pointer for the subroutine as four bytes in data memory. The location of the first byte of the four-byte pointer is specified indirectly by one of the 8086 registers (SI in this case). In this example, the 20-bit physical address of the first byte of the four-byte pointer is computed from DS and Sl. Finally, CALL FAR [BX] pushes CS and IP onto stack and loads IP and CS with the contents of four consecutive bytes pointed to by BX.
RET instruction is usually placed at the end of a subroutine which pops IP (pushed onto the stack by the intrasegment CALL instruction) or both IP and CS (pushed onto the stack by the intersegment CALL instruction), and returns control to the main program. RET disp 16, on the other hand, adds 16-bit value ( disp 16) to SP after placing the return address into IP (for intrasegment CALL) or into IP and CS ((for intersegment CALL). The main objective of inclusion of the 16-bit displacement operand with the RET instruction is to discard the parameters that were saved onto the stack before execution of the subroutine CALL instruction.
Similar to the CALL instruction, the jump instruction in Table 9.5 can be either intrasegment JMP (Jump within the current code segment; only IP changes) or intersegment JMP (Jump from one code segment to another code segment; both CS and IP contents are modified). Intrasegment Jump can have an operand with a short label, near label, reg16 or meml6. For example, the short label and near label operands use relative addressing mode. This means that the Jump is performed relative to the address of the JMP instruction. For jumps with short label, IP changes and CS is fixed. JMP di sp8 adds the second object code byte (signed 8-bit displacement) to (IP + 2), and (CS) is unchanged. With an 8-bit signed displacement, jump with a short label operand is allowed in the range from -128 to + 127 (0 being positive) from the address of the JMP instruction. Near label operand allows a JMP instruction to have a signed 16-bit displacement with a range -32K to +32K bytes from the address of the JMP instruction. An example of JMP short label or near label is JMP START. The 8086 assembler automatically computes the value of the displacement START at assembly time. The programmer does not have to worry about it. Based upon the displacement size of START (in this case), the assembler determines whether the JMP is to be performed with short or near label.
JMP reg 16 or JMP mem 16 specifies the JUMP address respectively by the I 6- bit contents of of a register or a memory location. The range for this JMP is from -32K to +32K bytes from the address ofthe JMP. An example of JMP reg16 is JMP SI which copies the contents of SI into IP. SI contains the 16-bit displacement. The 8086 computes the physical address from the current CS value and the new IP value. An example of JMP mem16 is JMP [DI] which uses the contents of DI as the address of the memory location containing the offset. This offset is placed into IP. The physical address is computed from this IP value and the current code segment value.
The intersegment JMP instruction includes operands with far label and mem32.
Jump with far label uses a 32-bit immediate operand ; the first 16 bits are loaded into IP while the next 16 bits are loaded into CS. An example of JMP with far label is JMP FAR BEGIN (or some 8086 assemblers use JMP FAR PTR BEGIN) which unconditionally branches to a label BEGIN in a different code segment.
Finally, JMP mem32 indirectly specifies the offset and the code segment values.
IP and CS are loaded from the 32-bit contents of four consecutive memory locations; each memory location contains a byte. As an example, JMP FAR [ S I] loads IP and CS with the contents of four consecutive bytes pointed to by SI in DS.
9.5.2 Conditional Branch Instructions
All 8086 conditional branch instructions use 8-bit signed displacement. That is, the displacement covers a branch range of -128 to +127, with 0 being positive. The structure of a typical conditional branch instruction is as follows:
If condition is true,
then IP +- IP + disp8,
otherwise IP +- IP + 2 and execute next instruction.
There are two types of conditional branch instructions. In one type, the various relationships that exist between two numbers such as equal, above, below, less than, or greater than can be determined by the appropriate conditional branch instruction after a COMPARE instruction. These instructions can be used for both signed and unsigned numbers. When comparing signed numbers, terms such as "less than" and "greater than" are used. On the other hand, when comparing unsigned numbers, terms such as "below zero" or "above zero" are used.
Table 9.6 lists the 8086 signed and unsigned conditional branch instructions. Note that in Table 9.6 the instructions for checking which two numbers are "equal" or
"not equal" are the same for both signed and unsigned numbers. This is because when two numbers are compared for equality, irrespective of whether they are signed or unsigned, they will provide a zero result (ZF = I) if they are equal and a nonzero result (ZF = 0) if they are not equal. Therefore, the same instructions apply for both signed and unsigned numbers for "equal to" or "not equal to" conditions. The second type of conditional branch instructions is concerned with the setting of flags rather than the relationship between two numbers. Table 9.7 lists these instructions.
Now, in order to check whether the result of an arithmetic or logic operation is zero, nonzero, positive or negative, did or did not produce a carry, did or did not produce parity, or did or did not cause overflow, the following instructions should be used: JZ, JNZ, JS, JNS, JC, JNC, JP, JNP, JO, JNO. However, in order to compare two signed or unsigned numbers (a in address A orb in address B) for various conditions, we use CMP A, B, which will form a- b. and then one of the instructions in Table 9.8.
Now let us illustrate the concept of using the preceding signed or unsigned instructions by an example. Consider clearing a section of memory word starting at B up to and including A, where (A)= 3000 16 and (B)= 2000 16 in DS = 100016, using the following instruction sequence:
Also, note that addresses are always positive numbers (unsigned). Hence, unsigned conditional jump instruction must be used to obtain the correct answer. The above examples are shown for illustrative purposes.
9.5.7 Iteration Control Instructions
Table 9.9 lists iteration control instructions. All these instructions have relative addressing modes.
LOOP disp8 decrements the CX register by 1 without affecting the flags and then acts in the same way as the JMP dsp8 instruction except that if CX ;o< 0, then the JMP is performed: otherwise, the next instruction is executed.
LOOPE (Loop while equal) I LOOPZ (Loop while zero), on the other hand, decrements CX by 1 without affecting the flags. The contents of CX are then checked for zero, and also the zero flag (ZF), that results from execution of previous instruction, is checked for one. If CX ;o! 0 and ZF = 1, the loop continues. If either CX = 0 or ZF = 0, the next instruction after the LOOPE or LOOPZ is executed. The following 8086 instruction sequence compares an array of 50 bytes with data byte OOH. As soon as a match is not found or end of array is reached, the loop exits. LOOPE instruction can be used for this purpose. The following 8086 instruction sequence illustrates this:
LOOPNE (LOOP while not equal) I LOOPNZ (Loop while not zero) is similar to LOOPE I LOOPZ except that the loop continues if ex ;o0 0 and ZF = 0. On the other hand, If ex = 0 or ZF = 1, the next instruction is executed. The following 8086 instruction sequence compares an array of 50 bytes with data byte 00H for a match. As soon as a match is found or end of array is reached, the loop exits. LOOPNE instruction can be used for this purpose. CX=0 and ZF=0 upon execution of the CMP instruction 50 times in the following would imply that data byte 00H was not found in the array. The following 8086 instruction illustrates this:
9.5.8 Interrupt Instructions
Table 9.10 shows the interrupt instructions. INT n is a software interrupt instruction. Execution of INT n causes the 8086 to push current es, IP, and Flags onto the stack, and loads CS and IP with new values based on interrupt type n; an interrupt service routine is written at this new address. IRET at the end of the service routine transfers control to the main program by popping old es, IP, and flags from the stack.
The interrupt on overflow is a type 4 (n = 4) interrupt. This interrupt occurs if the overflow flag (OF) is set and the INTO instruction is executed. The overflow flag
is affected, for example, after execution of a signed arithmetic (such as IMUL, signed multiplication) instruction. The user can execute an INTO instruction after the IMUL. If there is an overflow, an error service routine written by the user at the type 4 interrupt address vector is executed.
Interrupt instructions are discussed in detail later in this Chapter.