【微机原理与接口技术】学习笔记3 8086的寻址方式和指令系统

您所在的位置:网站首页 常见数据寻址方式有哪些种类和特点 【微机原理与接口技术】学习笔记3 8086的寻址方式和指令系统

【微机原理与接口技术】学习笔记3 8086的寻址方式和指令系统

2024-07-14 04:41| 来源: 网络整理| 查看: 265

文章目录 3.1 8086的寻址方式3.1.1 立即数寻址方式(Immediate Addressing)3.1.2 寄存器寻址方式(Register Addressing)3.1.3 直接寻址方式Direct Addressing3.1.4 寄存器间接寻址方式Register Indirect Addressing3.1.5 寄存器相对寻址方式Register Relative Addressing3.1.6 基址变址寻址方式Based Indexed Addressing3.1.7 相对基址变址寻址方式Relative Based Indexed Addressing3.1.8 其它寻址方式1. 隐含寻址2. I/O端口寻址1)直接端口寻址方式2)间接端口寻址方式 3. 一条指令有几种寻址方式4. 转移类指令寻址 3.1.9 总结★★★ 3.2 指令的机器码表示方法 * 本节内容供选用3.2.1 机器语言指令的编码目的和特点1.机器语言指令2.机器语言指令的编码特点 3.2.2 机器语言指令代码的编制 3.3 8086的指令系统3.3.1 数据传送指令1.通用数据传送指令 (General Purpose Data Transfer)1) MOV 传送指令 (Move)2) 进栈指令PUSH (Push Word onto Stack)3) 出栈指令POP (Pop Word off Stack)4) 交换指令XCHG (Exchange)5) 表转换指令XLAT (Table Lookup-Translation) 2. 输入输出指令 (Input and Output)1) IN 输入指令 (Input)2) OUT 输出指令 (Output) 3. 地址目标传送指令 (Address Object Transfers)1) LEA 取有效地址指令 (Load Effective Address)2) LDS 将双字指针送到寄存器和DS指令 (Load Pointer using DS)3) LES 将双字指针送到寄存器和ES指令 (Load Pointer using ES) 4. 标志传送指令(Flag Transfers)1) LAHF 标志送到AH指令 (Load AH from Flags)2) SAHF AH送标志寄存器 (Store AH into Flags)3) PUSHF 标志入栈指令 (Push Flags onto Stack)4) POPF 标志出栈指令 (Pop Flags off Stack) 3.3.2 算术运算指令1. 加法指令 (Addition)1) ADD 加法指令2) ADC 带进位的加法指令 (Addition with Carry)3) INC 增量指令 (Increment)4) AAA 加法的ASCII调整指令 (ASCII Adjust for Addition)5) DAA 加法的十进制调整指令 (Decimal Adjust for Addition) 2. 减法指令 (Subtraction)1) SUB 减法指令 (Subtraction)2) SBB 带借位的减法指令 (Subtract with Borrow)3) DEC 减量指令 (Decrement)4) NEG 取负指令 (Negate)5) CMP 比较指令 (Compare)6) AAS 减法的ASCII调整指令 (ASCII Adjust for Subtraction)7) DAS 减法的十进制调整指令 (Decimal Adjust for Subtraction) 3. 乘法指令 (Multiply)1) MUL 无符号数乘法指令 (Multiply)2) IMUL 整数乘法指令 (Integer Multiply)3) AAM 乘法的ASCII调整指令 (ASCII Adjust for Multiply) 4. 除法指令 (Division)1) DIV 无符号数除法指令 (Division,unsigned)2) IDIV 整数除法指令 (Integer Division)3) CBW 把字节转换为字指令 (Convert Byte to Word)4) CWD 把字转换成双字指令 (Convert Word to Double Word)5) AAD 除法的ASCII调整指令 (ASCII Adjust for Division) 3.3.3 逻辑运算和移位指令1. 逻辑运算指令 (Logical Operations)1) NOT 取反指令 (Logical Not)2) AND 逻辑与指令 (Logical AND)3) OR 逻辑或指令 (Logical OR)4) XOR 异或操作指令 (Exclusive OR)5) TEST 测试指令 (Test) 2. 算术逻辑移位指令 (Shift Arithmetic and Shift Logical)1) SAL 算术左移指令 (Shift Arithmetic Left)2) SHL 逻辑左移指令 (Shift Logic Left)3) SHR 逻辑右移指令 (Shift Logic Right)4) SAR 算术右移指令 (Shift Arithmetic Right) 3. 循环移位指令 (Rotate)1) ROL 循环左移指令 (Rotate Left)2) ROR 循环右移指令 (Rotate Right)3) RCL 通过进位位循环左移 (Rotate through Carry Left)4) RCR 通过进位位循环右移 (Rotate through Carry Right) 3.3.4 字符串处理指令1. MOVS字符串传送指令 (Move String)2. CMPS 字符串比较指令 (Compare String)3. SCAS 字符串扫描指令 (Scan String)4. LODS 数据串装入指令(Load String)5. STOS 数据串存储指令 (Store String) 3.3.5 控制转移指令1. 无条件转移和过程调用指令 (Unconditional Transfer and Call)1) JMP 无条件转移指令 (Jump)(1) 段内直接转移指令(2) 段内间接转移指令(3) 段间直接(远)转移指令(4) 段间间接转移指令 2) 过程调用和返回指令 (Call and Return)(1) 段内直接调用和返回(2) 段内间接调用和返回(3) 段间直接调用(4) 段间间接调用 2. 条件转移指令 (Conditional Transfer)1) 直接标志转移指令2) 间接标志转移 ★★ 3. 循环控制指令 (Iteration Control)1) LOOP循环指令 (Loop)2) LOOPE/LOOPZ 相等或结果为0时循环 (Loop If Equal/Zero)3) LOOPNE/LOOPNZ 不相等或结果不为0循环 (Loop If Not Equal/Not Zero)4) JCXZ 若CX为0跳转 (Jump If CX Zero) 4. 中断指令 (Interrupt)1) 中断概念2) 中断指令(1) INT n 软件中断指令 (Interrupt)(2) INTO 溢出中断指令 (Interrupt on Overflow)(3) IRET (Interrupt Return) 3.3.6 处理器控制指令1. 标志操作指令1) CLC,CMC和STC2) CLD和STD3) CLI和STI 2. 外部同步指令1) ESC 换码指令 (Escape)2) WAIT 等待指令 (Wait)3) LOCK 封锁总线指令 (Lock Bus) 3. 停机指令和空操作指令1) HLT 停机指令 (Halt)2) NOP 空操作或无操作指令 (No Operation)

指令Instruction和寻址方式:

计算机的指令,通常包含操作码(Opcode)和操作数(Operand)两部分,操作码指出操作的性质,操作数给出操作的对象。指令有单操作数、双操作数和无操作数之分。如果是双操作数,要用逗号分开,左边的为源操作数,右边的为目的操作数。

寻址方式:

寻址方式就是指令中说明操作数所在地址的方法。8086的寻址方式有以下几种: 立即数寻址:可直接从指令队列中取数,指令执行速度较快;寄存器寻址:操作数在寄存器中,执行速度最快;存储器寻址:操作数在存储器中,又分几种形式,执行速度较慢;其它寻址:如隐含寻址、I/O端口寻址、转移类指令寻址

下面主要以 MOV 指令(源操作数)为例来说明8086的寻址方式。8088的指令与8086完全兼容,各种寻址方式也完全相同。

3.1 8086的寻址方式 3.1.1 立即数寻址方式(Immediate Addressing)

操作数直接包含在指令中,它是一个 8 位或 16 位的常数,也叫立即数。

立即数可以送到寄存器中,还可送到一个存储单元( 8 位)中或两个连续的存储单元( 16 位)中去。立即数只能作源操作数,不能作目的操作数。以 A~F 打头的 16 进制数字出现在指令中时,前面一定要加一个数字 0 。

例如:MOV AL, 26H 。将 8 位立即数 26H 送到 AL 寄存器中。 例如,将 FF00H 送到 AX 的指令必须写成:MOV AX,0FF00H 。 例如:MOV CX, 2A50H。将立即数 2A50H 送到 CX 中,指令的机器码存放及执行过程如图3。

立即数寻址说是寻址,但是和地址没有太大关系。

3.1.2 寄存器寻址方式(Register Addressing)

操作数包含在寄存器中,由指令指定寄存器的名称。

16位寄存器可以是:AX、BX、CX、DX、SI、DI、SP、BP8位寄存器为:AH、AL、BH、BL、CH、CL、DH、DL

例:MOV DX,AX 。设指令执行前AX = 3A68H,DX=18C7H。则指令执行后 DX=3A68H,AX=3A68H (保持不变) 例:MOV CL, AH。 将 AH 中的 8 位数据传送到 CL 寄存器。

注意:源操作数的长度必须与目的操作数一致,否则会出错。 例如,MOV CX,AH是错误的。虽然 CX 放得下 AH 中的 8 位数据,但汇编程序不知道应该将它放入 CH 还是 CL 。

以下几种寻址方式,操作数都放在存储器中,需用不同的方法求出操作数的物理地址,来获得操作数。

3.1.3 直接寻址方式Direct Addressing

操作数的偏移地址也称为有效地址 EA(Effective Address)。在直接寻址方式下,存储单元的有效地址直接由指令给出,默认使用的段寄存器为数据段寄存器 DS。操作数的物理地址 = 16 × D S + E A 16×DS+EA 16×DS+EA 例:MOV AX, [2000H]。指令中直接给出有效地址 EA ,这里右边 EA=2000H,必须加 [ ] ,表示不是立即数,而是偏移地址。左边当然还是寄存器寻址。设 DS=3000H ,则源操作数的物理地址= 16 × 3000 H + 2000 H = 32000 H 16×3000H+2000H=32000H 16×3000H+2000H=32000H

因目的操作数是 16 位寄存器 AX 寻址,所以将存储单元中的一个字送进 AX 。若(32000H)=34H(数据的低位字节的地址),(32001H)=12H,则执行指令后,AX=1234H。

例:MOV AL, [2000H]。假设条件同上例,指令执行后将 32000H 单元中的字节送到 AL ,结果使 AL=34H 。执行过程示意图如下:

段超越前缀:如果要对代码段、堆栈段或附加段寄存器所指出的存储区进行直接寻址,应在指令中指定段超越前缀。例如,数据若放在附加段中,则应在有效地址前加说明符 ES: ,计算物理地址时要用 ES 作基地址,而不是默认值 DS。

例如:MOV AX, ES:[500H]。该指令的源操作数的物理地址 =16×ES+500H 。

符号地址:允许用符号地址代替数值地址,也就是给存储单元起一个名字,如 AREA1 ,寻址时只要使用其名字,不必记住具体数值。

例如:MOV AX,AREA1。指令执行后,将从有效地址为 AREA1 的存储单元中取出一个字送到 AX 中去。程序中事先应用说明语句也叫做伪指令来加以说明。例:

AREA1 DW 0867H ... MOV AX, AREA1

这里的 DW 伪指令语句用来定义变量。MOV 指令执行后将 AREA1 单元中内容送到 AX ,结果 AX=0867H 。比起直接寻址用方括号+数值,我们更推荐使用符号地址。

3.1.4 寄存器间接寻址方式Register Indirect Addressing

指令中给出的寄存器中的值不是操作数本身,而是操作数的有效地址 EA ,需要求出地址并根据地址得到操作数。寄存器名称外同样必须加方括号,可用的寄存器有:BX、BP、SI、DI 。应遵守以下约定:

约定1:如果指令中指定的寄存器是 BX、SI 或 DI ,则默认操作数存放在数据段中,则物理地址=16×DS+BX;或 =16×DS+SI ;或 =16×DS+DI 。 例 MOV BX, [SI]。设 DS=1000H,SI=2000H,(12000H)=318BH,则:物理地址 = 16×DS+SI = 10000H+2000H = 12000H。指令执行后,BX = 318BH,指令执行过程如图: 约定2:如果指令中用 BP 进行间接寻址,则默认操作数在堆栈段中。例如:MOV AX, [BP] 。操作数的物理地址 =16×SS+BP 。指令中也可以指定段超越前缀。例如:MOV BX,DS: [BP] 源操作数物理地址 =16×DS+BP;MOV AX,ES: [SI] 源操作数物理地址 16×ES+SI 。 3.1.5 寄存器相对寻址方式Register Relative Addressing

它与寄存器间接寻址十分相似,,可用的寄存器有:BX、BP、SI、DI,但在有效地址上还要加一个 8/16 位的位移量。 例:MOV BX, COUNT[SI]:

设 DS=3000H,SI=2000H ,位移量 COUNT=4000H ,(36000H)=5678H则物理地址 = 16×DS+SI+COUNT=30000H+2000H+4000H=36000H。执行结果 BX=5678H ,执行过程如图。可以理解为 DS * 16 + SI 为数组首地址,后面的 COUNT 为数组偏移量。

上述指令也可用 MOV BX, [COUNT+SI] 这种形式来表示。

3.1.6 基址变址寻址方式Based Indexed Addressing

有效地址是一个基址寄存器( BX 或 BP )和一个变址寄存器( SI 或 DI )的内容之和,两个寄存器均由指令指定。

若基址寄存器为 BX 时,代表数据段,段址寄存器用 DS ,则:物理地址 = 16×DS+BX+SI 或 =16×DS+BX+DI若基址寄存器为 BP 时,代表堆栈段,段址寄存器应使用 SS ,则:物理地址 = 16×SS+BP+SI 或 = 16×SS+BP+DI

例:MOV AX, [BX][SI]。设 DS=3000H,BX=1200H,SI=0500H, (31700H)=ABCDH ,则:物理地址 = 16×DS+BX+SI = 30000H+1200H+0500H = 31700H 。执行结果:AX=ABCDH ,指令执行过程如图。

3.1.7 相对基址变址寻址方式Relative Based Indexed Addressing

有效地址是基址和变址寄存器的内容,再加上 8/16 位位移量之和。

当基址寄存器为 BX 时,用 DS 作段寄存器,则: 物理地址 = 16×DS+BX+SI+8位或16位位移量 或 = 16×DS+BX+DI+8位或16位位移量当基址寄存器为 BP 时,应使用 SS 作段寄存器,则: 物理地址 = 16×SS+BP+SI+8位或16位位移量 或 = 16×SS+BP+DI+8位或16位位移量

例:MOV AX,MASK[BX][SI]

设 DS=2000H,BX=1500H,SI=0300H,MASK=0200H,(21A00H)=26BFH则物理地址 = 16×DS+BX+SI+MASK = 20000H+1500H+0300H+0200H=21A00H执行结果:AX=26BFH,指令执行过程如图:

相对基址变址寻址:涉及操作数的地址时,常使用方括号,带 [ ] 的地址必须遵循下列规则:

立即数可以出现在方括号内,表示直接地址,例如 [2000H] 。只有 BX、BP、SI、DI 可以出现在 [] 内,既可单独出现,也可几个寄存器组合(只能相加),或寄存器与常数相加,但 BX 和 BP 不允许出现在同个[]内,SI 和 DI 也不能同时出现。方括号有相加的含义,故下面几种写法是等价的:6[BX][SI] / [BX+6][SI] / [BX+SI+6]若 [ ] 内包含BP,则隐含使用 SS 提供基地址,它们的物理地址 = 16×SS+EA 。

包含 BP 的操作数有 3 3 3 种形式:

DISP[BP+SI] ;EA=BP+SI+DISPDISP[BP+DI] ;EA=BP+DI+DISPDISP[BP] ;EA=BP+DISP

其中,DISP 表示 8 8 8 位或 16 16 16 位位移量,也可以为 0 0 0 。这种情况下,也允许用段超越前缀将 SS 修改为 CS 、DS 或 ES 中的一个,计算物理地址时,应将上式中的 SS 改为相应的段寄存器。其余情况均隐含使用DS提供基地址,它们的物理地址计算方法 = 16×DS+EA 。

这类操作数可以有以下几种形式:

[DISP] ;EA=DISPDISP[BX+SI] ;EA=BX+SI+DISPDISP[BX+DI] ;EA=BX+DI+DISPDISP[BX] ;EA=BX+DISPDISP[SI] ;EA=SI+DISPDISP[DI] ;EA=DI+DISP

同样,也可用段超越前缀将式中的DS修改为CS、ES或SS中的一个。

3.1.8 其它寻址方式 1. 隐含寻址

指令中不指明操作数,但具有隐含规定的寻址方式。例如,DAA 它对 AL 中的数据进行十进制调整,结果仍保留在 AL 中。

隐含寻址方式常常用于BIOS和DOS系统调用中。

2. I/O端口寻址

8086有直接端口和间接端口两种寻址方式:

1)直接端口寻址方式

端口地址由指令直接提供,它是一个 8 位立即数 n= 00 ~ FFH 。例 IN AL, 63H 即 AL←端口 63H 中的内容。

2)间接端口寻址方式

被寻址的端口号由寄存器 DX 提供,端口号 =0000~ FFFFH 。例:

MOV DX, 213H ; DX = 端口地址号213H IN AL, DX ; AL ← 端口213H中的内容 3. 一条指令有几种寻址方式

上述寻址方式都针对源操作数。目的操作数可用除了立即寻址方式之外的所有寻址方式指定,所以一条指令可以有几种寻址方式。例:MOV [BX], AL。这里,源操作数为寄存器寻址,目的操作数为寄存器间接寻址方式。

4. 转移类指令寻址

将在本章后面讨论控制转移指令时介绍。

3.1.9 总结★★★

总结一下,上面的七种寻址方式,有几条原则:

立即数寻址,直接将一个数送进寄存器,只能够用于源操作数;寄存器寻址,用一个寄存器即可;[直接寻址 符号地址] 、[BX BP]、[SI DI] 三组任意搭配。比如说: 三组可以单独抽一个出来: 抽一个直接寻址,写成 [立即数] 或者 符号地址,就是直接寻址;抽第二组中的一个,写成 [BX] 、[BP] ,就是寄存器间接寻址,除了 BP ,寄存器间接寻址都是默认与数据段搭配;抽第三组中的一个,写成 [SI]、[DI] ,也是寄存器间接寻址; 三组中分别抽两个搭配: 抽第一组的一个和第二组的一个搭配,写成 直接数[BX], 符号地址[BX] 或者 直接数[BP], 符号地址[BP] 就是寄存器相对寻址;抽第二组的一个和第三组的一个搭配,写成 [BX][SI], [BX][DI] 或者 [BP][SI], [BP][DI] ,就是基址变址寻址;抽第一组的一个和第三组的一个搭配,写成 直接数[SI], 符号地址[SI] 或者 直接数[DI], 符号地址[DI] 就是寄存器相对寻址; 三组中分别抽一个搭配:就是相对基址变址寻址; 如果基址寄存器为 BX 时,段址寄存器用 DS ;如果基址寄存器为 BP 时,段址寄存器应使用 SS ;可以使用段超越前缀改变段地址寄存器为 CS 或 ES 。 3.2 指令的机器码表示方法 * 本节内容供选用 3.2.1 机器语言指令的编码目的和特点 1.机器语言指令

计算机只能识别二进制表示的机器语言指令,也称为机器码。编程时,一般可不必了解指令的机器码。

若要透彻了解计算机的工作原理,看懂包含机器码的程序清单,对程序进行正确的调试、排错等,就要了解机器语言。

2.机器语言指令的编码特点

对8086指令进行二进制编码时,可以对每种基本类型给出一个编码格式,对照格式填入不同的数字来表示不同的寻址方式、数据类型等,就能求得每条指令的机器码。

指令通常由操作码和操作数两部分组成:操作码很容易从指令编码表中查到;操作数采用寄存器和存储器寻址方式时,可以列表给出编码方式。操作数采用立即数和端口地址时,可直接填入指令的编码格式表中。 3.2.2 机器语言指令代码的编制

(略)

3.3 8086的指令系统

8086的指令共有六大类:数据传送指令、算术运算指令、逻辑运算和移位指令、字符串处理指令、控制转移指令、处理器控制指令。

本章除详细介绍各类指令外,还将介绍部分伪指令,并给出许多短小的程序设计例子,以便更好理解指令功能。

3.3.1 数据传送指令

除 SAHF 和 POPF 指令外,对标志位均没有影响。

1.通用数据传送指令 (General Purpose Data Transfer) 1) MOV 传送指令 (Move)

指令格式:MOV 目的, 源 指令功能:目的操作数←源操作数 注意:MOV 指令允许数据传送的途径如下图。但 CS 不能做目的操作数。指令中至少要有一项明确说明传送的是字节还是字。 例: 由于 DATA 表示数据段的段址,是一个 16 16 16 位立即数,不能被直接送进 DS,需要先送进另一个数据寄存器(如 AX ),再传到 DS 中。

MOV AL, 'B' ;AL←将字符B的ASCII码(42H) MOV AX, DATA ;DATA为直接寻址, 取DATA的内容; AX为寄存器寻址 MOV DS, AX

在汇编语言程序中,数据通常存放在数据段中。下面将举例介绍数据段的基地址、段中各变量的偏移地址、变量定义等概念。例如,下面是某个程序的数据段:

DATA SEGMENT ;数据段开始 AREA1 DB 14H, 3BH ;定义了两个字节define byte AREA2 DB 3 DUP(0) ;定义了三个字节, 都是重复的0 define byte ARRAY DW 3100H, 01A6H ;定义了两个字,四个字节 STRING DB 'GOOD' ;定义了一系列字节ASCII码 DATA ENDS ;数据段结束

数据占用存储空间的情况如图:

AREA1 的偏移地址为 0000HAREA2 的偏移地址为 0002HARRAY 的偏移地址为 0005H字符串 'GOOD' 从 0009H 开始存放。

代码说明如下:

数据段以段说明符 SEGMENT 开始,ENDS 结束, DATA \text{DATA} DATA 是数据段的段名。DB 伪操作符用来定义字节变量。DW 定义字变量,低字节在低位地址,高字节在高位地址。DUP 复制操作符,前面的 3 说明在存储器中保留 3 个字节单元,初值均为 0 0 0 。

汇编后, DATA \text{DATA} DATA 被赋予具体的段地址,各变量将自偏移地址 0000H 开始依次存放,各符号地址也被赋予确定的值,等于它们在数据段中的偏移量。

还有一个必须掌握的用法:MOV DX,OFFSET ARRAY。 这里不是直接寻址!

将 ARRAY 的偏移地址送到 DX ,其中,OFFSET 为属性操作符,表示应把其后的符号地址的值(而不是内容)作为操作数。若 ARRAY 的值如上图,则指令执行后,符号地址 ARRAY 的偏移量 0005H 被送到了 DX 中。除了偏移地址,还可以送段地址,替换 OFFSET 为 SEG 。

例:设 AREA1 和 AREA2 的值如上图,说明以下指令功能:

MOV AL, AREA1 ;AL ← AREA1中的内容 14H MOV AREA2, AL ;0002H单元 ← 14H MOV AX, TABLE[BP][DI] ;将地址为16×SS+BP+DI+TABLE的字单元中的内容送进AX

注意,不能直接把一个内存单元中的值直接送到另一个内存单元之中,需要用一个寄存器中转。

2) 进栈指令PUSH (Push Word onto Stack)

指令格式: PUSH 源 指令功能: 将源操作数推入堆栈,源操作数必须是一个字

源操作数可以是 16 位通用寄存器、段寄存器或存储器中的数据字,但不能是立即数(后来开放了,能够进栈立即数)。执行 PUSH 操作后,使 SP←SP-2 ,再把源操作数压入 SP 指示的位置上。 3) 出栈指令POP (Pop Word off Stack)

指令格式: POP 目的 指令功能:把当前 SP 所指向的一个字送到目的操作数中

目的操作数可以是 16 位通用寄存器、段寄存器或存储单元,但不能是 CS 。每执行一次出栈操作,SP←SP+2,SP 向高地址方向移动,指向新的栈顶。

例:设 SS=2000H SP=40H AX=25FEH BX=3120H,依次执行指令:

PUSH BX PUSH AX POP BX

堆栈中的数据和 SP 的变化情况如图3.14所示。

4) 交换指令XCHG (Exchange)

指令格式:XCHG 目的, 源 指令功能: 源操作数和目的操作数相交换 注意:交换可以在寄存器之间、寄存器与存储器之间进行,但段寄存器不能作为操作数,也不能直接交换两个存储单元中的内容

例:设AX=2000H,DS=3000H,BX=1800H,(31A00H)=1995H,执行指令 XCHG AX,[BX+200H]:

源操作数物理地址=3000×10H+1800H+200H=31A00H,其中数据=1995H指令执行后,AX=1995H,(31A00H)=2000H 5) 表转换指令XLAT (Table Lookup-Translation)

指令格式:

XLAT 转换表 :“转换表”为表格首地址或 XLAT :“转换表”可省略不写

指令功能: 将 1 1 1 个字节从一种代码转换成另一种代码。

使用 XLAT 指令前,应建立一个表格,最多 256 个字节;且置:BX ← 转换表始址,AL ← 表头地址到要找的某项间的位移量;指令执行时,根据位移量从表中查到转换后的代码值,送入 AL 中。

整个过程见下面的例子。

例:下表是十进制数字 0~9 的 LED 七段码对照表,试用 XLAT 指令求数字 5 的七段码值。

先用 DB 伪指令建 1 1 1 个表格,存放 0~9 的七段码值。表格起始地址为 TABLE,数字 0~9 的七段码存放在相对于 TABLE 的位移量为 0~9 的单元中。 程序如下:

TABEL DB 40H, 79H, 24H, 30H, 19H ;七段码表格 DB 12H, 02H, 78H, 00H, 18H ... MOV AL, 5 ;AL ← 数字5的位移量 MOV BX, OFFSET TABLE ;BX ← 表格首地址 XLAT TABLE ;查表得AL=12H 2. 输入输出指令 (Input and Output) 1) IN 输入指令 (Input)

指令格式: ① IN AL, 端口地址 :AL←从 8 位端口读入 1 字节;或 IN AX, 端口地址 :AX←从 16 位端口的地址读入1 个字。属于直接端口寻址。 ② IN AL, DX :端口地址存放在 DX 中或 IN AX, DX 。属于间接端口寻址。

格式① ,端口地址(00~FFH)直接包含在 IN 指令里,共允许寻址 256 个端口。当端口地址大于 FFH 时,必须用格式②寻址,即先将端口号送入 DX ,再执行输入操作,DX 允许范围 0000~ FFFFH 。

例:用 IN 指令从输入端口读取数据的例子。

;以A~F打头的16进制数字出现在指令中时,前面一定要加一个数字0 IN AL, 0F1H ; AL←从F1H端口读入1字节 IN AX, 80H ; AL←80H端口内容 ; AH←81H端口内容 MOV DX, 310H ; 端口地址310H先送入DX IN AL, DX ; AL←310H端口内容

例: IN 指令也可以用符号表示地址。例如要求从一个模/数(A/D)转换器中读取 1 字节数字到 AL 中。

ATOD EQU 54H ;A/D转换器端口地址为54H ;EQU类似于C语言的#define预编译指令,不存在54H这一个内存单元 IN AL, ATOD ;将54H端口的内容读入AL中 2) OUT 输出指令 (Output)

指令格式: ① OUT 端口地址, AL :8 位端口← AL 内容;或 OUT 端口地址, AX :16 位端口 ← AX 内容; ② OUT DX,AL :DX=端口地址;或 OUT DX, AX

例:用 OUT 指令对输出端口进行操作的例子。

OUT 85H, AL ;85H端口←AL内容 MOV DX, 0FF4H ;DX指向端口0FF4H OUT DX, AL ;FF4H端口←AL内容 MOV DX, 300H ;DX指向16位端口 OUT DX, AX ;300H端口←AL内容 ;301H端口←AH内容 3. 地址目标传送指令 (Address Object Transfers)

这是一类专用于传送地址码的指令,可以用来传送操作数的段地址和偏移地址。

1) LEA 取有效地址指令 (Load Effective Address)

指令格式:LEA 目的,源 指令功能: 取源操作数地址的偏移量,送到目的操作数 源操作数必须是存储单元,目的操作数是一个除段寄存器之外的 16 位寄存器。

例 设:SI=1000H,DS=5000H,(51000H)=1234H,指令执行结果如下:

LEA BX, [SI] ;[SI]的偏移地址为1000H,BX←1000H MOV BX, [SI] ;偏移地址为1000H单元的内容为1234H ;指令执行后,BX←1234H ;MOV BX, OFFSET [SI] 这样写是语法错误

例 下面两条指令是等价的,它们都取(存储单元) TABLE 的偏移地址,送到 BX 中。 OFFSET 是一个预编译操作,必须在编译的时候要知道 TABLE 的偏移地址。

LEA BX, TABLE MOV BX, OFFSET TABLE

例 某数组含 20 个元素,每个元素占一个字节,序号为 0~19 。设 DI 指向数组开头处,如要把序号为 6 的元素的偏移地址送到 BX 中,不能直接用 MOV 指令来实现,因为 MOV 的 OFFSET 是一个预编译指令,必须要求后面的偏移地址可以在预编译时确定下来。需要使用下面指令:

LEA BX, 6[DI] 2) LDS 将双字指针送到寄存器和DS指令 (Load Pointer using DS)

指令格式:LDS 目的, 源 指令功能: 从源操作数指定的存储单元中,取出 1 1 1 个 4 字节地址指针,后两个字节(事先设置好的段地址)送进目的寄存器 DS ,前两个字节(事先设置好的偏移地址)送入指令中指定的目的寄存器中。

源操作数必须是存储单元,目的操作数必须是 16 位寄存器,常用 SI 寄存器,但不能用段寄存器。

例 设:DS=1200H,(12450H)=F346H,(12452H)=0A90H。执行指令:

LDS SI, [450H]

结果: 存储单元前 2 字节内容为 F346H ,SI←F346H,后 2 字节内容为 0A90H ,DS←0A90H 。

3) LES 将双字指针送到寄存器和ES指令 (Load Pointer using ES)

指令格式:LES 目的, 源 指令功能:与 LDS 指令的操作基本相同,但段寄存器为 ES,目的操作数常用 DI 。 例 设 DS=0100H,BX=0020H,(01020H)=0300H,(01022H)=0500H

LES DI, [BX]

存储单元前 2 字节内容为 0300H ,DI←0300H ,后 2 字节内容为 0500H ,ES←0500H 。

4. 标志传送指令(Flag Transfers) 1) LAHF 标志送到AH指令 (Load AH from Flags)

指令格式:LAHF 指令功能:把标志寄存器(16位)的 SF、ZF、AF、PF 和 CF 传送到 AH 寄存器的相应位。操作示意图如图。

2) SAHF AH送标志寄存器 (Store AH into Flags)

指令格式:SAHF 指令功能:把 AH 内容存入标志寄存器。指令功能与 LAHF 的操作相反。

3) PUSHF 标志入栈指令 (Push Flags onto Stack)

指令格式:PUSHF 指令功能:把整个标志寄存器(一个字)的内容推入堆栈,并使 SP←SP-2 。

4) POPF 标志出栈指令 (Pop Flags off Stack)

指令格式:POPF 指令功能:把 SP 所指的一个字,传送给标志寄存器 FLAGS,并使得 SP←SP+2 。

3.3.2 算术运算指令

算术运算指令可处理四种类型的数,表示方法见下表:

无符号二进制整数带符号二进制整数无符号压缩十进制整数(Packed Decimal)无符号非压缩十进制整数(Unpacked Decimal)

注意:

二进制数可以是 8 位或 16 位,如果是带符号数,则用补码表示。 可以写成十六进制。压缩十进制数:在一个字节中存放两个 BCD 码十进制数。非压缩十进制数:低半字节存放一个十进制数,高半字节为全零。

系统提供加、减、乘、除四种基本运算指令,还有各种调整指令,见表。

1. 加法指令 (Addition) 1) ADD 加法指令

指令格式:ADD 目的, 源 指令功能:目的←源+目的

2) ADC 带进位的加法指令 (Addition with Carry)

指令格式:ADC 目的,源 指令功能:目的←源+目的+CF 说明:

它们的源操作数可以是寄存器、存储器或立即数。目的操作数只能用寄存器和存储单元,存储单元可以有表3.2中所示的24种表示方法。源和目的操作数不能同时为存储器,而且它们的类型必须一致,即都是字节或字。如果有两个 32 的数相加,就先加低十六位数,然后连同进位参与到高十六位数的相加中。

例 列举上述两加法指令的实例,说明其用法。

ADD AL, 18H ;AL←AL+18H ADC BL, CL ;BL←BL+CL+CF ADC AX, DX ;AX←AX+DX+CF ADD AL, COST[BX] ;将AL内容和物理地址=DS:(COST+BX)的存储字节相加,结果送到AL中 ADD COST[BX], BL ;将BL与物理地址=DS:(COST+BX)的存储字节相加,结果留在该存储单元

它们影响标志位:CF、OF、PF、SF、ZF和AF。

例 试用加法指令对两个 8 位 16 进制数 5EH 和 3CH 求和,分析指令执行后对标志位的影响。程序如下:

MOV AL, 5EH ;AL=5EH (94) MOV BL, 3CH ;BL=3CH (60) ADD AL, BL ;结果AL=9AH

相加过程的算式表示: 运算后的标志位:

ZF=0,运算结果非0;AF=1,低 4 位向高 4 位有进位;CF=0,D7 位没有向前产生进位;SF=1,D7=1;PF=1,结果中有偶数个 1 ;OF=1,由两个数以及它们结果的符号决定,当两个加数符号相同,而结果的符号与之相反时,OF=1。如何对这些标志进行解释,取决于编写的程序,或者说是人为决定的。 3) INC 增量指令 (Increment)

指令格式:INC 目的 指令功能:目的 ← 目的 + 1 目的操作数可以是通用寄存器或内存(存储单元)。指令执行后影响 AF、OF、PF、SF和ZF,但进位标志 CF 不受影响。

例 INC指令的例子。

INC BL ;BL寄存器中内容增1 INC CX ;CX寄存器中内容增1 INC BYTE PTR[BX] ;内存字节单元内容增1 INC WORD PTR[BX] ;内存字单元内容增1

指令中只有一个操作数,如果是内存单元,则要用 PTR 操作符说明是字还是字节。

4) AAA 加法的ASCII调整指令 (ASCII Adjust for Addition)

指令格式:AAA 指令功能: 用 ADD 或 ADC 指令对两个非压缩 BCD 数或以 ASCII 码表示的十进制做加法后,结果在 AL 中,用此指令将 AL 中的结果进行调整。另外,若 AF=1 ,表示有进位,则进到 AH 中。

例 非压缩十进制数的 9 可表示成 0000 1001,5 则为 0000 0101,高 4 位均为 0 。设AH=0 ,若 AL= BCD 9,BL= BCD 5,求两数之和。运算过程: 例 求 ASCII 码表示的数 9(39H) 与 5(35H) 之和。设 AH=0 ,则运算过程: 如想把 AX 中的结果表示成 ASCII 码,只要在 AAA 指令后加一条指令:

OR AX, 3030H

就可使 AX 中的结果变成了ASCI码 3134H 。

5) DAA 加法的十进制调整指令 (Decimal Adjust for Addition)

指令格式:DAA 指令功能:对两个压缩 BCD 数相加后的结果(已在 AL 中)进行调整。 注意:要对 AL 中高半字节和低半字节分别进行调整。

例 若 AL=BCD 38,BL=BCD 15 ,求两数之和。运算过程: 例 若 AL=BCD 88,BL=BCD 49,求两数之和。运算过程:

2. 减法指令 (Subtraction) 1) SUB 减法指令 (Subtraction)

指令格式:SUB 目的, 源 指令功能:目的 ← 目的 - 源 例:

SUB AX, BX ;AX←AX-BX SUB DX, 1850H ;DX←DX-1850H SUB BL, [BX] ;BL中内容减去物理地址=DS:BX处的字节,结果存入BL 2) SBB 带借位的减法指令 (Subtract with Borrow)

指令格式:SBB 目的, 源 指令功能: 目的 ← 目的 - 源 - CF 例:

SBB AL, CL ;AL←AL-CL-CF

SBB主要用于多字节减法中。

3) DEC 减量指令 (Decrement)

指令格式:DEC 目的 指令功能:目的 ← 目的 - 1 例:

DEC BX ;BX←BX-1 DEC WORD PTR[BP] ;堆栈段中位于[BP]偏置处的字减1 ;DEC对内存单元进行操作, 用PTR说明目的数大小 4) NEG 取负指令 (Negate)

指令格式:NEG 目的 指令功能:目的 ← 0 - 目的 例:

NEG AX ;将AX中的数取负(改变数的符号位) NEG BYTE PTR[BX] ;对数据段中位于[BX]偏置处的字节取负 5) CMP 比较指令 (Compare)

指令格式:CMP 目的, 源 指令功能:目的 - 源 结果不会送到目的,仅反映在标志位上。

例:

CMP AL, 80H ;AL与80H作比较 CMP BX, DATA1 ;BX与数据段中偏移量为DATA1处的字比较

比较指令主要用在希望比较两个数的大小,而又不破坏原操作数的场合。

6) AAS 减法的ASCII调整指令 (ASCII Adjust for Subtraction)

指令格式:AAS 指令功能:在用 SUB 或 SBB 指令,对两个非压缩 BCD 数,或以 ASCII 码表示的十进制数相减后,对 AL 中所得结果进行调整,如有借位,则 CF 置 1 。

例 设 AL=BCD 3, CL=BCD 8,求两数之差。很显然,结果为 BCD 5,但要向高位借位。运算过程:

7) DAS 减法的十进制调整指令 (Decimal Adjust for Subtraction)

指令格式:DAS 指令功能:在用 SUB 或 SBB 指令,对两个压缩 BCD 数相减(结果已存在 AL )后,进行调整。同样,它也要对 AL 中高半字节和低半字节分别进行调整。

例 设 AL=BCD 56,CL=BCD 98,求两数之差。运算过程:

3. 乘法指令 (Multiply)

补码统一了有符号数和无符号数的加减法,但是乘除法却做不到。

1) MUL 无符号数乘法指令 (Multiply)

指令格式:MUL 源 指令功能:把源操作数和累加器中的数,都当成无符号数,然后将两数相乘。其中有一个操作数一定是累加器。

如果源操作数是 1 个字节,则 AX ← AL * 源若源操作数是 1 个字, 则 (DX,AX) ← AX * 源源操作数可以是寄存器或存储单元,不能是立即数当源操作数是存储单元时,应在操作数前加 BYTE 或 WORD ,说明是字节还是字。

例:

MUL DL ;AX←AL*DL MUL CX ;(DX,AX)←AX*CX MUL BYTE[SI] ;AX←AL*(内存中某字节), BYTE说明字节乘法 MUL WORD[BX] ;(DX,AX)←AX*(内存中某字), WORD说明字乘法

MUL 指令执行后影响 CF 和 OF 标志。如果结果的高半部分不为零,则 CF 、OF 均置 1 。否则,CF 、OF 均清 0 。通过测试这两个标志,可检测并去除结果中的无效前导零。

例:设 AL=55H,BL=14H,计算它们的积。只要执行下面这条指令:

MUL BL

结果:AX=06A4H。由于 AH=06H≠0 ,高位部分有效,所以置 CF=1 和 OF=1 。

2) IMUL 整数乘法指令 (Integer Multiply)

指令格式:IMUL 源 指令功能:把源操作数和累加器中的数,都作为带符号数,进行相乘。

存放结果的方式与 MUL 相同,最后给乘积赋予正确的符号。指令执行后,如果乘积的高半部分不是全 0 或全 1 ,则置 CF=1,OF=1 。 若结果高半部分为全 0 或全 1 ,则使 CF=0,OF=0。这样来决定是否需要保存积的高半部分。

例 设 AL=-28,BL=59,试计算它们的乘积。

IMUL BL ;AX=F98CH=-1652, CF=1, OF=1 3) AAM 乘法的ASCII调整指令 (ASCII Adjust for Multiply)

指令格式:AAM 指令功能:对存于 AL 的两个非压缩 BCD 数相乘的积进行调整,结果在 AX 中,高位放 AH ,低位在 AL 。两个 ASCII 码数相乘前,应先屏蔽掉每个数字的高半字节。 调整过程: 把 AL 内容除以 10 ,商放在 AH 中,余数在 AL 中。即

AH ← AL/10所得的商AL ← AL/10所得的余数

指令执行后,将影响 ZF、SF和PF 。

例 求两个非压缩十进制数 09 和 06 之乘积。可用如下指令实现:

MOV AL,09H ;置初值 MOV BL,06H MUL BL ;AL←09与06之乘积36H AAM ;调整得AH=05H(十位), AL=04H(个位)

最后,可在 AX 中得到正确结果 AX=0504H ,即BCD数 54 。

如果 AL 和 BL 中分别存放 9 和 6 的ASCII码,则求两数之积时要用以下指令实现:

AND AL,0FH ;屏蔽高半字节 AND BL,0FH MUL BL ;相乘 AAM ;调整

如要将结果转换成ASCII码,可再用指令 OR AX, 3030H 来实现,使 AX=3534H。

8086/8088 指令系统中,不允许采用压缩十进制数做乘法,乘法调整指令仅此一条。

4. 除法指令 (Division) 1) DIV 无符号数除法指令 (Division,unsigned)

指令格式:DIV 源 指令功能: 对两个无符号二进制数进行除法操作。

如果源操作数为字节,被除数必须事先放在 AX 中,并且有:( 16 16 16 位除以 8 8 8 位,结果可能是 16 16 16 位,AL放不下,会产生除法错)

AL ← AX/源(字节)的商AH ← AX/源(字节)的余数

要是被除数只有 8 位,必须把它放在 AL 中,并将 AH 清 0 ,然后相除。(8位除以8位)

若源操作数为字,被除数必须放在 DX 和 AX 中,并且有:( 32 32 32 位除以 16 16 16 位,结果可能是 32 32 32 位,AX放不下,会产生除法错)

AX ← (DX,AX)/源(字)的商DX ← (DX,AX)/源(字)的余数

要是被除数只有 16 位,除数也是 16 位,则必须将 16 位被除数事先放入 AX,再将 DX 清 0 (无符号扩展),然后相除。(16位除以16位)

与被除数和除数一样,商和余数都是无符号数。

2) IDIV 整数除法指令 (Integer Division)

指令格式:IDIV 源 指令功能:功能与 DIV 相同,但操作数都必须是带符号数,商和余数也都是带符号数,而且规定余数的符号和被除数的符号相同。

进行除法操作时,如果商超过了目标寄存器 AL 或 AX 所能存放数的范围,计算机会自动产生除法错中断,相当于执行了除数为 0 的运算,所得的商和余数都不确定。

例 两个无符号数 7A86H 和 04H 相除的商,应为 1EA1H 。若用 DIV 指令进行计算,即

MOV AX, 7A86H MOV BL, 04H DIV BL

这时,由于 BL 中的除数 04H 为字节,而被除数为字,商 1EA1H 大于 AL 中能存放的最大无符号数 FFH ,结果将产生除法错误中断。

对于带符号数除法IDIV指令,字节操作时要求被除数为 16 位;字操作时要求被除数为 32 位。如果被除数不满足这个条件,不能简单地将高位置 0 ,而应该先用下面的符号扩展指令 (Sign Extension)将被除数转换成除法指令所要求的格式,再执行除法指令。

3) CBW 把字节转换为字指令 (Convert Byte to Word)

指令格式:CBW 指令功能:把 AL 中字节的符号位扩充到 AH 的所有位,这时 AH 被称为是 AL 的符号扩充。

如果 AL 中的 D7=0 ,就将这个 0 扩展到 AH 中去,使 AH=00H ,即 若 AL 中的 D7=1 ,则将这个 1 扩展到 AH 中去,使 AH=FFH ,即

CBW 指令执行后,不影响标志位。

4) CWD 把字转换成双字指令 (Convert Word to Double Word)

指令格式:CWD 指令功能:把 AX 中字的符号位扩充到 DX 寄存器的所有位中去。

若 AX 中的 D15=0 ,则 DX←0000H ,即 若 AX 中的 D15=1 ,则 DX←FFFFH,即

注意,CBW和CWD是针对有符号数除法说的,无符号数除法直接扩充零即可。

例 编程求 -38/3 的商和余数。

MOV AL, 11011010B ;被除数=-38 MOV CH, 00000011B ;除数+3 CBW ;将AL符号扩展到AH中, 使AX=1111 1111 1101 1010B IDIV CH ;AX/CH 16位除以8位 ;AL=1111 0100B = -12 (商) ;AH=1111 1110B = -2(余数) 5) AAD 除法的ASCII调整指令 (ASCII Adjust for Division)

指令格式:AAD 指令功能:在做除法前把 BCD 码转换成二进制数。 前面介绍的调整指令,都是在用加法、减法和乘法指令后,紧跟着用一条 AAA、AAS或AAM 指令,对运算结果进行调整。而除法的 ASCII 调整指令不同,它是在除法之前进行的。

在把 AX 中的两位非压缩 BCD 数除以一个非压缩 BCD 数之前,先用 AAD 指令,把 AX 中的被除数调整成二进制数,并存入 AL ,然后才能用 DIV 指令进行运算。调整的过程为:

AL←AH×10+ALAH←00

本指令根据 AL 寄存器的结果影响 SF、ZF和PF 。

例 设 AX 中存有两个非压缩 BCD 数 0307H ,即十进制数 37 ,BL 中存有一个非压缩 BCD 数05H,若要完成 AX/BL 的运算,可用以下指令:

AAD DIV BL

第1条指令先将 AX 中的两个 BCD 数转换成二进制数,03×10+7=37=25H,并将 25H→AL ,显然经调整后的被除数 25H 才真正代表 37 ,再用 DIV 指令做除法,可得正确的结果:

AL=7(商)AH=2(余数) 3.3.3 逻辑运算和移位指令

逻辑运算和移位指令,对字节或字操作数进行按位操作,见表3.7。

1. 逻辑运算指令 (Logical Operations) 1) NOT 取反指令 (Logical Not)

指令格式:NOT 目的 指令功能:目的←目的取反 目的操作数可以是 8 位或 16 位寄存器或存储器,对存储器操作数要说明类型。

例 NOT 指令只有一个操作数,介绍几种用法。

NOT AX ;AX←AX取反 NOT BL ;BL←BL取反 NOT BYTE PTR[BX] ;对存储器字节单元内容取反后送回该单元

以下为双操作数指令。源操作数可以是 8 或 16 位立即数、寄存器、存储器,目的操作数只能是寄存器或存储器,两个操作数不能同时为存储器。

指令执行后,均将 CF 和 OF 清 0 0 0 ,ZF、SF 和 PF 反映操作结果,AF 未定义,源操作数不变。

2) AND 逻辑与指令 (Logical AND)

指令格式:AND 目的, 源 指令功能:目的←目的∧源 主要用于使操作数的某些位保留(和“1”相与),而使某些位清除(和“0”相与)。

例 设 AX 中是数字 5 和 8 的 ASCII 码,即 AX=3538H ,将它们转换成 BCD 码,结果仍放回AX 。指令如下:

AND AX, 0F0FH ;AX←0508H, 屏蔽高4位, 截得低4位 3) OR 逻辑或指令 (Logical OR)

指令格式:OR 目的, 源 指令功能:目的←目的∨源 主要用于使操作数的某些位保留(和“0”相或),而使某些位置1(和“1”相或)。 例 设 AX 中存有两个 BCD 数 0508H,要将它们分别转换成 ASCII码 ,结果仍在 AX 中。可用如下指令实现:

OR AX, 3030H ;AX←3538H 4) XOR 异或操作指令 (Exclusive OR)

指令格式:XOR 目的, 源 指令功能:对两个操作数进行按位逻辑异或运算,结果送回目的操作数,即目的←目的 XOR 源 用于使操作数的某些位保留(和“0”相异或),而使某些位取反(和“1”相异或)。

例 若 AL 中存有某外设端口的状态信息,其中 D1 位控制扬声器发声,要求该位在 0 和 1 之间来回变化,原来是 1 变成 0 ,原来是 0 变成 1 ,其余各位保留不变。可用以下指令实现:

XOR AL, 00000010B 5) TEST 测试指令 (Test)

指令格式:TEST 目的, 源 指令功能:目的∧源,并修改标志位,但不回送结果 它常用在要检测某些条件是否满足,但又不希望改变原有操作数的情况下。

例 设 AL 寄存器中存有报警标志。若 D7=1 ,表示温度报警,程序要转到温度报警处理程序T_ALARM ;D6=1,则转压力报警程序 P_ALARM 。为此,可用 TEST 指令来实现这种功能:

TEST AL, 80H ;查AL的D7=1? JNZ T_ALARM ;是1(非零),则转温度报警程序 TEST AL, 40H ;D7=0,D6=1? JNZ P_ALARM ;是1,转压力报警

其中,JNZ 为条件转移指令,表示结果非 0 (ZF=1)则转移。

2. 算术逻辑移位指令 (Shift Arithmetic and Shift Logical)

可对寄存器或存储器中的字或字节的各位进行算术移位或逻辑移位,移动的次数由指令中的计数值决定,如图3.17。

1) SAL 算术左移指令 (Shift Arithmetic Left)

指令格式:SAL 目的, 计数值

2) SHL 逻辑左移指令 (Shift Logic Left)

指令格式:SHL 目的, 计数值 指令功能:以上两条指令的功能完全相同。均将目的操作数的各位左移,每移一次,最低位 LSB 补 0 0 0 ,最高位 MSB 进标志位 CF 。移动一次,相当于将目的操作数乘以 2 。

计数值表示移位次数,可以是 1 。若大于 1 ,则用 CL 存放,需要事先将次数存入 CL 。移位次数最多为 31 (即 00011111B )。

MOV AH, 00000110B ;AH=06H SAL AH, 1 ;将AH内容左移一位后, AH=0CH MOV CL, 03H ;CL←移位次数3 SHL DI, CL ;将DI内容左移3次 SAL BYTE PTR[BX], 1 ;将内存单元字节左移1位 3) SHR 逻辑右移指令 (Shift Logic Right)

指令格式:SHR 目的, 计数值 指令功能:使目的操作数各位右移,每移一次,最低位进入 CF ,最高位补 0 。

右移次数由计数值决定,同 SAL/SHL 指令一样。若目的操作数为无符号数,每右移一次,使目的操作数除以2。

例 用右移的方法做除法 133/8=16…5 ,即:

MOV AL, 10000101B ;AL=133 MOV CL, 03H ;CL=移位次数 SHR AL, CL ;右移3次,AL=10H,余数5丢失 4) SAR 算术右移指令 (Shift Arithmetic Right)

指令格式:SAR 目的, 计数值 指令功能:每移位一次,最低位进入 CF ,但最高位(即符号位)保持不变,而不是补0。相当于对带符号数进行除2操作。

例 用SAR指令计算 -128/8=-16 的程序段如下:

MOV AL, 10000000B ;AL=-128 MOV CL, 03H ;右移次数为3 SAR AL, CL ;算术右移3次后, AL=0FH=16 3. 循环移位指令 (Rotate)

算术逻辑移位指令,移出的操作数数位均丢失。循环移位指令则把数位从操作数的一端移到其另一端,从操作数中移走的位不会丢失。

1) ROL 循环左移指令 (Rotate Left)

指令格式:ROL 目的, 计数值

2) ROR 循环右移指令 (Rotate Right)

指令格式:ROR 目的, 计数值 例:

ROL BX, CL ;将BX中的数, 不带进位位左移规定次数 ROR WORD PTR[SI], 1 ;将内存单元的字, 不带进位右移1次 3) RCL 通过进位位循环左移 (Rotate through Carry Left)

指令格式:RCL 目的, 计数值

4) RCR 通过进位位循环右移 (Rotate through Carry Right)

指令格式:RCR 目的, 计数值

目的操作数可以是 8/16 位的寄存器操作数或内存操作数,计数值含义同上,即 1 或由 CL 指定。

ROL 和 ROR 为小循环移位指令,没有把 CF 包含在循环中;RCL 和 RCR 为大循环指令,把 CF 作为整个循环的一部分参加循环移位。CF 的值由最后一次被移出的值决定。

例 设 CF=1,AL=1011 0100B,

若执行指令 ROL AL, 1,则 AL=0110 1001B,CF=1,OF=1 ;若执行指令 ROR AL, 1 ,则 AL=0101 1010B,CF=0,OF=1;若执行指令 RCR AL, 1,则 AL=1101 1010B,CF=0,OF=0;若执行指令 MOV CL, 3 和 RCL AL, CL ,则 AL=1010 0110B,CF=1,OF 不确定。

总的来说,移位指令 shl, sal, shr, sar; rol, ror, rcl, rcr 指令的格式都是一致的,都是 指令 目的, 1 或 CL 。

3.3.4 字符串处理指令

字符串是指一系列存放在存储器中的字或字节数据。

使用字符串操作指令时,可用指令中的源串和目的串名(即操作数)来表明是字节还是字,也可在指令助记符后加 B 说明是字节,加 W 说明是字操作,每种指令都有3种格式。 5条1字节字符串操作指令见表3.8。 字符串指令执行时,必须遵守以下的隐含约定:

源串位于数据段中,源串字符的始址(或末址)为 DS:SI 。目的串位于附加段中,目的串字符的始址(或末址)为 ES:DI 。每执行一次字符串指令,指针 SI 和 DI 会自动修改,指向下一待操作单元。DF 标志控制字符串处理的方向: DF=0 递增。执行一次字节串操作,SI 、DI 各 +1 ;字串操作,SI 和 DI 各 +2;DF=1 递减。执行一次字节串操作,SI、DI 各 -1 ;字串操作,SI 和 DI 各 -2 。STD 指令使 DF=1,CLD 指令使 DF=0 。 CX=要处理的字符串长度(字节或字数)。

为加快串运算指令的执行速度,可在基本指令前加重复前缀,使数据串指令重复执行。每重复执行一次,SI 和 DI 都根据方向标志自动修改,CX 的值则自动减 1 。能与基本指令配合使用的重复前缀有:

REP 无条件重复 (Repeat)REPE/REPZ 相等/结果为零则重复 (Repeat while Equal/Zero)REPNE/REPNZ 不相等/结果非零则重复 (Repeat while Not Equal/Not Zero) 1. MOVS字符串传送指令 (Move String)

指令格式:MOVS 目的串, 源串 指令功能:把源串中的一个字节或字,传送到目的串中且自动修改指针 SI 和 DI 。 利用 MOVS 指令,能很方便地将数据从内存的某一地址(源地址)传送到另一个地址(目的地址),还能自动修改源和目的地址;若使用重复前缀,可用一条指令传送一批数据。

例 要求把数据段中以 SRC_MESS 为偏移地址的一串字符 “HELLO!”,传送到附加段中以 NEW_LOC 开始的单元中。实现该操作的程序如下: 比较发现,使用有重复前缀 REP 的 MOVSB 指令,程序更简洁。

2. CMPS 字符串比较指令 (Compare String)

指令格式:CMPS 目的串, 源串 指令功能:将源串中数据减去目的串数据,但不改变两数据串的原始值,结果反映在标志位上。操作后源串和目的串指针会自动修改。

常用此指令来比较两个串是否相同,并由其后的条件转移指令,根据 CMPS 执行后的标志位值,决定程序的转向。

CMPS 指令前可加重复前缀, 下面每两条指令功能相同:

REPE CMPS;CX≠0 (未比完)且串相等时重复比较REPZ CMPS;ZF=1(两串相等),则重复比较REPNE CMPS ;若CX≠0(串没有结束)和串不相等重复比较REPNZ CMPS ;ZF=0 ,则重复比较

例 比较两个字符串,一个是在程序中设定的口令串 PASSWORD,另一个是从键盘输入的字符串 IN-WORD ,若输入串与口令串相同,程序开始执行。否则程序驱动扬声器发声,警告用户口令不符,拒绝往下执行。这可以用 CMPS 指令来实现,有关程序段如下:

DATA SEGMENT ;数据段 PASSWORD DB '8086 CPUI' ;口令串 IN_WORD DB '8088 CPU' ;从键盘输入的串 COUNT EQU 8 ;串长度 DATA ENDS CODE SEGMENT ;代码段 ASSUME DS:DATA, ES:DATA ... LEA SI, PASSWORD ;源串指针 LEA DI, IN_WORD ;目的串指针 MOV CX, COUNT ;串长度 CLD ;地址增 REPZ CMPSB ;CX≠0且串相等时重复比较 JNE SOUND ;若不相等,转发声程序 OK: ... ;比完且相等,往下执行 ... SOUND: ... ;使PC机扬声器发声 ... ;并退出 CODE ENDS 3. SCAS 字符串扫描指令 (Scan String)

指令格式:SCAS 目的串 指令功能:从 AL (字节操作)或 AX (字操作)寄存器的内容,减去 ES:DI 为指针的目的串元素,结果反映在标志位上,但不改变源操作数。串操作后目的串指针 DI 会自动修改。

利用 SCAS 指令,可在内存中搜索所需要的数据(关键字)。指令执行前,必须事先将它存在 AL (字节)或 AX (字)中。SCAS 指令前也可加重复前缀。

例 在某字符串中搜寻字符 A 。若有,搜索次数送到 BX ;若无,将 BX 清 0 。设字符串始址 STRING 的偏址为 0 ,字符串长度为 CX 。程序段如下:

MOV DI, OFFSET STRING ;DI=字符串偏移地址 MOV CX, COUNT ;CX=字符串长度 MOV AL, 'A' ;AL=关键字A的ASCII码 CLD ;清方向标志 REPNE SCASB ;CX≠0(没查完)和 ;ZF=0(不相等)时重复 JZ FIND ;若ZF=1,已搜到,转出 MOV DI, 0 ;若ZF=0,没搜到,DI←0 FIND: MOV BX, DI ;BX←搜索次数 HLT ;停机 4. LODS 数据串装入指令(Load String)

指令格式:LODS 源串 指令功能:把数据段中以 SI 作为指针的串元素,传送到 AL (字节操作)或 AX (字操作)中,同时修改 SI 。

为该指令加重复前缀没有意义。因为每重复传送一次数据,累加器中的内容就被改写,执行重复传送操作后,只能保留最后写入的那个数据。

5. STOS 数据串存储指令 (Store String)

指令格式:STOS 目的串 指令功能:将累加器 AL 或 AX 中的一个字节或字,传送到以 ES:DI 为目标指针的目的串中,同时修改 DI ,以指向串中的下一个单元。

STOS 指令与 REP 重复前缀连用,即执行指令 REP STOS ,能方便地用累加器中的一个常数,对一个数据串进行初始化。例如,初始化为全 0 的串。

例 数据段中有个数据块, 存有 8 位带符号数,始址BLOCK ,要求将正、负数分开,正数送到附加段中始址为 PLUS_DATA 的缓冲区,负数送到附加段中始址为 MINUS_DATA 的缓冲区。 数据块可看成一个数据串,用 SI 作源串指针,DI 和 BX 作正、负数目的缓冲区指针,CX 控制循环次数。程序段如下:

START: MOV SI, OFFSET BLOCK ;SI为源串指针 MOV DI, OFFSET PLUS_DATA ;DI为正数目的区指针 MOV BX, OFFSET MINUS_DATA ;BX为负数目的区指针 MOV CX, COUNT ;CX放循环次数 CLD GOON: LODS BLOCK ;AL←取源串的一个字节 TEST AL, 80H ;是负数? JNZ MINUS ;是,转MINUS STOSB ;非负数,将字节送正数区 JMP AGAIN ;处理下一个字节 MINUS: XCHG BX, DI ;交换正负数指针 STOSB ;负数送入负数区 XCHG BX, DI ;恢复正负数指针 AGAIN: DEC CX ;次数减1 JNZ GOON ;未处理完,继续传送 HLT ;已完,停机

程序中,正负数的存储均使用 STOSB 指令,该指令必须以 SI 为源指针,DI 为目的指针。但存储负数时,负数区的目的指针在 BX 中,因此要用 XCHG 指令将 BX 内容送进 DI ,让 DI 指向负数区,同时也把 DI 中的正数区目的指针保护起来。

执行 STOSB 指令后,再用 XCHG 指令将 BX 和 DI 交换回来,以便下次转回 GOON 标号后,LODS 指令仍能正确执行。

3.3.5 控制转移指令 1. 无条件转移和过程调用指令 (Unconditional Transfer and Call) 1) JMP 无条件转移指令 (Jump)

指令格式:JMP 目的 指令功能: 无条件地转移到目的地址去执行。 这类指令又分成两种类型:

段内转移,或近(NEAR)转移。转移指令的目的地址和 JMP 指令在同一代码段中,转移时仅改变 IP 的内容,段地址 CS 的值不变。段间转移,又称远(FAR)转移。转移指令的目的地址和 JMP 指令不在同一段中,转移时,CS 和 IP 的值都要改变,程序要转移到另一个代码段去执行。

就转移地址提供的方式而言,又可分为两种方式:

直接转移。在指令码中直接给出转移的目的地址,目的操作数用一个标号来表示。它又可分为段内直接转移和段间直接转移。间接转移。目的地址包含在某个 16 位寄存器或存储单元中,CPU必须根据寄存器或存储器寻址方式,间接地求出转移地址。同样,这种转移类型又可分为段内间接转移和段间间接转移。

所以无条件转移指令可分成段内直接转移 SHORT/NEAR PTR 、段内间接转移 WORD PTR 、段间直接转移 FAR PTR 和段间间接转移 DWORD PTR 四种不同类型和方式,如表所示。

(1) 段内直接转移指令

指令格式:

JMP SHORT 标号 立即短转移JMP NEAR PTR 标号 (或JMP 标号) 立即近转移

段内相对转移指令,目的操作数均用标号表示。

转向的有效地址= IP+8位/16位位移量(DISP) 。若转移范围在 -128~+127 字节内,称为短转移,指令中只需要用8位位移量,在标号前加说明符SHORT。若位移量是 16 位,称为近转移,目的地址与当前IP的距离在 -32768~+32767 字节之间。可加说明符NEAR PTR ,也可省略。这类指令用得最多。

例 给出一个含有一条无条件转移指令的简单程序的列表文件,它是由汇编语言源程序经汇编程序翻译后产生的。即

(2) 段内间接转移指令

转向的 16 位地址存放在一个 16 位寄存器或字存储器单元中。

用寄存器寻址的段内转移指令,转向的地址存放在寄存器中,执行操作:IP←寄存器内容 。 例:JMP BX,若指令执行前,BX=4500H ;指令执行时,IP←4500H ,程序转到代码段内偏移地址为 4500H 处执行。

用存储器间接寻址的段内转移指令,先计算出存储单元的物理地址,再从中取一个字送到 IP 。即IP←字存储单元内容。 例:JMP WORD PTR 5[BX] :WORD PTR 说明是字操作:

设指令执行前 DS=2000H, BX=100H, (20105H)=4F0H则指令执行后 IP=(20000H+100H+5H) = (20105H)=4F0H ,转到段内 IP=4F0H 处执行。 (3) 段间直接(远)转移指令

指令中用远标号直接给出转向的 CS:IP ,程序从一个代码段转到另一个代码段。例:

JMP FAR PTR PROG_F

FAR PTR 说明 PROG_F 为远标号。指令执行的操作:

IP←PROG_F 的段内偏移量CS←PROG_F 所在段的段地址设标号 PROG_F 的逻辑地址=3500H:080AH,则:指令执行后,IP=080AH,CS=3500H,程序转到 3500:080AH 处执行。 (4) 段间间接转移指令

操作数为存储器(这里不存在寄存器的使用),要转移的目标地址 CS:IP 存放在存储器中,需要加说明符 DWORD PTR,表示转向地址需要双字。

例:JMP DWORD PTR [SI+0125H],设指令执行前,CS=1200H,IP=05H,DS=2500H,SI=1300H;内存单元 (26425H)=4500H,(26427H)=32F0H,指令中的位移量 DISP=0125H。执行过程如图:

2) 过程调用和返回指令 (Call and Return)

把某些能完成特定功能又常用的程序段,编写成独立模块,称为过程(Procedure)或子程序(Subroutine)。在主程序中用 CALL 语句调用这些过程,格式为:CALL 过程名 。

过程以 PROC 开头,ENDP 结束。过程中要安排一条返回指令 RET ,过程执行完后能正确返回主程序。若在过程运行中又调用另一过程,称为过程嵌套。

主程序和过程在同一代码段,称为近调用,不在同一段则称为远调用。过程调用的寻址方式与转移指令类似,但没有段内短调用。由于调用结束后需返回原程序继续运行,要执行保护和恢复返址操作,比转移JMP更复杂。

CALL 指令分两步执行:

第一步:返址入栈,将 CALL 下面指令的地址推入堆栈: 近调用执行的操作:SP←SP-2 ,IP 入栈远调用执行的操作:SP←SP-2 ,CS 入栈;SP←SP-2 ,IP 入栈 第二步:转到子程序入口执行相应的子程序。入口地址由 CALL 指令的目的操作数提供,寻址方法与 JMP指令类似。第三步,执行过程中的 RET 指令时,从栈中弹出返址,使程序返回主程序继续执行。也有两种情况: 从近过程返回,从栈中弹出 1 1 1 个字→ IP ,并且使 SP←SP+2从远过程返回,先从栈中弹出 1 1 1 个字→ IP ,并且使 SP←SP+2 ;再弹出 1 1 1 个字→ CS ,并使SP←SP+2

下面举例说明 CALL 和 RET 指令的 4 种寻址方式。

(1) 段内直接调用和返回

例:CALL PROG-N ;PROG-N是一个近标号。该指令含 3 3 3 个字节,编码格式为: 设调用前:CS:IP=2000H:1050H,SS:SP=5000H:0100H,PROG-N 与 CALL 指令之间的字节距离等于 1234H (即 DISP=1234H )。则执行CALL指令的过程:

SP←SP-2,即新的 SP=0100H-2=00FEH, 返回地址的 IP 入栈。由于存放 CALL 指令的内存首地址为CS:IP=2000:1050H,该指令占 3 字节,所以返回地址为 2000:1053H,即 IP=1053H 。于是 1053H 被推入堆栈。根据当前 IP 值和位移量 DISP 计算出新的 IP 值,作为子程序的入口地址,即 IP = IP+DISP = 1053H+1234H = 2287H。程序转到本代码段中偏移地址为2287H处执行

指令 CALL PROG_N 的执行过程如图:

RET 指令的寻址方式与 CALL 一样,在本例中也是段内直接调用。执行过程如下:

IP←(SP和SP+1) 单元内容 即返址 IP=1053H 从栈中弹出SP←SP+2,SP=00FEH+2=0100H,即恢复原 SP

结果,返回 CALL 下面的那条指令,即从 2000:1053 处继续执行程序,如上图。

(2) 段内间接调用和返回

例 下面是两条段内间接调用指令的例子,返址在寄存器或内存中。

CALL BX CALL WORD PTR[BX+SI]

它们执行的操作分三步,前两步与直接调用相同,第三步不同,具体为:

SP←SP-2IP 入栈IP←EA ,计算出目的地址的有效地址 EA ,送入 IP ,以此转移。

设:DS=1000H, BX=200H, SI=300H, (10500H)=3210H

CALL BX

转移地址在BX中,此调用指令执行后,IP←0200H,转到段内偏移地址为 0200H 处执行。

CALL WORD PTR[BX+SI]

子程序入口地址在内存字单元中,其值为 (16×DS+BX+SI) = (10000H+0200H+0300H) = (10500H) = 3210H , 即 EA=3210H 。此指令执行后,IP←3210H ,转到段内偏移地址为3210H 处执行。对应的RET指令执行的操作与段内直接过程的返回指令类似。

(3) 段间直接调用

例 CALL FAR PTR PROG_F ;PROG_F是一个远标号。该指令含 5 个字节,编码格式为:

设调用前:CS:IP=1000:205AH,SS:SP=2500:0050H ,标号 PROG-F 所在单元的地址指针CS:IP=3000:0500H 。

存放CALL指令的内存首址为 1000:205AH ,由于该指令长度为5个字节,所以返回地址应为 1000:205FH 。执行远调用CALL指令的过程如图3.22所示,具体为:

SP←SP-2 即 SP=0050H-2=004EHCS 入栈 即 CS=1000H 入栈SP←SP-2 即 SP←004CHIP 入栈 即 IP=205FH 入栈转子程序入口,将 PROG-F 的段地址和偏移地址送 CS:IP。即 CS←3000H,IP←0500H 。

执行子程序 PROG-F 。过程 PROG-F 中的 RET 指令的寻址方式也是段间直接调用,返回时执行的操作为:

SP←SP+2 即 SP←004C+2=004EHIP←栈中内容,即 IP←205FHSP←SP+2 ,SP←004EH+2=0050HCS←栈中内容,CS←1000H

所以程序转返回地址 CS:IP=1000:205FH 处执行。

(4) 段间间接调用

操作数必须是存储单元,从该单元开始存放的双字表示过程的入口地址,指令中用 DWORD PTR 说明是对存储单元进行双字操作。

例 CALL DWORD PTR[BX]

设调用前,DS=1000H,BX=200H,(10200H)=31F4H,(10202)=5200H 。执行时先将返址的 CS:IP 推入堆栈,再转向过程入口。指令中操作数地址= DS×16+BX=10000H+200H=10200H 从中取得的双字就是过程入口地址,即: IP←(10200H) 即 IP=31F4HCS←(10202H) 即 CS=5200H

8086还有另一种带参数的返回指令,形式为:

RET n

n 称为弹出值,它让CPU在弹出返回地址后,再从堆栈中弹出 n 个字节的数据,也就是让 SP 再加上 n 。n可以是0000~FFFFH范围内的任何一个偶数。 例如,指令 RET 8 ,表示从堆栈中弹出地址后,再使 SP 的值加上 8 。

2. 条件转移指令 (Conditional Transfer)

将上条指令执行后的状态标志,作为测试条件,来决定是否转移。当条件成立,程序转向指令中给出的目的地址去执行;否则,仍顺序执行。

条件转移均为段内短转移,转移指令与目的地址必须在同一代码段中。转移距离范围为 -128~+127 字节。8 位偏移量需用符号扩展法扩展到 16 位后才能与 IP 相加。

在指令中,目的地址均用标号表示,指令格式: 条件操作符 标号。条件转移指令共18条,归类成直接标志转移和间接标志转移两大类。

1) 直接标志转移指令

助记符中直接给出标志状态测试条件,以 CF、ZF、SF、OF 和 PF 等5个标志的10种状态为判断条件,形成10条指令,如表。有的指令有两种助记符,代表同样的指令,如JZ/JE。

例 求 AL 和 BL 中的两数之和,若有进位,则 AH 置1,否则 AH 清0。程序如下:

ADD AL, BL ;两数相加 JC NEXT ;若有进位,转NEXT MOV AH, 0 ;无进位,AH清0 JMP EXIT ;往下执行 NEXT: MOV AH, 1 ;有进位,AH置1 EXIT: … ;程序继续进行 2) 间接标志转移 ★★

不在指令助记符中直接给出标志状态位的测试条件,但仍以某一个或几个标志的状态组合为测试条件,若条件成立则转移,否则顺序往下执行。

间接标志转移指令共有8条,列于表中。每条指令都有两种不同的助记符。在无符号数比较测试指令中,指令助记符中的“A”是英文Above的缩写,表示“高于”之意,“B”是英文Below的缩写,表示“低于”之意。 例 设 AL=F0H,BL=35H ,执行指令

CMP AL, BL ;AL-BL JAE NEXT ;AL大于等于BL,则转到NEXT

JAE/JNB 根据 CF 标志是否为0决定转移。若 CF=0 ,即无进位,则转移,这与直接标志转移指令中的 JNC 功能完全一样。同样,JB/JNAE 与 JC 指令的功能相同。

带符号数进行比较时,不能仅根据 SF 或 OF 标志来判定,而要将它们组合起来考虑。指令助记符中,“G”(Great than)表示“大于”,“L”(Less than)表示“小于”。

例 设某学生的英语成绩已存放在 AL 中,如低于 60 分,打印F(FAIL);高于或等于 85 分,打印G(GOOD);在 60~84 分之间,打印P(PASS)。程序为

CMP AL, 60 ;与60分比较 JB FAIL ;


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3