汇编语言从入门到精通-5微机CPU的指令系统1

微机CPU的指令系统

5.1 汇编语言指令格式
  为了介绍指令系统中指令的功能,先要清楚汇编语言是如何书写指令的,这就象在学习高级语言程序设计时,要清楚高级语言语句的语义、语法及其相关规定一样。

5.1.1 指令格式
  汇编语言的指令格式如下:

    指令助忆符 [操作数1 [, 操作数2 [, 操作数3]]]   [;注释]

  指令助忆符体现该指令的功能,它对应一条二进制编码的机器指令。指令的操作数个数由该指令确定,可以没有操作数,也可以有一个、二个或三个操作数。绝大多数指令的操作数要显式的写出来,但也有指令的操作数是隐含的,不需要在指令中写出。

  当指令含有操作数,并要求在指令中显式地写出来时,则在书写时必须遵守:

    ● 指令助忆符和操作数之间要有分隔符,分隔符可以是若干个空格或TAB键;
    ● 如果指令含有多个操作数,那么,操作数之间要用逗号","分开。

  指令后面还可以书写注释内容,不过,要在注释之前书写分号";"。

5.1.2 了解指令的几个方面
  在学习汇编指令时,指令的功能无疑是我们学习和掌握的重点,但要准确、有效地运用这些指令,我们还要熟悉系统对每条指令的一些规定或约束。

  归纳起来,对指令还要掌握以下几个方面内容:

    1、要求指令操作数的寻址方式;
    2、指令对标志位的影响、标志位对指令的影响;
    3、指令的执行时间,对可完成同样功能的指令,要选用执行时间短的指令(见汇编语言从入门到精通-指令汇总)。

5.2、指令系统
  指令系统是CPU指令的集合,CPU除了具有计算功能的指令外,还有实现其它功能的指令,也有为某种特殊的应用而增设的指令。

  通常,把指令按其功能分成以下几大类:

    数据传送指令        循环指令 

    标志位操作指令          转移指令 

    算术运算指令        条件设置字节指令 

    逻辑运算指令        字符串操作指令 

    移位操作指令        ASCII-BCD码运算调整指令 

    位操作指令           处理器指令   

    比较运算指令

  下面,我们逐一介绍每类指令中的指令。

5.2.1 数据传送指令
  数据传送指令又分为:传送指令、交换指令、地址传送指令、堆栈操作指令、转换指令和I/O指令等。

  除了标志位操作指令SAHF和POPF指令外,本类的其它指令都不影响标志位。

  1、传送指令MOV(Move Instruction)

  传送指令是使用最频繁的指令,它相对于高级语言里的赋值语句。指令的格式如下:

    MOV Reg/Mem, Reg/Mem/Imm

  其中:Reg—Register(寄存器),Mem—Memory(存储器),Imm—Immediate(立即数),它们可以是8位、16位或32位(特别指出其位数的除外)。在本网络课件的网页中,都将采用上述缩写,此后不再说明。

  指令的功能是把源操作数(第二操作数)的值传给目的操作数(第一操作数)。指令执行后,目的操作数的值被改变,而源操作数的值不变。在存储单元是该指令的一个操作数时,该操作数的寻址方式可以是任意一种存储单元寻址方式。

  下面列举几组正确的指令例子:

  源操作数是寄存器

    MOV CH, AL   MOV BP, SP      MOV ECX, EBX
    MOV DS, AX   MOV [BX], CH   MOV [BX+SI], AX
  源操作数是存储单元

    MOV AL, [100H]   MOV BX, ES:[DI]   MOV EDX, [BX]
    MOV BX, VARW   MOV AX, [BX+SI]   MOV CH, [BX+DI+100H]
    其中:VARW是字类型内存变量(下同)。
  源操作数是立即数

    MOV AL, 89H     MOV BX, -100H      MOV EDX, 12345678H
    MOV VARW, 200H     MOV [BX], 2345H   MOV [BX+DI], 1234H

  在汇编语言中,主要的数据传送方式如图5.1所示。虽然一条MOV指令能实现其中大多数的数据传送方式,但也存在MOV指令不能实现的传送方式。

 

图5.1 MOV指令数据传送示意图

  对MOV指令有以下几条具体规定,其中有些规定对其它指令也同样有效。

    1)、两个操作数的数据类型要相同,要同为8位、16位或32位;如:MOV BL, AX等是不正确的;

    2)、两个操作数不能同时为段寄存器,如:MOV ES, DS等; 

    3)、代码段寄存器CS不能为目的操作数,但可作为源操作数,如:指令MOV CS, AX等不正确,但指令MOV AX, CS等是正确的;

    4)、立即数不能直接传给段寄存器,如:MOV DS, 100H等; 

    5)、立即数不能作为目的操作数,如:MOV 100H, AX等; 

    6)、指令指针IP,不能作为MOV指令的操作数; 

    7)、两个操作数不能同时为存储单元,如:MOV VARA, VARB等,其中VARA和VARB是同数据类型的内存变量。

  对于规定2、4和7,我们可以用通用寄存器作为中转来达到最终目的。表5.1列举一个可行的解决方案,尽供参考。读者可考虑用其它办法来完成同样的功能。

表5.1 MOV指令的变通方法

功能描述

不正确的指令

可选的解决方法

把DS的值传送给ES

MOV  ES, DS

MOV  AX, DS
MOV  ES, AX

把100H传给DS

MOV  DS, 100H

MOV  AX, 100H
MOV  DS, AX

把字变量VARB的值传送给字变量VARA

MOV  VARA, VARB

MOV  AX, VARB
MOV  VARA, AX


  对于情况1:不同位数数据之间的传送问题,在80386及其以后的CPU中,增加一组新的指令——传送-填充指令,它可把位数少的源操作数传送给位数多的目的操作数,多出的部分按指令的规定进行填充。

  2、传送—填充指令(Move-and-Fill Instruction)

  传送—填充指令是把位数短的源操作数传送给位数长的目的操作数。指令格式如下:

    MOVSX/MOVZX  Reg/Mem, Reg/Mem/Imm     ;80386+

  其中:80386+表示80386及其之后的CPU,其它类似符号含义类同,不再说明。

  指令的主要功能和限制与MOV指令类似,不同之处是:在传送时,对目的操作数的高位进行填充。根据其填充方式,又分为:符号填充和零填充。

  传送—填充指令的功能如图5.2所示。

(a). MOVSX的执行效果

 (b). MOVZX的执行效果

 图5.2 传送—填充指令执行过程示意图

  1、符号填充指令MOVSX(Move with Sign-Extend)

    MOVSX的填充方式是:用源操作数的符号位来填充目的操作数的高位数据位。

  2、零填充指令MOVZX(Move with Zero-Extend)

    MOVZX的填充方式是:恒用0来填充目的操作数的高位数据位。

  例5.1 已知:AL=87H,指令MOVSX  CX, AL,MOVZX  DX, AL执行后,问CX和DX的值是什么?
    解:根据传送-填充指令的填充方式可知:

  指令MOVSX CX, AL执行后,(CX)=0FF87H,指令MOVZX DX, AL执行后,(DX)=0087H。

  从上例可看出,两条指令的源操作数完全一样,但因为它们的填充方式不同,所得到的结果而就不同。

  试比较下列指令,分析它们执行结果的相同和不同之处:

    MOV AX, 87H   MOVSX AX, 87H   MOVZX AX, 87H

  3、交换指令XCHG(Exchange Instruction)

  交换指令XCHG是两个寄存器,寄存器和内存变量之间内容的交换指令,两个操作数的数据类型要相同。其指令格式如下:

    XCHG  Reg/Mem, Reg/Mem

  该指令的功能和MOV指令不同,后者是一个操作数的内容被修改,而前者是两个操作数都会发生改变。寄存器不能是段寄存器,两个操作数也不能同时为内存变量。

图5.3 XCHG指令的执行功能示意图

  例5.2 已知:AX=5678H,BX=1234H,指令XCHG  AX, BX执行后,AX和BX的值是什么?
  解:这是两个寄存器内容进行交换,指令执行后,有:(AX)=1234H,(BX)=5678H。

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

  指令LEA是把一个内存变量的有效地址送给指定的寄存器。其指令格式如下:

    LEA Reg, Mem

  该指令通常用来对指针或变址寄存器BX、DI或SI等置初值之用。其功能如下图所示。

                                            

图5.4 LEA指令的功能示意图

  例如:

    …

    BUFFER   DB  100 DUP(?)

    …

    LEA    BX, BUFFER     ;把字节变量BUFFER在数据段内的偏移量送给BX

    …

  问题:指令“LEA  BX BUFFER”和“MOV  BX, OFFSET BUFFER”的执行效果是一样的吗?指令“LEA BX,[BX+200]”和“MOV BX,OFFSET [BX+200]”二者都正确吗?

    1、OFFSET是将数值回送变量或标号的偏移地址值. 

    2.LEA是将数值回送变量或标号的有效地址值.

    3.SEG, 汇编程序将回送变量或标号的段地址值. 

    4、LEA  BX,LIST5、MOV  BX,OFFSET  LIST6、可以看出,LEA和OFFSET这两条指令在功能上是相同的,BX寄存器都可得到符号地址LIST的值,而且此时MOV指令的执行速度会比LEA指令更快。但是,OFFSET只能与简单的符号地址相连,而不能和诸如LIST[SI]或[SI]等复杂操作数相连。因此,LEA指令在取得访问变量的工具方面是很有用的。

  5、取段寄存器指令(Load Segment Instruction)

  该组指令的功能是把内存单元的一个“低字”传送给指令中指定的16位寄存器,把随后的一个“高字”传给相应的段寄存器(DSESFSGSSS)。其指令格式如下:

    LDS/LES/LFS/LGS/LSS Reg, Mem

  指令LDS(Load Data Segment Register)和LES(Load Extra Segment Register)在8086CPU中就存在,而LFSLGS(Load Extra Segment Register)、LSS(Load Stack Segment Register)是80386及其以后CPU中才有的指令。

  若Reg是16位寄存器,那么,Men必须是32位指针;若Reg是32位寄存器,那么,Men必须是48位指针,其低32位给指令中指定的寄存器,高16位给指令中的段寄存器。指令的执行结果如图5.5所示。

   

(a) 32位指针

   

(b) 48位指针

图5.5、LDS指令的执行步骤示意图

  例如:

    …

    POINTER   DD 12345678H

    …

    LDS    BX, POINTER

    …

  指令的执行结果如图5.5所示。各寄存器的内容分别为:(BX)=5678H,(DS)=1234H。
  下面控件是学习和掌握MOVMOVSX/MOVZXXCHGLEA、LDS/LES/LFS/LGS/LSS指令的,它可检查用户输入这些指令的合法性,并对合法的指令显示其执行的结果。

  注意:如果指令中含有表示内存单元的寻址方式,那么其控件中的"内存单元的类型"即表示该指令中内存单元的数据类型。

  6、堆栈操作指令(Stack Operation Instruction)

  堆栈是一个重要的数据结构,它具有“先进后出”的特点,通常用来保存程序的返回地址。它主要有两大类操作:进栈操作和出栈操作。

  1)、进栈操作

  a、PUSH(Push Word or Doubleword onto Stack)

    指令格式: PUSH Reg/Mem
          PUSH Imm          ;80286+

      • 一个字进栈,系统自动完成两步操作:SP←SP-2,(SP)←操作数;

      • 一个双字进栈,系统自动完成两步操作:ESP←ESP-4,(ESP)←操作数。

  b、PUSHA(Push All General Registers)

    指令格式:PUSHA       ;80286+

    其功能是依次把寄存器AX、CX、DX、BX、SP、BP、SI和DI等压栈。

  c、PUSHAD(Push All 32-bit General Registers)

    指令格式:PUSHAD       ;80386+

    其功能是把寄存器EAX、ECX、EDX、EBX、ESP、EBP、ESI和EDI等压栈。

  2)、出栈操作

  a、POP(Pop Word or Doubleword off Stack)

    指令格式:POP Reg/Mem

      • 弹出一个字,系统自动完成两步操作:操作数←(SP),SP←SP-2;

      • 弹出一个双字,系统自动完成两步操作:操作数←(ESP),ESP←ESP-4。

  b、POPA(Pop All General Registers)

    指令格式:POPA       ;80286+

    其功能是依次把寄存器DI、SI、BP、SP、BX、DX、CX和AX等弹出栈。其实,程序员不用记住它们的具体顺序,只要与指令PUSHA对称使用就可以了。

  c、POPAD(Pop All 32-bit General Registers)

    指令格式:POPAD      ;80386+

    其功能是依次把寄存器EDI、ESI、EBP、ESP、EBX、EDX、ECX和EAX等弹出栈,它与PUSHAD对称使用即可。

  7、转换指令XLAT(Translate Instruction)

    转换指令有两个隐含操作数BX和AL。指令格式如下:

      XLAT/XLATB

    其功能是把BX的值作为内存字节数组首地址、下标为AL的数组元素的值传送给AL。其功能描述的表达式是:AL←BX[AL],其功能示意图如图5.6所示。

图5.6 XLAT/XLATB指令的功能示意图

  8、I/O指令

    有关I/O指令将在第8.1.2节——I/O指令——中介绍,在此从略。

 

原文地址:https://www.cnblogs.com/little-kwy/p/9874768.html