第3章 8086/8088 指令系 统 指令系统是微处理器的基本功能描述,是各种程序设计语言的基础。8086/8088 指令 系统是Intel80X86 系列微处理器的基本指令集,包括数据传送指令、算术运算指令、逻辑运 算指令和移位指令、控制转移指令和处理器控制指令。这些指令是汇编语言程序设计的 基础。 3.1 概述 程序是人操纵驾驭计算机的工具,程序设计语言是编制程序的工具。程序设计语言主 要分为机器语言、汇编语言和高级语言。这些语言的使用环境不同,操纵计算机的方法不 同,各有优缺点。 3.1 机器语言与汇编语言 1. 机器语言能被计算机硬件直接识别并执行,它由二进制代码组成。机器语言中的每一 条称为指令,计算机能够识别的所有指令的集合称为指令系统。指令是计算机能够执行的 最小功能单位,机器语言程序就是由一条条的指令按一定顺序组织起来的指令序列。计算 机的CPU 不同,指令系统也不同。Intel公司的80X86 系列CPU,因其硬件结构设计上的 包容性,指令系统具有兼容性,用8088/8086CPU 的指令系统设计的程序可以在80X86 系 列的CPU 上执行。8088/8086CPU 的指令系统常被称为80X86 系列CPU 的基础指令。 本章以8086CPU 为主,介绍常用计算机指令的格式、寻址方式和用法。 一条指令一般由操作码和操作数两部分组成。操作码详细地说明指令要执行的操作, 操作数是指令执行时需要的数据。机器语言中操作码和操作数都是二进制代码,因而难于 记忆、书写和输入,即使对于计算机的设计者,也一样难于使用。因此,指令中的操作码和操 作数用便于记忆的符号代替,编程语言因而有了第一次发展,由机器语言进化到汇编语言。 符号化的操作码称为指令助记符,操作数称为操作数助记符。本章以汇编语言指令的形式, 介绍8086CPU 指令集中常用的指令格式、寻址方式和用法。 第3 章 8086/8088 指令系统 43 3.1.2 指令的基本构成 1.指令的一般格式 一条指令包含操作码和操作数两部分。任何指令都含有操作码,操作数可以有一个,也 可以有两个,还可以没有。只有一个操作数的指令常称为单操作数指令,有两个操作数的指 令常称为双操作数指令。形式上无操作数的指令,通常操作数是隐含的。操作数有源操作 数和目的操作数之分。 如图3-1所示,8086CPU 指令由1~7字节组成。操作码占1~2 字节,操作数占 2~5字节。操作码的长度取决于指令系统的规模大小。操作数的长度与指令的寻址方式 有关。 图3-1 指令的基本组成 2.操作数类型 8086/8088CPU 的算术运算单元只能处理整数,不能处理小数,因此本章中所有指令 的操作数都是整数,没有小数。8086CPU 指令的操作数有三种类型:立即数操作数、寄存 器操作数和存储器操作数。 . 立即数操作数又称为常数,可以是数值型常数,也可以是字符型常数。数值型常数 可以是字节或字类型的整数,可以无符号或有符号。立即数在指令中只能作为源操 作数,不能作为目的操作数。例如: MOV AX, 2023H ;2023H 是字类型的无符号整数,AX=2023H MOV AX,-1423H ;-1423H 是字类型的带符号整数,AX=EBDDH(补码) MOV AH,'A' ;'A'是字符型常数,将'A'的ASCII 值41H 赋给AH 寄存器 MOV AL, 6 ;6 是数值型操作数,默认为十进制,指令执行后AL=6 . 寄存器操作数,8086CPU 的8个16位的通用数据寄存器AX、BX、CX、DX、SP、BP、 SI、DI和4个段寄存器CS、DS、SS、ES可作为16位寄存器操作数,AH、BH、CH、 DH 和AL、BL、CL、DL可作为8位寄存器操作数。控制寄存器IP、Flags只在特定 指令中作为操作数。寄存器操作数在指令中可作为源操作数,也可作为目的操作 数,段寄存器CS除外,它只能作为源操作数。 . 存储器操作数,就是用内存单元中的数据作为操作数。存储器操作数既可以作为源 操作数,也可以作为目的操作数,但多数指令要求源和目的操作数不能同时为存储 器操作数。指令中的操作数如果是存储器操作数,指令中通常给出的是存储单元的 地址或用某种方式指明存储单元的地址,指令执行时CPU 根据这个地址从存储单 元中取出操作数,然后执行指令。存储器操作数的长度类型可以是1字节、2字节 (字)或者4字节(双字)。寄存器操作数和存储器操作数相对于立即数又称为变数。 44 微型计算机原理与接口技术(第2 版) 数据在内存中以“高高低低”的原则存放,低字节存于低地址内存中,高字节存于高地址 内存中。存储器操作数如果是多字节,指令中指明的存储单元地址通常是它的低地址,或称 为首地址。如寄存器AX中的内容为6E53H,将它存入20000H 中,结果如图3-2所示。 图3-2 数据存放 3.指令的书写格式 指令的书写格式如下: 标号:操作码助记符 目的操作数助记符,源操作数助记符;注释 例如:GOON: MOV AX,BX ;数据传送 . 标号是字母、数字组合的符号,代表指令,是指令的地址———用符号表示的地址。标 号后跟冒号“:”作为间隔符。不是每条指令都有标号,标号由程序员根据编程需要 设定。标号一般由字母开头的字母、数字组成,长度不超过31个字符。不允许使用 汇编语言中的保留字作标号。 . 操作码助记符与操作数助记符之间至少应有一个空格作为间隔符。如果指令有两 个操作数,操作数之间以逗号“,”作为间隔符。紧挨操作码助记符的操作数为目的 操作数,另一个为源操作数。 . 操作数助记符与注释之间用分号“;”作为间隔符。注释部分可有可无,可以跟在指 令的后面,也可以单独一行,若注释超过一行,则新行以分号“;”开头。简明扼要的 注释可以增加程序的可读性,汇编语言程序的可读性很差,应尽量多写注释。 . 指令中的标点符号应为ACSII字符。 3.2 寻址方式 8088/8086CPU 对内存采用分段管理,内存单元地址由段基址和段内偏移地址组成, 段基址和段内偏移地址称为内存单元的逻辑地址。指令中存储器操作数的内存单元地址一 般给出的是段内偏移地址,段基址以默认方式指明。段内偏移地址,在多数时候指令也不是 直接给出,而是给出一种计算偏移地址的公式或方法。这么做的原因一方面是编程需要,如 循环程序每次循环处理不同的数据,数据的地址就应该以某种规律变化;另一方面,与数据 在内存中的存放形式有关,如一维数组、二维数据等。当然,也与程序员的个人编程习惯有 关。实际上,寻址方式就是CPU 为方便编程而设置的存取存储器操作数的方式方法。 寻址方式,即获得地址的方法,主要指获得段内偏移地址的方法,段基址常采用默认方 第3 章 8086/8088 指令系统 45 式获得。指令的操作数有三种类型:立即数、寄存器操作数和存储器操作数。立即数作为 指令的一部分出现在指令中,随着CPU 取指令的动作进入CPU 内,不需要再寻址;寄存器 操作数本就在CPU 内部,寄存器的符号就是地址;所以,寻址方式主要解决的是存储器操 作数的段内偏移地址的获得方法。操作数的段基址由相应的段寄存器DS、ES或SS提供, 指令中以默认的方式表达。立即数、寄存器操作数,它们不需要寻址,但是,为了理论的统一 性,也给它们命名了寻址方式。下面分别介绍8086CPU 指令中操作数的寻址方式,共有 8种。 3.2.1 立即寻址 操作数是立即数,例如: MOV AL, 76 ;把十进制数76 传送给AL,字节(8 位)数据传送 MOV AX, 2000H ;把2000H 传送给AX,字(16 位)传送 MOV BX, 34H ;把0034H 传送给BX,字(16 位)传送 MOV SI, 0 ;把0000H 传送给SI,字(16 位)传送 MOV AH, 'A' ;把A 的ASCII 41H 传送给AH,字节传送 MOV AX, 'BA' ;把BA 的ASCII 传送给AX,AX=4241H,字传送 MOV CL, 10010010B ;把二进制数10010010 传送给CL,字节传送 ADD AL, 6 ;寄存器AL+6,结果回送到AL 中 立即数作为操作数,这个操作数的寻址方式称为立即寻址,其实它不用寻址。立即数操 作数只能作源操作数,不能作目的操作数。立即数可以以十进制形式书写,而且默认是十进 制,书写时不用加后缀。立即数如果是十六进制,则需要加后缀H,而且如果是字母开头的 十六进制数,汇编语言要求前面加0,如MOV BX,0FE60H 。立即数如果是二进制形式, 则后缀要加B。 3.2.2 直接寻址 直接寻址是存取存储器操作数的方法之一。数据段内存储单元中的数据作为操作数, 指令中直接给出操作数所在的内存单元的偏移地址。偏移地址可以是数值形式的地址,也 可以是用符号表示的地址,用符号表示的地址称为符号地址。例如,内存单元偏移地址 2000H 中存有数据55H,在指令中这个操作数的形式为[2000H],符号[]表示地址。例如: MOV BL, [2000H] ;将偏移地址为2000H 的存储单元中的数据传送给BL MOV BX, [3200H] ;将偏移地址3200H 的连续两个存储单元中的数据传送给BX MOV AL, BUFF ;将数据段中BUFF 单元存储的数据传送给AL MOV AX, STR ;将数据段中STR 和STR+1 单元存储的数据传送给AX MOV THERE, BX ;将BX 中的数据传送给以THERE 开始的连续两个单元中 操作数[2000H]的寻址方式为直接寻址,如果2000H 单元存储的数据为55H,MOV BL,[2000H]指令执行后BL=55H。 MOV BX, [3200H] 46 微型计算机原理与接口技术(第2 版) 指令中操作数[3200H]的寻址方式为直接寻址。将以偏移地址3200H 为首地址的连 图3-3 直接寻址 续两个内存单元的内容传送给BX 寄存器。如图3-3所示,3200H 单元存储的数据为F8H,传送给BL寄存器,3201H 单元存储的数据 为03H,传送给BH 寄存器。上面指令执行后BX=03F8H。 注意:BX为16位的寄存器,决定了这条指令为16位的数据传 送指令。 上面指令示例中的BUFF、STR、THERE都是存储单元的偏移 地址,也称为符号地址,它们应该在程序开始处予以定义,否则不能 使用。它们的寻址方式为直接寻址,可以书写为 MOV AL, [BUFF] ;将BUFF 存储单元中的数据传送给AL MOV AX, [STR] ;STR、STR+1 存储单元的数据分别传送给AL、AH MOV [THERE], BX ;BL、BH 中的数据分别传送给存储单元THERE、THERE+1 更常见的写法为 MOV AL, BUFF MOV AX, STR MOV THERE, BX 8088/8086CPU 对内存采用分段管理,汇编指令中存储器操作数的地址包括段基址和 段内偏移地址两部分。上面指令中的[2000H]、[3200H]、BUFF、STR、THERE,都是段内 偏移地址,它们的段基址由DS指明。通常情况下,存储器操作数默认在数据段,段基址在 DS。在特殊说明的情况下,存储器操作数的段基址也可以替换为CS、ES或SS。表3-1说 明了8088/8086CPU 系统中逻辑地址的来源。 表3-1 8088/8086CPU 系统中逻辑地址的来源 操作类型默 认 段可替换的段偏移地址 取指令CS 无IP 堆栈操作SS 无SP BP作基地址SS CS,DS,ES 由寻址方式决定 BX作基地址DS CS,ES,SS 由寻址方式决定 一般数据读/写DS CS,ES,SS 由寻址方式决定 串操作中的源串DS CS,ES,SS SI 串操作中的目的串ES 无DI CPU 执行指令时,在BIU 中按照段基址x10H+段内偏移地址的方法,计算产生20位 的物理地址并送到地址总线上,然后BIU 对选中的存储单元进行数据存取。例如: MOV BL, [2000H] 设DS=1200H,指令在执行过程中,首先BIU 在地址加法器中进行计算: 1200H×10H+2000H=14000H 第3 章 8086/8088 指令系统 47 然后从14000H 内存单元取出55H 传送给BL寄存器。 如果操作数的段基址不是DS段,指令要特别说明。例如,在ES段,指令应书写为 MOV BL, ES:[2000H] 这种用法称为段超越,“:”为段超越符,物理地址的计算方法为ES×10H+2000H。 3.2.3 寄存器寻址 操作数在CPU 内部的寄存器中,即寄存器操作数。8086/8088CPU 的8个16位的通 用数据寄存器AX、BX、CX、DX、SP、BP、SI、DI和4个段寄存器CS、DS、SS、ES可以作为16 位寄存器操作数,AH、BH、CH、DH 和AL、BL、CL、DL可以作为8位寄存器操作数。寄存 器操作数在指令中可以作为源操作数也可以作为目的操作数,通常源和目的操作数的长度 应该保持一致,可以都是字节类型,也可以都是字类型。下面示例中源和目的操作数的寻址 方式都是寄存器寻址。 MOV AL, BL ;把BL 的内容复制到AL 中,字节传送 MOV AH, BH ;把BH 的内容复制到AH 中,字节传送 MOV CH, CL ;把CL 的内容复制到CH 中,字节传送 MOV BH, AL ;把AL 的内容复制到BH 中,字节传送 MOV AX, BX ;把BX 的内容复制到AX 中,字传送 MOV DX, CX ;把CX 的内容复制到DX 中,字传送 MOV SP, BP ;把BP 的内容复制到SP 中,字传送 MOV SI, DI ;把DI 的内容复制到SI 中,字传送 MOV DI, AX ;把AX 的内容复制到DI 中,字传送 MOV BX, ES ;把ES 的内容复制到BX 中,字传送 ADD AX, BX ;AX+BX 结果保存在AX 中,16 位加法运算 3.2.4 寄存器间接寻址 寄存器间接寻址可以表示任何存储单元的数据。内存单元的偏移地址存放在寄存器 中,可以是SI、DI、SP、BX寄存器中的任何一个,但不能是其他寄存器。例如,如果偏移地址 为0100H 的内存单元中的数据作为操作数,而且这个地址已经存储在SI寄存器中(SI= 0100H),指令中我们可以使用[SI]形式表示这个操作数,[]表示这是地址。 MOV AL, [SI] ; 将[SI]表示的存储单元中的数据传送给AL 操作数[SI]的寻址方式为寄存器间接寻址。上述指令的功能为:SI的内容为内存单元 的偏移地址,DS为段基址(默认),指令执行时CPU 中的BIU 按照公式DS×10H+SI计算 出存储单元的物理地址并送到地址总线上。参照图3-4,如果DS=2000H,则DS×10H+ SI=2000H×10H+0100H=20100H,BIU 从物理地址为20100H 的内存单元中取出数据 53H 送给EU,EU 将53H 传送给AL,指令执行结束。 48 微型计算机原理与接口技术(第2 版) 图3.4 段中的数据 注意,[SI]表示存储区域的首地址。因此[SI]可以表示一个内存单元,也可以表示2个 连续的内存单元,甚至是4个连续的内存单元。这一点与直接寻址[1000H]的用法一致。 再如: MOV AX, [SI] ;将DS:[SI]指明的连续两个内存单元中的数据传送到AX MOV DX, [DI] ;将DS:[DI]指明的连续两个内存单元中的数据传送到DX MOV [BX], AX ;AX 的内容传送到DS:[BX]指明的连续两个内存单元中 MOV CX, [BP] ;将SS:[BP]指明的连续两个内存单元中的数据传送到CX 操作数[SI]、[DI]、[BX]、[BP]的寻址方式都是寄存器间接寻址。8086CPU 中能作为 寄存器间接寻址方式使用的寄存器只有4个:BX、BP、SI、DI。这4个寄存器作为间接寻址 使用时,要用[]申明,这时常称它们为地址指针寄存器或间址寄存器。BP作为间址寄存器 时,段基址默认为SS,其他3个的默认段基址为DS,但都可以段超越。例如: MOV DX, ES:[DI] ;将ES:[DI]指明的连续两个内存单元中的数据传送到DX 如果ES=3000H,DI=0102H,则ES×10H+DI=3000H×10H+0102H=30102H,上述指 令的具体功能为:以30102H 为首地址,从内存中取出连续两个内存单元中的数据传送给 DX,指令执行的结果为:DX=C396H。 如果某种情况下要求间接寻址操作数必须具有确定的数据长度,要求汇编语言在其前 边增加属性操作符PTR,例如,指令MOV [SI],4中的两个操作数的长度都不是确定的, CPU 执行指令时是进行字节传送,还是字传送? 存在不确定性,这时需要使用BYTE PTR、WORDPTR、DWORDPTR这几种伪指令操作符去限定数据类型。例如: MOV BYTE PTR[SI], 4 ;将04H 赋值给SI 表示的内存单元 MOV WORD PTR[DI], 4 ;将0004H 赋值给以DI 为首地址的连续两个内存单元 MOV AL, 4 ;将4 赋值给AL,字节传送,因为AL 具有确定的数据长度 3.2.5 寄存器相对寻址 寄存器相对寻址是定位存储器操作数的另一种方法,是在寄存器间接寻址的基础上,存 取跟它有一定距离(位移量)的内存单元中的数据所使用的寻址方式。例如,存取数据表中 的数据,可以用间址寄存器存放数据表首地址,用位移量指明要存取表中的哪一个数据。寄 存器相对寻址表示的内存单元,它的偏移地址由两部分组成:一部分由间接寻址寄存器提 第3 章 8086/8088 指令系统 49 供;另一部分是指令给定的8位或16位的地址位移量。二者相加形成操作数的有效地址。 例如: MOV AX, [BX+DATA] ;将以BX+DATA 为首地址的连续两个内存单元中的数据 ;传送给AX MOV AL, [SI+20H] ;将以SI+20H 为地址的内存单元中的数据传送给AL MOV CX, [DI+DATA] ;将以DI+DATA 为首地址的连续两个内存单元中的数据传送给CX MOV DX, [BP+DATA] ;将堆栈段中以BP+DATA 为首地址的连续两个内存单元中的数据 ;传送给DX 上述指令的书写格式很灵活,也可以书写成如下形式: MOV AX, [BX]+DATA MOV AL, 20H [SI] MOV CX, DATA [DI] MOV DX, DATA+[BP] 寄存器相对寻址方式对寄存器的要求与寄存器间接寻址一样,只有4个寄存器:BX、 BP、SI、DI可以使用,并且要用[]申明。BP在寄存器相对寻址时,段基址默认为SS,其他3 种情况,段基址默认为DS。 3.2.6 基址变址寻址 基址变址寻址也是以寄存器间接寻址为基础,寻址数组中的数据。它由一个基址寄存 器(BX或BP)加上一个变址寄存器(SI或DI),作为操作数的偏移地址。例如: MOV AX, [BX][SI] ;将以BX+SI 为首地址的连续两个内存单元中的数据送给AX MOV CX, [BP][DI] ;将以BP+DI 为首地址的连续两个内存单元中的数据送给CX MOV [BX][DI], AL ;将AL 中的数据存入BX+DI 表示的内存单元中 MOV [BP][SI], DX ;将DX 中的数据存入以BP+SI 为首地址的连续两个内存单元中 8086CPU 中,寄存器BX和BP为基址寄存器,SI和DI为变址寄存器。这种寻址方式 中,一个基址寄存器加一个变址寄存器构成操作数,操作数的形式只有4种: [BX][SI] [BX][DI] [BP][SI] [BP][DI] 这种寻址方式的段基址是DS还是SS呢? 8086汇编规定以基址为主,如果基址寄存器 为BP,则操作数的段基址默认由SS提供;若BX为基址寄存器,则段基址默认由DS提供。 例如: MOV AX, [BX][DI] ;源操作数的物理地址为DS×10H+BX+DI MOV [BP][DI], DX ;目的操作数的物理地址为SS×10H+BP+DI 基址变址寻址方式要求必须一个基址和一个变址组合,不允许两个基址或两个变址组 合。下面指令是错误的。 50 微型计算机原理与接口技术(第2 版) MOV AX, [BX][BP] 基址变址寻址可以寻址存储器数组中的任何元素。将数组的首地址装入基址寄存器,将 要存取元素的序号存入变址寄存器,通过修改变址寄存器中的内容访问数组中的各个元素。 3.2.7 基址变址相对寻址 基址变址相对寻址是在基址变址寻址的基础上增加一个位移量,这种寻址方式常常用 来寻址存储器中的二维数组。操作数的地址由基址寄存器加上变址寄存器再加上地址位移 量构成。如果基址寄存器为BP,则段基址默认由SS提供;若基址寄存器为BX,则段基址默 认由DS提供。例如: MOV AX, BUFF[BX][SI] ;将BUFF+BX+SI 作为偏移地址的连续两个内存单元 ;的数据传送给AX MOV STRING[BX][DI], DX ;将DX 的内容传送到以STRING+BX+DI 为偏移地址的 ;连续两个内存单元 MOV CX, [BP+DI+20H] ;将BP+DI+20H 作为偏移地址的连续两个内存单元的 ;数据传送给CX MOV FILE[BP][SI], AL ;将AL 的内容传送到以FILE+BP+SI 为偏移地址的内存 ;单元 指令也可以书写为 MOV AX, [BUFF+BX+SI] MOV [STRING+BX+DI], DX MOV [FILE+BP+SI], AL 基址变址相对寻址方式要求必须一个基址和一个变址组合,不允许两个基址或两个变 址组合。 这种寻址方式主要用于寻址二维数组中的数据。如果程序中定义了4行10列的二维 数组FILE,FILE作为数组首地址,基址寄存器BX寻址行,变址寄存器SI寻址列,则可以 很方便地实现数据阵列检索。 3.2.8 隐含寻址 操作码隐含地指明操作数,例如乘法指令、字符串操作指令。 MUL BL ;AL 乘以BL,结果存在AX 中,隐含乘数AL 和乘积AX MOVSB ;把DS:SI 指明的内存单元的数据传送到ES:DI 指明的内存单元 3.3 8086CPU 指令系统 8088CPU 和8086CPU 的指令系统完全相同,共有133条基本指令,本节将这些指令 第3 章 8086/8088 指令系统 51 分为6个功能组进行介绍。 . 数据传送指令 . 算术运算指令 . 逻辑运算与移位指令 . 串操作指令 . 程序控制指令 . 处理器控制指令 汇编语言的基本语法规则及基本概念,如变量、标号、表达式及运算符等,将在介绍指令 的过程中讲解,不单独讲解。在介绍具体指令之前,先介绍一些符号约定: OPRD 各种类型的操作数 src 源操作数 dst 目的操作数 acc 累加器AX 或AL port 输入/输出端口 count 计数器 3.3.1 数据传送指令 数据传送指令是汇编语言中使用最频繁的指令,通常细分为通用数据传送指令、输入/输 出指令、地址传送指令和标志寄存器传送指令。 1.通用数据传送指令MOV,PUSH,POP,XCHG,XLAT 1)MOV 指令格式: MOV dst,src 功能:数据传送,把src的内容传送到dst中。 说明:把源操作数复制到目标操作数中,它可以实现: (1)立即数到通用寄存器的数据传送。 例如: MOV AL,4 ;AL=4 MOV AX,1000H ;AX=1000H MOV SI,037BH ;SI=037BH 但是 MOV DS,2000H ;语法错误,不能用立即数给段寄存器赋值 应该为 MOV AX,2000 MOV DS,AX 52 微型计算机原理与接口技术(第2 版) (2)立即数到存储单元的数据传送。 例如: MOV WORD PTR[DI], 2000H 图3-5 数据传送 将立即数2000H 传送到内存单元,内存单元的地址以间接寻址 的方式由DI提供。设DS=3000H,DI=1500H,目的操作数的物理 首地址为31500H,指令执行后如图3-5所示。 PTR是属性运算符,功能为修改操作数的类型。WORDPTR 的作用是将操作数的类型设置为字类型,BYTEPTR的作用是将操 作数的类型设置为字节类型。例如: MOV BYTE PTR[SI], 4AH 将立即数4AH 传送到内存单元,内存单元的地址以间接寻址的方式由SI提供,传送一 字节。 MOV [DI],04AH ;语法错误: 源和目的操作数的类型都不确定 这条指令不可用,因为源和目的操作数的类型都不确定,指令执行结果也不确定,这种 情况称为二异性。指令执行时可能传送一字节,将立即数4AH 传送给[DI]指明的内存单 元,也可能传送两字节,4A 赋给内存单元[DI],0赋给内存单元[DI+1]。 MOV 指令中的两个操作数的类型必须至少有一个是确定的,另一个依附这一个。属 性运算符PTR帮助确定存储器操作数的类型。 (3)CPU 内部寄存器之间的数据传送。 例如: MOV AL,BL ;BL 传送给AL,传送一字节 MOV AX,BX ;BX 传送给AX,传送一个字 MOV DS,AX ;给数据段寄存器赋值 MOV SI,BP ;BP 传送给SI,传送一个字 (4)寄存器与存储单元之间的数据传送。 例如: MOV AL,[2000H] ;将2000H 单元的内容传送给AL,传送一字节 MOV AX,[SI] ;将以SI 为首地址的连续两个内存单元中的数据传送给AX MOV [3200H], CX ;将CL 存入3200H 单元,将CH 存入3201H 单元 MOV ARRY[DI], DL ;将DL 的内容存入ARRY+DI 的内存单元中 MOV DL,[BX][SI] ;将BX+SI 内存单元中的数据传送给DL (5)存储单元之间的数据传送。 不能用一条MOV 指令实现内存单元之间的数据传送。8086汇编语法规定MOV 指 令中两个操作数不能同时为存储器操作数。要实现存储单元之间的数据传送,需要两条指 令。例如: MOV [DI], [SI] ;语法错误 第3 章 8086/8088 指令系统 53 应该为 MOV AX,[SI] MOV [DI], AX 使用MOV 指令时注意: (1)MOV 指令不影响标志寄存器的任何标志位。 (2)源和目的操作数不可同时为存储器操作数。 (3)源和目的操作数必须等长,即同时为字节类型或字类型。 (4)不能用立即数给段寄存器赋值。 (5)不允许给CS赋值。 (6)MOV 指令不能访问IP和FLAGS。 2)PUSH,POP PUSH 和POP是堆栈操作指令助记符。堆栈是程序在内存中开辟的一个数据存储 区,用于保存函数调用或者中断处理过程中的程序返回地址,或者是程序暂时不用而又必须 保存的数据。程序中,堆栈是用段定义语句在内存中定义的一个段,段基址存放在SS寄存 器,段内偏移地址存放在SP寄存器。堆栈段的起始单元称为栈底,堆栈指针SP常称为 栈顶。堆 栈是一种线性表,只在栈顶一端进行数据输入/输出操作。堆栈操作采用先进后出 (或后进先出)的存取方法。数据存入堆栈称为压入堆栈,使用PUSH 指令。从堆栈中取出 数据称为弹出堆栈,使用POP指令。程序中,堆栈初始化时,堆栈段起始物理地址为SS* 10H,段的最大长度为FFFFH,堆栈段的末地址最大为SS*10H+FFFFH,堆栈指针默认 图3-6 堆栈段 SP=0。假设SS=2000H,堆栈段如图3-6所示。 堆栈指令的操作数必须是16位的字类型操作数。所以, PUSH 指令执行时,首先将操作数的高字节数据存入SP-1单 元中,低字节数据存入SP-2单元中,然后执行SP-2修改堆栈 指针。SP总是指向堆栈中最上层包含数据的存储单元,它称 为栈顶。如果连续向堆栈中压入数据,SP的值越来越小,代 表堆栈中可用的存储区域越来越少,栈顶向堆栈段的起始单 元方向移动。 图3-6中,第一次向堆栈压入数据时,SP=0000H,假设 DX=C56EH,执行PUSHDX指令,高字节C5H 存入SP-1= FFFFH 单元中,低字节6EH 存入SP-2= FFFEH 单元中。 然后执行操作SP-2=SP,即0000H-2=FFFEH。堆栈段 起始单元物理地址为20000H,第一次压入的数据存储在堆栈段的末端,物理地址为 2FFFEH 和2FFFFH 单元,堆栈指针SP=FFFEH。 从堆栈中弹出数据时,首先弹出SP中的数据(16位数据中的低8位),然后弹出SP+1 中的数据(16位数据中的高8位),接下来执行SP+2调整指针。数据的弹出过程与压入过 程相反,堆栈指针SP增大,向堆栈段的末端方向移动。 指令格式: 54 微型计算机原理与接口技术(第2 版) PUSH src ;压栈指令 POP dst ;出栈指令 PUSH 指令把操作数压入堆栈,执行过程为 (1)src的高8位存入[SP-1],src的低8位存入[SP-2]; (2)SP-2送SP。 例如: 设SS=2000H,SP=102H,AX=623EH,执行下面的指令后: PUSH AX AX的数据62H 存入20101H 单元,3EH 存入20100H 单元,SP=0100H。 POP指令把操作数弹出到dst中,执行过程为 (1)把[SP]的内容弹出到dst的低8位,把[SP+1]的内容弹出到dst的高8位; (2)SP+2送SP。 例如:设SS=2000H,SP=100H,执行下面的指令后: POP BX 堆栈中20100H 单元的数据传送给BL,20101H 单元的数据传送给BH,BX=623EH, SP=102H。 堆栈操作指令属于单操作数指令,操作数可以是寄存器,也可以是存储器。堆栈指令的 操作数必须是字类型,可以是16位的通用寄存器或段寄存器,也可以是两个连续的内存单 元,可以采用任何寻址方式。8086CPU 不允许立即数作为堆栈操作的操作数,CS不能作为 出栈指令的操作数。堆栈指令不影响任何标志位。 例如: PUSH DI ;将DI 中的数据压入堆栈 PUSH SI ;将SI 中的数据压入堆栈 PUSH DX ;将DX 中的数据压入堆栈 PUSH DS ;将DS 中的数据压入堆栈 PUSH CS ;将CS 中的数据压入堆栈 PUSH WORD PTR[1000H] ;将以1000H 单元开始的连续两个单元的内容压入堆栈 PUSH WORD PTR[SI] ;将以[SI]单元开始的连续两个单元的内容压入堆栈 PUSH WORD PTR[BP+6] ;将以[BP+6]单元开始的连续两个单元的内容压入堆栈 POP DI ;从栈顶中弹出两个单元的数据送给DI POP SI ;从栈顶中弹出两个单元的数据送给SI POP DX ;从栈顶中弹出两个单元的数据送给DX POP DS ;从栈顶中弹出两个单元的数据送给DS POP WORD PTR[1000H] ;将SP 单元的数据弹出送给1000H 单元,SP+1 单 ;元的数据弹出送给1001H 单元 POP WORD PTR[SI] ;将SP 单元的数据弹出送给[SI]单元,SP+1 单元的 ;数据弹出送给[SI+1]单元 POP WORD PTR[BX+DI] ;将SP 单元的数据弹出送给[BX+DI]单元,SP+1 单 ;元的数据弹出送给[BX+DI+1]单元 第3 章 8086/8088 指令系统 55 注意:程序中,压栈操作和出栈操作通常成对出现,以保持堆栈的平衡。 3)交换指令XCHG 指令格式:XCHG OPRD1,OPRD2 功能:两个操作数交换。 说明:操作数可以是通用寄存器,不能是段寄存器;可以是存储器单元,但两个操作数 不能同时为存储器操作数。两个操作数的字长必须相等。 例如: XCHG AX, BX XCHG AL, [SI] XCHG [BX+DI], CX 4)字节转换指令XLAT XLAT主要用于查表转换和隐含寻址。该指令的功能是将内存单元[BX+AL]的单字 节内容传送给AL寄存器,指令执行前后AL的内容发生转换。使用XLAT 指令前,需要 预置DS:BX指向一张表,BX作为表的首地址。如果查表中第9字节的内容,需要预置AL 为9。 指令格式:XLAT 【例3-1】 DS数据段中存放有7段LED显示器表,如图3-7所示。TABLE为表首地 图3-7 码值表 址,查表取出LED显示器数字3的显示字型码。 MOV BX, OFFSET TABLE MOV AL, 3 XLAT ;AL=4FH OUT 88H, AL ;LED 显示数字3 2.输入/输出指令IN/OUT 8086CPU 对所有输入/输出端口统一管理,提供了一个与 内存储器地址空间分开的、完全独立的地址空间,I/O 端口的 地址有8位和16位两种形式。8086CPU 对I/O 端口的管理 与对内存储器的管理不同,输入/输出指令中操作数的寻址方式也不同,是输入/输出指令特 有的。. 直接端口寻址方式:当端口地址是8位的二进制数时,可以在指令中直接使用该 地址。 . 寄存器间接寻址方式:当端口地址为16位时,不能直接使用,需要预先将其传送到 DX寄存器中,并且只能是DX作为间接寻址寄存器。 8086CPU 无论从端口输出数据还是输入数据,都要通过累加器AL或AX,所以输入/ 输出指令又称为累加器专用传送指令。 1)输入指令IN 格式: IN ACC, port ;直接寻址,8 位port 为立即数端口地址 56 微型计算机原理与接口技术(第2 版) 或 IN AC C, D X ;间接寻址,DX 存有16 位端口地址 例如: IN AL , 60 H ;从60H 端口输入一字节 IN AX, 90H ;从90H 端口输入一个字 IN AL, DX ;从DX 端口输入一字节 IN AX, DX ;从DX 端口输入一个字 2)输出指令OUT 格式: OU T p or t, A CC ;直接寻址,port 为8 位立即数端口地址 或 OU T D X, AC C ;间接寻址,DX 存有16 位端口地址 例如: OU T 6 0H , AL ;AL 从60H 端口输出 OUT 90H, AX ;AX 从90H 端口输出 OUT DX, AL ;AL 从DX 端口输出 OUT DX, AX ;AX 从DX 端口输出 【例3-2】 从并行口0378H 输出一个字符'A'。 MO V D X, 03 78 H MOV AL,'A' OUT DX,AL 3.地址传送指令LEA,LDS,LES 地址传送指令共3条。 1)取有效地址指令LEA 指令格式:LEA dst,src 功能:把源操作数的地址偏移量传送到目标操作数。 说明:源操作数必须是存储器操作数,目标操作数必须是16位寄存器。 例如: LE A B X, T AB LE ;TABLE 的偏移地址传送给BX,TABLE 为符号变量 LEA SI, DATA[BX] ;SI=BX+DATA 设BUFF为符号变量,比较下面两条指令的功能: MO V D I, O FF SE T BU F F LEA DI, BUFF 第3 章 8086/8088 指令系统 57 上面两条指令的功能完全相同,但LEA 指令更简洁。OFFSET 为取值运算符,又称为 数值返回运算符,用于求变量或标号的属性值。常见的取值运算符还有SEG。 . SEG运算符用于求变量或标号所在段的段基址。例如: MO V A X, S EG B UF F ;BUFF 的段基址送AX . OFFSET用于求变量或标号的偏移地址。例如: MO V A X, O FF SE T BU F F ;BUFF 的偏移地址送AX 2)取地址指针指令LDS 指令格式:LDS dst, src 功能:将段基址传送给DS寄存器,偏移地址传送给16位的地址指针寄存器。 说明:双字操作。从源操作数中连续取出4字节。 例如: LD S B X, ES : [1 00 0 H] 图3-8 LDS指令 设从ES:[1000H]单元起顺序存放4字节,如图3-8所示,上面 指令的执行将0378H 作为偏移量传送给BX,将2000H 作为段基址传 送给DS。 3)取地址指针指令LES 与LDS指令功能相似,只是段基址装入ES,而不是DS。例如: LE S S I, [1 00 0 H] 4.标志寄存器传送指令LAHF,SAHF,PUSHF,POPF 这4条指令都是隐含寻址方式。 1)LAHF指令 指令格式:LAHF 功能:把标志寄存器FLAGS的低8位装入AH 寄存器。 2)SAHF指令 指令格式:SAHF 功能:把AH 传送到FLAGS的低8位,指令影响标志位。 3)PUSHF指令 指令格式:PUSHF 功能:把FLAGS压入堆栈。 4)POPF指令 指令格式:POPF 功能:从堆栈中弹出两字节传送给FLAGS,指令影响标志位。 58 微型计算机原理与接口技术(第2 版) 3.3.2 算术运算指令 8088/8086CPU 提供了加、减、乘、除4种基本算术运算指令,可以实现二进制数的运 算,也可以实现十进制数的运算,可以实现字节运算,也可以实现字运算,可以进行有符号数 运算,也可以进行无符号数运算,有符号数运算以补码形式进行。这4种算术运算指令都对 标志位产生影响。算术运算指令应尽量使用累加器作操作数。 1.加法运算指令和调整指令ADD,ADC,INC,AAA,DAA 1)不带进位的加法运算指令ADD ADD指令完成两个操作数相加,并将结果保存在目的操作数中。 指令格式:ADD OPRD1, OPRD2 功能:操作数OPRD1与OPRD2相加,结果保存在OPRD1中。 说明:操作数OPRD1可以是累加器AL或AX,也可以是其他通用寄存器或存储器操 作数,OPRD2可以是累加器、其他通用寄存器或存储器操作数,还可以是立即数。OPRD1 和OPRD2不能同时为存储器操作数,不能为段寄存器。ADD指令的执行对6个状态标志 位都产生影响。 例如: AD D A L, B L ;AL+BL 结果存回AL 中 ADD AX, SI ;AX+SI 结果存回AX 中 ADD BX, 3DFH ;BX+03DFH 结果存回BX 中 ADD DX, DATA[BP+SI] ;DX 与内存单元相加,结果存回DX 中 ADD BYTE PTR[DI], 30H ;内存单元与30H 相加,结果存回内存单元中 ADD [BX], AX ;内存单元[BX]与AX 相加,结果存回[BX]中 ADD [BX+SI], AL ;内存单元与AL 相加,结果存回内存单元中 【例3-3】 求D9H 与6EH 的和,并注明受影响的标志位状态。 MO V A L, 0 D9 H MOV BL, 6EH ADD AL, BL 11011001 + 01101110 `10``1`00`0111 结果AL=47H,标志位CF=1,PF=1,AF=1,ZF=0,SF=0,OF=0。 2)带进位的加法运算指令ADC ADC指令主要用于多字节数的加法运算,以保证低位向高位的进位被正确接收。ADC 指令完成两个操作数相加之后,再加上Flags的进位标志CF的值,CF的值可能为1或0。 指令格式: ADC OPRD1, OPRD2 功能:操作数OPRD1与OPRD2相加后,再加上CF的值,结果保存在OPRD1中。 说明:对操作数的要求与ADD指令一样。 例如: 第3 章 8086/8088 指令系统 59 AD C A L, B L ; AL + BL+CF 结果存回AL ADC AX, BX ;AX+BX+CF 结果存回AX ADC [DI], 30H ;[DI]+30H+CF 结果存回[DI]单元中 【例3-4】 求E583AD9FH 与C725BC6EH 的和,结果存放在DX:AX中。 MO V A X, 0 AD 9F H ; A X= AD9FH MOV BX, 0BC6EH ;BX=BC6EH ADD AX, BX ;AX=6A0DH,CF=1 MOV DX, 0E583H MOV BX, 0C725H ADC DX, BX ;DX=ACA9H,DX:AX=ACA96A0DH,CF=1 在多字节数的加法运算中,首先进行低位数相加,再进行高位数相加。最低位相加可以 用ADD指令,是因为不需要加进位CF。高位数相加需要使用ADC指令,如果低位的加法 运算使CF=1,说明刚才的加法运算有进位,这个进位必须送到高位数中,否则运算结果是 错误的。 3)加1指令INC 加1指令INC又称增量指令,该指令不影响CF标志位。 指令格式:INC OPRD 功能:OPRD加1后送回OPRD。 说明:操作数OPRD可以是寄存器或存储器操作数,指令可以完成字节或字的加1 操作。例 如: IN C A L INC AX INC BYTE PTR[SI] INC WORD PTR[BX+DI] 4)十进制数加法调整指令AAA、DAA ADD和ADC指令允许BCD数作为操作数进行加法运算,按照十进制数的方式完成加 法运算。但是,CPU 在完成运算时依然按照二进制数进行,所以在ADD或ADC指令之后, 应进行十进制的调整。 . 指令格式:AAA 功能:将AL中的数进行十进制调整,结果保存在AX中。 说明:之前的加法指令必须是两个非压缩BCD 码相加,结果在AL中。AAA 指令隐 含操作数AL和AH。指令执行时: (1)若AL的低4位值大于9或辅助进位AF=1,则将AL加6,将AH 加1,并将AF 和CF标志位均置1。 (2)AL高4位清0。 . 指令格式:DAA 功能:将AL中的数进行十进制调整,结果保存在AX中。 说明:之前的加法指令必须是两个压缩BCD 码相加,结果在AL中。AAA 指令隐含 60 微型计算机原理与接口技术(第2 版) 操作数AL和AH。指令执行时: ① 若AL的低4位值大于9或辅助进位AF=1,则将AL加6,AF置1。 ② 若AL的值大于9FH 或进位CF=1,则将AL加60H,CF置1。 2.减法运算指令SUB,SBB,DEC,NEG,CMP,AAS,DAS 1)不带借位CF的减法指令SUB 指令格式:SUB OPRD1,OPRD2 功能:操作数OPRD1减去OPRD2,结果保存在OPRD1中。 说明:操作数OPRD1可以是累加器AL或AX,也可以是其他通用寄存器或存储器操 作数,OPRD2可以是累加器、其他通用寄存器或存储器操作数,还可以是立即数。OPRD1 和OPRD2不能同时为存储器操作数,不能为段寄存器。SUB指令的执行对6个状态标志 位都产生影响。 例如: SU B A L, B L ;AL-BL,结果存回AL SUB CX, BX ;CX-BX,结果存回CX SUB DX, [SI] ;DX 与[SI]内存单元相减,结果存回DX SUB DATA[BX], CL ;内存单元的数减去CL,结果存回内存单元 SUB BL, 2 ;BL-2,结果在BL 中 SUB WORD PTR[BP+SI],100H ;内存单元减去100H,结果存回内存 【例3-5】 D9H 与6EH 相减,并注明受影响的标志位状态。 MO V AL , 0D 9H MOV BL, 6EH SUB AL, BL 11011001 - 01101110 01101011 `` ``` 结果AL=6BH,标志位CF=0,PF=0,AF=1,ZF=0,SF=0,OF=1。 2)带借位CF的减法指令SBB 指令格式:SBB OPRD1, OPRD2 功能:操作数OPRD1减去OPRD2再减去CF的值,结果保存在OPRD1中。 说明:与SUB指令相同,常用于多字节数减法,对6个状态标志位都产生影响。 例如: SB B A L, 3 0H ;AL-30H-CF,结果存回AL SBB AX, BX ;AX-BX-CF,结果存回AX SBB [DI], AH ;[DI]-AH-CF,结果存回内存单元[DI]中 3)减1指令DEC DEC指令又称为减量指令,该指令不影响CF 标志位,对其他5个状态标志位产生 影响。指 令格式:DEC OPRD 功能:操作数OPRD减1后回送OPRD。 说明:操作数OPRD可以是寄存器或存储器操作数,指令可以完成字节或字的减1 第3 章 8086/8088 指令系统 61 操作。例 如: DE C C X DEC CL DEC BYTE PTR [ARRAY+SI] 4)操作数求补指令NEG 指令格式:NEG OPRD 功能:(0-OPRD)结果送回OPRD,即对OPRD包括符号位在内逐位取反后加1,结果 回送到OPRD。 说明:OPRD可以是寄存器或存储器操作数。如果操作数非0,则指令的执行使CF= 1,否则CF=0。NEG指令的执行对6个状态标志位都产生影响。 【例3-6】 MOV AL,31H NEG AL; AL=CFH,标志位CF=1,PF=1,AF=1,ZF=0,SF=1,OF=0 5)比较指令CMP 比较指令CMP用于比较两个数的大小,不外乎大于、小于、等于、大于或等于、小于或 等于几种情况。指令执行结束后,通过检测状态标志位的值,就可以判定是哪一种情况,程 序可以据此设定执行方向,因此,比较指令后面常跟有条件转移指令。 指令格式: CM P OP RD 1, O PR D2 功能:OPRD1减去OPRD2,结果并不回送给OPRD1。CMP指令的执行影响6个状 态标志位。 说明:指令的执行不影响两个操作数,操作数不变,但影响6个状态标志位。OPRD1 可以是寄存器或存储器操作数,OPRD2可以是立即数、寄存器或存储器操作数。 例如: CM P A L, A H ;AL 与AH 比较 CMP AX, BX ;AX 与BX 比较 CMP [SI+DATA], AX ;[SI+DATA]连续两个存储单元的数与AX 比较 CMP CL, 8 ;CL 与8 比较 CMP POINTER[BX], 100H ;[BX+POINTER]连续两个存储单元的数与100H 比较 【例3-7】 CM P A L, 0 ;AL 与0 比较 JE EQUA ;若相等,则转移到EQUA 处继续执行,否则顺序执行下一条指令 … EQUA: CMP BL, CL ;BL 与CL 比较 JA GOON ;若BL 大于CL,则转移到GOON 处执行,否则顺序执行下一条指令 … 如果希望实现BL小于CL,则转移,可以使用JB 条件转移指令。如果希望实现BL大 于或等于CL,则转移,可以使用JAE 条件转移指令。如果希望实现BL小于或等于CL,则