微机原理教案准备_第1页
微机原理教案准备_第2页
微机原理教案准备_第3页
微机原理教案准备_第4页
微机原理教案准备_第5页
已阅读5页,还剩90页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

3.1指令系统概述指令系统是微处理器所能执行的各种指令的集合,定义了一个微处理器所能完成的基本操作。不同的微处理器具有不同的指令系统,本章以Intel公司的8086为例来介绍微处理器的指令系统。采用8086CPU的指令系统作为范例的原因有以下几点:(1)应用的广泛性。几乎所有的微机系统使用的都是x86系列的CPU(主要生产厂家有Intel公司和AMD公司)。(2)指令的兼容性。8086的指令系统是所有x86系列CPU的指令系统的基础,编写的程序可以直接在80286、80386乃至Pentium、Core2Duo上执行。(3)资料的丰富性。x86系列CPU普及程度极广,其相关技术资料很容易找到,给应用开发带来很大方便。(4)与课程内容配合。【几个概念】指令——控制CPU完成指定操作的命令。机器指令——指令的二进制代码形式。例如:1100110100100001(或表示成十六进制形式为:CD21H)。汇编指令——助记符形式的指令。例如:INT21H。指令系统——CPU的所有指令及其使用规则的集合。8086指令按功能分为六大类(92种),下表列出了最常用的一些指令。8086CPU常用指令一览表指令类型助记符数据传送一般数据传送MOV,PUSH,POP,XCHG,XLAT输入输出指令IN,OUT地址传送指令LEA,LDS,LES标志传送指令PUSHF,POPF算术运算加法指令ADD,ADC,INC减法指令SUB,SBB,DEC,CMP乘、除法指令MUL,DIV十进制调整指令DAA,AAA,DAS,AAS,AAM,AAD逻辑运算和移位AND,OR,NOT,XOR,TESTSHL,SAL,SHR,SAR,ROL,ROR,RCL,RCR串操作MOVS,CMPS,SCAS,LODS,STOS控制转移JMP,条件转移指令(Jxx),LOOP/LOOPE/LOOPNEINT/IRET,CALL/RET处理器控制CLC,STC,CLD,STD,HLT3.1.1指令的基本组成指令分为操作码(也称为指令码)和操作数两个部分,操作码表示这条指令所要进行的是什么样的操作,操作数指示所要操作的对象。大多数8086指令的长度在1~4个字节之间,其长度与操作码和指令中操作数的多少以及操作数的类型有关。操作数越多,指令就越长。8086指令系统规定,一条指令的操作数最多只能有两个。1.指令格式8086CPU的指令格式如下:操作码[目的操作数][,源操作数]其中:操作码用便于记忆的助记符来表示(一般是英文单词的缩写)。操作数可以是双操作数(源操作数和目的操作数),也可以是单操作数,有的指令甚至可以不给出操作数(隐含操作数)。【例1】双操作数的指令:MOVAX,BX;MOV是操作码,AX是目的操作数,BX是源操作数单操作数的指令:CALLproc1;CALL是操作码,proc1是目的操作数无操作数的指令:STC;STC是操作码2.操作数类型8086指令系统中的操作数主要分为三类:立即数操作数、寄存器操作数和存储器操作数。1)立即数操作数

所谓立即数是指具有固定数值的操作数,即常数。它可以是字节(8位)或字(16位),当它们分别代表无符号数和带符号数时,其各自的取值范围如下表所示。立即数操作数的取值范围8位数16位数无符号数00H-0FFH(0~255)0000H-0FFFFH(0~65535)有符号数80H-7FH(-128~+127)8000H-7FFFH(-32768~+32767)立即数的取值超出了规定的范围,就会发生错误。在指令中,立即数操作数只能用作源操作数,而不能用作目的操作数。【例2】MOVAX,1200H;正确,立即数可以用做源操作数MOV1200H,AX;错误,立即数不能用做目的操作数2)寄存器操作数寄存器操作数存放在8086CPU的8个通用寄存器或段寄存器中,既可以作为源操作数,也可以用作目的操作数。通用寄存器中的AX、BX、CX、DX既可以作为四个16位寄存器,用来存放字操作数,也可以当作八个8位寄存器(AH、AL、BH、BL、CH、CL、DH、DL),用来存放字节操作数。SI、DI、BP、SP只能存放字操作数。AX(16位)AX(16位)AH(8位)AL(8位)BX(16位)BH(8位)BL(8位)CX(16位)CH(8位)CL(8位)DX(16位)DH(8位)DL(8位)SI(16位)SI(16位)DI(16位)DI(16位)BP(16位)BP(16位)SP(16位)SP(16位)段寄存器用来存放当前操作数的段基地址。在与通用寄存器或存储器传送数据时,段寄存器可作为源操作数或目的操作数。CS(16位)CS(16位)DS(16位)ES(16位)SS(16位)段寄存器存放当前操作数的段基地址注意:1.不允许用一条指令把立即数传送到段寄存器。如果需要这样做,可用某个通用寄存器作为中间桥梁,用两条传送指令实现。2.不允许用传送指令把某个值传送给CS。3.仅有个别指令将标志寄存器FLAGS作为操作数。【例3】MOVDS,1200H;错误,不允许把立即数传送到段寄存器改为:MOVAX,1200H;正确,使用AX作为中介把立即数1200H送到DS寄存器MOVDS,AX【例4】MOVCS,AX;错误,不允许用显式指令把值传送给CS寄存器MOVFLAGS,AX;错误,不允许用数据传送指令给标志寄存器赋值POPF;正确,可以把堆栈栈顶的内容弹出到标志寄存器3)存储器操作数存储器操作数可以是字节(8位)、字(16位)或双字(32位),分别要占据一个、两个或四个存储单元。存储器操作数在指令中既可作为源操作数,也可作为目标操作数。但对大多数指令,不允许源操作数和目标操作数同时为存储器操作数。若确实要对两个存储器操作数进行操作,可以使用任一通用寄存器作为中间桥梁来实现。在汇编语言中,存储器单元是用逻辑地址来制定的,而逻辑地址是由段基地址和偏移地址两部分构成。所以,要访问存储器操作数必须首先确定操作数所在的段基地址。如上所说,段基地址是放在段寄存器中的,所以,访问存储器操作数前,应先确定对应的段寄存器是否已经初始化为所需要的段基地址。那么,访问存储器操作数要使用四个段寄存器中的哪一个呢?8086CPU规定,若指令中没有指明使用哪一个段寄存器的内容作为段基地址来访问存储器操作数,则根据操作数的特征来确定所使用的默认段寄存器。各种存储器操作所约定的默认段寄存器、段超越(即显式地指明段寄存器)所允许的段寄存器、以及相应的偏移地址来源见下表。段寄存器使用的一些基本约定存储器操作类型默认的段寄存器允许超越的段寄存器段内偏移地址来源取指令CS无IP堆栈操作SS无SP通用数据传送DSCS,ES,SS按寻址方式取得串操作源串地址DSCS,ES,SSSI串操作目的串地址ES无DIBP作为基址寄存器SSCS,DS,ES按寻址方式取得【例5】MOVAL,[2A00H];通用数据传送,用DS的内容作为段基地址,偏移地址为2A00H

PUSHAX;堆栈操作,用SS的内容作为段基地址,偏移地址在SP中

LODSW;串操作,用DS的内容作为源串地址的段基地址,偏移地址在SI中

ADDAL,[BP+DI];BP作为基址寄存器,用SS的内容作为段基地址,偏移地址为BP和DI之和3.1.2指令的执行时间了解指令的执行时间,对编写时间敏感的程序是很重要的。例如:在用软件产生定时或延时时或工业控制领域中对某些实时性要求较严的诚和,都需要估算出一段程序的运行时间。一条指令的执行时间以时钟周期数为单位。不同指令的执行时间有较大的差别,这里列出了部分常用指令的执行时间及其访问存储器的次数。常用指令执行时间指令所需时钟周期数访问内存次数MOV累加器到内存内存到累加器寄存器到寄存器内存到寄存器寄存器到内存10(14)10(14)28(12)+EA9(13)+EA11011MOV立即数到寄存器立即数到内存寄存器到段寄存器内存到段寄存器段寄存器到寄存器段寄存器到内存410(14)+EA28(12)+EA29(13)+EA010101ADD或SUB寄存器到寄存器内存到寄存器寄存器到内存立即数到寄存器立即数到内存39(13)+EA16(24)+EA417(25)+EA01202MUL累加器乘8位寄存器累加器乘16位寄存器累加器和内存字节乘累加器和内存字乘70~77118~133(76~83)+EA[124(128)~139(143)]+EA0011IMUL累加器乘8位寄存器累加器乘16位寄存器累加器和内存字节乘累加器和内存字乘80~98128~154(86~104)+EA[134(138)~160(164)]+EA0011DIV除数在8位寄存器中除数在16位寄存器中除数为8位内存数除数为16位内存数80~90144~162(86~96)+EA[150(154)~168(172)]+EA0011IDIV除数在8位寄存器中除数在16位寄存器中除数为8位内存数除数为16位内存数101~112165~184(107~118)+EA[171(175)~190(194)]+EA0011循环和移位在寄存器中移1位在寄存器中移若干位内存数据移1位内存数据移若干位28+4*位数15(23)+EA20(28)+EA+4*位数JMP段内/段间直接转移段内间接转移段间间接转移158(12)+EA24(32)+EA条件转移JCXZ6(不转移)18(转移)其它条件转移指令Jxx4(不转移)16(转移)注:(1)表中EA表示偏移地址。小括号内的数为8088进行字操作的时钟数。因为8088的数据线只有8位,每个总线周期只能传送一个字节,所以对字操作要再加上4个时钟周期。(2)对条件转移指令,若条件满足,执行的时间比较长。因为要产生转移,就要包括取下一条指令所需的时间。若条件不满足,执行时间就较短。因为此时不产生转移,而是执行下一条指令。存取操作数的时间与采用的寻址方式有关。寄存器寻址执行的时间最短,而对存储器操作数则还需考虑计算偏移地址所花的时间。这里列出了不同寻址方式下,计算偏移地址所需要的时间。计算偏移地址EA所需时间寻址方式计算EA所需时钟数直接寻址6寄存器间接寻址5寄存器相对寻址9基址、变址寻址[BX+SI],[BX+DI]7[BP+SI],[BP+DI]8基址、变址加相对寻址[BX+SI+位移量],[BP+DI+位移量]11[BX+DI+位移量],[BP+SI+位移量]12注:若有段超越,则需再加上两个时钟周期。可以看出,对同一种指令,如果寻址方式不同,其指令执行时间可能相差很大。寄存器操作数的指令执行速度最快,立即数操作数次之,存储器操作数指令的执行速度最慢。这是由于寄存器位于CPU的内部,执行寄存器操作数指令时,8086的执行单元(EU)可以直接从CPU内部寄存器中取得操作数,不需要访问内存,因此执行速度很快。立即数操作数作为指令的一部分,在取指时已经被8086总线接口单元(BIU)取出后存放在指令队列中,执行指令时也不需要访问内存,因而执行速度也比较快。而存储器操作数先要由总线接口单元计算出其所在单元的20位物理地址,然后再执行存储器的读写操作。所以相对前述两种操作数来说,指令的执行速度最慢。【例】当通用数据传送指令(MOV)的操作数分别为:寄存器、立即数和存储器时,分别计算指令的执行时间,已知CPU的时钟频率为5MHz。CPU的时钟频率为5MHz,即一个时钟周期为0.2μs。则从寄存器到寄存器之间的传送指令的执行时间为:

t=2×0.2=0.4μs立即数传送到寄存器的指令执行时间为:

t=4×0.2=0.8μs

而存储器到寄存器的字节传送,设存储器采用基址、变址寻址方式,则指令执行时间为:

t=(8+EA)×0.2=(8+8)×0.2=3.2μs从上例可以看出,不同类型的寻址方式或不同类型的操作数可以导致指令执行时间相差一个数量级,因此,我们在编写程序时:1)尽量使用寄存器作为操作数;2)尽量使用简单的寻址方式。3.28086的寻址方式寻址方式,主要是指获得操作数所在的地址的方法。在8086系统中,一般将寻址方式分为两大类,一类是寻找操作数的地址,另一类是寻找要执行的下一条指令的地址,即程序的地址。后者主要在程序转移或过程调用时用来寻找目的地址或入口地址,这将在调用指令(CALL)和程序转移指令(JMP)中介绍。本节我们主要讨论针对操作数地址的寻址方式。在8086指令系统中,基本的寻址方式有7种,另外通常也把隐含寻址也当作是一种不同的寻址方式:①立即寻址

②直接寻址

③寄存器寻址

④寄存器间接寻址⑤寄存器相对寻址⑥基址变址寻址⑦基址变址相对寻址⑧隐含寻址8086寻址方式一览表寻址方式名称源操作数的例子源操作数的允许形式立即操作数立即寻址MOVAX,1200H指令中的常数寄存器操作数寄存器寻址MOVAX,BX通用寄存器或段寄存器存储器操作数直接寻址MOVAX,[1200H]“[常数]”或“[变量]”或“变量”寄存器间接寻址MOVAX,[DI][BX、BP、SI、DI之一]寄存器相对寻址MOVAX,[BX+1200H][BX、BP、SI、DI之一+位移量]基址变址寻址MOVAX,[BX+DI][BX或BP+SI或DI]基址变址相对寻址MOVAX,[BX+DI+1200H][BX或BP+SI或DI+位移量]3.2.1立即寻址(ImmediateAddressing)要点:▪操作数直接在指令中给出▪只适用于源操作数立即寻址方式中,操作数是一个常数(也称为立即数)。操作数作为指令的一部分,紧跟在指令的操作码之后(见例2图(a)),存放于内存的代码段中。并在CPU取指令时随指令码一起取出。立即数可以是8位或16位的整数。注意:立即寻址方式只适用于源操作数。【例1】MOVAX,1C8FH;正确,把16位二进制数1C8FH送到AX寄存器中

ADDBYTEPTR[2A00H],8FH;正确,把8位二进制数8FH累加到2A00H内存单元中

MOV2A00H,AX;错误,立即数不能作为目的操作数【例2】指令“MOVAX,3102H”将16位的立即数3102H送入累加器AX。指令执行后,AH=31H,AL=02H。这是一条三字节指令,指令在存储器中的存放形式及其执行情况如下图(b)所示。......操作码操作数高8位操作数低8位.........(b)代码段...MOV操作码31H02H.........存储器代码段(a)存储器AHALAX3.2.2直接寻址(DirectAddressing)要点:▪指令中直接给出操作数的偏移地址(形式上为一个16位二进制数)直接寻址指令是在指令的操作码后面中直接给出操作数的16位偏移地址,偏移地址也称为有效地址(EA,EffectiveAddress),该地址与指令的操作码一起存放在内存的代码段,按低8位-高8位的顺序存放,取指令时与指令操作码一起被送入CPU。直接寻址指令中,默认使用DS寄存器作为操作数的段基址寄存器。当然也可以显式地指定使用其他段寄存器——称为段超越前缀,如下例中第二条指令中的“ES:”。【例1】MOVAX,[2A00H];将内存中从DS:2A00H开始的连续两个字节的内容传送到AX寄存器

MOVDX,ES:[8000H];将内存中从ES:8000H开始的连续两个字节的内容传送到AX寄存器

MOVSI,BUFFER;将内存中从DS:BUFFER开始的连续两个字节的内容传送到SI寄存器上述第三条指令中的BUFFER这种形式的地址称为符号地址——用符号来表示一个具体的偏移地址。注意:请仔细区别直接寻址指令与立即寻址指令二者的不同。直接寻址指令中的数值是操作数的16位偏移地址,而不是操作数本身。为了区分二者,指令系统规定偏移地址是一个数字时要加上方括号(符号地址可省略方括号)。【例2】指令“MOVAX,[3102H]”将数据段中偏移地址为3102H和3103H两个单元中的内容送到AX。如果(DS)=2000H,则所访问的操作数的物理地址为:20000H+3102H=23102H指令执行后:AX=1122H。指令的执行情况如下图所示。......MOV操作码31H02H...22H...存储器数据段AHALAX11H代码段23103H23102H另外,若操作数不是存放在DS段,则在指令中要使用段超越前缀加以声明。【例3】指令“MOVBX,ES:[1200H]”用ES寄存器中的内容作为段基地址,将偏移地址为1200H和1201H两单元的内容送到BX寄存器中。3.2.3寄存器寻址(RegisterAddressing)要点:▪操作数放在某个寄存器中寄存器寻址方式中,操作数放在CPU的某个寄存器中,它可以是通用寄存器(8位或16位),也可以是基址寄存器(BX,BP)、变址寄存器(SI,DI)或段寄存器。注意:寄存器寻址指令在取操作数时不需要访问存储器,因此与段地址无关,故指令中不可以使用段超越前缀。【例1】MOVAX,BX;将BX寄存器的内容传送到AX寄存器

MOV[3F00H],AX;将AX寄存器的内容传送到从DS:3F00H开始的连续两个内存单元

MOVCL,AL;将AL寄存器的内容传送到CL寄存器

MOVAX,BL;错误,源操作数和目的操作数的字长不同

MOVES:AX,DX;错误,寄存器寻址不能使用段超越前缀【例2】指令“MOVSI,AX”将AX的内容送到寄存器SI中。若指令执行前AX=2233H,SI=4455H,则指令执行后SI=2233H,而AX中的内容保持不变,仍为2233H。4455H4455H2233HSIAX执行前2233H2233H2233H执行后SIAX采用寄存器寻址时,操作数在CPU的寄存器中,指令在执行时不必通过访问内存就可取得操作数,故执行速度较快。3.2.4寄存器间接寻址(RegisterIndirectAddressing)要点:▪操作数的偏移地址放在寄存器中▪只有SI、DI、BX和BP可作间址寄存器寄存器间接寻址与寄存器寻址方式不同,指令中指定的寄存器的内容不是操作数,而是操作数的偏移地址。也就是说操作数的偏移地址放在寄存器中,操作数本身则在存储器中。用来做间接寻址的寄存器有时也称为指针寄存器,或简称指针(试比较C语言中的指针)。寄存器间接寻址方式可用的寄存器只允许是SI、DI、BX和BP,统称为间址寄存器。选择不同的间址寄存器,涉及的段寄存器将有所不同。在默认情况下,用SI、DI、BX作间址寄存器时,操作数在数据段,段基地址由DS决定;用BP作间址寄存器,则操作数在堆栈段,段基地址由SS决定。但无论选择哪一个间址寄存器,都允许段超越,即可在指令中用段超越前缀指明当前操作数在哪一个段。注意:因为间址寄存器中放的是操作数地址,所以用作间址的寄存器必须加上方括弧,以避免与寄存器寻址混淆。【例1】MOVAX,[BX];以BX的内容为偏移地址,DS的内容为段地址,取出一个字到AX寄存器MOVSI,[BP];以BP的内容为偏移地址,SS的内容为段地址,取出一个字到SI寄存器MOVCL,CS:[DI];使用段超越前缀,所要访问的数据在代码段中MOVAX,[DX];错误,DX不能用作间址寄存器MOVCL,[AX];错误,AX不能用作间址寄存器【例2】指令“MOVAX,[SI]”的寻址过程示例。已知DS=6000H,SI=1200H,(61200H)=44H,(61201H)=33H,则指令执行后,AX=3344H。指令的执行情况如下图所示。.........44H...存储器数据段33H44HAX33H61201H61200H6000DS1200SI60000+120061200地址因为指令中没有指定段超越,所以寻址时使用默认的段寄存器DS。若操作数所在段的段地址在ES中,则本例中的指令应写成:MOVAX,ES:[SI]。3.2.5相对的寄存器间接寻址(RelativeRegisterIndirectAddressing)要点:▪操作数的偏移地址=间址寄存器的内容加上8/16位的位移量▪只有SI、DI、BX和BP可作间址寄存器相对的寄存器间接寻址简称为寄存器相对寻址,在这种寻址方式中,操作数存放在存储器中,而其偏移地址等于指令中给出的间址寄存器的内容与给出的8/16位的位移量之和。操作数的段由哪个段寄存器指定,仍由所使用的间址寄存器决定。位移量也可看作相对值,故把这种带位移量的寄存器间接寻址方式称为寄存器相对寻址。有时,寻址方式中的基本偏移量也称为基地址。至于位移量和基地址哪个放在间址寄存器中,哪个作为位移量可任意,因为最终总是由二者相加得到偏移地址。点击观看相对寄存器寻址的动画演示。【例1】MOVAX,[BX+8];操作数的偏移地址为BX的内容加上8,段地址在DS中

MOVCX,TABLE[SI];TABLE是用符号表示的基地址,位移量在SI中

MOVAX,[BP+1000H];操作数的偏移地址为BP的内容加上1000H,段地址在SS中注意:以上指令中的地址表达式有两种不同的写法,它们都是正确的。【例2】指令MOVAX,BUFF[BX]的操作。假定DS=6000H,BX=1000H,BUFF=2A00H,(63A00H)=66H,(63A01H)=55H。物理地址=60000H+1000H+2A00H=63A00H.........66H...存储器数据段55H66HAX55H63A01H63A00H60000(DS)1000(BX)+2A00(BUFF)63A00地址指令执行后:AX=5566H寄存器相对寻址常用于存取表格或一维数组中的元素——把表格的起始地址作为基地址,用元素的下标计算出位移量,即可存取表格中的任意一个元素。位移量的计算方法是:位移量=下标×每个元素的字节数注:经常也会把表格的起始地址作为位移量,把元素的下标计算出来的值作为基地址。【例3】某数据表的首地址(偏移地址)为TABLE,要取出该表中的第10个元素(均为8位二进制数)传送到AL寄存器中,可用如下指令段实现

MOVSI,9;第10个数的下标为9(位移量是从0开始的)

MOVAL,TABLE[SI];第10个数的偏移地址为TABLE+9

如果该表中的每个元素占用两个字节(16位),则上述指令段应改为MOVSI,9;第10个数的下标为9ADDSI,SI;每个元素占两个字节,所以用元素的下标乘2得到位移量(18)

MOVAL,TABLE[SI];第10个数的偏移地址为TABLE+18在汇编语言中,地址表达式的书写格式允许有不同的形式。例如,以下几种写法本质上是完全等价的:

MOVAX,DATA[SI]

MOVAX,[SI]DATA

MOVAX,[DATA+SI]

MOVAX,[SI+DATA]

另外,在有些教科书中将使用BX、BP作为间址寄存器的寄存器相对寻址方式称为基址寻址方式;而将使用SI、DI作为间址寄存器的寄存器相对寻址方式称为变址寻址方式。3.2.6基址加变址寻址(IndexedBasedRegisterIndirectAddressing)要点:▪操作数的偏移地址由一个基址寄存器的内容和一个变址寄存器的内容相加得到▪地址表达式中只允许出现一个变址寄存器(SI或DI)和一个基址寄存器(BX或BP)基址加变址寻址方式中,操作数的偏移地址是由一个基址寄存器(BX或BP)的内容和一个变址寄存器(SI或DI)的内容相加而得到。注:1)在默认的情况下,指令中若用BX作基址寄存器,则段地址在DS中;而如果用BP作基址寄存器,则段地址在SS中。——但可以使用段超越覆盖此规则。2)指令中不允许同时出现两个基址寄存器或两个变址寄存器。【例1】MOVAX,[BX][SI];操作数的偏移地址由BX的内容和SI的内容相加得到

MOVAX,[BX+SI];同上,另一种格式

MOVAX,DS:[BP][DI];操作数的偏移地址由BP和DI的内容相加得到,段基地址在DS中,而不是在SS中

MOVAX,[BX][BP];错误,地址表达式中不能出现两个基址寄存器

MOVAX,[DI][SI];错误,地址表达式中不能出现两个变址寄存器【例2】指令MOVAX,[BX][SI]的操作。假定DS=8000H,BX=2000H,SI=1000H。

物理地址=80000H+2000H+1000H=83000H

.........22H...存储器数据段11H22HAX11H83001H83000H80000(DS)2000(BX)+1000(SI)83000地址指令执行后:AX=1122H3.2.7相对的基址加变址寻址(IndexedBasedRelativeRegisterIndirectAddressing)要点:▪操作数的偏移地址由基址寄存器的内容、变址寄存器的内容和一个8/16位的位移量三者相加得到▪地址表达式中只允许出现一个变址寄存器(SI或DI)和一个基址寄存器(BX或BP)这种寻址方式事实上是基址加变址寻址方式的扩充。指令中指定了一个基址寄存器和一个变址寄存器,同时还给出一个8位或16位的位移量,将三者内容相加就得到操作数的偏移地址。至于默认的段寄存器,仍由所使用的基址寄存器决定。指令允许使用段超越。【例1】指令MOVAX,DATA[DI][BX]的寻址过程。假定DS=8000H,BX=2000H,DI=1000H,DATA=200H。

.........34H...存储器数据段12H34HAX12H83201H83200H80000(DS)2000(BX)1000(DI)+200(DATA)83200地址指令执行后,AX=1234H。与寄存器间接寻址方式类似,相对的基址加变址寻址同样也可以表示成多种形式,例如:

MOVAX,DATA[SI][BX]

MOVAX,[BX+DATA][SI]

MOVAX,[BX+SI+DATA]

MOVAX,DATA[BX+SI]

同样地,相对的基址加变址寻址也不允许在指令中同时出现两个基址寄存器或两个变址寄存器。下列指令格式是非法的:

MOVAX,DATA[SI][DI]

MOVAX,DATA[BX][BP]使用相对的基址-变址寻址方式可以很方便地访问二维数组。方法如下:把数组在内存中的首地址(偏移地址)作为位移量,元素所在行的行起始位移量放入基址寄存器,元素所在列的列位移量放入变址寄存器。然后在指令中使用相对的基址加变址寻址方式即可。(注:变址寄存器和基址寄存器可交换使用)【例2】二维数组A定义如下:A=A=183252409它在内存中从地址Array开始按行存放:相对位移量Array+0+1+2+3+4+5+6+7+8...183252409...A[0,0]A[0,1]A[0,2]A[1,0]A[1,1]A[1,2]A[2,0]A[2,1]A[2,2]假定现在要取出A[1,2]送到AL寄存器中。根据上面介绍的方法:1)把数组在内存中的首地址Array作为位移量2)元素所在行的行位移量=行号*每行元素个数*每元素字节数=1*3*1=3。完成行位移量计算的指令段如下:MOVAX,1;行号MOVCX,3;每行元素个数MULCX;行号*每行元素个数,结果在AX中MOVCX,1;每元素字节数MULCX;行号*每行元素个数*每元素字节数,结果在AX中MOVSI,AX;行位移量放入变址寄存器3)元素所在列的列位移量=列号*每元素字节数=2*1=2。完成列位移量计算的指令段如下:MOVAX,2;列号MOVCX,1;每元素字节数MULCX;列号*每元素字节数,结果在AX中MOVBX,AX;列位移量放入基址寄存器然后用相对的基址加变址指令把A[1,2]传送到AL寄存器:MOVAL,Array[SI][BX];等价于MOVAL,Array+5可以看出,存储单元Array+5中的内容就是元素A[1,2]。3.2.8隐含寻址要点:▪指令中未显式地给出操作数,而是隐含的、固定的;▪隐含寻址并非没有操作数,而是由于操作数固定,因此无需显式地写出。【例】指令MULBL的功能是把AL中的内容与BL中的内容相乘,乘积送到AX寄存器。即AL×BL→AX。这条指令隐含了被乘数寄存器AL及乘积寄存器AX。类似的指令还有:XLAT、IMUL、DIV、IDIV、CBW、CWD、MOVS、LODS、STOS、CMPS、SCAS等。3.2.9比例寻址要点:▪比例寻址只适用于80386、80486及后续的x86系列CPU,如Pentium等。▪比例寻址是指将基址寄存器或变址寄存器的内容乘上一个比例因子。比例因子为1、2、4、8中的任一值。【例】MOVAX,[ESI*8]MOVAX,[ESI*2+10]MOVAX,[EBX*4+EDX]MOVAX,[EBX+ESI*4+TABLE]可以看出,当比例因子为1时,上述指令与寄存器间接寻址、寄存器相对寻址、基址变址寻址、基址变址相对寻址等价。注:1)上述指令中,ESI、EBX等为32位寄存器。这样的寄存器有8个:EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP,它们是8086通用寄存器的扩充。2)在80386以后的CPU中,8个32位通用寄存器都可以作为基址寄存器使用,除ESP外的其它7个32位通用寄存器都可以作为变址寄存器使用。3)在80386以后的CPU中,增加了FS和GS两个段寄存器。4)在80386以后的CPU中,所有寻址方式中隐含的段寄存器取决于使用的基址寄存器:如果基址寄存器为ESP和EBP,则隐含的段寄存器为SS,其他情况下隐含的段寄存器为DS。5)如果地址表达式中有两个寄存器,则不带比例因子的寄存器是基址寄存器;如果两个寄存器都不带比例因子,则左边的寄存器是基址寄存器。如果地址表达式中只有一个寄存器,则它就是基址寄存器。3.38086指令系统本节将详细介绍8086指令系统。下面是本节中用到的一些符号及其含义。OPRD泛指各种类型的操作数

mem存储器操作数

acc累加器操作数

dest目的操作数src源操作数

disp8位或16位偏移量,可用符号地址表示

DATA8位或16位立即数

PORT输入/输出端口,可用数字或表达式表示()表示寄存器的内容或存储单元的内容

[]表示偏移地址请注意,以下通用规则对本节介绍的所有指令都适用:1)立即数不能作为目的操作数。2)CS和IP寄存器不能作为操作数使用(源和目的都不允许)。3)双操作数指令中的两个操作数不能都是存储器(串操作指令除外),不能都是段寄存器,也不能一个是立即数,一个是段寄存器。4)源操作数和目的操作数的类型至少有一个能够确定。如果两个都确定,则二者类型必须相同。5)双操作数指令中,必须将目标操作数写在前面,源操作数写在后面,二者之间用逗号分隔。8086指令可分成以下6类:

数据传送类算术运算类逻辑运算和移位类串操作类程序控制类处理器控制类3.3.1数据传送指令要点:▪数据传送指令几乎都是双操作数指令,某些指令在形式上虽然为单操作数,但实际上另一个操作数是隐含的。▪数据传送指令能够将源操作数的内容传送到目的操作数中,或者将两个操作数内容进行交换。数据传送指令是程序中使用最为频繁的一类指令,无论什么样的程序,都需要将原始数据、中间运算结果、最终结果及其它控制、状态信息在CPU的寄存器和存储器之间进行多次传送。数据传送指令能够实现的操作如下图:CSCS立即数(常数).........存储器段寄存器DS、ES、SS通用寄存器请注意此图中线段的方向!I/O端口仅累加器数据传送类指令按功能又可分为四小类:▪通用数据传送▪地址传送▪标志传送▪输入输出通用数据传送要点:▪数据传送指令能够将源操作数的内容传送到目的操作数中,或者将两个操作数内容进行交换。▪一般情况下,通用数据传送指令中的操作数是作为普通数据来对待的。▪使用通用数据传送指令时要注意指令语法规则。通用数据传送指令包括一般传送指令M0V、堆栈操作指令PUSH和P0P、交换指令XCHG、查表转换指令XLAT和字位扩展指令CBW和CWD。①一般传送指令MOV【格式及操作】MOVdest,src;dest←src【功能】将源操作数的内容传送到目的操作数,而源操作数内容保持不变。也就是说,MOV指令实际上是完成了一次数据的复制。【例1】MOVAL,08H;AL←08HMOVBX,SI;BX←SI

M0VDS,AX;DS←AX

MOV[2000H],CH;(DS:2000H)←CH

MOV指令的操作数之一为存储器时,若传送的是字操作数,那么将对连续两个存储器单元进行存取,字操作数的高8位对应存储器的高地址单元,字操作数的低8位对应存储器的低地址单元。【例2】

M0V[BX],1234H;(DS:BX)←1234H。若DS=8000H,BX=08H,则指令执行后,(80008H)=34H,(80009H)=12HMOVAX,[6000H];若(DS:6000H)=11H,(DS:6001H)=22H,则指令执行后,AX=2211H数据传送指令应遵循指令系统的通用规则。【例3】MOVAX,BL;错误!两个操作数的类型必须相同

MOV[BX],[SI];错误!两个操作数不能都是存储器单元

MOVDS,1200H;错误!不允许把立即数直接传送到段寄存器

MOVSS,ES;错误!两个操作数不能都是段寄存器

MOVCS,AX;错误!CS寄存器不能作为目的操作数MOV10H,AL;错误!立即数不能作为目的操作数以上操作在规则上是不允许的,但如果我们确实要执行这样的操作,则可以用间接的方法实现。【例4】两个存储器单元之间的数据传送可用以下方法实现:MOVAX,[SI]MOV[BX],AX立即数传送到段寄存器可用以下方法实现:MOVAX,1200HMOVDS,AX段寄存器之间的数据传送可用以下方法实现:MOVAX,ESMOVSS,AX点击这里查看更多的例子。[top]②堆栈操作指令PUSH/P0P堆栈的概念堆栈的操作为什么要按“后进先出(LIFO)”的方式工作呢?这是由于设置堆栈的目的决定的。我们知道,在运行一个主程序时,常常需要调用子程序或响应中断而进入中断服务程序,这都需要暂时停止正在执行的程序,而转去执行子程序或中断服务程序,但在子程序或服务程序执行完后,必须能够返回到主程序刚才被中断的地方继续执行原来的程序。这就要求在转子程序前必须保存返回地址(也称断点),即调用子程序(或中断服务程序)的那条指令的下一条指令的CS和IP的内容。另外,还要保存子程序中要用到的寄存器原来的值。这些内容都要用堆栈来进行保存。在执行子程序(或中断服务程序)的过程中,有可能又会需要调用子程序(或中断服务程序),如下图所示,这就需要保护多个断点,并保证能够逐个正确返回,这意味着后保存的断点地址应该先取出。这就是堆栈要按“后进先出”方式工作的原因。断点1执行子程序2断点2主程序断点1执行子程序2断点2主程序子程序1子程序调用示意图子程序调用示意图子程序2堆栈压入数据时总是从高地址向低地址方向增长,从堆栈取数据时正好相反;堆栈操作以SS:SP为指针,堆栈指针SP总是指向栈顶,每压入一个数据,SP减2;每弹出一个数据,SP加2;SP的初值决定了堆栈的大小,SP的值不允许小于零;堆栈的存取以字(16位二进制数)为单位;堆栈指令中的操作数只能是寄存器或存储器操作数,而不能是立即数。

∶∶∶SSSP栈顶单元堆栈段堆栈增长方向低地址高地址存储器(2)堆栈操作指令堆栈操作指令共有两条,压栈指令PUSH和弹出(出栈)指令POP。这两条指令中都只需指明一个操作数即可,另一个操作数隐含为堆栈栈顶。

【格式及操作】PUSHsrc;src压入堆栈,SP减2POPdest;栈顶内容弹出到dest,SP加2【功能】PUSH指令把16位的操作数压入栈顶,POP指令从栈顶弹出一个16位数据到目的操作数。这里,操作数src和dest可以是:

寄存器(包括数据寄存器、地址指针和变址寄存器);段寄存器(CS除外,PUSHCS指令是合法的,而P0PCS指令是非法的);

存储器单元。无论是哪一种操作数,其类型都必须是字操作数。若为寄存器,必须是16位寄存器;若为存储器,则应是两个地址连续的存储单元。点击观看PUSH和POP指令动画演示。【例5】

PUSHAX;通用寄存器AX的内容压入堆栈PUSHBP;基址指针寄存器BP的内容压入堆栈

PUSHDATA[SI];两个连续的存储单元的内容压入堆栈

POPDS;栈顶内容弹出到段寄存器DS中POP[BX];栈顶内容弹出到两个连续的存储单元中【例6】若AX=1122H,则PUSHAX指令执行前后的情况如下图所示。yyyyxxSP堆栈段SS低地址高地址压栈前yyxx11H22HSP堆栈段SS压栈后1122HAX1122HAX-2【例6】若栈顶内容为5678H,则POPAX指令执行前后的情况如下图所示。yyyyxx56H78HSP堆栈段SS低地址高地址出栈前yyxxSP堆栈段SS出栈后xxxxHAX5678HAX+2[top]③交换指令XCHG【格式及操作】XCHGOPRD1,OPRD2;(OPRD1)←→(OPRD2)【功能】将源操作数与目的操作数的内容互相交换。交换指令对操作数的要求:源操作数和目的操作数均可以是寄存器或存储器,但不能同时为存储器。操作数不能为段寄存器。【例7】设DS=2000H,SI=0200H,AL=11H,(20200H)=88H,则执行指令“XCHG[SI],AL”后,AL=88H,(20200H)=11H。AL的内容与(20230H)存储单元的内容进行了交换。【例8】把AX和BX的内容进行交换。XCHGAX,BX;注:也可以写成XCHGBX,AX[top]④查表转换指令XLAT【格式及操作】XLAT;AL←((BX)+(AL))或:XLATsrc_table;src_table为要查找的数据表的首地址【功能】以DS的内容作为段地址,以BX+AL之和作为偏移地址,从该存储器单元取出一个字节送到AL。XLAT指令可以根据数据表中元素的序号取出表中的相应元素(也可以看成是对一维数组的访问)。指令的使用方法是:(1)在数据段中先定义数据表或一维数组(注意,数据表或数组中的元素必须是字节类型);(2)将表或数组的首地址(偏移地址)送到BX,要查找的元素的序号(下标)送AL(注:序号(下标)从0开始);(3)执行XLAT指令,表或数组中指定序号(下标)的元素就被传送到AL中。利用XLAT指令实现代码转换操作十分方便。【例9】利用XLAT指令实现二进制数到ASCII码的转换。ASCIIDB30H,31H,32H,33H,34H,35H,36H,37HDB38H,38H,41H,42H,43H,44H,45H,46H...CONV:LEABX,ASCII;BX←ASCII码表首地址M0VAL,8;假定要把8转换为对应的ASCII码(38H)XLAT;查表转换执行结果:AL=38H,即8所对应的ASCII码。注意:因为转换时使用AL存放元素的下标,所以转换表长度最大为256个字节元素(即256个表项)。点击观看XLAT指令动画演示。[top]⑤字位扩展指令CBW/CWD算术运算指令要求两个操作数的字长必须满足一定规则。例如:对加、减和乘法运算指令,两个操作数必须等字长;而对除法运算指令,要求被除数的字长应为除数的两倍。因此,有时需要将一个字节的数扩展为字,或将一个字的数扩展为双字。但有符号数的扩展并非只是前面补零那么简单,而是在扩展时应根据符号位决定前面补为全零还是补为全1,即将符号位扩展到整个高8位(或高16位)。例如,要把有符号数24H扩展为一个字,则结果为0024H;而如果要扩展的数是84H,则结果为FF84H。扩展指令共有两条:CBW和CWD,这两条指令都是隐含操作数指令。【格式及操作】CBW;当(AL)<80H时,AH=0,否则AH=FFH。CWD;当(AX)<8000H时,DX=0,否则DX=FFFFH。【功能】CBW通过将AL的符号位扩展到AH把一个8位数扩展为16位数,结果在AX中;CWD通过将AX的符号位扩展到DX把一个16位数扩展为32位数,结果在DX:AX中。【例10】把字节8EH扩展为字,程序如下:

MOVAL,8EH

CBW;结果:AX=FF8EH【例11】把字43FFH扩展为双字,程序如下:MOVAX,43FFH

CWD;结果:DX:AX=000043FFH地址传送指令要点:▪地址传送指令用于将某个操作数的地址传送到寄存器中,以便作为地址指针使用。▪LEA用于把操作数的偏移地址传送到指定的16位的寄存器中。▪LES/LDS用于把存放在存储单元中的32位操作数地址取出传送到指定的段寄存器和一个16位的寄存器中。8086指令系统提供了三条用于传送地址的指令:LEA、LDS和LES。①偏移地址传送指令LEA【格式及操作】LEAreg16,mem;将mem的偏移地址送到指定的16位寄存器【功能】将mem的偏移地址送到指定的16位寄存器。注意,源操作数mem必须是一个存储器操作数,目标操作数reg16必须是一个16位的通用寄存器。【例1】用寄存器间接寻址方式把存储器中从BUFFER开始的两个字节分别送到AL和AH寄存器。LEABX,BUFFER;先将BUFFER的偏移地址传送到BX寄存器

MOVAL,[BX];取出BUFFER中的第一个数据送AL

MOVAH,[BX+1];取出BUFFER中的第二个数据送AH

【例2】设BX=1000H,DS=6000H,(61005H)=33H,(61006H)=44H。试比较以下两条指令的执行结果:

LEABX,[BX+5]

MOVBX,[BX+5]

见下图。LEA指令执行后:BX=1005H;MOV指令执行后:BX=4433H。.........44H33H............61005H61006H10H05H44H33HBXBX执行LEA指令后执行MOV指令后存储器点击观看LEA指令操作动画演示。点击观看LEA指令应用动画。[top]②地址指针传送指令LDS【格式及操作】LDSreg16,mem32;将源操作数mem32中的内容传送到DS和reg16【功能】把存储器mem32中存放的一个32位的远地址指针(包括偏移地址和段地址)传送到reg16和DS。低16位的内容作为偏移地址传送到reg16,高16位的内容作为段地址传送到数据段寄存器DS。指令中,源操作数mem32为存储器操作数,目标操作数reg16是任意一个16位的通用寄存器。访问源操作数mem32使用的段寄存器默认为DS。LDS指令非常类似于MOV指令,它们都是将存储器操作数的内容传送到目的操作数。它们的区别是:LDS指令传送的是32位数据。MOV指令只能传送8位或16位数据;LDS指令把传送的数据看成是地址。MOV指令传送的数据做什么用途取决于上下文;LDS指令的目的操作数是两个寄存器:DS和一个通用寄存器。MOV指令的目的操作数只能是一个寄存器或一个存储器单元。【例3】设DS=6000H,存储器中从6000H:0348H开始的4个单元中存放了一个32位的远指针9000H:8011H,而9000H:8011H单元中存放了数据1234H,如图所示。以下指令将32位远指针装入DS:SI中,然后使用该指针把9000H:8011H单元的内容传送到AX。LDSSI,[0348H];将DS:0384H中的32位指针(9000H:8011H)传送到DS和SI

MOVAX,[SI];将9000H:8011H中的内容传送到AX12H34H...90H00H80H11H...12H34H...90H00H80H11H...6000H:0384H9000H:8011H80119000+98011DSSI1234HAXMOV指令的操作LDS指令的操作[top]③地址指针传送指令LES【格式及操作】LESreg16,mem32;将源操作数mem32中的内容传送到ES和reg16【功能】这条指令的功能和LDS指令非常类似,所不同的是,目的操作数内容的高16位被传送到ES,而不是DS。标志传送指令要点:▪标志传送指令包括PUSHF、POPF、LAHF和SAHF。▪PUSHF指令把标志寄存器的内容压入堆栈,POPF指令把堆栈栈顶的内容弹出到标志寄存器。▪LAHF指令把5个状态标志传送到AH,SAHF指令把AH的7、6、4、2、0位传送到标志寄存器的对应位。①标志压栈指令PUSHF【格式及操作】PUSHF;将标志寄存器的内容压入堆栈,SP减2本指令为隐含寻址,源操作数为标志寄存器,目的操作数为堆栈。本指令主要用于保护标志寄存器的内容。②标志出栈指令POPF【格式及操作】POF;将栈顶的内容弹出到标志寄存器,SP加2本指令为隐含寻址,源操作数为堆栈,目的操作数为标志寄存器。本指令用于恢复标志寄存器原来的内容。【例1】PUSHF;保护标志寄存器的内容到堆栈,以防下面的加法操作破坏标志寄存器的内容MOVAX,NUM1;执行加法操作ADDAX,NUM2POPF;恢复标志寄存器的内容③标志卸出指令LAHF【格式及操作】LAHF;将5个状态标志位传送到AH寄存器【功能】LAHF指令将标志寄存器FLAGS中的5个标志位:SF(符号标志)、ZF(零标志)、AF(辅助进位标志)、PF(奇偶标志)和CF(进位标志)分别传送到AH的对应位,如下图所示。OODITFLAGSSZAPCAH1502467④标志存入指令SAHF【格式及操作】SAHF;将AH寄存器的5个状态标志位传送到标志寄存器【功能】SAHF和LAHF指令的操作正好相反,它将AH中的第7、6、4、2、0位分别传送到标志寄存器FLAGS的对应位。该指令的执行显然会影响标志位SF、ZF、AF、PF和CF,它们将分别被AH的对应位的状态修改,但其它标志位不受影响。LAHF与SAHF指令的用途是为了方便修改某些状态标志。先把标志传送到AH,修改后再写回标志寄存器。【例2】把AF标志置为1。程序段如下:LAHFORAH,00010000BSAHF注:其实要修改某个标志位,也可以用算术指令实现,因为大多数算术指令都会影响这5个状态标志。特别地,对CF标志位,还有专用指令可以修改它。输入输出指令(I/O传送指令)要点:▪输入输出指令是专门用于对输入/输出端口进行读写的指令。▪输入输出指令只能通过AL(或AX)对输入/输出端口进行读写。▪输入输出指令只允许用两种寻址方式:直接寻址和寄存器间接寻址(只能使用DX作为间址寄存器)。输入输出指令简称I/O指令,是专门用于对输入/输出端口(I/O端口)进行读写的指令,共有两条:IN和OUT。使用I/O指令有两点要注意:1)使用哪个寄存器来暂存输入(或输出)的数据?8086指令系统规定,只能通过AL(或AX)与I/O端口进行数据传送。所以指令中的操作数必定有一个是AL(或AX)。2)I/O端口地址如何指定?在8086系统中,不同的I/O端口也是用地址来区分的。I/O指令只允许使用两种寻址方式:(1)直接寻址:在指令中给出一个8位的I/O端口地址,地址范围为0~FFH;(2)寄存器间接寻址:端口地址由DX寄存器指定,地址范围为0~FFFFH。①输入指令IN【格式及操作】INacc,PORT;从I/O端口读数据,传送到AL(或AX),使用直接寻址或:INacc,DX;同上,但使用寄存器间接寻址【功能】从I/O端口输入一个字节到AL或输入一个字到AX中。-在IN指令中,源操作数是一个端口(地址直接写在指令中或由DX间接给出),目的操作数只能是累加器(AL或AX)。-指令的具体形式有以下四种:INAL,port;8位端口地址,输入一个字节到ALINAX,port;8位端口地址,输入一个字到AXINAL,DX;16位端口地址,输入一个字节到ALINAX,DX;16位端口地址,输入一个字到AX【例1】INAL,80H;从地址为80H的端口输入一个字节到ALINAL,DX;从指定端口输入一个字节到AL,端口地址在DX寄存器中【例2】从地址为3A0H的端口输入一个字节到AL。程序段如下:MOVDX,3A0H;将16位端口地址送DX(只能使用DX!)INAL,DX;从该端口输入一个字节到AL注:在此程序段中,IN指令不能写成“INAL,3A0H”,因为3A0H超出直接寻址规定的地址范围。[top]②输出指令OUT【格式及操作】OUTPORT,acc;将AL(或AX)中的内容输出到I/O端口,直接寻址或:OUTDX,acc;同上,但使用寄存器间接寻址【功能】把AL中的8位数据或AX中的16位数据输出到I/O端口。-在OUT指令中,源操作数只能是累加器(AL或AX),目的操作数是I/O端口(地址直接写在指令中或由DX间接给出)。-指令的具体形式有以下四种:OUTport,AL;8位端口地址,将AL中的8位数据输出到端口OUTport,AX;8位端口地址,将AX中的16位数据输出到端口OUTDX,AL;16位端口地址,将AL中的8位数据输出到端口OUTDX,AX;16位端口地址,将AX中的16位数据输出到端口【例3】OUT43H,AL;将AL的内容输出到地址为43H的端口OUTDX,AX;将AX的内容输出,端口地址在DX寄存器中OUT280H,AL;错误!端口地址超出直接寻址规定的地址范围OUT20H,[SI];错误!输出指令的源操作数只能是累加器OUTBX,AL;错误!间接寻址只能使用DX作为间址寄存器【例4】将存储器单元MYDATA中的8位数据输出到280H端口。程序段如下:MOVDX,280H;将16位端口地址280H传送到DX中MOVAL,MYDATA;把MYDATA单元中的数据传送到ALOUTDX,AX;将AL的内容输出到280H端口3.3.2算术运算指令要点:▪算术运算指令可实现加、减、乘、除四类基本算术运算。▪大多数算术运算指令均会影响5个状态标志(CF、ZF、SF、AF、OF)。▪对加减法运算,无符号数和有符号数使用同一套指令,但应注意:参加运算的操作数要么都是无符号数,要么都是有符号数。▪算术运算应考虑溢出问题。概述:8086指令系统提供了加、减、乘、除4组基本的算术运算指令,可实现字节或字、无符号数或有符号数的运算。算术运算指令有单操作数的,也有双操作数的。单操作数指令的操作数不能够是立即数;而双操作数指令中,立即数只能作为源操作数。算术运算会涉及到运算结果是否溢出的问题。无符号数和有符号数的运算是否溢出分别用CF和OF来判断。除4组基本的算术运算指令外,8086指令系统还提供了与之对应的4类十进制运算调整指令。算术运算指令的执行大多会对标志位产生影响。算术运算中的溢出问题:以8位二进制数的加法为例,两个8位数相加时有4种情况:二进制运算对应的十进制运算数据作为无符号数数据作为有符号数Case1:无符号数和有符号数均不溢出00001000+0001111000100110结果:26H(38)CF=0,OF=08+3038未超出8位无符号二进制数表示范围+8+(+30)+38未超出8位有符号二进制数表示范围Case2:无符号数溢出,有符号数不溢出00001000+11111101100000101结果:5CF=1,OF=08+253261超出8位无符号二进制数表示范围+8+(-3)+5未超出8位有符号二进制数表示范围Case3:无符号数不溢出,有符号数溢出00001000+0111110110000101结果:-123(补码)CF=0,OF=18+125133未超出8位无符号二进制数表示范围+8+(+125)+133超出8位有符号二进制数表示范围Case4:无符号数和有符号数均溢出10001000+11110111101111111结果:127CF=1,OF=1136+247383超出8位无符号二进制数表示范围-120+(-9)-129超出8位有符号二进制数表示范围上面四种情况说明,算术运算溢出的判别是比较复杂的,不能只用一个标志位来判别。算术运算溢出是一种出错状态,在运算过程中应当避免。算术运算指令可分成以下5组:加法运算减法运算乘法运算除法运算BCD码运算调整加法运算指令要点:▪加法指令实现两个操作数的求和运算,或者是单个操作数的增量运算。▪判断加法运算是否溢出,应根据操作是有符号数加法还是无符号数加法区别对待。▪加法运算会改变状态标志位的值。▪对加法运算,无符号数和有符号数使用同一套指令,但应注意:参加运算的操作数要么都是无符号数,要么都是有符号数。加法指令包括不带进位的加法指令ADD、带进位的加法指令ADC和加1(增量)指令INC。①不带进位的加法指令ADD【格式及操作】ADDdest,src;dest←(dest)+(src)【功能】实现两个操作数的相加,其结果送回目的操作数中。加法指令对操作数的要求如下:可以是字节(8位),也可以是字(16位),但二者必须一致。源操作数可以是立即数。可以是无符号数,也可以是有符号数,但二者应一致。不允许都是存储器操作数。不允许是段寄存器。【例1】ADDCL,20H;CL←(CL)+20HADDAX,SI;AX←(AX)+(SI)ADD[BX+2],AL;(BX+2)←((BX)+2)+(AL)ADDDX,[BX+SI];DX←(DX)+((BX)+(SI))ADDAX,CL;错误!操作数类型应一致ADD[SI],[BX];错误!不允许两个操作数都是存储器ADDDS,AX;错误!不允许把段寄存器作为操作数加法指令对全部6个状态标志位都会产生影响。【例2】试分析以下两条指令执行后的状态:MOVAL,7EH

ADDAL,5BH

分析:我们用手工的方法来模拟以上两条指令的执行,如下......01111110+0101101111011001根据运算过程可得出各状态标志位的值:(Ci表示第i位的进位)C3=1,所以AF=1;C7=0,所以CF=0;C7⊕C6=1,所以OF=1;结果中1的个数为奇数,所以PF=0;结果的bit7=1,所以SF=1;结果不为零,所以ZF=0。其中CF=0意味着若操作数是无符号数,则结果没有产生溢出;而OF=1意味着若操作数是有符号数,则运算结果溢出。事实上,根据运算结果AL=D9H>7FH(8位有符号数的最大值)和D9H<FFH(8位无符号数的最大值)也可得到相同结果。[top]②带进位的加法指令ADC【格式及操作】ADCdest,src;dest←(dest)+(src)+(CF)【功能】源操作数dest、目的操作数src、进位标志CF三者相加,结果送回目的操作数中。ADC指令在格式、功能及对标志位的影响方面都与ADD指令基本相同,只是CF也要参加求和运算。【例3】设CF=1,写出以下指令执行后的结果。MOVAL,7EH

ADCAL,86H

指令执行后:AL=7EH+ABH+1=2AH,且CF=1。ADC指令主要用于多字节的加法运算中。由于8086一次最多只能进行16位的加法运算,故对于多字节加法,应把操作数分成若干个16位数(或8位数)分别求和,而在高位相加时,必须要考虑低位的进位,这时就要用到ADC指令。【例4】求两个32位无符号数0107A379H与10067E4FH二者之和。MOVDX,0107H;第一个数高16位传送到DX

MOVAX,0A379H;第一个数低16位传送到AX

MOVBX,1006H;第二个数高16位传送到BX

MOVCX,7E4FH;第二个数低16位传送到CX

ADDAX,CX;低16位相加,进位在CF中ADCDX,BX;高16位相加,并加上低16位的进位

相加的最后结果为:110E21C8H。[top]③加1(增量)指令INC【格式及操作】INCdest;dest←(dest)+1【功能】目的操作数加1,结果仍送回目的操作数中。本指令的功能类似于C语言中的“++”运算符,通常在循环程序中用于修改地址指针及循环次数。指令中的操作数可以是寄存器或存储器操作数;可以是8位,也可以是16位。但不能是段寄存器,也不能是立即数。【例5】INCAX;AX←(AX)+1

INCBL;BL←(BL)+1

INCBYTEPTR[SI];将SI所指向的字节单元的内容+1INC指令不影响CF标志,但对其它5个状态标志AF、OF、PF、SF及ZF会产生影响。减法运算指令要点:▪减法指令实现两个操作数的求差运算,或者是单个操作数的减量运算。▪判断减法运算是否溢出,应根据操作是有符号数减法还是无符号数减法区别对待。▪减法运算会改变状态标志位的值。▪对减法运算,无符号数和有符号数使用同一套指令,但应注意:参加运算的操作数要么都是无符号数,要么都是有符号数。减法指令包括不带借位的减法指令SUB、带借位的减法指令SBB、减1(减量)指令DEC、求补指令NEG以及比较指令CMP。①不带借位的减法指令SUB【格式及操作】SUBdest,src;dest←(dest)-(src)【功能】用目标操作数减去源操作数,结果仍送回目标操作数。SUB指令对操作数的要求以及对状态标志位的影响和ADD指令完全相同。请参考ADD指令。【例1】SUBAL,60H

SUB[BX+20H],DX

SUBAX,CXSUBAL,[BX+SI];AL的内容与SS:(BP+SI)单元的内容相减,结果送AL[top]②带借位的减法指令SBB【格式及操作】SBBdest,src;dest←(dest)-(src)-(CF)【功能】用目的操作数减去源操作数以及标志位CF的值,结果仍送到目的操作数。SBB指令对操作数的要求以及对状态标志位的影响与SUB指令完全相同,只是CF也要参加求差运算。【例2】SBBBL,30H;BL←(BL)-30H-(CF)SBBDX,[SI];DX←(DX)-((SI))-(CF)SBB指令主要用于多字节的减法运算,它与ADC指令的用法基本类似。【例3】x、y、z均为32位数,分别存放在地址为X、Y、Z的三个存储单元中,用指令序列实现w=x+y+24-z,结果放在W单元中。解:因为x、y、z均为32位数,所以我们用两个16位寄存器完成32位运算。程序段如下:MOVAX,X

MOVDX,X+2;DX:AX←x

ADDAX,Y

ADCDX,Y+2;DX:AX←x+y

ADDAX,24

ADCDX,0;DX:AX←x+y+24

SUBAX,ZSBBDX,Z+2;DX:AX←x+y+24-z

MOVW,AX

MOVW+2,DX;32位结果存入W单元[top]③减1(减量)指令DEC【格式及操作】DECdest;dest←(dest)-1【功能】将目的操作数的内容减1,结果仍然放在目的操作数中。本指令的功能类似于C语言中的“――”运算符,通常在循环程序中用于修改地址指针及循环次数。DEC指令对操作数的要求以及对标志位的影响与INC指令完全相同。【例4】DECSI;SI←(SI)-1

DECBX;BX←(BX)-1

DECBYTEPTR[DI];(DI)←((DI))-1【例5】编写一个延时程序,延时时间任意。解:可以用空循环的方法消耗时间,在循环中对计数器CX减1,直到CX=0为止。MOVCX,1000H;用CX作为计数器,计数初值为FFFFHNEXT:DECCX;计数器(CX)减1JNZNEXT;若CX≠0则循环

...;延时结束[top]④比较指令CMP【格式及操作】CMPdest,src;(dest)-(src)【功能】CMP指令对两个操作数相减,但相减的结果不送回目的操作数,而只是根据相减的情况设置标志位。比较指令对操作数的要求及对标志位的影响与SUB指令完成相同。【例6】CMPBX,2100H;(BX)-2100H,修改标志位

CMPCL,DH;(CL)-(DH),修改标志位比较指令在使用时,一般在其后紧跟一个条件转移指令,根据比较结果来决定程序转向。【例7】比较AL、BL、CL中带符号数的大小,将最小数放在AL中。CMPAL,BL;AL和BL比较

JLEBBB;若AL≤BL,则转到NEXT

XCHGAL,BL;若AL>BL,则交换NEXT:CMPAL,CL;AL和CL比较

JLEL;若AL≤CL,则转到STOP

XCHGAL,CL;若AL>CL,则交换STOP:HLT[top]⑤求补指令NEG【格式及操作】NEGdest;dest←0-(dest)【功能】目的操作数为正数时,本指令计算目的操作数的负数的补码,结果仍然放在目的操作数中。目的操作数为负数时,本指令计算目的操作数的绝对值,结果仍然放在目的操作数中。【例8】若AL=47H,则执行NEGAL后,AL=B9H,CF=1。

本例中,结果B9H为(-47H)的补码。NEG指令对六个状态标志位均有影响。但要注意以下两点:(1)执行NEG指令后,一般情况下都会使CF为1。因为用零减去某个操作数,自然会产生借位,而减法的CF值正是反映无符号数运算中的借位情况。除非给定的操作数为零才会使CF为0。(2)若操作数的值为80H(-128)或为8000H(-32768),则执行NEG指令后,其结果仍为80H或8000H,但OF置1,其它情况下OF均置0。乘法运算指令要点:▪有符号数和无符号数的乘法需要使用不同的乘法指令。▪乘法指令只需指出源操作数(即指令中只需指定乘数),被乘数和目的操作数隐含为累加器(和DX)。▪乘法运算中乘数(被乘数)的字长与积的字长的关系:8位×8位→16位乘积,16位×16位→32位乘积。乘法指令对被乘数、乘数及乘积的存放有如下规定:乘积被乘数乘数8位乘法AXAL指令中给出16位乘法DX:AXAX指令中给出①无符号数乘法指令MUL【格式及操作】MULsrc;AX←(AL)×src(8位乘法)或DX:AX←(AX)×src(16位乘法)【操作数】指令中的源操作数可以是8位(或16位)的寄存器或存储器单元,但不能是立即数。【例1】MULDL;AX←(AL)×(DL)MULBX;DX:AX←(AX)×(BX)MULBYTEPTR[SI];AX←(AL)×((SI))

MULW0RDPTR[DI];DX:AX←(AX)×((DI)+1):(DI))MUL10;错误!源操作数不能为立即数MULAL,BL;错误!目的操作数无需写出【标志位】如果乘积的高8位(8位乘法)或高16位(16位乘法)不为零——即AH或DX中包含乘积的有效数字,则CF=0F=l,否则CF=0F=0。其它标志无定义。【备注】在某些情况,可用左移指令来代替无符号数乘法指令(左移1位相当于乘2),请参见移位指令的说明。②有符号数乘法指令IMUL【格式及操作】IMULsrc;AX←(AL)×src(8位乘法)或DX:AX←(AX)×src(16位乘法)【操作数】与上述MUL指令的要求相同。只是此指令把操

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论