第一章:8086的指令格式和寻址方式
简介
- 指令:
- 控制计算机完成某种操作的命令。
- 通俗的来讲: 人向计算机发出的并且能够让计算机所识别的一种命令,它用来控制、要求计算机来做意见具体的事情。
- 指令的兼容性:
- 同一系列机的指令都是兼容的。
- 8086尽管与现在的i5/i7没法比,但是他们是一个体系的。
- 即用8086指令集所编写的指令,在今天的i7上仍可以运行
- 概括:
- 微机的基本工资原理可概括为程序存储和程序控制
- 程序就是指令的集合
- 指令是微处理器所能执行的操作命令,是由一系列二进制代码组成。
- 不同的微处理器可识别的指令系统不同
- 一个微机系统所能执行的全部指令的集合成为指令系统。
- 由于指令本身是机器码或二进制代码的形式,编程人员不易编写和检查,所以在编程时,每条指令用一定格式的助记符来代替它,这种助记符形式的语言称为汇编语言
- 当微机执行用汇编语言编写的程序时,首先将其转换成机器码,这个过程称为编译,然后再执行经转换后的机器码形式的指令序列。
8086的指令格式
- 简要:
- 8086的指令由操作码和操作数两部分组成。
- 操作码指出指令的操作类型,操作数则指出操作的对象。
- 一条指令最多有两个操作数,也可能只有一个操作数,或者一个操作数也没有,但是必须有操作码
-
指令的具体格式:
[标号:] 操作码 [操作数1] [操作数2] [;注释]
- 方括号表示括号内的内容不一定存在
- 标号: 实际上表示的是地址,即内存码段中存放该指令的第一个字节的地址。
- 在分支、循环的程序结构中,当程序需要跳转到该指令处时,用标号指出具体的目的地地址。
- 操作码:指出操作的类型或者操作的性质。比如:加法、传送等
- 操作数: 指出操作的对象.
- 一般来说是操作数本身或者存放操作数的内存(或I/O端口)地址
- 每条指令的操作数多少要视具体指令的性质而定。
- 操作数1: 目标操作数,运算结果的去向或者另外一个数据的来源(加法运算时)
- 操作数2: 源操作数,操作数的来源
-
注释:在指令后可以用分号间隔,对指令进行注解,称为注释。不进行编译
MOV AX, BX ;表示将BX寄存器中的内容传送到AX寄存器中
- 零操作数指令:
操作码
- 这种情况表面上是没有操作数,实际上是固定了的,因此没有必要显示了
- 单操作数指令:
操作码 操作数
- 指令中的操作数类型:
- 立即操作数:参加操作数的数据本身
- 立即数本身是参加操作的数据,可以是8位或16位,只能作为源操作数。
- 立即数可以是无符号或者带符号数,数值符合其取值范围。
- 寄存器操作数:数据存放的地址
- 参加运算的数据存放在指令给出的寄存器中,可以是16位或8位。
- 多数情况下,寄存器操作数指的是通用寄存器,控制寄存器不会再指令中直接的出现,而段寄存器无法有程序员控制。
- 在这3类操作数中,寄存器操作数所需运行时间最短。
- 存储器(内存)操作数:数据存放的地址
- 参加运算的数存放在存储器的某一个或某两个单元中
- 表现形式:
[ ]
,即指令的操作数出现[]
,表示要寻址的数在内存中。 - 括号里面放的是操作数在内存中的偏移地址。
-
举例:
MOV AL, [1200H] MOV AX, [1200H] 1. 第一条指令: 把内存中偏移地址为1200H,存储的数据传送给AL 2. 第二条指令: 把内存中偏移地址为1200H开头的连续2个字节的地址,存储的数据传送给AX.即把1200H单元的内容给AL,把1201H单元的内容给AH. 3. 由第二条指令我们看出,存储器操作数到底是传了几个单元的数据是不确定的,完全要取决于另外一个操作数(目标操作数)的字长。
- 即指令中一旦出现
[]
,说明就在内存中,具体在内存那个位置,就看[]
,内部的内容。 - 在这3类操作数中存储器操作数所需时间最长。
- 注意: 8086、8088是16位CPU,指令操作数可以是8位或16位。
- 立即操作数:参加操作数的数据本身
8086的寻址方式
- 顾名思义: 就是寻找操作数所在地址的方法。
- 在汇编语言中,操作数是操作的对象,指明参加操作的数或者他所在的地址。指令中的操作数来源主要有以下4种:
- 操作数包含在指令中,即操作数为常数。即立即数
- 操作数在CPU的某个寄存器中,此时操作数是该寄存器名
- 操作数在内存中,此时在指令中表示的事该操作数所在的内存的偏移地址。
- 操作数在I/O端口中,此时在指令中表示的事该操作数所在的I/O端口的地址。
- 这4种来源的操作数通过不同的寻址方式来描述。在汇编语言中,是通过不同的书写方式来区分不同的寻址方式
立即寻址
- 操作数为常数,成为立即数。
- 只能作为源操作数
- 操作数直接放在指令编码中,紧跟在操作码的后面,存放在存储器的码段区域内。
- 立即数可以是8或16位
-
举例;
MOV AX,2030H
寄存器寻址
- 操作数放在CPU的内部寄存器中,而寄存器名在指令中指出。
- 8086、8088的寄存器的宽度均为8或16位二进制,在寻址时,源操作数与目的操作数的寄存器宽度要一致。
-
举例:
MOV AX,BX
存放于存储器(内存)中的寻址方式
- 指令操作的对象在内存中,表现形式为:
[]
- 指令中给出运算对象在内存某个逻辑段中的偏移地址。[偏移地址]
- 即只要指令中出现
[]
,那就是存储器寻址 - 但是
[]
中的偏移地址给出的形式有多种样式,因此,根据不同的形式,有细分出了下面几种寻址方式 - 注意: 前面我们讲过段寄存器存放的事内存各个逻辑段的首地址,而且是程序员不能操作的,是由操作系统直接分配的。因此我们只管偏移地址就行了
1. 直接寻址
[]
中的内容直接给出的是操作数在内存中的偏移地址。即指令中直接给出操作数的偏移地址。- 在直接寻址中,默认的操作数所在的段是数据段,即操作数的物理地址是由数据段的段地址和指令中给出的偏移地址组成的。
- 段超越:即默认在数据段,但是我不想让他在数据段。用指令给出所在逻辑段,指令中必须加上段超越前缀。
-
举例:
例题1: MOV AX,[1006H] 如果执行前(DS) = 4000H (41006H) = 12H (41007) = 34H,则执行后(AX) = 1234H 分析: 将内存数据段内偏移地址为1007H,1006H两个单元中的16位数据复制到寄存器AX中去。 物理地址 = DS*16 + 1006H = 41006H 根据目的操作数(AX)的宽度(16位)决定读取一个字节或者两个字节的内存单元。 例题2:段超越 MOV SS:[2000H], BX 分析: 此时目的操作数为内存中,源操作数在寄存器中,即将寄存器中的数传递到内存中去 在内存中的那个段呢? 如果没有前缀:SS: 那么就是内从中的数据段,偏移地址为2000H处,但是加了SS: 前缀,那就代表将BX寄存器中的数据传递到内存堆栈段内偏移地址为2001H和2000H这两个单元中。
2. 寄存器间接寻址
- 顾名思义就是[]中没有直接给出操作数在内存中的偏移地址,而是间接给出的。
- []中的内容给出的是寄存器,就是说寄存器中存放了操作数在内存中的偏移地址。
- 操作数存放在内存中,数据在内存中的偏移地址为方括号中通用寄存器的内容。
- 即只要指令中出现 [寄存器],就是寄存器间接寻址。
- 注意: 仅有4个通用寄存器可用于存放数据的偏移地址。这4个寄存器也叫间址寄存器
- 这4个分别为:BX/BP/SI/DI
- []中出现这4个寄存器不同,那么操作数存放在内存中的段区域也不同。
- 若以BX/SI/DI间接寻址,操作数存储在数据段,即操作数的物理地址是由数据段的段基址DS和对应寄存器存储的偏移地址组合而成的
- 若以BP间接寻址,操作数存储在堆栈段,即操作数的物理地址是由堆栈段的段基址SS和BP寄存器存储的偏移地址组合而成的
- 注意: 存储器间接寻址也支持段超越!
-
举例:
MOV AX,[BX] MOV AX,[BP]
3. 寄存器相对寻址
- 操作数的偏移地址为寄存器的内容 + 一个位移量
- 操作数所在的内存段由间址寄存器决定,当然也支持段超越
- 细分的话又分为基址寻址、变址寻址
- BX/BP成为基址寄存器
- SI/DI为变址寄存器
-
常见表现形式:
MOV AX,10H[BX] MOV AX,[BX]10H MOV AX,[BX+10H] MOV AX,[BX]+10H
- 相对寻址主要用于一维数组的操作
- 常将位移量作为表头地址,间址寄存器值作为表内相对地址。
4. 基址加变址寻址
- 操作数的偏移地址为一个基址寄存器的内容 + 一个变址寄存器的内容
- 操作数的段地址由选择的基址寄存器决定
- 基址寄存器为BX,默认在数据段
- 基址寄存器为BP,默认在堆栈段
- 也支持段超越
-
举例:
MOV AX, [BX+SI+110H] ;在数据段 MOV AX, [BP+SI+110H] ;在堆栈段 MOV AX, [BP][SI]110H ;在堆栈段
隐含寻址
- 指令中隐含了一个或两个操作数的地址,即操作数在默认地址中
-
举例:
MUL BL 相当于: AL*BL -> AX 默认了