寄存器
在学习汇编的过程中,我们经常需要操作寄存器,那么寄存器又是什么呢?它是用来干什么的?
它有什么分类?又该如何操作?…
你可能会有许多的问题,答案都会在这一章进行揭晓。
寄存器的概念
一个典型的CPU由运算器、控制器、寄存器等器件组成 ,这些器件靠内部总线相连,内部总线实现CPU内部各个器件之间的联系,而CPU与外设(主板上的其他器件)之间的联系则由外部总线连接。
简单来说,在CPU中:
1):运算器进行信息处理;
2):寄存器进行信息存储;
3):控制器控制各种器件进行工作;
4):内部总线连接各种器件,在他们之间进行数据的传送;
下图为cpu组成:
从上述描述中我们可以看出寄存器可以用来存储指令和数据。对于一个汇编程序员来说,CPU的主要部件是寄存器。寄存器是CPU中程序可以用指令读写的器件。程序员通过改变各种寄存器中内容来实现对CPU的控制。不同的CPU,寄存器的个数、结构是不同的。8086CPU由14个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。这些寄存器有着不同的功能,在不同的场合扮演着不同的角色。后续的讲解中我们将逐渐接触到这些寄存器,这里我们就不一一介绍。
这里我们先介绍一些通用寄存器:AX、BX、CX、DX
8086CPU所有寄存器都是16位的,可以存放两个字节,上述4个寄存器通常用来存放一般性的数据,被称为通用寄存器。以AX为例,寄存器的逻辑结构如下图
一个16位寄存器可以存储一个16位的数据,例如如果AX中存储的是32这个数值,存放结果如下图所示:
而8086CPU为了兼容上一代CPU中的寄存器(上一代CPU中的寄存器位8位),上述这些寄存器又可以分为两个可独立使用的8位寄存器来用:AX可以分为AH、AL,同理,BX又可以分为BH、BL,CX可以分为CH、CL,DX可以分为DH、DL(H位high,L为low),以AX为例,它拆分成两个独立的8位寄存器表示如下:
AX的低8bits构成了AL寄存器,高8bit构成了AH寄存器,AH和AL都是可以独立使用的寄存器。
思考:mov ah,78H (已知该指令是将78H的数据传入ah寄存器中),该语句会影响AL的值吗?
字的存储
我们应该听过字节的概念,1字节等于8比特位,那么字和字节又有什么关联呢?1个字等于2个字节。
比特记为bit,字节记为Byte,字记为word,所以有如下关系:
1Byte = 8bits,1word = 2Bytes = 16bits
而8086CPU出于兼容性的考虑,一次性可以处理两种尺寸的数据:字节以及字数据
一个寄存器可以存储一个字数据,例如数据2000,其二进制数值为:0000 0111 1101 0000,储存格式如下:
这样就是2000在寄存器中的存储格式(以AX为例),在AH中储存了它的高八位,AL存储了它的低八位。AH和AL中的数据可以看成一个整体是数值为2000,又可以看成是两个独立的数据,分别是7和208。上述是从寄存器出发,描述了一个16位数据在寄存器中的存储格式,而我们在使用汇编的过程中还会操作内存,那么在内存中一个字又可以用怎么样的格式体现呢?
我们要知道内存单元是字节单元也就是说一个字节单元对应一个内存单元,当我们要保存一个子数据时,我们应该用两个地址连续的内存单元来保存。数据的低字节存放在低地址单元中,高字节存放在高地址单元中,假设我们从0地址开始存放2000,情况如下:
我们用0、1两个内存单元存放数据2000(07D0H)。0、1两个单元用来储存一个字,这两个单元可以看成一个起始地址为0的字单元,对于这个字单元来说,0是低地址单元,1是高地址单元。07H被存放在高地址单元,而D0H被存放在低地址单元。同理,我们也可以把2,3看成一个字单元。在这里有一个新的概念:字单元,用来描述一种用来存储字型数据的内存单元。
物理地址与段地址
CPU在访问内存单元之前,应该要给出内存单元的地址。所有的内存单元构成的存储的空间是一个一维的线性空间,每一个内存单元在这个空间中都有一个唯一的地址,我们称之为物理地址。
那么8086CPU又是如何形成这些物理地址的呢?
我们案例中的8086CPU是16位机,这种CPU具备如下特性:
1):一次最多可以处理16位的数据;
2):寄存器的最大宽度是16位;
3):寄存器和运算器之间的通路为16位;
也就是说,8086CPU内部一次性能处理的数据长度最大为16位。内存单元的地址在送上地址总线之前还需要经过寄存器进行处理,也就是说16位CPU,能一次性处理16位的地址。
但是8086CPU的地址总线是20位,也就是说8086CPU可以传送20位地址,这与上述说法相悖,那这又是为什么呢?
8086CPU在内部有一个地址加法器可以将两个16位地址合成一个20位物理地址,示意图如下:
当CPU要操作内存时,内部有如下事件发生:
1):CPU中的相关部件提供了两个16位地址,一个称为段地址,一个称为偏移地址;
2):段地址和偏移地址经过内部总线送入地址加法器;
3):地址加法器将两个16位地址合成一个20位的物理地址;
4):地址加法器将20位的物理地址通过内部总线送入输入输出控制电路;
5):输入输出控制电路将20位地址送入地址总线
6):20位物理地址被地址总线送到存储器
地址加法器采用物理地址=段地址*16+偏移地址的方法来合成物理地址,这样一个16位机就可以访问20位地址,寻址能力也从64KB扩大成1MB。
例如CPU要访问地址为123C8H的内存单元,地址加法器的工作过程为:
我们在学习段地址的过程中,不需要过多探究它的深层含义,只要知道他们的本质含义就可以了。
CS和IP
在讲CS和IP之前,我们需要了解一个概念:段。
上节我们讲到“段地址”,那么段又是什么呢?段和段地址有什么关系呢?
在中文中我们可以很好的理解段的含义:表示某个范围/区间,也就是说“段地址”我们可以理解为一段地址,更规范的说法是一块地址连续且起始地址为16倍数的存储单元定义为一个段。也就是说我们可以将内存进行分段处理,当然我们不要误解为内存本身就是一段一段的,这是一个错误的认知。内存本身是连续的,只不过8086CPU采用“物理地址=段地址16+偏移地址”来产生物理地址,我们可以通过分段的方式来管理内存。
假设目前有两个段:10000H ~ 1007FH(段地址为1000H)、10080H ~ 100FFH,段地址为(1008H),两个段大小均为80H,其内存中分布示意如下:
这样我们在编程时就可以根据需要将一块地址连续的存储单元看成一个段,通过“物理地址=段地址16+偏移地址”来定位段中的内存。注意:段地址一定是16的倍数,且段的最大长度为64KB。
思考:
1):为什么段地址一定是16的倍数?
2):为什么段的最大长度为64KB?
从上述描述中我们已经知道了什么是段了,在前面的讲述中我们说段地址是由CPU中的相关部件提供,那么这个相关部件是哪个呢?在众多的寄存器中的有4个 段寄存器:CS,DS,SS,ES。当CPU要访问内存时,由他们提供段地址。这里我们看一下CS。
CS和IP是8086CPU中最关键的两个寄存器。它们指示CPU当前要读取的指令的地址。CS称之为代码段寄存器,IP为指令指针寄存器。
在8086CPU中,任意时刻设CS中的值为M,IP中的值为N,则CPU将从M*16+N地址单元中取出一条指令并执行。也就是说,当前执行的指令在哪由CS和IP来决定。可以表示为CS:IP。下图为CPU通过CS、IP寄存器进行指令操作:
上图说明如下:
1):CS中内容为2000H,IP内容为0000H:说明物理地址为20000H
2):内存20000H~20009H内存单元中存放着可执行的机器码
3):内存20000H~20009H内存单元中存放的可执行的机器码对应的汇编指令如下:
地址:20000H~20002H 内容:B8 23 01 对应的汇编指令:mov ax,0123H
地址:20003H~20005H 内容:BB 03 00 对应的汇编指令:mov bx,0003H
地址:20006H~20007H 内容:89 D8 对应的汇编指令:mov ax,bx
地址:20008H~20009H 内容:01 D8 对应的汇编指令:add ax,bx
那么上述的状态下程序又是如何执行的呢?
1):CPU从CS:IP指向的存储单元中读取指令,读取的指令进入指令缓冲区;
2):IP=IP+所读取的指令的长度,从而指向下一条指令;
3):执行指令。重复1、2步。
注意:8086CPU在启动/复位启动之后,CS被设置为FFFFH,IP被设置为0000H,也就说,8086CPU在启动时执行的的第一条指令为FFFF0H指向单元中的指令。
思考:我们可以修改CS:IP的指向吗?
评论区