微处理器8086

2015/12/02 Assembly

微处理器8086

8086系统结构

8086 CPU曾是使用广泛的16位微处理器。80386和80486及Pentium系列都是从8086发展而来的,称为80X86系列。8086是由Intel公司设计生产的,内部集成了约2.9×104 个晶体管,具有40个引脚的双列直插式封装芯片。由于引脚数的限制,它的数据总线和地址总线是复用的。标准型8086工作的时钟频率是5 MHz,改进型8086的工作时钟频率为8 MHz、10 MHz。它使用单一的+5 V电压,引脚信号与TTL(Transistor-Transistor Logic,晶体管-晶体管逻辑电路)电平兼容。

以8086微处理器构成的16位微机为例,其微处理器内部的ALU、寄存器、大多数的指令等均被设计成16位(二进制)。8086各有一条16位数据总线和20位地址总线,因此它每次读、写的数据宽度为16位,也可以是8位,可以访问2^20(即1M)个存储单元。

8086 CPU内部结构

从功能上,8086可以分为两个单元,即指令执行单元(Execution Unit,EU)和总线接口单元(Bus Interface Unit,BIU)。BIU和EU的操作是并行的。指令执行单元EU主要由算术逻辑运算单元(ALU)、标志寄存器(FR)、通用寄存器组、暂存器和EU控制器5个部件组成,其主要功能是执行指令。BIU主要由地址加法器、专用寄存器组、指令队列和总线控制逻辑4个部件组成,其主要功能是形成访问存储器的物理地址、访问存储器并取指令暂存到指令队列中等待执行,访问存储器或I/O端口读取操作数参加EU运算或存放运算结果等。

传统的CPU在执行一个程序时,总是先从存储器中取出下一条指令,读出一个操作数,然后执行指令,指令花费时间等于取指令时间加上执行指令的时间。在8086 CPU体系结构中,这些步骤分配给两个独立的处理单元,EU负责执行指令,BIU负责取指令、读出操作数和写入结果。这两个单元能够相互独立地工作,并在大多数情况下,使大部分取指令和执行指令重叠进行,即在取指令的同时,指令执行单元也在同时工作,有效地加快了系统的运算速率,指令花费时间等于执行指令的时间。

指令执行单元

EU包含1个16位的ALU、8个16位通用寄存器、1个16位标志寄存器(FR)、1个数据暂存寄存器和EU控制器等。

EU负责所有指令的解释和执行,同时管理上述有关的寄存器。负责从BIU的指令队列缓冲器中取指令,并对指令译码,根据指令要求向EU内部各部件发出控制命令,以完成各条指令规定的功能。

EU对指令的执行是从取指令操作码开始的,它从BIU的指令队列缓冲器中每次取一个字节。如果指令缓冲器中是空的,那么EU就要等待BIU通过外部总线从存储器中取得指令并送到EU,通过译码电路分析,发出相应控制指令,控制“ALU数据总线”中数据的流向。如果是运算操作,操作数据经过暂存寄存器送入ALU,运算结果经过“ALU数据总线”送到相应寄存器,同时标志寄存器FR根据运算结果改变状态。在指令执行过程中常会发生从存储器读或写数据的事件,这时就由EU提供寻址用的16位有效地址,在BIU中汇总经过运算形成一个20位的物理地址,送到外部总线进行寻址。

总线接口单元

BIU是8086 CPU与存储器和I/O设备之间的接口部件,负责对全部引脚的操作,即8086 CPU所有对存储器和I/O设备的操作都是由BIU完成的。

BIU由20位地址加法器、专用寄存器组、6字节的指令队列缓冲器和总线控制逻辑等组成。提供了20位地址总线、16位双向数据总线和若干条控制总线。其具体功能是负责从内存单元中预取指令,并将它们送到指定队列缓冲器暂存。CPU执行指令时,总线接口单元要配合EU,从指定的内存单元或者I/O端口中取数据传送给EU,或者把EU的处理结果传送到指定的内存单元或I/O端口中。

8086 CPU寄存器组

8086微处理器内部共有14个16位寄存器,包括通用寄存器、地址指针和变址寄存器、段寄存器、指令指针寄存器和标志寄存器。

通用寄存器组

Intel 8086 CPU EU中有8个16位通用寄存器,它们可分成两组。

  • 一组由AX、BX、CX和DX构成,称为数据寄存器,可用来存放16位的数据或地址,也可把它们当作8个8位寄存器来使用,即把每个通用寄存器的高半部分和低半部分分开。低半部分被命名为AL、BL、CL和DL;高半部分则被命名为AH、BH、CH和DH。
  • 另一组包含4个16位寄存器,称为地址指针寄存器和变址寄存器,用来存放操作数的偏移地址。

数据寄存器

  • AX:称为累加器。它是算术运算时使用的主要寄存器,所有外部设备的I/O指令只能使用AL或AX作为数据寄存器。
  • BX:称为基址寄存器。它可以用作数据寄存器,在计算存储器地址时,又可作为地址寄存器使用,是具有双重功能的寄存器。
  • CX:称为计数寄存器。在字符串操作、循环操作和移位操作时作为计数器。
  • DX:称为数据寄存器。在乘、除法中作为辅助累加器,在I/O操作中作为地址寄存器。

地址指针和变址寄存器

  • 堆栈指针寄存器(Stack Pointer,SP):用于存放栈顶偏移值,和堆栈段寄存器一起构成了堆栈的栈顶地址。
  • 基址指针寄存器(Base Pointer,BP):可以和堆栈寄存器一起构成堆栈的栈顶地址,也可以在间接寻址中作为地址寄存器,并能用来存放参与运算的16位操作数及运算结果。
  • 源变址寄存器(Source Index,SI):在间接寻址时,可以作为地址寄存器或变址寄存器。在字符串操作中作为源操作符字符串的变址寄存器。
  • 目的变址寄存器(Destination Index,DI):在间接寻址时,可以作为地址寄存器或变址寄存器;在字符串操作中作为目的字符串的变址寄存器。

SI和DI可以单独作为地址指针使用。但在串操作指令中,SI必须作为源串操作数的地址指针,DI必须作为目的串操作数的地址指针,两者不能互换。

段寄存器

8086 CPU总线接口单元BIU中设置有4个16位段寄存器,它们是代码段寄存器(CS)、数据段寄存器(DS)、堆栈段寄存器(SS)和附加段寄存器(ES)。

  • 代码段寄存器(Code Segment,CS):存放当前正在运行的程序代码所在段的段基址,表示当前使用指令代码可以从该段寄存器指定的存储器段中取得,相应的偏移量由IP提供。
  • 数据段寄存器(Data Segment,DS):存放当前程序使用的数据所存放段的最低地址,即存放数据段的基址。
  • 堆栈段寄存器(Stack Segment,SS):存放当前堆栈的底部地址,即存放堆栈段的段基址。
  • 附加段寄存器(Extra Segment,ES):在串操作指令中,用于存放目的串数据的段起始地址。在其他情况下可存放第二个数据段段基址。

指令指针和标志寄存器

指令指针寄存器

指令指针寄存器(IP)是一个16位寄存器,用来存放将要执行的下一条指令在代码段中的偏移地址。在程序运行过程中,BIU自动修改IP中的内容,使它始终指向将要执行的下一条指令。程序不能直接访问IP,但是可通过某些指令修改IP的内容。

标志寄存器

8086 CPU中设置了一个16位标志寄存器(FR),用来存放运算结果的特征和控制标志。

9个标志位可分成两类:一类是状态标志,用来表示运算结果的特征,包括CF、PF、AF、ZF、SF和OF;另一类是控制标志,用来控制CPU的操作,包括IF、DF和TF。

  • CF(Carry Flag):进借位标志位。CF=1,表示本次运算中最高位(第7位或第15位)有进位(加法运算时)或有借位(减法运算时);CF=0,表示本次运算中最高位(第7位或第15位)无进位(加法运算时)或无借位(减法运算时)。
  • PF(Parity Flag):奇偶标志位。PF=1,表示本次运算结果的低8位中有偶数个1;PF=0,表示有奇数个1。
  • AF(Auxiliary Carry Flag):辅助进借位标志位。AF=1,表示8位运算结果中低4位向高4位有进位(加法运算时)或有借位(减法运算时);否则,AF=0。
  • ZF(Zero Flag):零标志位。ZF=1,表示运算结果为0(各位全为0);否则,ZF=0。
  • SF(Sign Flag):符号标志位。SF=1,表示运算结果的最高位(第7位或第15位)为1;否则,SF=0。
  • OF(Overflow Flag):溢出标志位。OF=1,表示算术运算结果产生溢出;否则,OF=0。溢出标志位是根据操作数的符号及其变化情况设置的。例如,加法运算时,两个操作数符号相同,而结果的符号与之相反,则OF=1;否则,OF=0。
  • IF(Interrupt Flag):中断允许标志位,用来控制8086是否允许接收外部中断请求。IF=1,表示允许CPU响应可屏蔽中断INTR。IF标志可通过指令置位和复位。IF的状态不影响非屏蔽中断请求(NMI)和CPU内部中断请求。
  • DF(Direction Flag):方向标志位。在串操作指令中,若DF=0,表示串操作指令执行后地址指针自动增量,串操作由低地址向高地址方向进行;DF=1,表示地址指针自动减量,即串操作由高地址向低地址方向进行。DF标志位可通过指令置位和复位。
  • TF(Trap Flag):陷阱标志位,是为调试程序而设定的陷阱控制位。TF=1,表示控制CPU进入单步工作方式,此时CPU每执行完一条指令就自动产生一次内部中断。当该位复位后,CPU恢复正常。

基本时序

时序的基本概念

计算机的工作是在时钟脉冲CLK的统一控制下,一个节拍一个节拍地实现的。CPU执行某一个程序之前,先要把程序(已变为可执行的目标程序)放到存储器的某个区域。在启动执行后,CPU就发出读指令的命令,存储器接到这个命令后,从指定的地址(在8086中由代码段寄存器CS和指令指针IP给定)读出指令,把它送至CPU的指令寄存器中,然后CPU对读出的指令经过译码器分析之后,发出一系列控制信号,以执行指令规定的全部操作,控制各种信息在系统各部件之间传送。

8086执行指令涉及3种周期,即时钟周期、总线周期和指令周期。首先要掌握这3种周期的区别与相互之间的联系。

  • 时钟周期T :是时钟脉冲的重复周期,是CPU的时钟频率的倒数,是CPU的时间基准,由计算机的主频决定。例如,8086的主频为5 MHz,则1个时钟周期为200 ns。执行指令的一系列操作都是在时钟脉冲CLK的统一控制下一步一步进行的。
  • 总线周期(Bus Cycle):8086 CPU与外部交换信息总是通过总线进行的。完成一次总线操作所需的时间,称为总线周期,一般包含多个时钟周期T (典型为4个),每当CPU要从存储器或I/O端口存取一个字节或字时,就需要一个总线周期。
  • 指令周期:执行一条指令所需的时间。每条指令的执行由取指令、译码和执行等操作组成,不同指令的指令周期是不等长的,一个指令周期由一个或若干个总线周期组成。

8086存储器组织

8086系统中的存储器是一个最多1 MB的序列,即可寻址的存储空间为1 MB,系统为每字节分配一个20位的物理地址(对应的十六进制数地址范围为00000H~FFFFFH)。

在存储器中任何两个相邻的字节被定义为一个字。在一个字中,每字节都有一个地址,并且这两个地址中较小的一个被用来作为该字的地址。 一个字的起始地址可以从偶地址开始,也可以从奇地址开始,并且较高存储器地址的字节存放该字的高8位,较低存储器地址的字节存放该字的低8位。

8086 CPU有20条地址线,能寻址外部存储空间为1MB,而在8086 CPU内部能向存储器提供地址码的地址寄存器有6个,均为16位,所以用这6个16位地址寄存器任意一个给外部存储器提供地址,只能提供64K个地址,不能提供完整的1MB存储空间地址。这6个16位地址寄存器分别为BX、BP、SI、DI、SP、IP。

为了使8086 CPU能寻址到外部存储器1MB空间中任何一个单元,采用了地址分段方法(将1MB空间分成若干个逻辑段),每段不超过64 KB。段与段能连续排列;也能部分重叠、完全重叠、断续排列。段数也没有一定限制。一个存储单元可以只属于某一段,也可以属于多个互相重叠的段。最终将寻址范围扩大到1MB。

在1MB的存储空间中,每个存储单元的实际地址编码称为该单元的物理地址(用PA表示)。一个段的起始地址的高16位自然数为该段的段地址。在一个段内的每个存储单元,可以用相对于本段的起始地址的偏移量来表示,这个偏移量称为段内偏移地址,也称为有效地址(EA)。

注意:

  • 各逻辑段的起始地址必须能被16整除,即一个段的起始地址(20位物理地址)的低4位二进制码必须是0。
  • 在1MB的存储空间中,可以有216 个段地址。每相邻的两个段地址之间相隔16个存储单元;在一个段内有216 =64K个偏移地址,即一个段最大为64 KB。
  • 在一个64 KB的段内,每个偏移地址单元的段地址是相同的,所以段地址也称为段基址;由于相邻两个段地址只相隔16个单元,所以段与段之间大部分空间互相覆盖。

把1MB的存储空间分成若干个逻辑段以后,对一个段内的任意存储单元,都可以用两部分地址来描述,一部分为段地址(段基址),另一部分为段内偏移地址(有效地址EA)。段地址和段内偏移地址都是无符号的16位二进制数,常用4位十六进制数表示。这种方法表示的存储器单元的地址称为逻辑地址。逻辑地址的表示格式为“段地址:偏移地址”。一个存储单元用逻辑地址表示后,CPU对该单元的寻址就应提供两部分地址,即段地址和段内有效地址。段地址和段内有效地址分别由以下段寄存器提供。

  • CS:提供当前代码(程序)段的段地址。
  • DS:提供当前数据(程序)段的段地址。
  • ES:提供当前附加数据段的段地址。
  • SS:提供当前堆栈段的段地址。

BX、BP、SI、DI:CPU对存储器进行数据读/写操作时,由这些寄存器以某种寻址方式向存储器提供段内偏移地址。

  • SP:堆栈操作时,提供堆栈段的段内偏移地址。
  • IP:CPU取指令时,提供所取指令代码所在单元的偏移地址。

已知某存储单元的逻辑地址,该单元的物理地址=段地址×10H+段内偏移地址。

8086的寻址方式

寻址方式就是指令中用于说明操作数所在地址的方法。可以说,寻址方式的多少也是衡量CPU功能的指标。8086的寻址方式十分丰富,32位微机的寻址方式在其基础上稍有增加。

8086指令中的操作数有一个或两个,个别指令有3个,称为源操作数和目的操作数。除目的操作数不允许为立即数(即立即寻址)外,其余寻址方式均适合源操作数和目的操作数。

立即寻址

操作数直接包含在指令中,此时的操作数也叫立即数。这种寻址方式也就称为立即数寻址方式。它紧跟在操作码的后面,与操作码一起放在代码段区域中。例如:

MOV  AX,4000H    ;将立即数4000H送到AX寄存器

立即数可以是8位的,也可以是16位的。 注意:

  • 在所有的指令中,立即数只能作源操作数,不能作目的操作数。
  • 以字母开头的十六进制数前必须以数字0作前缀。
  • 立即数可以是用+、-、×、/表示的算术表达式,也可以用圆括号改变运算顺序。
  • 立即数只能是整数,不能是小数、变量或者其他类型的数据。

寄存器寻址

寄存器寻址,这种寻址方式的操作数放在寄存器中,用寄存器的符号来表示。对于16位操作数,寄存器可以是AX、BX、CX、DX、SI、DI、SP、BP等;对于8位操作数,则用寄存器可以是AH、AL、BH、BL、CH、CL、DH、DL。

例如:

    INC  BX        ;将BX的内容加1
    MOV  BX,CX    ;执行该指令后BX=CX,CX的内容保持不变

采用寄存器寻址方式的指令,其机器码字节数较少。此外,由于操作就在CPU内部进行,不必执行访问存储器的总线周期,故执行速度快。

注意:

  • 在一条指令中,可以对源操作数采用寄存器寻址方式,也可以对目的操作数采用寄存器寻址方式,还可以两者都采用寄存器寻址方式。
  • 源操作数的长度必须与目的操作数一致;否则会出错。例如,不能将BH寄存器的内容传送到DX中,尽管DX寄存器放得下BH的内容,但汇编程序不知道将它放到DH还是DL中。

存储器寻址

存储器寻址这种方式的操作数在存储器中,指令中给出其存放地址代码或地址代码的表达形式。存储器寻址是变化最多的寻址方式。根据操作数的有效地址EA(Effective Address)的形成方法不同,这种寻址方式又可分为直接寻址、寄存器间接寻址、基址寻址、变址寻址以及基址变址寻址等。

直接寻址

操作数总是在存储器中,其有效地址EA由指令以具体数值的形式直接给出。要注意的是,指令中的有效地址外必须加一对方括号,以便与立即数相区别。

    MOV  AX,[21070H]    ;将物理地址为21070H单元的16位数读取到AX
                          

在采用直接寻址方式时,如果指令前面没有前缀指明操作数在哪一个段,则默认的段寄存器是数据段寄存器DS。但8086/8088系统中还允许段超越,即允许操作数存放在以代码段、堆栈段或附加段为基准的存储区域中。此时只要在指令中指明是段超越就可以,也就是说,16位的偏移地址可以与CS、SS或ES中的段地址组合,形成操作数的物理地址。

例如:

    MOV  BX,ES:[4000H]    ;操作数存放在由ES指示的附加段中
                              ;源操作数的物理地址ES×10H+4000H

其中冒号“:”称为修改属性运算符,其左边的段寄存器符号就是段超越前缀。

寄存器间接寻址

操作数的有效地址EA直接取自某一个基址寄存器或变址寄存器。在这种方式中,对于约定的逻辑段,其段超越前缀可以省略。可使用BX、SI和DI这3个16位的寄存器作为间接寻址寄存器,并且规定约定访问的是由DS指示的数据段。若使用BP作为间接寻址寄存器,则约定访问的是由SS指示的堆栈段(实际上,8086/8088指令系统中并没有[BP]形式的操作数,但汇编时遇到[BP]形式也不算错,会按[BP+0]编译)。

MOV  BX,[SI]    ;源操作数的物理地址=DS×10H+SI

设:DS=3000H,SI=2004H,[32004H]=2478H 则:源操作数的物理地址=DS×10H+SI=30000H+2004H=32004H。

寄存器相对寻址

操作数的有效地址是一个基址或变址寄存器的内容与指令中指定的8位或16位位移量(简记为disp)之和。同样,当指令中指定的寄存器是BX、SI或DI时,段寄存器使用DS,当指定寄存器是BP时,段寄存器使用SS。

    MOV  BX,disp[SI]    ;源操作数的物理地址=DS×10H+SI+disp

设:DS=1000H,SI=3000H,disp=4000H,[17000H]=1234H 则:源操作数的物理地址=DS×10H+SI+disp=10000H+3000H+4000H=17000H。

基址变址寻址

操作数的有效地址是一个基址寄存器(BX或BP)与一个变址寄存器(SI或DI)的内容之和。在这种方式中,只要用到BP寄存器,那么默认的段寄存器就是SS;在其他情况下,默认的段寄存器均为DS。

MOV  AX,[BP][SI]  ;源操作数的物理地址=SS×10H+BP+SI

设:SS=3000H,BP=1200H,SI=0500H,[31700H]=0EFCDH 则:源操作数的物理地址=SS×10H+BP+SI=30000H+1200H+0500H=31700H。

基址变址相对寻址

若使用基址变址寻址方式时允许带一个8位或16位的位移量disp,则称为基址变址相对寻址。

MOV  AX,disp[BX][SI]    ;源操作数的物理地址=DS×10H+BX+SI+disp

设:DS=2000H,BX=1500H,SI=0300H,disp=0200H,[21A00H]=26BFH 则:源操作数的物理地址=DS×10H+BX+SI+disp=20000H+1500H+0300H+0200H=21A00H。

端口寻址

CPU与外设端口交换数据时需要寻找外设端口的地址,这种寻址方式称为端口寻址。端口寻址也有直接寻址和间接寻址之分。

端口直接寻址

外设端口的地址以8位立即数的形式直接出现在指令中。

例如:

    IN  AL,36H    ;从36H端口输入一个8位数据到AL寄存器

端口间接寻址

外设端口的地址先存入DX寄存器后再出现在指令中。

例如:

    MOV DX,2400H  ;将2400H送到DX寄存器
    OUT  DX,AL;将AL寄存器的内容输出到DX所指示的2400H端口地址

注意,端口地址超过8位时必须用间接寻址。

指令系统

计算机是通过执行指令序列来工作的,每种计算机都有一组指令集提供给用户使用,这组指令集称为该计算机的指令系统。不同CPU的计算机使用不同的指令系统,8086 CPU的指令系统不仅包含8位机的全部指令,而且增加了一些功能较强的16位数据处理指令,如乘法、除法指令,因而同时具有8位和16位的处理能力。

8086指令的特点

任何一条指令都由操作码(Opcode)和操作数两部分组成。

指令中的操作码部分表明指令的操作性质,一般有1~2 B;操作数部分既可以表示参加操作的数,也可以表示参加操作的数所在位置。当表示参加操作的数所在位置时,操作数部分又称为地址码。操作数部分有0~4 B。在一条指令中,操作码部分是必需的,而操作数部分可能隐含在操作码中,或者由操作码后面的指令给出。

灵活的指令格式

8086的指令中有1B长,此时指令中的操作数部分隐含在操作码中,大部分对16位寄存器操作的指令都只有1B长;当操作数在内存中,编程又需要复杂的寻址方式时,有的指令多达6 B长。 比如,1B指令:

指令助记符 指令的十六进制数代码

              DAA           27H

该指令是十进制数加法调整指令,这个十进制数就隐含在寄存器AL中。

再如,6B指令: 指令助记符     指令的十六进制数代码

        MOV  [BX+SI+1020H],3040H

表达式BX+SI+1020H代表一个地址,该指令是把数3040H送到该地址指示的内存单元中。

指令格式的一对多形式

用助记符编写的指令最终要翻译成二进制代码由CPU执行。为了方便用户理解,可用两种不同的助记符描述同一问题,如JE/JZ。当两个无符号数进行比较操作时,用户理解为相等则转移,也可理解为ZF=1则转移。虽然助记符不同,但其二进制代码是一样的。

较强的运算指令

当用8位机完成乘法运算时,只能用连加或对位权移位等方式编写一段程序实现。8086中有乘法、除法指令,给用户提供了极大方便。

指令有极强的寻址能力

微机系统中,参加操作的数据有可能在CPU的寄存器、内存或外部设备中。指令中如何提供数据所在位置,以便提高程序执行效率,这就需要CPU提供强有力的寻址能力。细分8086指令的寻址方式多达9种,特别是对内存的寻址方式十分灵活。

指令有处理多种数据的能力

8086指令能够处理8位/16位数、带符号/无符号数以及压缩BCD数/非压缩BCD数。带符号数和无符号数有相应的乘法、除法指令,压缩BCD数/非压缩BCD数有相应的调整指令。

8086指令的分类

8086指令系统按功能可分为6种。

  • 数据传输类 这类指令的功能是将源操作数的内容传送到目的操作数中。这类指令形式较多,寻址方式也十分丰富,在程序设计中使用频率很高。
  • 算术运算类 这类指令的功能是完成加、减、乘、除运算。每次运算会对6种状态标志产生影响。使用这类指令时,要注意指令的书写形式(源操作数和目的操作数的存放位置)以及乘/除运算中参加运算的数据类型。
  • 逻辑运算类 这类指令的功能有两种:一种是完成逻辑“反”“与”“或”“异或”和“测试”,另一种是对数据的移动。这类指令是按二进制位进行的,所以又称为位操作指令。这种运算也对状态标志位产生影响。
  • 串操作类 串操作指令有着不同的寻址方式,段寄存器和变址寄存器按DS:SI和ES:DI组合寻址。这类指令在执行前根据编程需要设置DF标志,在这些指令前加上指令前缀,可以完成指令的循环操作。
  • 程序控制类 程序中执行跳转、调用子程序、中断服务等指令,都要使原来的CS:IP或IP寄存器的内容改变,使之指向下一条要执行指令的位置。程序中的分支、循环、中断等都会用到这些指令,这些指令可分为有条件(又可分为单条件和多条件)指令和无条件指令。其条件的产生是先执行运算指令,使状态标志发生变化,然后通过这些指令测试来控制程序转移。转移可在同一段中进行(仅改变IP内容),也可以在不同段中进行(CS和IP都改变)。
  • 处理机控制类 这类指令提供程序控制CPU的各种功能,如使处理机暂停、等待、封锁总线等,还可以对FR寄存器中的一些标志进行置“1”或清“0”等操作。

数据传送指令

数据传送是计算机系统中最主要的操作,可以把数据从计算机系统的一个部位传送到另一个部位。这里,把发送数据的部位称为源,接收数据的部位称为目的。8086系统设置了基本数据传送、输入/输出、地址传送和标志传送等多种数据传送类指令。

通用数据传送指令

MOV指令

MOV指令是形式最简单、用得最多的指令。它允许在CPU的寄存器之间、存储器和寄存器之间传送字节或字数据,也可以将立即数传送到寄存器或存储器中。

格式:MOV 目的操作数 源操作数 功能:目的操作数←源操作数 该指令将源操作数(字或字节)传送到目的操作数,源操作数保持不变。

传送指令及其操作举例。

    MOV  AX,1020H           ;字传送,AX=1020H
    MOV  DS,AX              ;DS=AX=1020H
    MOV  BX,3040H           ;BX=3040H
    MOV  DX,5060H           ;DX=5060H
    MOV  [BX+08],DX  ;DS:[BX+08]=DX,
                             ;即1020H:[3040H+08]=5060H,
                             ;或[13248H]=5060H,[13249H]=50H,[13248H]=60H

注意:

  • 立即数、代码段寄存器CS只能作源操作数。
  • 立即数不能传送给段寄存器。
  • IP寄存器不能作源操作数或目的操作数。
  • MOV指令不能在两个存储单元之间直接传送数据,也不能在两个段寄存器之间直接传送数据。
  • 两个操作数的类型属性要一致。

下列指令是非法的。

    MOV  AX,BL              ;类型不一致
    MOV  CS,AX              ;CS不能作目的操作数
    MOV  [BX],[2300H]   ;不能在两个存储单元之间直接传送数据
  • 堆栈操作指令 堆栈是以“后进先出”方式工作的一个存储区,堆栈区的段地址由SS寄存器的内容确定,而栈顶位置由堆栈指针SP寄存器的内容来确定。堆栈操作指令包括入栈(PUSH)和出栈(POP)指令两类。这两条指令必须以字为操作数,且不能采用立即寻址方式。

PUSH入栈操作

格式:PUSH 源操作数 功能:SP←SP-2,[SP]←源操作数 即将源操作数压入堆栈。 说明:源操作数可以是16位通用寄存器、段寄存器或存储器中的字数据。每次执行PUSH指令的步骤为:首先修改SP的值,SP=SP-2;然后源操作数的低字节放在栈顶的低地址单元,即[SP]=源操作数的低8位;源操作数的高字节放在栈顶的高地址单元,即[SP+1]=源操作数的高8位。 由于入栈操作都是以字为单位进行的,所以SP总是减2调整的。

POP出栈操作。

格式:POP 目的操作数 功能:目的操作数←[SP],SP←SP+2 即将当前SP所指向的堆栈顶部的一个字送到指定的目的操作数中。 说明:目的操作数可以是16位通用寄存器、段寄存器或存储单元,但CS不能作目的操作数。每执行一次POP指令后,SP=SP+2,即SP向高地址方向移动,指向新的栈顶。

设SS=3000H,SP=0050H,BX=1320H,AX=25FEH,如果依次执行下列指令:

    PUSH  BX   ;SP=SP-2=004EH,SS:[SP]=BX=1320H
    PUSH  AX   ;SP=SP-2=004CH,SS:[SP]=AX=25FEH
    POP   BX   ;BX=SS:[SP]=3000H:[004CH],SP=SP+2=004EH
  • 数据交换指令XCHG 格式:XCHG 目的操作数,源操作数 功能:目的操作数←→源操作数 即完成数据交换。把一个字节或一个字的源操作数与目的操作数相互交换。交换能在通用寄存器与累加器之间、通用寄存器之间、通用寄存器与存储器之间进行。但段寄存器和立即数不能作为一个操作数,源操作数和目的操作数不能同时为存储单元。

例如:

    XCHG  AL,CL           ;AL和CL之间进行交换
    XCHG  [2530H],CX    ;CX内容和数据段内偏移地址为2530H的字数据交换

累加器专用传送指令

8086 CPU要与外部设备交换数据,必须通过累加器AX(16位数据)或AL(8位数据)传送给I/O端口,外设从输出端口取数据,完成数据输出;反之,外设将数据传送到I/O端口,CPU从端口中将数据取到AX或AL中,完成数据输入。

硬件系统根据外设情况,设计端口地址为16位(外设较多)或8位(外设较少),而数据的大小也会根据具体情况设计,可以是8位A/D转换器转换得到8位数据,也可以是16位A/D转换器转换得到16位数据。8086有相应的指令处理这些情况。

输入指令IN。

格式:

    IN  AL,n     ;AL←[n]
    IN  AX,n     ;AX←[n+1][n]
    IN  AL,DX    ;AL←[DX]
    IN  AX,DX    ;AX←[DX+1][DX]

功能:从I/O端口输入数据至AL或AX。允许把一个字节由一个输入端口传送到AL中,或者把一个字由两个连续的输入端口传送到AX中。若端口地址超过8位二进制数(00~FFH),则必须用DX寄存器来保存该端口地址,这样用DX作端口地址时,最多可寻64K(0000~FFFFH)个端口。

输入指令及操作举例。

    IN  AL,36H    ;AL=[36H]
    IN  AX,47H    ;AX=[47H],即:AH=[48H],AL=[47H]
    MOV DX,0284H  ;DX=0284H
    IN  AX,DX     ;AX=[DX],即:AH=[0285H],AL=[0284H]

输出指令OUT。

格式:

    OUT  n,AL    ;AL→[n]
    OUT  n,AX    ;AX→[n+1][n]
    OUT  DX,AL      ;AL→[DX]
    OUT  DX,AX      ;AX→[DX+1][DX]

功能:将AL或AX的内容输出至I/O端口。可以将AL的内容传送到一个输出端口,或将AX中的内容传送到两个连续的输出端口。端口寻址方式与取指令相同。

输出指令及操作举例。

    OUT  20H,AL    ;AL→[20H]
    MOV  DX,0148H  ;DX=0148H
    OUT  DX,AX     ;AX→[DX],即:AH→[0149H],AL→[0148H]

换码指令XLAT。

格式:

    XLAT

这条指令没有明显的操作数,其操作数需要另外的指令提供,所以单独执行该指令不能达到预期要求。

换码是指令能够完成1 B的查表转换。有时需要将一种代码转换成另一种代码,或在处理实际问题时,采用一种映射关系来完成转换。前提是正确找到映射关系,利用存储器地址的连续性和规律建立表格,然后用该指令完成转换。 执行该指令之前,需先执行以下两条指令:

    MOV  BX,表的偏移首地址
    MOV  AL,被转换码

由于该指令不能单独执行,有时称之为复合指令。

地址目标传送指令

取有效地址指令LEA。

格式:LEA 目的操作数,源操作数 功能:把源操作数的偏移地址传送至目的操作数。这条指令通常用来建立串操作指令所需的寄存器指针。源操作数必须是一个内存单元地址,目的操作数必须是一个16位的通用寄存器。

例如:

    LEA  BX,BUFR    ;把变量BUFR的偏移地址EA送到BX

双字指针送寄存器和DS指令LDS。

格式:LDS 目的操作数,源操作数

功能:完成一个地址指针的传送。地址指针包括偏移地址和段地址,它们已分别存放由源操作数给出最低地址的4个连续存储单元中(即存放了一个32位的双字数据),指令将该数据的高16位(作为段地址)送入DS,低16位(作为偏移地址)送入目的操作数所指的一个16位通用寄存器或者变址寄存器中。

例如:

    LDS  SI,[BX]  ;把BX所指32位地址指针的段地址送入DS,偏移地址送入SI

双字指针送寄存器和ES指令LES。

格式:LES 目的操作数,源操作数

功能:这条指令除将地址指针的段地址送入ES外,其余与LDS类似。

例如:

    LES  DI,[BX+6]  ;ES=DS:[BX+8],DI=DS:[BX+6]

标志传送指令

标志送AH指令LAHF。

这条指令的功能是将标志寄存器的低8位数据传送至AH寄存器。

AH送标志寄存器低字节指令SAHF。

这条指令与LAHF指令的操作相反,可以将寄存器AH的内容送至标志寄存器的低8位。根据AH的内容,将影响CPU的状态标志位,但是对OF、DF和IF无影响。

标志入栈指令PUSHF。

将标志寄存器的内容压入堆栈顶部,同时修改堆栈指针,但不影响标志位。

标志出栈指令POPF。

把当前堆栈顶部的一个字,传送到标志寄存器,同时修改堆栈指针,影响标志位。

算术运算指令

8086系统提供加、减、乘、除4种基本算术操作。这些操作都可用于字节或字的运算,适用于带符号数或无符号数的运算,带符号数用补码表示。同时8086也提供了各种校正操作,故可以进行十进制算术运算。

加法指令

加法指令ADD。

格式:ADD 目的操作数,源操作数 功能:目的操作数←目的操作数+源操作数 该指令完成两个操作数相加,结果送至目的操作数。目的操作数可以是通用寄存器以及存储器,源操作数可以是通用寄存器、存储器或立即数。这条指令对标志位CF、OF、PF、SF、ZF和AF有影响。

注意:源操作数和目的操作数不能同时为存储器,而且它们的类型必须一致,即同为字节或字。 例如:

    ADD  AL,10H        ;AL←AL+10H
    ADD  BX,[3000H]  ;通用寄存器与存储单元内容相加

带进位的加法指令ADC。

格式:ADC 目的操作数,源操作数 功能:目的操作数←目的操作数+源操作数+CF 这条指令与ADD指令类似,只是在两个操作数相加时,要把进位标志CF的现行值加上去,结果送至目的操作数。ADC指令主要用于多字节运算中。该指令对标志位的影响与ADD相同。

ADC指令及其操作举例。

    MOV  AX,2000H     ;AX=2000H
    MOV  DS,AX        ;DS=2000H
    ADD  AX,40H       ;AX=AX+40H=2000H+0040H=2040H,CF=0
    MOV  BX,5000H     ;BX=5000H
    MOV  [BX],AX    ;DS:[BX]=AX,即2000H:[5000H]=2040H,
                       ;也即[25001H]=20H,[25000H]=40H
    ADC  AL,[BX+01];AL=AL+DS:[BX+01]+CF
                       ;AL=40H+2000H:[5000H+01]+0
                       ;  =40H+[25001H]+0=40H+20H+0=60H,CF=0

增量指令INC。

格式:INC 操作数

功能:完成对指定的操作数加1,然后返回此操作数。此指令主要用于在循环程序中修改地址指针和循环次数等。这条指令执行的结果影响标志位AF、OF、PF、SF和ZF,对进位标志CF没有影响。

例如:

    INC  AL      ;AL寄存器中的内容增加1
    INC  BX      ;BX=BX+1

减法指令

减法指令SUB。

格式:SUB 目的操作数,源操作数 功能:目的操作数←目的操作数-源操作数 即完成两个操作数相减,从目的操作数中减去源操作数,结果放在目的操作数中。

例如:

    SUB  CX,BX         ;CX←CX-BX
    SUB  [BP+2],CL  ;将SS段中BP+2所指单元中的内容减去CL中的值

带借位的减法指令SBB。

格式:SBB 目的操作数,源操作数

功能:目的操作数←目的操作数-源操作数-CF

这条指令与SUB类似,只是在两个操作数相减时,还要减去借位标志位CF的当前值。本指令对标志位AF、CF、OF、PF、SF和ZF都有影响。同ADC指令一样,本指令主要用于多字节操作数相减。

设当前值DS=2000H,AX=2060H,BX=5000H,[25000H]=40H,CF=1,则执行以下指令

    SBB  AX,[BX]   ;AX=AX-DS:[BX]-CF=2060H-2000H:[5000H]-1
                      ;  =2060H-[25000H]-1=2060H-40H-1=201FH

后寄存器AX的内容为201FH,而CF=0。

减量指令DEC。

格式:DEC 操作数 功能:操作数←操作数-1 即对指令的操作数减1,然后送回此操作数。 说明:在相减时,把操作数作为一个无符号二进制数来对待。指令执行的结果影响标志位AF、OF、PF、SF和ZF,但不影响CF标志位。

取补指令NEG。

格式:NEG 操作数 功能:操作数← 0-操作数 对操作数取补(负),即用零减去操作数,再把结果送回原操作数。 例如:

    NEG    AL

若AL=00111100B,则取补后为11000100B,即00000000B-00111100B=11000100B。 该指令影响标志位AF、CF、OF、PF、SF和ZF。其结果一般总是使标志位CF=1,除非在操作数为零时,才使CF=0。在字节操作时对补码80H取补,或在字操作时对补码8000H取补,则操作数没有变化,但标志位OF置位。NEG指令实质为减法,对其他标志位的影响同减法指令SUB。

比较指令CMP。

格式:CMP 目的操作数,源操作数 功能:目的操作数-源操作数 比较指令完成两个操作数的相减,使结果反映在标志位上,但并不送回目的操作数中。比较指令主要用于比较两个数的大小关系,在比较指令之后,可根据CF、ZF及OF等标志位来判断两者的大小关系,从而确定程序的走向。CMP指令对标志位的影响同减法指令SUB。

设当前DS=2000H,AL=20H,BX=3000H,[23000H]=50H,则执行以下指令后,寄存器AL的内容仍为20H,但ZF、CF、OF、SF、PF和AF等标志位被更新。

    CMP  AL,[BX]    ;AL-DS:[BX]
                       ;即20H-2000H:[3000H]=20H-50H=0D0H
                       ;ZF=0,CF=1,OF=0,SF=1,PF=0,AF=0

乘法指令

无符号数乘法指令MUL。

格式:MUL 源操作数 功能:字节数相乘:AX←AL×源操作数 字型数相乘:DX AX←AX×源操作数 该指令完成字节与字节相乘或字与字相乘。其中源操作数即乘数由指令给出,而被乘数和乘积是默认的,被乘数为8位数时放在AL中,为16位数时放在AX中。8位数相乘,结果为16位数,放在AX中;16位数相乘,结果为32位数,高16位放在DX中,低16位放在AX中。注意:源操作数可以是常用寄存器或存储器,但不能为立即数。当结果的高半部分=0时,设置CF=0、OF=0,表示高半部分无有效数字;否则,设置CF=1,OF=1,其余状态标志位都不确定。

乘法指令举例。

    MOV  AL,02          ;AL=02H
    MOV  BL,03          ;BL=03H
    MUL  BL              ;结果为AX=AL×BL=02H×03H=0006H
    MOV  AX,0120H       ;AX=0120H
    MUL  WORD PTR[BX]  ;结果为DX AX=AX×WORD PTR[BX]
    MOV  AL,30H         ;AL=30H
    CBW                  ;字扩展AX=0030H
    MOV  BX,2000H       ;BX=2000H
    MUL  BX              ;DX AX=0030H×2000H=00060000H

符号数乘法指令IMUL。

格式:IMUL 源操作数 功能:字节数相乘:AX←AL×源操作数 字型数相乘:DX AX←AX×源操作数

这是一条带符号数(即补码数)的乘法指令,同MUL一样,可以进行字节与字节、字与字的乘法运算。结果放在AX或DX AX中。当结果的高半部分不是结果的低半部分的符号扩展时,标志位CF和OF都置1;否则都置0。

除法指令

无符号数除法指令DIV。

格式:DIV 源操作数 功能:字节数相除:AL←AX/源操作数的商,AH←AX/源操作数的余数 字型数相除:AX←DX AX/源操作数的商,DX←DX AX/源操作数的余数

该指令对两个无符号二进制数进行除法操作。源操作数可以是字或者字节。指令执行后,所有的状态标志位都是不确定的。当发生商溢出时,所得商和余数均为不确定,同时CPU会产生除法出错中断以进行相应处理。

除法指令举例。

    MOV  DX,01       ;DX=01H
    MOV  AX,86A1H    ;AX=86A1H
    MOV  BX,100      ;BX=64H,对应十进制数100
    DIV  BX           ;AX=03E8H,DX=01H

这里除数为BX,为字型数相除,除数用十进制表示为100,被除数为DX:AX,即186A1H,用十进制表示为100001,相除结果商为1000,即03E8H,余数为l,所以程序执行后AX=03E8H,DX=01H。

整数除法指令IDIV。

格式:IDIV 操作数

功能:该指令的执行过程同DIV指令。但IDIV指令认为操作数为有符号数即补码数,产生的商也为有符号数即补码数,余数的符号与被除数相同。

在除法指令中,字节运算时被除数在AX中,运算结果商在AL中,余数在AH中。字运算时被除数为DX:AX构成的32位数,运算结果商在AX中,余数在DX中。

例如,AX=2000H,DX=200H,BX=1000H,则“DIV BX”执行后,AX=2002H,DX=0000H。除法运算中,源操作数可为常用寄存器或存储器,但不能是立即数。除法指令执行后对所有的标志位都无定义。

符号扩展指令

由于除法指令中的字节运算要求被除数为16位数,而字运算要求被除数是32位数,在8086系统中往往需要用符号扩展的方法取得被除数所要的格式。另外,在两个用补码表示的符号数进行加减运算时为了保持属性(字节或双字)一致,也需要用符号扩展的方法。8086指令系统中包括两条符号扩展指令CBW和CWD,它们都采用隐含寻址方式。 格式:CBW 功能:将AL中字节数的符号位扩展到AH的各个位,形成AX中的字数据。 格式:CWD 功能:将AX中字数据的符号位扩展到DX中的各个位,形成DX和AX中的双字数据。

BCD调整指令

BCD编码可以方便地用来表示十进制数和进行十进制数的运算,通过以下的BCD调整指令可以将运算结果调整为用BCD码表示的十进制数。

组合BCD数。

格式:DAA 功能:组合BCD数的加法调整指令,半字节1位BCD相加,超过9或有进位,要加6调整。若低半字节调整后有进位,则高半字节再做加6调整。

DAA指令举例。

    MOV  AL,37H     ;AL=37H
    MOV  BL,35H     ;BL=35H
    ADD  AL,BL      ;两个十六进制数相加,AL此时为37H+35H=6CH
    DAA              ;DAA调整,这时AL为72H

这里为两个两位组合BCD码的加法运算,AL包含两位BCD码,分别为3和7;BL包含两位BCD码,分别为3和5;当低半字节7和5相加时,超过9,需要加6调整,调整后为2,同时有进位,高半字节3和3相加为6,加上进位为7,所以调整后AL=72H。

格式:DAS 功能:组合BCD数的减法调整指令,半字节1位BCD相减,有借位,要减6调整。

分离BCD数。

格式:AAA 功能:分离BCD数的加法调整指令,只取低半字节,其余同DAA指令。

格式:AAS 功能:分离BCD数的减法调整指令,只取低半字节,其余同DAS指令。

格式:AAM 功能:分离BCD数的乘法调整指令,两个BCD数相乘,结果在AL中,除以10后商在AH中,余数在AL中。

格式:AAD 功能:分离BCD数的除法调整指令,该调整指令要放在除法指令之前。先将两个BCD数转换为一字节二进制数(高位、10+低位)得到被除数,放于AL中,AH清零;运算后,商送AL,余数送AH。

位操作指令

这类指令包括逻辑运算指令和移位循环指令两种类型,它们均可直接对寄存器或存储器中的字节或字数据按位进行操作。

逻辑运算指令

取反指令NOT。

格式:NOT 操作数 功能:对操作数按位求反。此指令对标志位无影响。

逻辑与指令。

格式:AND 目的操作数,源操作数 功能:目的操作数←目的操作数AND源操作数

即对两个操作数按位进行逻辑“与”运算,结果送回目的操作数。

例如:

    AND  AL,0FH      ;将AL中的高4位清零,低4位保留

逻辑或指令OR。

格式:OR 目的操作数,源操作数

功能:对两个操作数按位进行逻辑“或”运算,结果送回目的操作数。

例如:

    AND  AL,0FH
    AND  AH,0F0H
    OR  AL,AH       ;完成拼字的操作
    OR  AX,0FFFH    ;将AX低12位置1
    OR  BX,BX       ;清相应标志

异或操作指令XOR。

格式:XOR 目的操作数,源操作数 功能:对两个操作数按位进行“异或”运算,结果送回目的操作数。

例如:

    XOR  AL,AL      ;使AL清零
    XOR  SI,SI      ;使SI清零
    XOR  CL,0FH     ;使CL低4位取反,高4位不变

测试指令TEST。

格式:TEST 目的操作数,源操作数 功能:完成与AND指令相同的操作,结果只影响标志位,不改变目的操作数。通常使用它进行数据中某些位是0或1的测试。

例如:检测AL中的最低位是否为1,为1则转移,可用以下指令:

    TEST  AL,01H
    JNZ  THERE
    …
    THERE:

逻辑运算类指令中,单操作数的NOT指令中操作数不能为立即数;其他4种双操作数逻辑运算指令中,源操作数可以是8位或者16位的立即数、寄存器或存储器,目的操作数只能是寄存器或存储器,但两个操作数不能同时为存储器。它们对标志位的影响情况如下:NOT不影响标志位,其他4种指令将使CF=OF=0,AF无定义,而SF、ZF和PF则根据运算结果而定。

移位循环指令

移位或循环指令的目的操作数可以是通用寄存器或存储器,可以是字节也可以是字;源操作数给出移位的次数,只能是1或者是CL寄存器中的数值。也就是说,如果移位次数不是1次,就要先将移位次数送入CL,然后再执行源操作数为CL的移位指令。CL的值为0,则不移位。以CL为源操作数的移位指令执行以后,CL的值不变。

移位指令执行后,标志位CF、SF、ZF和PF随运算结果变化。而OF的变化如下:当移位次数为1时,若移位前后目的操作数的最高位不同,则CF←1,否则CF←0;当移位次数大于1时,OF是不确定的。

循环指令执行后,标志位CF随运算结果变化,SF、ZF、AF和PF不受影响,OF的变化同移位指令。

(1)逻辑右移指令SHR。

格式:SHR 操作数,移位次数

功能:将操作数中的8位或16位二进制数向右移动1位或者CL位,最右边位(即最低位)或者最后移出位移至CF标志位,最左边的1位(即最高位)或CL位依次补0,如图2.24(a)所示。

例如:

若AL=11000011,则逻辑右移指令

SHR    AL,1 执行后,AL=01100001,CF=1。

又如:

若AL=11000011,且CL=3,则逻辑右移指令

SHR    AL,CL 执行后,AL=00011000,CF=0。

(2)算术右移指令SAR。

格式:SAR 操作数,移位次数

功能:将操作数中的8位或16位二进制数向右移动1位或者CL位,最右边位(即最低位)或者最后移出位修改CF标志,最左边位(即最高位)既向右移动又保持不变,如图2.24(b)所示。

例如:

若AL=11000011,则算术右移指令

SAR    AL,1 执行后,AL=11100001,CF=1。

又如:

若AL=11000011,且CL=3,则算术右移指令

SAR  AL,CL 执行后,AL=11111000,CF=0。

另外,算术右移指令执行后,将保持目的操作数的符号位不变。例如:

MOV  CH,80H
MOV  CL,4
SAR  CH,CL 这3条指令执行后,CH=0F8H,CL=4,补码数0F8H的真值是-8。移位前CH=80H,补码数80H的真值是-128,而-128/16=-8。可见,算术右移4次的作用是将补码数除以16。

(3)算术/逻辑左移指令SAL/SHL。

格式:SAL/SHL 操作数,移位次数

功能:将操作数中的8位或16位二进制数向左移动1位或者CL位,最左边位(即最高位)或者最后移出位修改CF标志位,最右边的1位(即最低位)或CL位移入0,如图2.24(c)所示。

例如:

若AL=11000011,则逻辑左移指令

SHL  AL,1 执行后,AL=10000110,CF=1。

又如:

若AL=11000011,且CL=3,则逻辑左移指令

SHL  AL,CL 执行后,AL=00011000,CF=0。

(4)循环左移指令ROL。

格式:ROL 操作数,移位次数

功能:将操作数中的8位或16位二进制数向左移动1位或者CL位,左边移出位既修改CF标志又移入右边的空出位,最后移出位移至最右边位(即最低位),同时保留在CF标志中,如图2.25(a)所示。

例如:

若AL=11000011,且CL=5,则循环左移指令

ROL  AL,CL 执行后,AL=01111000,CF=0。

(5)循环右移指令ROR。

格式:ROR 操作数,移位次数

功能:将操作数中的8位或16位二进制数向右移动1位或者CL位,右边移出位既修改CF标志又移入左边的空出位,最后移出位移至最左边位(即最高位),同时保留在CF标志中,如图2.25(b)所示。

例如:

若AL=11000011,则循环右移指令

ROR  AL,1 执行后,AL=11100001,CF=1。

(6)带进位循环左移指令RCL。

格式:RCL 操作数,移位次数

功能:与ROL指令类似,但是将操作数及CF标志位中的9位或17位二进制数一同向左移动1位或者CL位,如图2.25(c)所示。

例如:

若A=11000011,CF=1,则指令

RCL  AL,1 执行后,AL=10000111,CF=1。

(7)带进位循环右移指令RCR。

格式:RCR 操作数,移位次数

功能:与ROR指令类似,但是将操作数及CF标志中的9位或17位二进制数一同向右移动1位或者CL位,如图2.25(d)所示。

图2.25 循环移位指令示意图 (a)ROL指令;(b)ROR指令;(c)RCL指令;(d)RCR指令

例如:

若AL=11000011,CF=1,CL=4,则指令

RCR  AL,CL 执行后,AL=01111100,CF=0。

2.3.6 串操作指令 1.串操作

串操作指令用来实现内存区域中数据串的操作,这些数据串可以是字节类型的字节串,也可以是字类型的字串。串操作指令共有5种。

注意:

①各指令所使用的默认寄存器是SI(源串地址)、DI(目的串地址)、CX(串长度)和AL(存取或搜索的默认值)。

②源串在数据段,目的串在附加段。

③方向标志与地址指针的修改规则为:若标志位DF=1,修改地址指针时用减法;若DF=0,修改地址指针时用加法。另外,MOVS、STOS、LODS指令不影响标志位。

④串操作指令针对字节串操作时,指令助记符后加字母B;针对字串操作时,指令助记符后加字母W,如MOVSB、MOVSW等。

(1)串传送指令MOVS。

格式:MOVS

功能:即把数据段中由SI间接寻址的一个字节(或字)数据传送到附加段中由DI间接寻址的一个字节(或字)单元中;然后根据方向标志DF及所传送数据的类型(字节或字)的不同,对SI及DI进行±1(字节型)或±2(字型)的修改,即修改地址指针。另外,该指令在重复前缀REP的控制下,可以将数据段中的整串数据传送到附加段中。

【例2.21】  在数据段中有一字符串,其长度为17B,要求把它们传送到附加段中的一个缓冲区中,其中源串存放在数据段中从符号地址MESS1开始的存储区域内,每个字符占一个字节;MESS2为附加段中用来存放字符串区域的首地址。实现上述功能的程序段如下:

LEA  SI,MESS1      ;置源串偏移地址
LEA  DI,MESS2      ;置目的串偏移地址
MOV  CX,17         ;置串长度
CLD                 ;方向标志复位(DF=0)
REP  MOVSB          ;字符串传送 (2)串比较指令CMPS。

格式:CMPS

功能:即把数据段中由SI间接寻址的一个字节(或字)数据与附加段中由DI间接寻址的一个字节(或字)数据进行比较,使比较的结果影响标志位;然后根据方向标志DF及所进行比较的操作数的类型(字节或字)对SI及DI进行±1(字节型)或±2(字型)的修改,即修改地址指针。另外,该指令在重复前缀REPE/REPZ或者REPNE/REPNZ的控制下,可以在两个数据串中寻找第一个不相等的字节(或字),或者第一个相等的字节(或字)。

(3)串扫描指令SCAS。

格式:SCAS

功能:即使用由指令指定的关键字节或关键字(存放在AL或AX中),与附加段中由DI间接寻址的一个字节(或字)数据进行比较,使比较的结果影响标志位;然后根据方向标志DF及所进行操作的数据类型(字节或字)的不同,对DI进行±1(字节)或±2(字)的修改,即修改地址指针。另外,该指令在重复前缀REPE/REPZ或REPNE/REPNZ的控制下,可在指定的数据串中搜索第一个与关键字节(或字)匹配的字节(或字),或者搜索第一个与关键字节(或字)不匹配的字节(或字)。

【例2.22】  在附加段中有一个字符串,存放在以符号地址MESS2开始的区域中,长度为17,要求在该字符串中搜索空格符(其ASCII码为20H)。实现上述功能的程序段如下:

LEA  DI,MESS2      ;装入目的串偏移地址
MOV  AL,20H        ;装入关键字节(空格的ASCII码)
MOV  CX,17         ;装入字符串长度
REPNE  SCASB        ;在字符串中重复搜索,直至找到或搜完 上述程序段执行后,DI的内容即为相匹配字符的下一个字符的地址,CX的内容是剩下还未比较的字符个数。若字符串中没有所要搜索的关键字节(或字),则当查完之后(CX=0),退出重复操作状态。

(4)串存储指令STOS。

格式:STOS

功能:即把指令中指定的一个字节或一个字(分别存放在AL及AX寄存器中),传送到附加段中由DI间接寻址的字节或字单元中,然后根据方向标志DF及所进行操作的数据类型(字节或字)对DI进行修改。在重复前缀的控制下,可连续将AL或AX的内容存入附加段中的一段内存区域中。该指令不影响标志位。

【例2.23】  要对附加段中从MESS2开始的5个连续的内存字节单元进行清零操作,可用下列程序段实现:

LEA  DI,MESS2      ;装入目的区域偏移地址
MOV  AL,00H        ;为清零操作做准备
MOV  CX,5          ;设置区域长度
REP  STOSB          ;重复置0共5次 (5)串装入指令LODS。

格式:LODS

功能:该指令与串存储指令的功能相反,实现从数据段中由SI间接寻址的字节串(或字串)中读出数据传送到AL(或AX)中的操作。

2.重复前缀

串操作指令可以与重复前缀配合使用,从而使得串操作得以重复执行,并在条件不满足时停止执行。重复前缀的几种形式和功能如表2.12所列。

表2.12 串操作指令与重复前缀

串操作指令 可添加的重复前缀 重复条件 MOVS或STOS REP 当CX≠0时,重复,然后CX=CX-1 CMPS或SCAS REPE/REPZ REPNE/REPNZ 当CX≠0且ZF=1时,重复,然后CX=CX-1; 当CX≠0且ZF=0时,重复,然后CX=CX-1 LODS 无 2.3.7 程序控制转移指令 转移类指令可以改变代码段寄存器CS与指令指针IP的值或仅改变IP的值,从而可以改变指令执行的顺序,以满足程序跳转、调用或中断等需要。

1.无条件转移、调用和返回指令

1)无条件转移指令JMP

格式:JMP 目的地址

功能:转移到目的地址所指示的指令去执行。

该指令分段内转移和段间转移两类。段内转移和段间转移又各分为直接转移和间接转移两种。其中,直接转移的目的地址以立即数或标号的形式给出,而间接转移的目的地址可由寄存器或存储器给出。

(1)段内转移。

JMP  short  label        ;段内直接近转移。IP=IP+8位位移量,目的地址label与
                         ;JMP指令所处地址的距离在-128~127范围内
JMP  (near ptr)  label ;段内直接近转移。IP=IP+16位位移量,near ptr可省略,
                         ;目的地址label与JMP指令处于同一段内
JMP  reg16/mem16         ;段内间接转移。IP=reg16/mem16(由操作数的寻址方式确定) (2)段间转移。

JMP  far ptrlabel     ;段间直接远转移。IP=label偏移地址,CS=label段地址
JMP  mem32            ;段间间接转移。
                      ;IP←[EA]=mem32低字内容,CS←[EA+2]=mem32高字内容 段间转移是远转移,目的地址与JMP指令所在地址不在同一段内。执行该指令时要修改CS和IP的内容。式中,label为标号,reg16/mem16为16位寄存器或存储器。

【例2.24】  无条件转移指令举例。

JMP  START               ;IP=IP+16位位移量,目的地址START
JMP  BX                  ;IP=BX
JMP  WORD  PTR[BX]     ;IP=DS:[BX]
JMP  DWORD PTR[BX+SI] ;IP=DS:[BX+SI],CS=DS:[BX+SI+2] 2)过程(子程序)调用和返回指令

格式:CALL…    ;调用指令

RET…或者RETF…   ;返回指令

功能:调用指令CALL用来调用一个过程或子程序。返回指令RET用于从过程或子程序中返回到原调用处。

由于过程或子程序有段内(即近NEAR)和段间(即远FAR)调用之分,所以CALL也有NEAR和FAR之分。相应的返回指令RET也分段内与段间返回两种。

调用指令先将断点地址压入堆栈,再转入调用地址。其具体格式及相应功能如下。

(1)段内调用。

CALL  (near  ptr)  label  ;段内直接调用,label为近标号;near ptr可省略
                            ;SP←SP-2,[SP]←IP(压断点地址)
                            ;IP=IP+16位位移量(取目的地址)
CALL  reg16/mem16        ;段内间接调用,regl6/mem16为16位寄存器或存储器
                         ;SP←SP-2,[SP]←IP
                         ;IP← reg16/mem16(由操作数的寻址方式确定) (2)段间调用。

CALL  far ptr label      ;段间直接调用,label为远标号
                         ;SP←SP-2,[SP]←CS,SP←SP-2,[SP]←IP
                         ;IP←label的偏移地址,CS←label的段地址
CALL  mem32              ;段间间接调用,mem32为4B存储器
                         ;SP←SP-2,[SP]←CS,SP←SP-2,[SP]←IP
                         ;IP←[EA]=mem32低字内容,CS←[EA+2]高字内容 返回指令包括以下两种情况。

第一种,段内返回指令:

RET                ;IP←[SP],SP←SP+2
RET  exp           ;IP←[SP],SP←SP+2,SP←SP+exp 其中exp是能计算出数值的表达式,当RET正常返回后,再做SP=SP+exp操作。

第二种,段间返回指令:

RETF               ;IP←[SP],SP←SP+2,CS←[SP],SP←SP+2
RETF  exp          ;IP←[SP],SP←SP+2,CS←[SP],SP←SP+2,SP←SP+exp 需要说明的是,用户在书写源程序时,返回指令只需用RET即可,汇编程序会根据被调用子程序的类型属性,自动将返回指令汇编为RET或RETF。

2.条件转移指令

8086提供了多条不同的条件转移指令,它们根据标志寄存器中各标志位的状态,决定程序是否进行转移。条件转移指令的目的地址必须在现行的代码段(CS)内,并且以当前指令指针IP的内容为基准,其位移必须在-128~127的范围内。

条件转移指令是根据两个数的比较结果或某些标志位的状态来决定转移的。在条件转移指令中,有的根据对符号数进行比较和测试的结果实现转移。这些指令通常对溢出标志位OF和符号标志位SF进行测试。对无符号数而言,这类指令通常测试标志位CF。对于带符号数分大于、等于、小于3种情况;对于无符号数分高于、等于、低于3种情况。在使用这些条件转移指令时,一定要注意被比较数的具体情况及比较后所能出现的预期结果。

条件转移指令的格式及功能如下。

格式:JCC label

功能:若条件CC为“真”,则转移到label执行;若条件CC为“假”,则顺序执行下条指令。条件转移指令不影响标志位。

式中CC是转移条件,通常由状态标志值或其组合构成。label是转移的目的地址,为短程标号,在机器码中为补码形式的8位位移量。

JC——CF标志为1,则转移。

JNC——CF标志为0,则转移。

JE/JZ——ZF标志为1,则转移。

JNE/JNZ——ZF标志为0,则转移。

JS——SF标志为1,则转移。

JNS——SF标志为0,则转移。

JO——OF标志为1,则转移。

JNO——OF标志为0,则转移。

JP/JPE——PF标志为1,则转移。

JNP/JPO——PF标志为0,则转移。

JA/JNBE——高于/不低于等于转移,CF∨ZF=0。

JNA/JBE——不高于/低于等于转移,CF∨ZF=1。

JB/JNAE——低于/不高于等于转移,CF=1。

JNB/JAE——不低于/高于等于转移,CF=0。

JG/JNLE——大于/不小于等于转移,(SF∨OF)∨ZF=0。

JGE/JNL——大于/不小于等于转移,(SF∨OF)=0。

JL/JNGE——小于/不大于等于转移,(SF∨OF)=1。

JLE/JNG——小于/不大于等于转移,(SF∨OF)∨ZF=1。

3.循环控制指令

对于需要重复进行的操作,微机系统可用循环程序结构来完成,8086系统为了简化程序设计,设置了一组循环控制指令,这组指令主要对CX或标志位ZF进行测试,确定是否循环,指令均不影响任何标志位。

循环控制指令的格式及功能如下。

(1)JCXZ指令。

格式:JCXZ label

功能:若CX=0,转到label处;否则下行(即顺序执行下一条指令)。

(2)LOOP指令。

格式:LOOP label

功能:CX←CX-1,若CX=0,转到label处;否则下行。

(3)LOOPZ指令。

格式:LOOPZ label

功能:CX←CX-1,若CX=0且ZF=1,转到label处;否则下行。

(4)LOOPNZ指令。

格式:LOOPNZ label

功能:若CX=0且ZF=0,转到label处;否则下行。

其中,操作数label是转移或循环的目的地址,为短程标号,在机器码中为8位补码位移量。

【例2.25】  要求在数据段中TAB开始的100个字节数中查找数据“34H”(假定该数据存在),并将其所在单元的偏移地址存入BX寄存器。可用以下程序片段实现:

MOV  AL,34H
MOV  CX,100
LEA  BX,TAB-1      ;BX=OFFSET TAB-1
L1:INC  BX         ;BX=BX+1,地址调整
CMP  AL,[BX]     ;AL-[BX],比较置标志
LOOPNZ  L1          ;未找到则重复,循环控制 4.中断调用与返回指令

8086系列CPU还提供了功能强大的中断操作,可通过中断调用和返回指令来实现。中断调用指令用于使CPU中断当前程序,转去执行中断处理程序或调用中断服务子程序。中断返回指令使CPU从中断服务程序中返回到原中断处。

中断调用指令先将标志寄存器和断点地址压入堆栈后,再转入中断服务程序入口地址。中断返回指令由堆栈弹出断点地址和标志值,进而返回原中断地址处。

中断调用及返回指令的格式及功能说明如下。

(1)中断调用指令。

INT n    ;SP←SP-2,[SP]←FR,TF清零、IF清零(存标志内容)
              ;SP←SP-2,[SP]←CS,SP←SP-2,[SP]←IP(存断点地址)
              ;IP<[4×n],CS←[4×n+2](取入口地址)
INTO          ;若溢出标志OF=1,执行INT 4;若OF=0,顺序执行下条指令 其中,n 为8位立即数(取值00H~FFH),用于表示中断类型号(共256个)。FR为标志寄存器。4×n 表示4n 所指地址的存储单元。除TF、IF外,中断指令不影响其他标志位。

(2)中断返回指令。

IRET        ;IP←[SP],SP←SP+2,CS←[SP],SP←SP+2,FR←[SP],SP←SP+2 2.3.8 处理器控制指令 1.标志处理指令

标志处理指令用于修改标志寄存器FR中标志位的状态,主要有CF、DF和IF等3个,其常用指令及功能如表2.13所列。

表2.13 常用标志处理指令

指令助记符 功能 指令名称 STC CF←1 进位标志置1 CLC CF←0 进位标志置0 CMC CF←CF 进位标志取反 STD DF←1 方向标志置1(地址减量) CLD DF←0 方向标志置0(地址增量) STI IF←1 中断允许标志置1(开中断) CLI IF←0 中断允许标志置0(关中断) 2.CPU控制类指令

CPU(处理器)控制类指令用于控制微处理器的工作状态,均不影响标志位,下面仅列出一些常用的处理器控制指令。

(1)ESC指令。

格式:ESC 外操作码,操作数

功能:该指令为交权指令。主要用于在多处理器系统中使主CPU与外部处理器(如协处理器8087)配合工作。ESC指令使外部处理器能从8086 CPU指令流中取得它们的操作指令(6位外部操作码),并获得8086 CPU从内存中取出放在总线上的操作数进行操作处理。该指令不影响标志位。式中,外操作码为6位立即数;操作数可以是寄存器或存储器。若操作数为寄存器,ESC指令不进行操作。该指令不用修改处理器就可以扩充86系列CPU的指令集。

(2)等待指令WAIT。

格式:WAIT

功能:使CPU处于空操作状态。但每隔5个时钟周期CPU要检测一次TEST 引脚信号。若其为高电平,则CPU仍处于等待状态;若为低电平,则CPU退出等待状态,顺序执行下一条指令。该指令不影响标志位。该指令主要用于CPU与协处理器或外设之间的同步,也可用来等待外部中断发生,但中断结束后仍返回WAIT指令继续等待。

(3)总线封锁指令LOCK。

格式:LOCK…

功能:LOCK指令是一种前缀,可加在任何一条指令的前面。该指令执行时,将封锁总线的控制权,禁止其他的处理器使用总线,直到该指令执行完毕为止。该指令不影响标志,常用于多机系统。当CPU与其他处理器协同工作时,该指令可避免破坏有用信息。

3.其他

(1)暂停指令HLT。

格式:HLT

功能:该指令使CPU处于暂停状态。只有下面3种情况之一出现时,CPU才退出暂停状态:RESET线上有复位信号;NMI线上有中断请求;INTR线上有中断请求,且中断标志位IF=1。该指令常用于等待外部中断的发生。中断结束后可继续执行下面的程序。

(2)空操作指令NOP。

格式:NOP

功能:该指令不执行任何操作,也不影响标志位,只占有CPU的3个时钟周期。其机器码占一个字节,在调试程序时往往用这条指令占据一定的存储单元,以便在正式运行时用其他指令取代。

Search

    微信好友

    博士的沙漏

    Table of Contents