提示: 可以结合Ctrl + F 更好寻找知识点
指令格式包括操作码和操作数(或地址)两部分,根据操作码所制定的功能去寻咋后操作数所在地址的方式就是寻址方式。8086/8088的寻址方式包括两种:
所有操作数的流向都是由源到目标,在指令汇编语言格式的操作数区域中都是规定自右向左。
源和目标可以是寄存器或存储器,但不能同时使存储器(除个别串操作指令MOVS外)
注意寄存器是在CPU内部,而存储器指硬盘等CPU外部的存储设备
DS —— 数据段寄存器
DISP ——位移值
将立即数传送到目标寄存器或存储器中,操作数就在指令中,当执行指令时,CPU直接从紧跟着指令代码的后续地址单元中(经队列缓冲器取得该立即数),而不必执行总线周期。立即数可以是8位,也可以是16位;并规定只能是正数类型。这种寻址方式一般用于给寄存器赋初值,指令执行速度快。
示例:
MOV AX,‘AB’—— 长度十六位——把ASCII码BA(4241H)传送到AX中
(‘AB’在内存中的数据结构为ASCII码BA)
字节序用于处理器读取数据时,因为计算机电路是先处理低位子节,效率比较高,所以计算机内部处理都是小段字节序。但因为人类习惯大端子节序,所以除了计算机的内部处理,网络传输与文件传输是大端子节序。
小端字节序:低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;
大端字节序:高字节数据存放在内存低地址处,低字节数据存放在内存高地址处。
例如:
*
队列缓冲器在第二章的8086/8088CPU的内部功能结构介绍过,位于BIU(总线接口单元)中,可实现并行重叠操作
总线周期:T1传地址、T2输出状态、T3传出数据、T4CPU采集数据。
总线周期是微处理器与存储器或I/O设备接口之间进行数据传送时,所需要的一个基准时间段。
寄存器寻址是最通用的数据寻址方式。
对于十六位操作数来说,寄存器可以为八个十六位通用寄存器,对于八位操作数来说,只能是那八个八位寄存器。
源操作数或/和目的操作数都可以采用寄存器寻址方法。这种寻址方式指令长度短,操作数在CPU内部,不需要总线周期,所以速度快。注意使用时源与目标操作数应有相同的数据类型长度。
注意,代码段寄存器不能用MOV指令来改变,因为若只改变CS而IP为未知数,则下一条指令的地址将是不确定的,这可能会引起系统运行的紊乱。
下面讨论存储器寻址的各种寻找方式。
当CPU寻找存储器操作数时,必须先经总线接口单元BIU的总线控制逻辑电路进行存取。
8086/8088 CPU所寻址的操作数地址的有效地址EA,是一个无符号的16位地址码,表示操作数所在段的首地址与操作数地址之间的子节距离。所以它实际上是一个相对地址。EA的值由汇编程序根据指令所采用的寻址方式自动计算得出。计算EA的通式为:
EA=基址值(BX或BP)+ 变址值(SI或DI)+位移量DISP
BX 基址寄存器 BP 基址指针寄存器
SI 源变址寄存器 DI 目标变址寄存器
一个寄存器,一个变量(数据)
直接数据寻址包括:直接寻址和位移寻址。
以上两种方式都是把位移量加到默认的数据段地址或其他段地址上形成的,但直接寻址的指令为4B长,位移寻址的指令为3B长。
汇编语言中很少采用绝对偏移地址通常采用符号地址,以下两个分别是绝对偏移地址和符号地址
MOV AX, [1680H]
把数据段存储器地址1680H和1681H两单元的字内容复制到AX中
MOV AX, NUMBER
把数据段存储器地址NUMBER中的字内容复制到AX中
寄存器间接寻址的操作数一定是在存储器中
指令中的方括号[]在汇编语言中表示间接寻址
MOV [SI],BL 把寄存器BL中的内容复制到数据段以SI作为有效地址的存储单元
MOV [BP],CL 把寄存器CL中的内容复制到堆栈段以BP作为有效地址的存储单元中
系统把由BP寻址的数据默认为在堆栈段中,其他间接寻址方式如BX、DI、SI寻址存储器均默认为数据段
MOV [SI],[BX] 除数据串操作指令外,不允许由存储器到存储器到传送。
在使用寄存器间接寻址时,要注意在某些情况下,要求用指定的类型运算伪指令BYTE PTR、WORD PTR或DWORD PTR 来规定传送数据的长度。
8086CPU的指令,可以处理两种尺寸的数据,byte(字节)和word(字)。所以在机器指令中要指明,指令进行的是字操作还是字节操作。有以下几种方法
(1)通过寄存器名指明要处理的数据的尺寸。
(2)没有寄存器指明的借助word ptr、byte ptr或dword ptr来指定(DWORD PTR 是双字)
(3)有些指令默认了访问的是字单元还是字节单元,比如,push指令只进行字操作。
基址加变址寻址类似于间接寻址,他也是间接的寻址存储器数据。其操作数的有效地址EA是一个基址寄存器(BX或BP)的内容与一个变址寄存器(SI或DI)的内容之和。
MOV DX,[ BP + SI ] 时,若BP=2000H,SI=0300H,SS=1000H,则指令执行后,将把堆栈段中12300H单元的字数据传送到DX寄存器。
同样注意,系统把由BP寻址的数据默认为在堆栈段中,其他间接寻址方式均默认为数据段。
寄存器相对寻址是带有位移量DISP的基址或变址寄存器(BX、BP或DI、SI)寻址。
MOV AX,[SI + 4000H]
相对基址加变址寻址是用基址、变址与位移量3个分量之和形成有效地址 的寻址方式
MOV FILE[BP+DI+2],DL 将DL存入以BP+DI+2之和作为有效地址的堆栈段存储单元。
该方式即转移类指令(转移指令JMP和调用指令CALL)的寻址方式,这种寻址方式最终是要确定一条指令的地址。
具体内容在后面详述
这类指令可完成寄存器与寄存器之间、寄存器与存储器之间以及寄存器与I/O端口之间的子节或字传送,除了SAHF和POPF指令对标志位有影响外,,这类指令所具有的共同特点是不影响标志寄存器的内容。
MOV(前面介绍过了)(mov)
注意一下MOV segreg,mem/reg
允许将由mem/reg指定的存储单元或寄存器中的十六位数据传送到由segreg所制定的段寄存器中(但代码段寄存器CS除外)
另外:
XCHG d,s
用于将源操作数与目标操作数(字节或字)相互对应交换位置。
可以在通用寄存器与累加器之间、通用寄存器之间、通用寄存器与存储器之间,但不能在两个存储单元之间交换,段寄存器与IP也不能作为源或者目标操作数。
又被称为代码转换或查表指令
该指令通过查表完成代码转换功能,执行操作是:AL<—[BX+AL]。将待转换的序号转换成对应的代码后,送回AL。
实现的方式是通过建立代码转换表(最大容量为256B),并定位在内存某逻辑段的一片连续地址中,利用相对位置实现转换。
如:想将AL中的十进制数5转换,首先要将数据段中该转换表的首地址的偏移位置0030H置入BX,再将5送入AL,然后执行XLAT,即图中右下角的三步代码。
LEA BX,[SI]指令是将SI指示的偏移地址(SI的内容)装入BX。
*
而MOV BX,[SI]指令是将由SI寻址的存储单元中的数据装入BX。
MOV CX,AX指令是将AX指示的数据(AX的内容)装进CX。
注意不同寄存器分别负责寄存数据/地址 ,mov移动的是数据,lea移动的是地址
LEA BX,[SI+100AH]的操作过程:
不要看图看花眼,该过程就是将100A与SI中的0030相加,得到103A并保存到BX中
还有以上两种,不仅会取偏移地址,还会取段地址,一共四个字节,前两个字节(即偏移地址)传送到指定的通用寄存器,后两个(即段地址)传送到DS段寄存器(LDS)/ES段寄存器(LES)
略
将源操作数与目标操作数相加,结果保留在目标中。并根据结果置标志位。
目标操作数不允许是立即数,其他同源操作数。
不允许两者同时为存储器操作数
PF 奇偶标志位的判别是看结果的1的数量,为奇数则为0,反之则为1。
数组加法:
存储器数组是一个按顺序排列的数据表。假定数据数组(ARRAY)包括从元素0~9共是个字节数。现演示累加元素3、元素5和元素7:
MOV AL,0
清零存放和数的AL
MOV SI,3
将SI指向元素3
ADD AL,ARRAY[SI]
加元素3
ADD AL,ARRAY[SI+2]
加元素5
ADD AL.ARRAY[SI+4]
加元素7
带进位加法(ADC)与ADD基本相同,唯一的不同就是进位标志位CF的原状态也将一起参与加法运算,带待运算结束,CF将重新根据结果置成新的状态。
该指令一般用于16位以上的多字节数字相加的软件中
如果必须处理非常大的、不能存放到双字数据长度(ADD可以使用的最大长度)中的整数,可以把值分割为多个双字数据元素,并且对每个元素执行独立的加法操作。
为了正确完成这个操作,必须检测每个加法操作的进位标志,如果进位标志被设置为1,就必须进位到下一对相加的数据元素。
如:实现BX和AX中的四字节数字与DX和CX中的四字节数字相加,其结果存入BX和AX中的程序段如下:
ADD AX,CX
低十六位相加,此时进位标志符可能会被置为1
ADC BX,DX
高十六位相加的同时要加上进位符
将目标操作数当作无符号数,完成加1操作后,结果仍保留在目标中.
目标操作数可以是8/16位通用寄存器或存储器操作数,但不允许是立即数。
INC DATA1
把数据段中DATA1存储单元的内容加一
注意对于间接寻址的存储单元加1指令,数据的长度必须用TYPE PTR、WORD PTR或DWORD PTR 类型伪指令加以说明。
另外,INC指令只影响溢出标志OF、符号标志SF、零标志ZF、辅助进位标志AF、奇偶性标志PF五个标志,而不影响CF
目标操作数只允许是通用寄存器或存储器操作数。
不允许两个操作数同时为存储器操作数,也不允许做段寄存器的减法。
SUB DI,TEMP[SI]
从DI中减去TEMP+SI寻址的数据段存储单元的字内容
注意操作数一般都是补码形式,如8811H,即1000 1000 0001 0001 其实是一个负数。
与ADC类似,会减去进位标志符
如:实现BX和AX中的四字节数字与DX和CX中的四字节数字相减,其结果存入BX和AX中的程序段如下:
SBB AX,CX
低十六位相减,此时进位(借位)标志符可能会被置为1
SBB BX,DX
高十六位相减的同时要减去进位符
DEC BYTE PTR[DI]
由DI寻址的数据段字节存储单元的内容减一
DEC WORD PTR[BP]
由BP寻址的堆栈段字存储单元的内容减一
同样,对于间接寻址存储器数据减一指令要用TYPE PTR 类型伪指令来标记数据长度
NEG是一条求补码的指令,简称求补指令
执行过程:取反再加1
执行结果:把目标操作数当作一个带符号数,如果原操作数是正数,则将变成绝对值相等的负数(补码形式);反之亦然。
注意执行NEG指令后,根据系统的约定,CF通常被置成1;这并不是由运算所致的新状态,而是该指令执行后的约定。只有当操作数为0时,才使CF为0.这是因NEG指令在执行时,实际上是用0减去某个操作数,自然在一般情况下要产生借位,而当操作数为0时,无需借位,故这时CF=0
运算但不送回结果,只置标志位。
目标操作数只可以是8/16位通用寄存器或存储器操作数。但不允许两个操作数同时位存储器操作数,也不允许进行段寄存器比较。
当判断两比较数大小时,要区分无符号数与有符号数:
如: 3-1
原码:3=0011 1=0001
补码:3=0011 -1=1111
相加:0010
OF=0 SF=0 OF⊕SF=0
3>=1
又如:1-3
补:1=0001 -3=1101
相加 1110
OF=0 SF=1 OF⊕SF=1
1<3
再如:-1-3
补码:-1=1111 -3=1101
相加:1100
OF=0 SF=1 OF⊕SF=1 -1<3
乘法指令用来实现两个二进制操作数的相乘操作,包括:无符号数乘法指令(MUL)和有符号数乘法指令(IMUL)
被乘数隐含在累加器AL/AX中;指令中由s指定的源操作数作乘数。
它可以是位通用寄存器或存储器操作数。相乘所得两倍位长的积,按其高8/16位与低8/16位两部分分别放到AH与AL或DX与AX中去。
若运算结果的高位字节或高位字有效,即AH!=0或DX!=0,
则将CF和OF两标志位同时置1,否则,CF=OF=0。
据此,根据CF和OF标志可判断相乘结果的高位字节或高位字是否为有效数值。
其余标志位为任意状态,不可预测
IMUL对OF和CF的影响是:若乘积的高位是低位的符号扩展,则OF=CF=0;否则均为1
低位是指积的值部分,高位指积的符号部分.常常是乘的结果不足16位/32位,就需要进行符号扩展,由于多出的位是在高位,所以叫高位符号扩展.
高位扩展符号的原则是正数填0负数填1.
符号扩展则CF=0;OF=0;否则CF=1,OF=1 是一种约定或者说是标识,在处理结果时,计算机会根据CF、OF的状态判断是否有符号扩展,从而做出相应正确处理.
包括无符号二进制数除法指令(DIV)和有符号二进制除法指令(IDIV)
被除数隐含在累加器AX(字节除)或DX、AX(字除)中。
对于字节除法,所得的商存于AL,余数存于AH。对于字除法,所得的商存于AX,余数存于DX。根据8086的约定,余数的符号应该与被除数的符号一致。
与DIV的主要区别在于对符号位处理的约定:
如果源操作数是字节/字数据,被除数应该为字/双字数据并隐含存放在AX/DX、AX中。
如果被除数也是字节/字数据在AL/AX中,那么,应将AL/AX的符号(AL7)/(AX15)扩展到AH/DX寄存器后,才能开始字节/字除法运算,运算结果商数在AL/AX寄存器中,AL7/AX15是商数的符号位;
余数在AH/DX中,AH7/DX15是余数的符号位,他应与被除数的符号一致。
在这种情况下,允许的最大商数为+127/+32767,最小商数为-127/-32767.
这两条指令是专门为IDIV指令设置的符号扩展指令,用来将被除数字节/字扩展为字/双字的符号,所扩充的高位字节/字部分均为低位的符号位。
他们在使用时应该放在IDIV指令之前,执行结果对标志位没有影响。
略
这类指令可分为:逻辑运算、移位和循环指令
与零-清零
或1-置1
异或1-取反
移位指令分为算术移位和逻辑移位。
根据移位操作的结果置标志寄存器中的状态标志(AF除外)。若移位位数是1位,以为结果使最高位(符号位)发生变化,则将溢出标志OF置1;若移多位,则OF标志无效。
循环移位指令是将操作数首尾相接进行移位,分为不带进位位与带进位位循环移位。这类指令只影响CF和OF标志。
指令中的count字段如果是1则直接写1,如果是n(n<=255),则必须将n先装入CL寄存器中,故count字段只能书写CL而不能用立即数n。
MOV CL,6
SAR DX,CL
DL的内容算术右移6位
RCL AX,CL
AX的内容连同CF循环左移6位
SAL Shift Arithmetic Left 算术左移
SAR Shift Arithmetic Right 算术右移
SHL SHift logic Left;逻辑左移
SHR SHift logic Right;逻辑右移
ROL ROtate shift Left 循环左移
ROR ROtate shift Right 循环右移
RCL Rotate with Carry shift Left 带进位循环左移
RCR Rotate with Carry shift Right 带进位循环右移
将由SI作为指针的源串中的一个字节/字,传送到由DI作为指针的目标串中,且相应地自动修改SI/DI,使之指向下一个元素。如果加上REP前缀,则每传送一个元素,CX自动减1,直到CX=0为止。
设当前CS=6180H,IP=120AH,DS=1000H,SI=2000H,DI=1020H,CX=0064H,DF=0。则操作过程如下↓
若要将源串的100B数据传送到目标串单元中去,设源串首元素的偏移地址为2500H,目标串首元素的偏移地址为1400H,则实现程序段如下:
CLD
DF置零,使SI、DI地址指针自动增加
MOV CX,100
串的长度
MOV SI,2500H
源串首元素的偏移地址
MOV DI,1400H
目标串首元素的偏移地址
REP MOVSB
重复传送操作,直到CX=0为止
用来从目标数据串中搜索(或查找)某个关键字,要求将待查找的关键字在执行该指令前先置入AX或AL中。
要求在长度为N的某字符串中查找是否存在$字符。若存在,则将所在地址送入BX,否则将BX清零。假定字符串首元素的偏移地址为DSTO。则实现程序段如下↓
读串指令用来将源串中由SI所指向的元素取到AX/AL寄存器中,修改SI的内容指向下一个元素
写串指令用来将AX/AL中的一个字/字节写入由DI作为指针的目标串中,同时修改DI以指向串中的下一个元素。
控制程序流向的指令。包括无条件跳转、条件跳转、循环控制和中断四种
允许程序流无条件地转移到由目标标号指定的地址,去继续执行从该地址开始的程序。
转移可分为段内转移和段间转移:
JMP有以下四种基本格式:
JMP BX ;
BX中的内容即转移目标的偏移地址
注意,为区分段内短转移(位移量为8位)和近转移(位移量为16位),其指令格式以JMP SHORT ABC (2字节)和JMP NEAR PTR ABC (3字节)的汇编语言形式来表示。
DS x 16 +ADDR3 + BX = 2160A
从2160A开始,往后两字节内容320E被送入IP,再往后两字节4000H被送到CS
注意,段间转移和段内间接转移都必须用无条件转移指令,而条件转移指令则只能用段内直接寻址方式。转移范围只能是本指令所在位置前后的-128~+127个字节。
这是无条件调用过程指令。
即CPU暂停执行调用下一个指令(断点),而挑往指定过程,待过程结束后,通过RET返回到断点处继续执行。
当调用过程时,如果是当前代码段的过程(近过程,用NEAR表示),则只需将当前IP值压入栈;如果是其他代码段的过程(远过程,用FAR表示),则要将CS和IP先后压入栈中。
RET指令就是从栈顶弹出由CALL指令压入的断点地址值,与CALL指令相呼应。
并且,为了能正确返回,返回指令的类型要与调用指令的类型相对应(CALL和RET都有好几种类型)
根据CPU执行上一条指令时,某一个或几个标志位的状态而决定是否控制程序转移,如果满足条件则转移,反之则继续执行下一条指令。
为缩短指令长度,所有条件转移指令都是短转移。
ZF=0 结果不为0
ZF=1 结果为0
A:Above
B:Below
N:No
E:Equal
G:Greater
L:Less
循环控制指令实际上是一组增强型的条件转移指令,但他是根据自己进行某种运算后来设置状态标志的。
循环控制指令都与CX寄存器配合使用,CX存放着循环次数。
同一指令的两种不同的助记符
CX减一送给CX,若ZF=1且CX!=0时循环;否则,顺序执行下一条指令
即相等就继续循环
同一指令的两种不同的助记符
CX减一送给CX,若ZF=0且CX!=0时循环;否则,顺序执行下一条指令
即不等则继续循环
如果CX=0就循环,不对CX寄存器内容进行操作。