4.2.2 CPU 寄存器组织
4.2.1节已经提到,计算机中的指令由操作码和操作数两部分组成。那么这些操作数既可以存放在CPU 内部的寄存器中,也可以存放在内存中,还可以存放在指令中。我们分别称之为寄存器操作数、存储器操作数和立即数。其中CPU 内部的寄存器在指令中使用的频度最大,因此掌握CPU 中各寄存器的用途是非常重要的。
因为IA-32由最初的8086/8088向后兼容扩展而来,因此,寄存器的结构也体现了逐步扩展的特点。本书先介绍8086的寄存器结构,逐步过渡到IA-32的寄存器结构。本书主要以IA-32为基础。
8086CPU 有8个16位通用寄存器,其中有4个数据寄存器、2个指针寄存器和2个变址寄存器,均可存放操作数,并可以参加算术运算和逻辑运算。另外,还有4个段寄存器和1个指令指针寄存器。寄存器在计算机中的存取速度比存储器快得多,可以相当于存储单元,用来存放运算过程中所需要的操作数地址、操作数及中间结果。另外,8086CPU 内部还有一个标志寄存器FLAG。8086CPU 寄存器组如图4.2所示。
图4.2 8086CPU 寄存器组
1.通用寄存器
在8086CPU 中设置了一些通用寄存器,它是一种面向寄存器的体系结构。在这种结构中,操作数可以直接存放在这些寄存器中,因而可以减少访问存储器的次数,又可缩短程序的长度,既提高了数据处理速度,又可少占内存空间。通用寄存器包括数据寄存器、指针寄存器和变址寄存器。
数据寄存器包括AX(Accumulator,累加器)、BX(Base Register,基址寄存器)、CX(Count Register,计数寄存器)、DX(Data Register,数据寄存器)。这四个数据寄存器,每一个可单独作为16位寄存器AX、BX、CX、DX 使用,也可作为8位寄存器使用。作为8位寄存器使用时,每一个又可作为两个寄存器。
以AX 寄存器为例,如果将一个字0000000000001010存入一个16位寄存器寄AX 中,那么这个字的高位字节和低位字节会分别存放在这个寄存器的高8位(8位~15位)寄存器和低8位(0位~7位)寄存器中。AH 中存储了它的高8位00000000,AL中存储了它的低8位00001010,如图4.3所示。AX 的高8位称为AH 寄存器,低8位称为AL寄存器。同样BX 作为两个8位寄存器使用时有BH、BL,而CX 有CH、CL,DX 有DH、DL。
图4.3 16位寄存器AX 分为两个8位寄存器
指针和变址寄存器也都是16位寄存器,且只能作为16位寄存器使用。其中指针寄存器有两个:BP(Base Pointer Register,基址指针寄存器)和SP(Stack Pointer Register,堆栈指针寄存器)。变址寄存器有两个:SI(Source Index Register,源变址寄存器)和DI(Destination Index Register,目标变址寄存器)。
指针寄存器SP和BP用来存取位于当前堆栈段中的数据,但SP和BP在使用上有区别。入栈(PUSH)和出栈(POP)指令是由SP 给出栈顶的偏移地址,故称为堆栈指针寄存器;BP则用来存放位于堆栈段中的一个数据区基址的偏移地址,故称作基址指针寄存器。
变址寄存器SI和DI是用来存放当前数据段的偏移地址。源操作数地址的偏移地址存放于SI中,所以SI被称为“源变址寄存器”;目的操作数地址的偏移地址存放于DI中,所以被DI称为“目的变址寄存器”。
2.段寄存器
8086CPU 把1M 字节的存储空间划分为若干个逻辑段。每个逻辑段的长度为64K 字节,并规定每个逻辑段20位起始地址的最低4位为0000B。这样,在20位段起始地址中只有高16位为有效数字,我们称这高16位有效数字为段的基地址(简称段基址),并存放于段寄存器中。8086CPU 共有4个16位段寄存器,指令能直接访问这4个段寄存器,它们分别是:CS(Code Segment Register,代码段寄存器),用来给出当前代码段的起始地址,存放CPU 可以执行的指令,CPU 执行的指令将从代码段取得;DS(Data Segment Register,数据段寄存器),指向程序当前使用的数据段,用来存放数据,包括参加运算的操作数和中间结果;SS(Stack Segment Register,堆栈段寄存器),给出当前程序所使用的堆栈段,即在存储器中开辟的堆栈区,堆栈操作的执行地址就在该段;ES(Extra Segment Register,附加段寄存器),附加段是一个附加的数据段,通常也用来存放数据,典型用法是存放处理之后的数据。
20位物理地址形成,是由段寄存器中的16位段基址,在最低位后面补4个0,加上16位段内偏移地址,在地址加法器内形成20位物理地址。
【例4.1】 假定(DS)=2000H,数据段中变量名VAL的偏移地址为0050H,其物理地址值是多少?
解:DS×16+0050H=20050H。
3.控制寄存器
控制寄存器有两个:一个是IP(IP Register,指令指针寄存器);另一个是FLAG(FLAG Register,状态标志寄存器)。
指令指针寄存器IP相当于程序计数器PC,存放要执行的下一条指令的偏移地址,用以控制程序中指令的执行顺序,通常与段寄存器CS配合使用,用作指令寻址,由CS和IP共同决定当前要取指令的地址,而且每执行一条指令,CS和IP会自动指向下一条指令。
例如,代码段寄存器CS存放当前代码段地址,IP指令指针寄存器存放了下一条要执行指令的段内偏移地址,假设CS=1200H,IP=0061H。通过组合,形成20位存储单元的物理地址为12061 H。
FLAG 寄存器在CPU 内部的寄存器中是一种特殊的寄存器,有时也称为PSW(Program Status Word,程序状态字),它用来存储相关指令执行结果的状态,为CPU 执行相关指令提供行为依据及控制CPU 的相关工作方式。
FLAG 和其他寄存器不一样,其他寄存器是用来存放数据的,整个寄存器具有一个含义,而FLAG 寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,并记录特定的状态标志信息,如图4.4所示。
图4.4 标志寄存器各位示意
标志寄存器的每一位可以理解为CPU 内部的一盏灯,而这些灯的亮与灭由运算结果决定,正确使用这些标志可使程序按人们预定的逻辑实现转移,使计算机能够准确地完成预定的任务。因此,正确理解各标志位的含义,确切了解每条指令对各标志位的影响,是汇编语言程序设计中最基本也是最重要的一个环节。
例如,算术运算指令和逻辑运算指令的运行结果都将定性地反映在不同的标志位上,以便后续的条件判断指令根据这些标志实现判断转移,转移的实质是修改CS和IP。这也正是计算机能够实现判断转移的底层原理。
8086CPU 的标志寄存器共有9个标志,其中6个为状态标志,3个为控制标志。
6个状态标志位如下:
CF(Carry Flag)进位/借位标志,指令执行结果的最高位是否有向更高位进位或借位,若有则CF置1,否则置0。
PF(Parity check Flag)奇偶校验标志,指令执行结果中1的个数是奇数个还是偶数个,若为奇数个则PF置0,否则置1。
AF(Auxiliary carry Flag)辅助进位/借位标志,当进行字节运算有低4位向高4位进位或借位时置1,否则置0。该标志位一般用在BCD 码运算中,判断是否需要十进制调整。
ZF(Zero Flag)零标志,指令执行结果是不是为0,若为0则ZF置1,否则置0。
SF(Sign Flag)符号标志,该标志位的状态总是与运算结果最高有效位的状态相同,因而它用来反应带符号数运算结果的正负情况。即SF为0,表明结果为正,SF为1,表明结果为负数。
OF(Overflow Flag)有符号数的溢出标志,带符号数加减运算的结果产生溢出时OF为1,否则OF为0。对带符号数,字节运算结果的范围为-128~+127,字运算结果的范围为-32 768~+32 767,超过此范围为溢出。
【例4.2】 将5796H 与-757BH 两数相加,并说明其标志位状态。
运算结果的原码为-1DE5H,并置标志位为CF=0、PF=1、AF=0、ZF=0、SF=1、OF=0。
3个控制标志位各具有一定的控制功能:
TF(Trag Flag)陷阱标志(单步中断标志),TF=1,程序执行当前指令后暂停,TF=0程序执行当前指令后不会暂停。
IF(Interrupt enable Flag)中断允许标志,用于控制CPU 能否响应可屏蔽中断请求,若IF=1,开中断,能够响应中断,IF=0,关中断,不能响应中断。
DF(Direction Flag)方向标志,用于指示串操作时源串的源变址和目的串的目的变址的变化方向,DF=1引起串操作指令的变址寄存器自动减值,DF=0引起串操作指令的变址寄存器自动增值。