§ 第2章 寄存器 - 图1

CPU中的主要部件是寄存器,寄存器是CPU中程序猿可以用指令读写的部件,程序猿通过改变各种寄存器中的内容来实现对CPU的控制

8086CPU有14个寄存器:AX, BX, CX, DX, SI, DI, SP, BP, IP, CS, SS, DS, ES, PSW,分类如下。关于每种寄存器的功能,点击这里查看

§ 第2章 寄存器 - 图2

一、通用寄存器

1.1 整个寄存器

§ 第2章 寄存器 - 图3

8086CPU的所有寄存器都是16位(Bit),可以存放两个字节。

以AX为例,通用寄存器的逻辑结构如图2.1所示

§ 第2章 寄存器 - 图4

  • 现在有一个十进制数据:18,转换为二进制后为:10010,在寄存器AX中的存储如下

§ 第2章 寄存器 - 图5

  • 现在有一个十进制数据:20000,其二进制表示:100111000100000,在寄存器AX中的存储:
    § 第2章 寄存器 - 图6

1.2 低+高

8086CPU的上一代CPU寄存器是8位的,为了保证兼容,使得原来基于上代CPU编写的程序能够运行在8086之上,8086CPU的AX,BX,CX,DX都可以分为两个独立的8位寄存器来使用。

§ 第2章 寄存器 - 图7

以AX为例,8086CPU的16位寄存器分为两个8位寄存器的情况如下图所示

§ 第2章 寄存器 - 图8

AX的低8位(0位-7位)构成了AL寄存器,高8位(8位-15位)构成了AH寄存器。AH和AL寄存器都是可以独立使用的8位寄存器

现在,将一个16位数据拆成两个8位数据后,数据的变化如下

§ 第2章 寄存器 - 图9

可以看到其中的16位数据可以拆为低8位和高8位数据

二、字在寄存器中的存储

§ 第2章 寄存器 - 图10

1个16位寄存器存储1个字,两个字节,这两个字节分为高8位字节和低8位字节§ 第2章 寄存器 - 图11

三、汇编指令

通过汇编指令控制CPU进行工作,看一下表2.1中的几条汇编指令

§ 第2章 寄存器 - 图12

在写一条汇编指令或一个寄存器的名称时不区分大小写

  1. // 以下两条指令意义一样
  2. mov ax, 18
  3. MOV AX, 18

3.1 16位寄存器数据改变

将CPU执行下表中所列的程序段中的每条指令后,对寄存器中的数据改变如下

程序段中的指令 指令执行后AX中的数据 指令执行后BX中的数据
mov ax, 4E20 H 4E20 H 0000 H
add ax, 1406 H 6226 H 0000 H
mov bx, 2000 H 6226 H 2000 H
add ax , bx 8226 H 2000 H
mov bx, ax 8226 H 8226 H
add ax, bx ? 8226 H

上面最后一条语句结果是什么?

§ 第2章 寄存器 - 图13

对于上面那个只能保存4位16进制的解释,这是因为1个16进制数据换算成二进制数据,就需要4bit来表示,所以一个寄存器有16bit,最终为一个寄存器保存4个16进制数据

§ 第2章 寄存器 - 图14

3.2 分为高低位寄存器数据改变

程序段中的指令 指令执行后AX中的数据 指令执行后BX中的数据
mov ax, 001A H 001A H 0000 H
mov bx, 0026 H 001A H 0026 H
add al, bl 0040 H 0026 H
add ah , bl 2640 H 0026 H
add bh, al 2640 H 4026 H
mov ah, 0 0040 H 4026 H
add al, 85H 00C5 H 4026 H
add al, 93H ? 4026 H

§ 第2章 寄存器 - 图15

四、物理地址

CPU访问内存单元时,要给出内存单元的地址。所有内存单元构成的储存空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址。

§ 第2章 寄存器 - 图16

CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。在CPU向地址总线上发出物理地址之前,必须要在内部先形成这个物理地址。

不同的CPU可以有不同的物理地址形成方式。现在讨论8086CPU是如何在内部形成内存单元的物理地址。

五、16位结构的CPU

8086CPU的上一代CPU(8080、8085)等是8位机,而8086是16位机,也可以说8086是16位结构的CPU。那么什么是16位结构的CPU呢?

还记得吗,最一开头说的CPU是由运算器、控制器、寄存器组成的,所以CPU的结构特性和它们之间是离不开关系的。

简单来讲:16位结构描述了一个CPU具有以下几方面的结构特性

§ 第2章 寄存器 - 图17

8086是16位结构的CPU,也就是说,在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。

内存单元的地址在送上地址总线之前,必须在CPU中处理、传输、暂时存放,对于16位CPU,能够一次性处理、传输、暂时存储16位的地址。

六、8086CPU给出物理地址的方法

8086CPU有20位地址总线,可以传送20位地址,达到§ 第2章 寄存器 - 图18寻址能力。8086CPU又是16位结构,在内部一次性处理、传输、暂时存储的地址为16位(只能找到§ 第2章 寄存器 - 图19个内存的数据)。从8086CPU的内部结构来看,如果将地址从内部简单发出,那么它只能送出16位的地址,表现出的寻址能力只有§ 第2章 寄存器 - 图20

8086CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。

§ 第2章 寄存器 - 图21

8086CPU相关部件的逻辑部件结构如下图2.6所示

§ 第2章 寄存器 - 图22

如图2.6所示,当8086CPU要读写内存时

  1. CPU中相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址
  2. 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件
  3. 地址加法器将两个16位地址合成为一个20位的物理地址
  4. 地址加法器通过内部总线将20位物理地址送入输入输出控制电路
  5. 输入输出控制电路将20位物理地址送上地址总线
  6. 20位物理地址被地址总线传送到存储器

地址加法器采用公式(1)来合成物理地址

§ 第2章 寄存器 - 图23

例如,8086CPU要访问地址为123C8 H的内存单元时,地址加法器的工作过程如图2.7所示

§ 第2章 寄存器 - 图24

§ 第2章 寄存器 - 图25

七、段地址x16+偏移地址=物理地址的本质含义

“段地址x16+偏移地址=物理地址“的本质含义:CPU在访问内存时,用一个基础地址(段地址x16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

下面,用一个例子做一个比喻。

7.1 例子1

比如说,学校、体育馆、图书馆在一条笔直的单行路上,学校位于路的起点,如下图所示

§ 第2章 寄存器 - 图26

现在你要去图书馆,想知道那里的地址,现在有两种可以告诉你图书馆的地址

  1. 从学校走2826m到达图书馆,这个2828m可以认为是图书馆的物理地址
  2. 从学校走2000m到体育馆,从体育馆再走826m到图书馆。第一个距离2000m,适当对于起点的基础地质,第二个距离826m是相对于基础地质的偏移地址。

7.2 例子2

给上面的例子加一个限制条件,你问我图书馆的地址我只能将它写在纸上告诉你。对于2827这个数据,我只能用4位数据的纸条才能写下。

§ 第2章 寄存器 - 图27

但是,现在只有很多3位数据的纸条,这样就只能以下面这种方式告诉你这个数据

§ 第2章 寄存器 - 图28

在第一张图写上200(段地址),在第二张纸上写上826(偏移地址),这样物理地址就为

§ 第2章 寄存器 - 图29%5Ctimes%2010%20%2B%20826(%5Ctext%7B%E5%81%8F%E7%A7%BB%E5%9C%B0%E5%9D%80%7D)%3D2826(%5Ctext%7B%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80%7D)%0A#card=math&code=200%28%5Ctext%7B%E6%AE%B5%E5%9C%B0%E5%9D%80%7D%29%5Ctimes%2010%20%2B%20826%28%5Ctext%7B%E5%81%8F%E7%A7%BB%E5%9C%B0%E5%9D%80%7D%29%3D2826%28%5Ctext%7B%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80%7D%29%0A&id=HZvEe)

8086CPU就是一个只能提供两张3位数据纸条的CPU

八、段地址并不分段

之前使用公式(1)计算物理地址的时候,提到过一个段地址。”段地址“这个名称中包含着段的概念,这种说法会对学习者产生舞蹈,使人误以为内存被划分为了一个一个的段,每一个段都有一个段地址 § 第2章 寄存器 - 图30

其实,内存并没分段,段的划分来自于CPU § 第2章 寄存器 - 图31 ,由于8086CPU用 § 第2章 寄存器 - 图32 的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。

也就是说:可以使用内存划分段的方式帮助记忆,但是真实的分段其实是来自于CPU

如图2.9所示,我们可以认为(虽然结果并不是这是):地址10000H~100FFH的内存单元组成一个段,该段的起始地址(基础地质)为10000H,段地址为1000H,大小为100H.

§ 第2章 寄存器 - 图33

我们也可以认为地址10000H~1007FH, 10080H~100FFH的内存单元组成两个段,它们的起始地址(基础地址)为:10000H和10080H,段地址为:1000H和1008H,大小都为80H.

§ 第2章 寄存器 - 图34

为了编程时的方便,可以将若干地址连续的内存单元看作一个段,用§ 第2章 寄存器 - 图35定位段的起始地址(基础地址),用偏移地址定位段中的内存单元。

有两点需要注意:

  • § 第2章 寄存器 - 图36必然是16的倍数,所以一个段的起始地址也一定是16的倍数
  • 偏移地址为16位,16位地址的寻址能力为§ 第2章 寄存器 - 图37,所以一个段的长度最大为§ 第2章 寄存器 - 图38

§ 第2章 寄存器 - 图39

§ 第2章 寄存器 - 图40

九、段寄存器

8086CPU在访问内存时需要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。

这里,需要知道,是什么部件提供段地址。段地址在8086CPU的段寄存器中存放。8086有4个段寄存器:CS, DS, SS, ES。当8086CPU要访问内存时由这4个段寄存器提供内存单元的段地址。

十、CS和IP

CS和IP是8086CPU中最关键的寄存器,它们指示了CPU当前要读取指令的地址。CS为代码段寄存器,IP为指针指针寄存器。

在8086PC机中,任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存§ 第2章 寄存器 - 图41单元开始,读取一条指令并执行

或者表述为:8086PC机,任意时刻,CPU将CS : IP指向的内容当作指令执行。

下面这张图2.10就展示了8086CPU读取、执行指令的工作原理

§ 第2章 寄存器 - 图42

可以看到,在2.10中,CS中存放的段地址:2000H,而IP中的内容为0000H,所以要取得地址为:20000H,取到的指令为mov ax, 0123H

内存20000H~20009H单元中存放着可执行的机器码,这些机器码对应的汇编指令如下:

  • 地址:20000H~20002H,内容:B8 23 01,长度:3Byte,对应汇编指令:mov ax,0123H
  • 地址:20003H~20005H,内容:BB 03 00,长度:3Byte,对应汇编指令:mov bx, 0003H
  • 地址:20006H~20007H,内容:89 D8,长度:2Byte,对应汇编指令:mov ax, bx
  • 地址:20008H~20009H,内容:01 D8,长度:2Byte,对应汇编指令:add ax, bx

下面,用一个动态图来展示CPU怎么读取指令,并且执行指令的过程

§ 第2章 寄存器 - 图43

通过上面的演示过程,可以知道8086CPU的工作过程可以简要描述如下:

  1. 从CS : IP指向的内存单元读取指令,读取的指令进入指令缓冲区
  2. IP=IP+所读取指令的长度,从而指向下一条指令
  3. 执行指令。转到步骤1,重复这个过程

在8086CPU加电启动或复位后(即CPU刚开始工作时),CS和IP被设置为CS=FFFFH,IP=0000H,即在8086PC机刚启动时,CPU从内存FFFF0H单元中读取指令执行,FFFF0H单元中的指令是8086机开机后执行的第一条指令

思考:什么时候把二进制信息看作指令,什么时候看作数据

之前学习过,在内存中,指令和数据没有任何区别,都是二进制信息。CPU在工作的时候把有的信息看作指令,有的信息看作数据。所以什么将内存中的信息看作指令?

答案:CPU将CS : IP指向的内存单元中的内容看作为指令。因为在任何时候,CPU将CS,IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码执行。

十一、修改CS、IP的指令

在CPU中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对CPU的控制。CPU从何处执行指令是由CS、IP中的内容决定的,程序猿可以通过改变CS、IP中的内容来控制CPU执行目标指令。

对于一般的通用寄存器,我们可以使用指令mov来改变AX中的值

  1. ; 使用mov指令改变AX寄存器中的值
  2. mov ax, 123 ; AX中的值设为123

8086CPU大部分寄存器的值都可以使用mov指令来改变,**mov**指令被称为传送指令

但是,**mov**指令不能设置CS、IP中的值,因为8086CPU没有提供这样的功能。能够改变CS、IP的内容的指令被统称为转移指令,一个最简单的可以修改CS、IP的指令:jmp指令。

  1. ; 使用jmp跳转指令修改CSIP中的值
  2. ; 1.如果想要同时修改CSIP的内容,使用 jmp 段地址:偏移地址的指令完成
  3. jmp 2AE3: 3 ; 执行后:CS=2AE3H, IP=0003HCPU将从2AE33H处读取指令
  4. jmp 3:0B16 ; 执行后,CS=0003H, IP=0B16HCPU将从00B46H处读取指令
  5. ; 2.仅仅想要修改IP中的内容,使用jmp 寄存器就可完成
  6. jmp ax ; 执行前:ax=1000H, CS=2000H, IP=0003H 功能类似于 mov IP, ax
  7. ; 执行后:ax=1000H, CS=2000H, IP=1000H
  8. jmp bx ; 执行前:bx=0B16H, CS=2000H, IP=0003H
  9. ; 执行后:bx=0B16H, CS=2000H, IP=0B16H

可以看P45问题3来帮助理解这个执行的过程

十二、代码段

前面(八、段地址并不分段)说过,对于8086PC机,可以将一组内存单元理解为一个段。

将长度为§ 第2章 寄存器 - 图44#card=math&code=%5Ctext%7BN%7D%28%5Ctext%7BN%7D%5Cleqslant%2064%5Ctext%7BKB%7D%29&id=GfdKS)的一组代码,存放在一组地址连续、起始地址为16倍数的内存单元中,可以认为这段内存是用来存放代码的,从而定义了一个代码段。

§ 第2章 寄存器 - 图45

拿一个例子来说

  1. mov ax, 0000 ; (B8 00 00) mov指令对应的二进制为B8
  2. add ax, 0123H ; (05 23 01) add指令对应的二进制位05
  3. mov bx, ax ; (8B D8)
  4. jmp bx ; (FF E3)

可以看到上面这段指令一共10个字节(B8 00 00 05 23 … FF E3)

§ 第2章 寄存器 - 图46

将上述的10个字节的指令,存放在123B0H~123B9H的一组内存单元中,这段内存就是一个内存段,段地址为123BH,长度为10个字节

§ 第2章 寄存器 - 图47

既然代码段中存放的是代码,所以这个是绝对不可以当作普通的二进制信息被执行,必须成为指令才可以,这个时候用到了上面的CS和IP,CS和IP所指向的内存单元就应该是代码段的物理地址。就像上面的123B0 H,就需要将它的物理地址放到CSIP中,CS=123BH, IP=0000H.

§ 第2章 寄存器 - 图48

§ 第2章 寄存器 - 图49

检测点

监测点2.1

1.写出每条汇编指令执行后相关寄存器中的值

  • § 第2章 寄存器 - 图50
  • § 第2章 寄存器 - 图51
  • § 第2章 寄存器 - 图52
  • § 第2章 寄存器 - 图53
  • § 第2章 寄存器 - 图54
  • § 第2章 寄存器 - 图55
  • § 第2章 寄存器 - 图56
  • § 第2章 寄存器 - 图57
  • § 第2章 寄存器 - 图58
  • § 第2章 寄存器 - 图59
  • § 第2章 寄存器 - 图60
  • § 第2章 寄存器 - 图61
  • § 第2章 寄存器 - 图62
  • § 第2章 寄存器 - 图63

2.只能使用目前学过的汇编指令,最多使用4条指令,编程计算2的4次方

  1. mov ax,2
  2. add ax,ax
  3. add ax,ax
  4. add ax,ax

add指令 在汇编中表示两个数相加,而在数学中 两个一样的数相加的值刚好等于这个数乘以2。但是这道题仅仅针对2的次方 如果是其他数的次方 4条或者更多指令只使用addmov指令是计算不出来结果的。

监测点2.2

1.给定段地址0001H,仅通过变化偏移地址寻址,CPU的寻址范围为 00010 H 到 1FFFF H 。

2.有一数据存放在内存20000H单元中,现给定段地址为SA,若想用偏移地址寻到此单元。则SA应满足的条件是:最小为 1001H,最大为 2000H。

提示,反过来思考一下,当段地址给定为多少,CPU无论怎么变化偏移地址都无法寻到20000H单元?

监测点2.3

下面的3条指令执行后,CPU修改几次IP?都是在什么时候?最后IP中的值是多少?

  1. ; 第一条指令
  2. mov ax, bx
  3. ; 第二条指令
  4. sub ax, ax
  5. ; 第三条指令
  6. jmp ax

只在最后的jmp ax中修改了一次IP,最后的IP值为0000 H.

实验部分

关于实验部分,因为WIN10系统不能进入8086虚拟环境,所以这里使用emu8086来做实验

最简单的汇编进门

  1. assume cs:code
  2. data segment
  3. db 'Welcome to asm','$'
  4. data ends
  5. code segment
  6. start:
  7. mov ax,4E20H
  8. add ax,1416H
  9. mov bx,2000H
  10. add ax,bx
  11. mov ax,001AH
  12. mov bx,0026H
  13. add al,bl
  14. add ah,bl
  15. add bh,al
  16. mov ah,0
  17. add al,bl
  18. add al,9CH
  19. code ends
  20. end start

通过F8单步调试后,可以看到对应的寄存器在不断的变化数据。