第2章 寄存器(CPU 工作原理)
一个典型的CPU(此处讨论的不是某一具体的CPU)由运算器、控制器、寄存器(CPU工作原理)等器件构成,这些器件靠内部总线相连。前一章所说的总线,相对于CPU内部来说是外部总线。内部总线实现CPU内部各个器件之间的联系,外部总线实现CPU和主板上其他器件的联系。简单地说,在CPU中:
运算器进行信息处理;
寄存器进行信息存储;
控制器控制各种器件进行工作;
内部总线连接各种器件,在它们之间进行数据的传送。
对于一个汇编程序员来说,CPU中的主要部件是寄存器。寄存器是CPU中程序员可以用指令读写的部件。程序员通过改变各种寄存器中的内容来实现对CPU的控制。
不同的CPU,寄存器的个数、结构是不相同的。8086CPU有14个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。我们不对这些寄存器进行一次性的介绍,在课程的进行中,需要用到哪些寄存器,再介绍哪些寄存器。
2.1 通用寄存器
8086CPU的所有寄存器都是16位的,可以存放两个字节。AX、BX、CX、DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。
以AX为例,寄存器的逻辑结构如图2.1所示。
图2.1 16位寄存器的逻辑结构
一个16位寄存器可以存储一个16位的数据,数据在寄存器中的存放情况如图2.2所示。
想一想,一个16位寄存器所能存储的数据的最大值为多少?
8086CPU的上一代CPU中的寄存器都是8位的,为了保证兼容,使原来基于上代CPU编写的程序稍加修改就可以运行在8086之上,8086CPU的AX、BX、CX、DX这4个寄存器都可分为两个可独立使用的8位寄存器来用:
AX可分为AH和AL;
BX可分为BH和BL;
CX可分为CH和CL;
DX可分为DH和DL。
图2.2 16位数据在寄存器中的存放情况
以AX为例,8086CPU的16位寄存器分为两个8位寄存器的情况如图2.3所示。
图2.3 16位寄存器分为两个8位寄存器
AX的低8位(0位~7位)构成了AL寄存器,高8位(8位~15位)构成了AH寄存器。AH和AL寄存器是可以独立使用的8位寄存器。图2.4展示了16位寄存器及它所分成的两个8位寄存器的数据存储的情况。
想一想,一个8位寄存器所能存储的数据的最大值为多少?
图2.4 16位寄存器及所分成的两个8位寄存器的数据存储情况
2.2 字在寄存器中的存储
出于对兼容性的考虑,8086CPU可以一次性处理以下两种尺寸的数据。
字节:记为byte,一个字节由8个bit组成,可以存在8位寄存器中。
字 :记为word,一个字由两个字节组成,这两个字节分别称为这个字的高位字节和低位字节,如图2.5所示。
图2.5 一个字由两个字节组成
一个字可以存在一个16位寄存器中,这个字的高位字节和低位字节自然就存在这个寄存器的高8位寄存器和低8位寄存器中。如图2.4所示,一个字型数据20000,存在AX寄存器中,在AH中存储了它的高8位,在AL中存储了它的低8位。AH和AL中的数据,既可以看成是一个字型数据的高8位和低8位,这个字型数据的大小是20000;又可以看成是两个独立的字节型数据,它们的大小分别是78和32。
关于数制的讨论
任何数据,到了计算机中都是以二进制的形式存放的。为了描述不同的问题,又经常将它们用其他的进制来表示。比如图2.4中寄存器AX中的数据是0100111000100000,这就是AX中的信息本身,可以用不同的逻辑意义来看待它。可以将它看作一个数值,大小是20000。
当然,二进制数0100111000100000本身也可表示一个数值的大小,但人类习惯的是十进制,用十进制20000表示可以使我们直观地感受到这个数值的大小。
十六进制数的一位相当于二进制数的四位,如0100111000100000可表示成:4(0100)、E(1110)、2(0010)、0(0000)四位十六进制数。
由于一个内存单元可存放8位数据,CPU中的寄存器又可存放n个8位的数据。也就是说,计算机中的数据大多是由1~N个8位数据构成的。很多时候,需要直观地看出组成数据的各个字节数据的值,用十六进制来表示数据可以直观地看出这个数据是由哪些8位数据构成的。比如20000写成4E20就可以直观地看出,这个数据是由4E和20两个8位数据构成的,如果AX中存放4E20,则AH里是4E,AL里是20。这种表示方法便于许多问题的直观分析。在以后的课程中,我们多用十六进制来表示一个数据。
在以后的课程中,为了区分不同的进制,在十六进制表示的数据的后面加H,在二进制表示的数据后面加B,十进制表示的数据后面什么也不加。如:可用3种不同的进制表示图2.4中AX里的数据,十进制:20000,十六进制:4E20H,二进制:0100111000100000B。
2.3 几条汇编指令
通过汇编指令控制CPU进行工作,看一下表2.1中的几条指令。
表2.1 汇编指令举例
汇编指令 |
控制CPU完成的操作 |
用高级语言的语法描述 |
mov ax,18 |
将18送入寄存器AX |
AX=18 |
mov ah,78 |
将78送入寄存器AH |
AH=78 |
add ax,8 |
将寄存器AX中的数值加上8 |
AX=AX+8 |
mov ax,bx |
将寄存器BX中的数据送入寄存器AX |
AX=BX |
add ax,bx |
将AX和BX中的数值相加,结果存在AX中 |
AX=AX+BX |
注意,为了使具有高级语言基础的读者更好地理解指令的含义,有时会用文字描述和高级语言描述这两种方式来描述一条汇编指令的含义。在写一条汇编指令或一个寄存器的名称时不区分大小写。如:mov ax,18和MOV AX,18的含义相同;bx和BX的含义相同。
接下来看一下CPU执行表2.2中所列的程序段中的每条指令后,对寄存器中的数据进行的改变。
表2.2 程序段中指令的执行情况之一(原AX中的值:0000H,原BX中的值:0000H)
程序段中的指令 |
指令执行后AX中的数据 |
指令执行后BX中的数据 |
mov ax,4E20H |
4E20H |
0000H |
add ax,1406H |
6226H |
0000H |
续表
程序段中的指令 |
指令执行后AX中的数据 |
指令执行后BX中的数据 |
mov bx,2000H |
6226H |
2000H |
add ax,bx |
8226H |
2000H |
mov bx,ax |
8226H |
8226H |
add ax,bx |
?(参见问题2.1) |
8226H |
问题2.1
指令执行后AX中的数据为多少?思考后看分析。
分析:
程序段中的最后一条指令add ax,bx,在执行前ax和bx中的数据都为8226H,相加后所得的值为:1044CH,但是ax为16位寄存器,只能存放4位十六进制的数据,所以最高位的1不能在ax中保存,ax中的数据为:044CH。
表2.3中所列的一段程序的执行情况。
表2.3 程序段中指令的执行情况之二
程序段中的指令 |
指令执行后AX中的数据 |
指令执行后BX中的数据 |
mov ax,001AH |
001AH |
0000H |
mov bx,0026H |
001AH |
0026H |
add al,bl |
0040H |
0026H |
add ah,bl |
2640H |
0026H |
add bh,al |
2640H |
4026H |
mov ah,0 |
0040H |
4026H |
add al,85H |
00C5H |
4026H |
add al,93H |
?(参见问题2.2) |
4026H |
问题2.2
指令执行后AX中的数据为多少?思考后看分析。
分析:
程序段中的最后一条指令add al,93H,在执行前,al中的数据为C5H,相加后所得的值为:158H,但是al为8位寄存器,只能存放两位十六进制的数据,所以最高位的1丢失,ax中的数据为:0058H。(这里的丢失,指的是进位值不能在8位寄存器中保存,但是CPU并不真的丢弃这个进位值,关于这个问题,我们将在后面的课程中讨论。)
注意,此时al是作为一个独立的8位寄存器来使用的,和ah没有关系,CPU在执行这条指令时认为ah和al是两个不相关的寄存器。不要错误地认为,诸如add al,93H的指令产生的进位会存储在ah中,add al,93H进行的是8位运算。
如果执行add ax,93H,低8位的进位会存储在ah中,CPU在执行这条指令时认为只有一个16位寄存器ax,进行的是16位运算。指令add ax,93H执行后,ax中的值为:0158H。此时,使用的寄存器是16位寄存器ax,add ax,93H相当于将ax中的16位数据00c5H和另一个16位数据0093H相加,结果是16位的0158H。
在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的,例如:
mov ax,bx mov bx,cx mov ax,18H mov al,18H add ax,bx add ax,20000 |
mov ax,bl (在8位寄存器和16位寄存器之间传送数据) mov bh,ax (在16位寄存器和8位寄存器之间传送数据) mov al,20000 (8位寄存器最大可存放值为255的数据) add al,100H (将一个高于8位的数据加到一个8位寄存器中) |
等都是错误的指令,错误的原因都是指令的两个操作对象的位数不一致。
检测点2.1
(1) 写出每条汇编指令执行后相关寄存器中的值。
mov ax,62627 AX= mov ah,31H AX= mov al,23H AX= add ax,ax AX= mov bx,826CH BX= mov cx,ax CX= mov ax,bx AX= add ax,bx AX= mov al,bh AX= mov ah,bl AX= add ah,ah AX= add al,6 AX= add al,al AX= mov ax,cx AX= |
2.4 物理地址
我们知道,CPU访问内存单元时,要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址。
CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。在CPU向地址总线上发出物理地址之前,必须要在内部先形成这个物理地址。不同的CPU可以有不同的形成物理地址的方式。我们现在讨论8086CPU是如何在内部形成内存单元的物理地址的。
2.5 16位结构的CPU
我们说8086CPU的上一代CPU(8080、8085)等是8位机,而8086是16位机,也可以说8086是16位结构的CPU。那么什么是16位结构的CPU呢?
概括地讲,16位结构(16位机、字长为16位等常见说法,与16位结构的含义相同)描述了一个CPU具有下面几方面的结构特性:
运算器一次最多可以处理16位的数据;
寄存器的最大宽度为16位;
寄存器和运算器之间的通路为16位。
8086是16位结构的CPU,这也就是说,在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。内存单元的地址在送上地址总线之前,必须在CPU中处理、传输、暂时存放,对于16位CPU,能一次性处理、传输、暂时存储16位的地址。