您好,欢迎来电子发烧友网! ,新用户?[免费注册]

当前位置:电子发烧友网 > 图书频道 > 电子 > 《微计算机原理》 > 第3章 8086指令系统

第2节 8086指令系统

 

§3.3.0 8086指令系统

  本节概述

  指令是计算机所能识别和执行的指示和命令,指令在计算机上执行时,控制器根据指令的要求,控制计算机的各部件协调工作。

  目标程序不能被操作系统装入和执行,为了让操作系统装入和执行,必须把目标程序连接为操作系统下的可执行文件,连接过程一般使用连接程序Link.EXE来完成。

  教学目标

  熟练掌握8086指令系统中的各种数据操作指令,并能编写自己的程序。

  学习内容

  概述

  数据传送指令

  算术运算指令

  逻辑运算、移位、循环指令

  控制转移指令

  串操作指令

  中断指令

  处理控制指令

  重点难点

  1、指令的运用

  2、程序的编写

  关键字

  指令

  参考资料

  1、《微型计算机技术及应用》,戴梅萼等编著,第二版,清华大学出版社

  2、《微型计算机原理》,季维法等编著,第一版,电子科技大学出版社

  3、《微型计算机原理—常见题型解析及模拟题》,武自芳主编,西北工业大学出版社

  4、《80X86/80X87汇编语言程序设计》,洪志全等编著,电子科技大学出版社

 

  §3.3.1 概述

  指令是计算机所能识别和执行的指示和命令,指令在计算机上执行时,控制器根据指令的要求,控制计算机的各部件协调工作。CPU能够直接执行的指令,也是用二进制编码表示的,称为机器指令,这种语言称为机器语言。机器语言不便于编程,在编程时,一般用助记符来代表机器指令,

  用助记符编写的程序,称为"汇编语言源程序",汇编语言源程序(文件扩展名ASM)需要翻译为机器指令表示的目标程序(文件扩展名OBJ),这一翻译过程称为"汇编",一般使用称为"汇编程序"的程序来进行翻译。典型的汇编程序如MicrosoftMASM 5.0。

  目标程序不能被操作系统装入和执行,为了让操作系统装入和执行,必须把目标程序连接为操作系统下的可执行文件,如DOS及Windows下的可执行文件扩展名为EXE或COM。连接过程一般使用连接程序Link.EXE来完成。

  汇编语言指令与机器指令间有一一对应关系,可以充分发挥CPU的性能,如图3-7。

  另外,使用高级语言编写的源程序,必须通过"编译"、"连接"形成可执行文件,如图3-8。

  能够直接执行的机器指令,用二进制编码表示。在Intel 系列CISC(复杂指令集计算机)CPU中,机器指令的长度为1~6字节。

  OP:操作码字段,6位,规定该指令的操作性质,如图3-9。

  D: 方向位。D=0, REG为源操作数; D=1,REG为目的操作数。

  W: 操作数大小. W=0, 操作数为字节; W=1, 操作数为字。

  REG: 寄存器编码如下表:

  MOD: 方式字段

  MOD=11, 寄存器方式, 两个操作数均在寄存器中,第一个寄存器由REG字段给出, 第二寄存器由R/M字段给出,R/M的编码与REG同.

  MOD=00、01、10:存储器方式,有一个操作数在存储器中,存储器的有效地址由R/M字段给出:(D8=8位常数,D16=16位常数)如下表所示。

  §3.3.2 数据传送指令

  传送指令执行寄存器、存储器、I/O接口电路、堆栈、地址的传送。有效的传送路径及方向如图3-10。

  1、 通用型传送指令

  (1) MOV

  一般格式: "MOV dst,src"

  dst=目标(destination),src=源(source)

  传送(move)的实质是复制(copy),即传送后,src中的值不变,。

  注意:① 上图中未标明的路径均是非法的。

  ② 不能给CS或IP赋值。

  ③ 常数不能直接赋给段寄存器。

  (2) 堆栈操作

  堆栈(STACK)是一段连续的内存,用于暂存数据,例如,可以把寄存器中的值暂存在堆栈中,需要时再取回到寄存器;在子程序和中断处理程序中,通常需要把寄存器中的值暂存在堆栈中。在子程序调用和中断发生时,返回的断点地址也保存在堆栈中。 堆栈段的基地址保存在SS寄存器中,堆栈的大小等于SP的初值。堆栈操作过程中,SP指向数据所在单元(称为"栈顶")。

  堆栈操作有两条指令,PUSH和POP。

  PUSH:把寄存器或存储器中的16位数值存入堆栈,。

  把数据存入堆栈称为"推入"或"入栈"。向堆栈中存入数据 时,SP的值减少,称堆栈具有"下推式"的特点。

  POP:把堆栈中SP处的16位数取至寄存器或内存中。

  把数据从堆栈中取出称为"弹出"或"出栈"。

  堆栈操作指令PUSH/POP只能进行16位数(字)操作,且遵从"先进后出"原则,操作过程如图3-11所示。

  使用堆栈还应注意"溢出"问题。

  (3) 交换指令XCHG

  把两个操作数的值相交换(Exchange)。

  (4) 翻译指令XLAT

  格式:XLAT 原始表

  或:XLAT ;形式上无操作数

  功能:查找一个字节表格中某一项的值。表格的名字(表示表格的起始地址)放在BX寄存器中,所查找项相对于表格起始地

  址的偏移量放在AL中;该指令执行后,AL等于所查找项的值。

  注意,即使使用"XLAT tab"格式,也必须把tab的偏移量放在BX中。

  2、 输入输出型传送指令

  CPU与外部设备之间必须通过"I/O接口电路"连接。8086的I/O接口电路,其主要作用是完成CPU与外部设备间的信息传送。CPU把信息直接送给外部设备对应的I/O接口电路,由I/O接口电路负责把信息送给外部设备。或者,外部设备把信息送入对应的I/O接口电路,CPU从I/O接口电路中读取信息。

  从编程的角度看,I/O接口电路由一些"端口"(PORT)构成,CPU把信息直接送给外部设备对应的端口,由端口负责把信息送给外部设备。或者,外部设备把信息送入对应的端口,CPU从端口中读取信息。

  8086CPU采用"端口寻址方式",即端口地址与存储器地址单独编号,使用专用的输入输出指令,在端口与AL或AX寄存器之间传送信息。端口地址范围是0000~FFFFH,每个端口可以存放8位二进制数,称为"8位端口"。

  输入输出指令有两个:IN(输入)、OUT(输出)。

  IN指令:把端口的值输入到AL或AX寄存器中。

  OUT指令:AL或AX寄存器中的值输出到端口。

  IN/OUT指令有两种用法:

  用法一:端口地址以常数给出,适用于端口地址00~FFH。

  用法二:端口地址放在DX寄存器中,适用于端口地址0000~FFFFH。

  3、 地址传送型指令

  这类指令用于处理存储器地址。如果一个存储单元的值是另一个存储单元的地址,该存储单元被称为"指针"(Pointer)。

  存储单元P的地址是1000H,存储单元X的地址是2000H,P中的值等于X的地址2000H,称为P指向X,或者说P是X的指针如图3-12所示。指针P仅包含X的地址偏移量(2字节),是一个"近指针"(Near型指针)。

  指针FP包含Y的段地址和偏移量(4字节),是一个"远指针"(Far型指针)。其中偏移量放在前2字节,段地址放在后2字节如图3-13所示。

  (1)LEA指令(装入有效地址,Load Effective Addres)

  LEA把内存数据的有效地址(地址偏移量,16位)送到一个16位通用寄存器。

  (2) LDS指令(装入有效地址和DS寄存器)

  LDS 把内存数据的段地址送DS,偏移量送另一个16位通用寄存器。

  (3)LES指令(装入有效地址和ES寄存器)

  LES 把内存数据的段地址送ES, 偏移量送另一个16位通用寄存器。

  4、 标志传送型指令

  标志传送指令用于读出标志寄存器(FLAG 或称PSW)的内容,或设置标志寄存器新的值,如图3-14所示。

  (1)LAHF (Load AH with Flag) 将标志寄存器的值装入AH(读出标志寄存器的值)。

  (2)SAHF (Save AH into Flag) 将AH的值装入标志寄存器(设置新的标志)。

  (3)PUSHF,POPF PUSHF:

  ① SP减2

  ② 将FLAG的值存入堆栈中SP处,FLAG中的值保 持不变

  POPF: ① 从堆栈中SP处取出一字送到FLAG

  ② SP加2

  §3.3.3 算术运算指令

  8086提供了加、减、乘、除四种基本算术运算,这些运算都可对字节或字进行运算,既可以对无符号数运算,也可对有符号数运算。无符号数和有符号数的加、减法运算使用相同的指令。乘、除运算中,无符号数和有符号数运算使用不同的指令。

  1、 加法

  (1) 加法的一般格式

  ADD dst,src

  功能:dst ←dst+src,源操作数与目的操作数相加,和放在目的操作数中。

  (2) 带进位的加法

  ADC dst,src

  功能:dst←dst+src+CF,源操作数与目的操作数相加,并考虑上一次加法的进位,和放在目的操作数中。

  (3) 加1指令   INC dst   功能:dst ←dst+1

  2、 减法

  (1) 减法的一般格式   SUB dst,src  功能:dst ←dst-src

  (2) 带进位的减法    SBB dst,src

  功能:dst←dst-src-CF,考虑上一次减法的借位。(上一次减法 的借位在CF中)

  (3) 减1指令    DEC dst   功能:dst←dst - 1

  (4) 求补指令   NEG dst   功能:dst ←0-dst

  (5) 比较指令

  CMP dst,src

  功能:比较dst和src的大小,比较的结果放在标志位中。

  该指令采用"dst-src"的算法实现比较,但相减后的差不送给dst。  条件转移指令(如JG,大于时转移;JNZ,当ZF=0时转移

  可以直接利用比较指令的比较结果。(条件转移指令后述)

  3、 乘法

  无符号数的乘法(MULtiplication)用MUL指令, 有符号数的乘法用IMUL指令(有符号数又称整数INTEGER)。 8086CPU可执行两个8位数相乘,或两个16位数相乘,如图3-15所示。

  指令格式为:

  MUL 操作数

  IMUL 操作数

  指令形式上只给出一个操作数(被乘数),但乘数和积是固定存放的。

  如:无符号数的乘法

  MUL BL ;AL × BL → AX

  MUL CX ;AX × CX → DX AX (DX为高16位)

  有符号数的乘

  IMUL BYTE PTR [DI] ; AL乘内存中的一字节值 ,

  ; 该内存的地址由DI的值指出。积存放在AX中。

  IMUL WORD PTR [DI] ;AX乘内存中的一个字, ;该字的地;址由DI的值指出。积存放在DX和AX中。

  注意:(1) 乘法指令的形式操作数不能为立即数;

  (2) MUL∕IMUL指令执行后,设置CF和OF标志,但AF,PF,SF,ZF的值不确定,这四个标志无意义。

  MUL指令:积的高一半为零,则CF=OF=0,否则,CF=OF=1。

  IMUL指令:积的高一半是低一半的符号扩展,则CF=OF=0, 否则,CF=OF=1。

  4、 除法

  无符号数的除法(DIVision)用DIV指令,

  有符号数的除法用IDIV指令 8086CPU可执行16位/8位,或32位/16位,如图3-16所示。

  指令格式为:

  DIV 操作数

  IDIV 操作数

  指令形式上只给出一个操作数(除数),但被除数、商和余数是固定存放的。

  注意:

  (1) DIV∕IDIV指令执行后,所有状态标志(CF,OF,AF,PF,SF,ZF)的值不确定,都无意义。

  (2) DIV∕IDIV指令执行后,如果商超出了范围(除数很小,极限为0),即除法溢出(或称商溢出),不使溢出标志置1。此时,CPU产生"0号中断"(除数为零中断)。

  (3) 有符号数除法,可能产生两种正确结果:如

  (-30)/(+8)= -4 余 +2 (余数的符号与被除数不同)

  (-30)/(+8)= -3 余 -6 (余数的符号与被除数相同)

  IDIV指令取第二种结果。

  数的扩展

  (1)概念

  数的扩展是指增加数的位数。如,把8位数扩展为16位数,或把16位数扩展为32位数,扩展后的数在数值上与原数相等。

  (2)必要性

  在乘法前,如果参与运算的乘数和被乘数不满足"8位×8位"或不满足"16位×16位",则需将其中一个数扩展。如:参与乘法的两个数为"8位×16位",应将其中的"8位"数扩展为"16位"数,变成"16位×16位"运算。

  在除法前,如果参与运算的除数和被除数不满足"16位/8位"或不满足"32位/16位",则需将被除数扩展。

  如果 原除法为"8位/8位",应将被除数扩展为16位,变成"16位/8位"运算。

  如果 原除法为"16位/16位",应将被除数扩展为32位,变成"32位/16位"运算。

  (3)扩展方法

  无符号数的扩展:

  8位→16位,只需把高8位清零。如把AH清零,使AL(8位)扩展为AX(16位)。

  16位→32位,只需把高16位清零。如把DX清零,使AX(16位)扩展为DXAX(32位)。

  有符号数的扩展:

  使用扩展指令。

  CBW指令(Convert Byte to Word):把AL(Byte,8位)扩展为AX(Word,16位)。

  CWD指令(Convert Word to Double Word):把AX(Word,16位)扩展为DXAX(Double Word,32位)。

  有符号数的扩展采用"符号扩展"方法,如: 0111 1111B (符号位为0)→0000 0000 0111 1111B (扩展部分全为0) 1000 1111B (符号位为1)→1111 1111 1000 1111B (扩展部分全为1)

  5、 十进制数的运算

  (1)BCD码的概念

  在计算机中,十进制数用二进制编码表示,称为BCD码(Binary Coded Decimal),又称"二--十进制码"。十进制有0~9 十个数码,可用四位二进制码来表示,如:  

有两种BCD码:组合BCD码和非组合BCD码.

  组合的BCD码:用一字节(8位)表示两位BCD码。因此,一字节能表示的组合BCD码范围是0~99。组合的BCD码又称"压缩的BCD码"(packed BCD format)或"组合十进制数"。

  如:一字节0101 0110B (56H)表示组合BCD码56。

  非组合的BCD码:用一字节(8位)的低4位表示一位BCD码,高4位为0。因此,一字节能表示的非组合BCD码范围是0~9。非组合的BCD码又称"非压缩的BCD码"(unpacked BCD format)或"分离十进制数"、"非压缩十进制数"。

  如:一字节0000 0111B (07H)表示非组合BCD码7。 非组合的BCD码 类似于 数字0~9的ASCII码。非组合的BCD码高4位为0000B,ASCII码的高4位为0011B。

  如: 数字7

  非组合的BCD码=00000111B

  ASCII=00110111B

  数字7 BCD码运算的优点:当数据含有小数时,用BCD码运算不会引入截断误差,而用二进制运算会引入截断误差。如12.34的二进制表达: 1100.0101 0111 0000 101…,用有限位数表达,必然引入截断误差。

  由于BCD码运算不会引入截断误差,常用于会计软件。另外,在工业控制中,BCD码常用于表示拨号开关位置代表的数值。

  (2) BCD码的运算

  BCD码的运算方式:ADD,SUB,MUL,DIV等指令是用于运算二进制数的,不能直接用于运算BCD码。要对BCD码进行运算,可采用两种方式:

  ①设置一套专用于BCD码的指令

  ②利用二进制运算指令和十进制调整指令

  8086CPU采用第二种方式,即利用二进制指令和十进制调整指令。

  十进制调整指令:

  DAA:Decimal Adjust for Addition,加法的十进制调整指令。

  DAS:Decimal Adjust for Subtraction,减法的十进制调整指令。

  AAA:ASCII Adjust for Addition,加法的ASCII调整指令。

  AAS:ASCII Adjust for Subtraction,减法的ASCII调整指令。

  AAM:ASCII Adjust for Multiply,乘法的ASCII调整指令。

  AAD:ASCII Adjust for Division,除法的ASCII调整指令。

  这里,使用术语"十进制"(Decimal)表示 组合的BCD码,

  使用术语"ASCII"表示 非组合的BCD码。

  使用二进制运算指令对BCD码进行运算,必须同时使用十进制调整指令进行调整,因为:

  ① 4位二进制表示的范围是0~9,A,B,C,D,E,F, BCD码只允许0~9。

  ② 4位二进制运算逢十六进一,而BCD码逢十进一。

  (3)BCD码的加法

  对BCD码做加法运算,每次只能运算一字节(2位组合BCD码或1位非组合BCD码),首先,使用二进制运算指令ADD/ADC,并将结果存于AL中,然后,对AL的值进行调整(DAA或AAA)。

  DAA指令把AL中的值调整为组合BCD码,并存于AL中。

  AAA指令把AL中的值调整为非组合BCD码,并存于AX中(AH高位)。

  结论:用二进制指令运算BCD码时,必须同时使用调整指令,组合BCD码加法和非组合BCD码加法的调整方法是 "加6调整"。即:当4位二进制码超过9时,或有辅助进位(AF=1)时,调整指令DAA/AAA指令把二进制运算指令ADD/ADC的结果加6。

  (4)BCD码的减法

  对BCD码做减法运算,每次只能运算一字节(2位组合BCD码或1位非组合BCD码),首先,使用二进制运算指令SUB/SBB,并将结果存于AL中,然后,对AL的值进行调整(DAS或AAS)。

  DAS指令把AL中的值调整为组合BCD码,并存于AL中。

  AAS指令把AL中的值调整为非组合BCD码,并存于AX中(AH高位)。

  结论:用二进制指令运算BCD码时,必须同时使用调整指令,组合BCD码减法和非组合BCD码减法的调整方法是:"减6调整"。即:当4位二进制码超过9时,或有辅助进位(AF=1)时,调整指令DAS/AAS指令把二进制运算指令SUB/SBB的结果减6。

  (5)BCD码的乘法和除法

  (一)乘法

  只能对非组合的BCD码做乘法运算,且每次只能运算一字节(1位非组合BCD码),首先,使用二进制运算指令MUL按二进制运算,然后,使用AAM指令把结果调整为非组合BCD码。

  (二)除法

  只能进行2位非组合的BCD码(被除数,放在AX中)除以1位非组合的BCD码运算。首先,使用调整指令AAD把被除数调整为二进制。然后,使用二进制运算指令DIV按二进制相除,在AL中获得商的二进制形式,在AH中获得余数的二进制形式。最后,用AAM指令把商调整为非组合BCD码,存于AX中。