9.5.8 Processor Control Instructions
Table 9.11 shows the processor control functions. Let us explain some of the instructions in Table 9.11.
-
ESC mem places the contents of the specified memory location on the data bus at the time when the 8086 ready pin is asserted by the addressed memory device. This instruction is used to pass instructions to a coprocessor such as the 8087 math coprocessor which shares the address and data bus with the 8086.
-
LOCK prefix allows the 8086 to ensure that another processor does not take control of the system bus while it is executing an instruction which uses the system bus. LOCK prefix is placed in front of an instruction so that when the instruction with the LOCK prefix is executed, the 8086 outputs a LOW on the LOCK pin of the 8086 for the duration of the next instruction. This Lock signal is connected to an external bus controller which prevents any other processor from taking over the system bus. Thus the LOCK prefix is used in multiprocessing.
-
WAIT causes the 8086 to enter an idle state if the signal on the TEST input pin is not asserted. This means that the 8086 will remain in the idle state until its TEST pin is asserted. The WAIT instruction can be used to synchronize the 8086 with other external hardware such as the 8087 (Math coprocessor).
9.6 8086 Assembler-Dependent Instructions
Some 8086 instructions do not define whether an 8-bit or a 16-bit operation is to be executed. Instructions with one of the 8086 registers as an operand typically define the operation as 8-bit or 16-bit based on the register size. An example is MOV CL, [ BX] , which moves an 8-bit number with the offset defined by [BX] in DS into register CL; MOV ex, [BX] , on the other hand, moves a 16-bit number from offsets (BX) and (BX + 1) in DS into CX Instructions with a single-memory operand may define an 8-bit or a 16-bit operation by adding B for byte or W for word with the mnemonic. Typical examples are
MULB [BX] and IDIVW [ADDR]. The string instructions may define this in two ways. Typical examples are MOVSB or MOVS BYTE for 8-bit and MOVSW or MOVS WORD for 16-bit. Memory offsets can also be specified by including BYTE PTR for 8-bit and WORD PTR for 16-bit with the instruction. Typical examples are INC BYTE PTR [ BX] and INC WORD PTR [BX].
9.7 Typical8086 Assembler Pseudo-Instructions or Directives
One of the requirements oftypical8086 assemblers such as MASM (discussed later) is that a variable’s type must be declared as a byte (8-bit), word (16-bit), or double word (4 bytes or 2 words) before using the variable in a program. Some examples are as follows:
Note that the directive DD is not used by all assemblers. In that case, one should use the directive DW twice to declare a 32-bit offset.
The EQU directive can be used to assign a name to constants. For example, the statement NUMB EQU 21H directs the assembler to assign the value 21H every time it finds NUMB in the program. This means that the assembler reads the statement MOV BH, NUMB as MOV BH, 21H. As mentioned before, DB, DW, and DD are the directives used to assign names and specific data types for variables in a program. For example, after execution of the statement ADDR ow 2050H the assembler assigns SOH to the offset name ADDR and 20H to the offset name ADDR + 1. This means that the program can use the instruction MOV BX, [ADDR] to load the 16-bit contents of memory starting at the offset ADDR in DS into BX. The DW sets aside storage for a word in memory and gives the starting address of this word the name ADDR.
In the following paragraphs, more assembler directives such as SEGMENT, ENDS, ASSUME, and DUP will be discussed.
9.7.1 SEGMENT and ENDS Directives
A section of a an 8086 program or a data array can be defined by the SEGMENT and ENDS directives as follows:
The segment name is START (arbitrarily chosen). The assembler will assign a numeric value to START corresponding to the base value of the data segment. The programmer must use the 8086 instructions to load START into DS as follows:
Note that all segment registers except CS must be loaded via a 16-bit general purpose register such as BX. A data array or an instruction sequence between the SEGMENT and ENDS directives is called a logical segment. These two directives are used to set up a logical segment with a specific name. A typical assembler allows one to use up to 31 characters for the name without any spaces. An underscore is sometimes used to separate words in a name, for example, PROGRAM_ BEGIN.
9.7.2 ASSUME Directive
As mentioned before, at any time the 8086 can directly address four physical segments, which include a code segment, a data segment, a stack segment, and an extra segment. The 8086 may contain a number of logical segments containing codes, data, and stack. The ASSUME directive assigns a logical segment to a physical segment at any given time. That is, the ASSUME directive tells the assembler what addresses will be in the segment registers at execution time.
For example, the statement ASSUME CS: PROGRAM_1, OS: DATA_1, SS: STACK_1 directs the assembler to use the logical code segment PROGRAM _I as CS, containing the instructions, the logical data segment OATA_I as OS, containing data, and the logical stack segment STACK _I as SS, containing the stack.
9.7.3 DUP, LABEL, and Other Directives
The DUP directive can be used to initialize several locations to zero. For example, the statement START DW 4 DUP ( 0) reserves four words starting at the offset START in DS and initializes them to zero. The DUP directive can also be used to reserve several locations that need not be initialized. A question mark must be used with DUP in this case. For example, the statement BEGIN DB 100 DUP (?) reserves 100 bytes of uninitialized data space to an offset BEGIN in DS. Note that BEG IN should be typed in the label field, DB in the OP code field, and 10 0 DUP (?) in the operand field.
A typical example illustrating the use of these directives is given next:
Note that LABEL is a directive used to the allocate stack from the next location after the top of the stack. The statement STACK_ TOP LABEL WORD allocates the stack for local variables from the next address after STACK_ TOP. In this example, 60 words are set aside for the stack. The WORD in this statement indicates that PUSH into and POP from the stack are done as words.
Also note that in the above, ASSUME directive tells the assembler to use the logical segment names CODE_I, DATA_I, and STACK_I as the code segment, data segment, and stack segment, respectively. The extra segment can be assigned a name in a similar manner. When the instructions are executed, the displacements in the instructions along with the segment register contents are used by the assembler to generate the 20-bit physical addresses. The segment register, other than the code segment, must be initialized before it is used to access data. The code segment is typically initialized upon hardware reset or by using ORG.
When the assembler translates an assembly language program, it computes the displacement, or offset, of each instruction code byte from the start of a logical segment that contains it. For example, in the preceding program, the CS: CODE_l in the ASSUME statement directs the assembler to compute the offsets or displacements by the following instructions from the start of the logical segment CODE_ I. This means that when the program is run, the CS will contain the 16-bit value where the logical segment CODE_ I is located in memory. The assembler keeps track of the instruction byte displacements, which are loaded into IP. The 20-bit physical address generated from CS and IP are used to fetch each instruction. Some versions of MASM use directive AT to assign a segment value.
Note that typical 8086 assemblers such as Microsoft and Hewlett-Packard HP64000 use the ORG directive to load CS and IP. For example, CS and IP can be initialized with 2000H and 0300H as follows:
Each 8086 stack segment is 64K bytes long and is organized as 32K 16-bit words. The lowest byte (valid data) of the stack is pointed to by the 20-bit physical address computed from current SP and SS. This is the lowest memory location in the stack (Top of the Stack) where data is pushed. The 8086 PUSH and POP instructions always utilize 16-bit words. Therefore, stack locations should be configured at even addrsesses in order to minimize the number of memory cycles for efficient stack operations. The 8086 can have several stack segments; however, only one stack segment is active at a time.
Since the 8086 uses 16-bit data for PUSH and POP operations from the top of the stack, the 8086 PUSH instruction first decrements SP by 2 and then the 16-bit data is written onto the stack. Therefore, the 8086 stack grows from high to low memory addresses of the stack. On the other hand, when a 16-bit data is popped from the top of the stack using the 8086 POP instruction , the 8086 reads 16-bit data from the stack into the specified register or memory, the 8086 then increments the SP by 2. Note that the 20-bit physical address computed from SP and SS always points to the last data pushed onto the stack. One can save and restore flags in the 8086 using PUSHF and POPF instructions. Memory locations can also be saved and restored using PUSH and POP instructions without using any 8086 registers. Finally, One must POP registers in the reverse order in which they are PUSHed. For example, if the registers BX, DX, and SI are PUSHed using
Typical 8086 software delay loops can be written using MOV and LOOP instructions. For example, the following instruction sequence can be used for a delay loop of 20 millisecond:
autodecrementing CX by 1. However, the 8086 goes to the next instruction and does not branch when CX = 0 after autodecrementing CX by 1, and this requires 5 cycles. This means that the DELAY loop will require 17 cycles for (count – 1) times, and the last iteration will take 5 cycles.
For 2-MHz 8086 clock, each cycle . 500ns. For 20 ms, total cycles= 40,000. The loop will require 17 cycles for (count – 1) times when CX 1= 0 and 5 cycles will be required when no branch is taken (CX = 0). Thus, totai cycles including the MOV = 4+ 17x(count – 1) + 5= 40,000. Hence, count e 2353 10 = 0931 16• Therefore, CX must be loaded with 2353 10 or 0931 16 •
Now, in order to obtain delay of 20 seconds, the above DELAY loop of 20 millisecond can be used with an external counter. Counter value= (20 sec) I (20 msec) = 1000. The following instruction sequence will provide an approximate delay of 20 seconds:
Next, the delay time provided by the above instruction sequence can be calculated. From Appendix F, the cycles required to execute the following 8086 instructions:
As before, assuming 4-MHz 8086 clock, each cycle is 250ns. Total time from the above instruction sequence for 20-second delay = Execution time for MOV DX + 1000 * (20 msec delay)+ 1000 *(Execution time for DEC)+ 999* (Execution time for JNE for Z = 0 when DX 1= 0) +(Execution time for JNE for Z = 1 when DX = 0) = 4 * 250ns + 1000 * 20msec + 1000 * 2 * 250ns + 999 * 16 * 250ns + 4 * 250ns e 20.0045 seconds which is approximately 20 seconds discarding the execution times of MOV DX, DEC, and JNE.