【微机原理与接口 5】—— 常用指令分析1 (数据传输类指令剖析)

一、数据传输类指令

1.1 通用数据传输指令

1.1.1 MOV指令

首当其冲的就是 M O V MOV 指令了,它的形式是 : M O V MOV 目标操作数,源操作数

下面重点看看 M O V MOV 指令对操作数的要求:

  1. 目标操作数和源操作数的字长必须相同
  2. 两个操作数不能同时为段寄存器
  3. 两个操作数不能同时为存储器操作数(也就是说,如果我们想把内存单元的某一个数赋值到内存的另外一个单元,是不能一步到位的,必须借助中间媒介)
  4. 目标操作数不能为立即数
  5. 立即数不能直接传输给段寄存器
  6. CS,IP 不作为目标操作数

辨析下面指令:
【1】MOV DS, 1000H (×):立即数不能够直接赋值给段寄存器
【2】MOV CS, AX (×):代码段寄存器不能作为目标操作数
【3】MOV VALUE1, CX (×):这里的 VALUE1 是一个定义了的变量,那么它就是一个立即数,立即数不能够作为目标操作数
【4】MOV [BX], [SI] (×):这里用方括号表示存储器寻址,那么 [SI] 就代表存储器里面的一个数,MOV 指令中两个操作数不能够同时为存储器操作数
【5】MOV DS, ES (×):两个操作数不能同时为段寄存器
【6】MOV AH, BX (×):两个操作数字长不一致,AH 是8位的,BX 是16位的
【7】迷惑题:MOV DX,09H (√):看起来这两个操作数字长不等,但是别忘了,09H 是0开头的,既然是0开头,前面有几个0都可以,那么09H 可以写成 0009H,这样就 OK 了

1.1.2 堆栈操作指令 PUSH , POP

学完了数据结构,对于堆栈的定义应该不陌生。但是这里需要说明一件事情:就是 堆栈操作指令所操作的数必须是一个字(两个字节),也就是 16位的数!

指令: P U S H PUSH 源操作数; P O P POP 目标操作数

先看看 P U S H PUSH ,我们知道但凡堆栈,都有栈顶指针。那么在这里我们默认栈顶指针都是在高地址的(下面),在有新数据压入时,栈顶指针自减,然后会往上变成低地址。
对于 PUSH 操作,我们首先先将栈顶指针 S P SP S P 2 S P SP - 2\to SP ,然后把数据压入(16位的!)

对于 POP 操作,类似地,我们先将栈顶指针做: S P + 2 S P SP+2\to SP (+代表往下,地址增大)

说明:8088/8086 对于单操作数的指令,都是不允许操作数是立即数的!!!

1.1.3 交换指令 XCHG

X C H G XCHG 操作数1, 操作数2

这个指令的作用就是将两个操作数的内容互换,但是对操作数有以下要求:

  1. 任何一个操作数都不能为立即数。因为这两个操作数既是源操作数,又是目标操作数。既然是目标操作数就不能是立即数。
  2. 两个操作数中必须得保证有一个是寄存器操作数,例如 BX, AX之类的
  3. 两个操作数不能够同时为存储器操作数。(也就是存储器寻址方式)
  4. 同样不允许有段寄存器作为操作数

例如: X C H G B X , [ B P + S I ] XCHG\quad BX, [BP+SI]
假设 BX寄存器内存放的内容是 BX = 6F30H, [ B P + S I ] [BP+SI] 是基址+变址寻址方式,由于没有段超越,所以BP默认的段寄存器是 SS,假设:SS = 2F00H, BP = 0200H,SI = 0046H 那么 [ B P + S I ] [BP+SI] 表示的偏移地址是:0246H,对应的物理地址就是:2F000H+0246H = 2F246H。那么也就是把 内存地址为 2F246H 的数和寄存器 BX 内的数交换

1.1.4 查表指令 XLAT

这个适用于查找一维数组中的元素。使用 XLAT 的时候不用写操作数,直接 XLAT 就OK。
但是,有几点说明:

  1. XLAT 规定:需要使用 BX 存放表头地址,AL 用于存放一维数组中元素距表头的距离。因此,需要查找的元素地址就是 BX+AL
  2. 那么 XLAT 的工作是将地址 BX+AL 所指向的数组元素赋值给 AL

1.2 地址传输类指令

1.2.1 LEA (近地址)

LEA 指令是取近地址的,也就是说,LEA 工作的区域就是在同一个段里面,因此不用考虑段基址

LEA REG, MEM。LEA指令的功能是将变量的 16 位的偏移地址写入到目标寄存器。注意:LEA 指令的源操作数一定要是存储器操作数!!

LEA 的目标操作数一定不能是段寄存器,而一定是通用寄存器!!,通常是间址寄存器

例子:LEA BX, [BX][SI]
假如有:BX = 1000H, SI = 1000H.那么偏移地址是 3000H,结果:BX = 3000H

1.2.2 LDS & LES (远地址)

LDS 和 LES 都是取的远地址。也就是在另外一个段的地址。这样一来,就需要同时取段基地址和偏移地址了。也就是说,LDS 和 LES 的源操作数应该是一个 32 位的存储器操作数

格式如下:
LDS 通用寄存器,存储器操作数
LES 通用寄存器,存储器操作数

例子:

LDS 的作用是将存储器操作数的偏移地址赋值给 通用寄存器,将其段地址赋值给 DS 寄存器
LES 的作用是将存储器操作数的偏移地址赋值给 通用寄存器,将其段地址赋值给 ES 寄存器

1.3 标志位传输指令

这里我们将要了解 4 个指令: L A H F , S A H F , P U S H F , P O P F LAHF, SAHF, PUSHF, POPF
首先是: L A H F LAHF S A H F SAHF ,它们的默认操作数是 F A L G S FALGS A H AH 。其中, L A H F LAHF 的英文全称是:Load AH from flags. 也就是说,它的功能是将 F L A G S FLAGS 寄存器的第八位赋值给 AH。

S A H F SAHF 的英文全称是:Store AH into flags. 意思是将 A H AH 里面的数存入 F L A G S FLAGS 的低八位

P U S H F PUSHF P O P F POPF 很简单,就是将 F L A G S FLAGS 的内容压入堆栈或者说弹出堆栈

1.4 输入输出指令

这一类指令很重要,我们首先需要明确几个定义:1. 什么是接口?2. 什么是端口?

所谓接口,比如说,我们电脑上有一个用来插 U 盘的东西,我们称之为 “USB接口”,这类和外部设备连接的 “口”,我们就叫做接口。一个计算机里面可以有好多接口。

而端口是什么呢?比如说,你电脑通过接口连接了某一个设备,而这个设备里面又会有许许多多的寄存器,我们电脑的 CPU 可以直接访问这些寄存器。因此,在外设里面,能够被 CPU 直接访问的寄存器就是端口。

在这里插入图片描述

既然有那么多端口,如果要想实现对端口数据的读或写,那么势必需要对这些端口进行地址编码,这样才能准确低找到所需要控制的端口。因此,也就引申出了下面端口的寻址方式:

根据端口地址码的长度,指令具有两种不同的端口地址表现形式:

  1. 假设我们的端口数目不多,小于256个,那么我们可以使用8位二进制来进行地址编码。那么这个8位的地址我们可以在指令里面直接给出来。(也就是可以寻址的端口数为: 2 8 = 256 2^8=256
  2. 如果端口很多,端口地址是 16位时,我们在指令里面的端口地址必须要由 D X DX 指定!这叫间接寻址。所能够寻址的端口数是 2 16 = 64 K 2^{16}=64K

另外,端口的编码也分为了两种方式:1. 独立编码的方式:端口地址的编码和存储空间的编码是两个不同的独立地址空间。2. 统一编址方式:对内存单元和端口进行统一的编址

下面我们来看看这两个指令:
【1】IN acc, PORT:acc 表示累加器,PORT 顾名思义就是端口的意思。IN 操作的功能是把 PORT 所指向的端口的内容读入 acc里面 (注意:acc 只能是 AX 或 AL)

【2】 OUT PORT, acc 就是把 acc里面的内容写进 PORT 所指向的端口里面

发布了140 篇原创文章 · 获赞 411 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_44586473/article/details/104943235