微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 8086指令系统---控制转移指令(二)

8086指令系统---控制转移指令(二)

时间:11-27 来源:互联网 点击:
  3 循环指令

  这一组指令在循环结构的程序中用来控制一段程序(称为循环体)的重复执行,在汇编指令中循环的转向地址用标号来表示,而在机器指令中给出的是位移量,所以执行循环指令时,若满足循环条件,CPU就计算转向地址:(IP)当前+8位位移量→(IP),即实现循环。

  若不满足循环条件,即退出循环,程序继续顺序执行。
  循环指令都是短转移格式的指令,也就是说,位移量是用8位带符号数来表示的,转向地址在相对于当前IP值的-128 ~ +127字节范围之内。

  对条件循环指令LOOPZ(LOOPE)和LOOPNZ(LOOPNE),除测试CX中的循环次数外,还将ZF的值作为循环的必要条件,因此,要注意将条件循环指令紧接在形成ZF的指令之后。

  在多重循环的程序结构中,如果各层循环都使用循环指令来控制,则应注意对CX中循环计数值的保存与恢复。
循环指令均不影响条件码。

LOOP  label    循环(loop)
  执行操作:① (CX)←(CX)-1
       ② 若(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束

  LOOPZ/LOOPE label 为零/相等时循环(loop while zero,or equal)
  执行操作:① (CX)←(CX)-1
       ② 若ZF=1且(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束

  LOOPNZ/LOOPNE label 不为零/不等时循环(loop while nonzero,or not equal)
  执行操作:① (CX)←(CX)-1
       ② 若ZF=0且(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束

例编写程序,实现两个数据块BLOCK1和BLOCK2相加,结果存入BLOCK2。
       DATA   SEGMENT
       BLOCK1   DW   100 DUP(?)
       BLOCK2   DW   100 DUP(?)
       DATA  ENDS
       ; - - - - - - - - - - - - - - - - - -
       CODE   SEGMENT
       ASSUME CS:CODE,DS:DATA,ES:DATA
    START:MOV   AX,DATA
       MOV   DS,AX        ; initialize the data segment
       MOV   ES,AX        ; initialize the extra segment
       CLD             ; DF=0 for autoincrement
       MOV   CX,100        ; load the counter
       MOV   SI,OFFSET BLOCK1  ; address of block1
       MOV   DI,OFFSET BLOCK2  ; address of block2
    NEXT: LODSW            ; load the data of block1 into AX
       ADD   AX,ES:[DI]     ; add the data of block2 to AX
       STOSW            ; store the sum to block2
       LOOP   NEXT        ; repeat 100 times
       MOV   AX,4C00H      ; return to DOS
       INT   21H
    CODE  ENDS
       END   START

 4 子程序调用与返回指令

  子程序是一种非常重要的计算机编程结构,它存储在存储器中,可供一个或多个调用程序(主程序)反复调用。主程序调用子程序时使用CALL指令,由子程序返回主程序时使用RET指令。由于调用程序和子程序可以在同一个代码段中,也可以在不同的代码段中,因此,CALL指令和RET指令也有近调用、近返回及远调用、远返回两类格式。

 ⑴ CALL NEAR PTR SUBPROUT 近调用(near call)
  近调用是CALL指令的缺省格式,可以写为"CALL subrotine"。它调用同一个代码段内的子程序(子过程),因此,在调用过程中不用改变CS的值,只需将子程序的地址存入IP寄存器。CALL指令中的调用地址可以用直接和间接两种寻址方式表示。

 ⑵ CALL FAR PTR SUBPROUT 远调用(far call)
  远调用适用于调用程序(也称为主程序)和子程序不在同一段中的情况,所以也叫做段间调用。和近调用指令一样,远调用指令中的寻址方式也可用直接方式和间接方式。

 ⑶ RET 返回指令(return)
  RET指令执行的操作是把保存在堆栈中的返回地址出栈,以完成从子程序返回到调用程序的功能。

● CALL SUBROUT 段内直接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← (IP)当前+16位位移量(在指令的第2、3个字节中)
  
  ● CALL DESTIN 段内间接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← (EA) ; (EA)为指令寻址方式所确定的有效地址

  ● CALL FAR PTR SUBROUT 段间直接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (CS)当前
         (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← 偏移地址(在指令的第2、3个字节中)
         (CS) ← 段地址(在指令的第4、5个字节中)

  ● CALL WORD PTR DESTIN 段间间接调用
  执行操作:① (SP) ← (SP)-2,((SP)) ← (CS)当前
         (SP) ← (SP)-2,((SP)) ← (IP)当前
       ② (IP) ← (EA) ; (EA)为指令寻址方式所确定的有效地址
         (CS) ← (EA+2)

  从CALL指令执行的操作可以看出,第一步是把子程序返回调用程序的地址保存在堆栈中。对段内调用,只需将IP的当前值,即CALL指令的下一条指令的地址存入SP所指示的堆栈字单元中。对段间调用,保存返回地址则意味着要将CS和IP的当前值分别存入堆栈的两个字单元中。

  CALL指令的第二步操作是转子程序,即把子程序的入口地址交给IP(段内调用)或CS:IP(段间调用)。对段内直接方式,调转的位移量,即子程序的入口地址和返回地址之间的差值就在机器指令的2、3字节中。对段间直接方式,子程序的偏移地址和段地址就在操作码之后的两个字中。对间接方式,子程序的入口地址就从寻址方式所确定的有效地址中获得。

  ● RET 段内返回(近返回)
  执行操作:(IP) ← ((SP)),(SP) ← (SP)+2

  ● RET 段间返回(远返回)
  执行操作:(IP) ← ((SP)),(SP) ← (SP)+2
       (CS) ←((SP)),(SP) ← (SP)+2

  ● RET N 带立即数返回
  执行操作:① 返回地址出栈(操作同段内或段间返回)
       ② 修改堆栈指针:(SP) ← (SP)+N

  子程序的最后一条指令必须是RET指令,以返回到主程序。如果是段内返回,只需把保存在堆栈中的偏移地址出栈存入IP即可,如果是段间返回,则要把偏移地址和段地址都从堆栈中取出送到IP和CS寄存器中。

  带立即数返回指令,除完成偏移地址出栈或偏移地址和段地址出栈的操作外,还要再使SP的内容加上一个立即数N,使堆栈指针SP移动到新的位置。指令中的N可以是一个常数,也可以是一个表达式。带立即数返回指令适用于C或PASCAL的调用规则,这些规则在调用过程(子程序)前先把参数压入堆栈,子程序使用这些参数后,如果在返回时丢弃这些已无用的参数,就在RET指令中包含一个数字,它表示压入到堆栈中参数的字节数,这样堆栈指针就恢复到参数入栈前的值。

  CALL指令和RET指令都不影响条件码。

 例根据下面调用程序和子程序的程序清单,画出RET指令执行前和执行后的堆栈情况。假设初始的SS:SP=A000:1000。
 
    0000  B8 001E   MOV  AX,30
    0003  BB 0028   MOV  BX,40
    0006  50      PUSH AX     ; push data1 into stack
    0007  53      PUSH BX     ; push data2 into stack
    0008  E8 0066   CALL ADDM    ; call subroutine
    000B  B4 02    MOV  AH,2
    …   …      …
    0071  ADDM     PROC NEAR  ; entry point (IP)←0071=000b+0066
    0071  55      PUSH BP     ; save BP
    0072  8B E4    MOV  BP,SP    ; addressing the stack with BP
    0074  8B 46 04  MOV  AX,[BP+4] ; get data2 from stack
    0077  03 46 06   ADD  AX,[BP+6] ; add data1
    007A  CD      POP  BP     ; get back BP
    007B  C2      0004 RET 4   ; return and revert SP
    007E  ADDM     ENDP

图 CALL指令和RET指令对堆栈的影响

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top