浅谈CPU — (CPU结构【寄存器】)

1.1 CPU的内部结构解析

CPU和内存是由许多晶体管组成的电子部件,通常称为IC(Integrated Circuit,集成电路)。从功能方面来看,CPU的内部由寄存器,控制器,运算器和时钟四部分构成,各部分之间由电流信号相互连通。

寄存器:可用来暂存指令,数据等处理对象,可以将其看做是内存的一种。根据种类的不同,一个CPU内部会有20~100个寄存器。

控制器:负责把内存上的指令,数据等读入寄存器,并根据指令的执行结果来控制整个计算机。

运算器:负责运算从内存读入寄存器的数据。

时钟:负责发出CPU开始计时的时钟信号。不过,也有些计算机的时钟位于CPU的外部。

1.2 CPU是寄存器的集合体

程序是把寄存器作为对象来描述的

使用高级语言编写的程序会在编译后转化成机器语言,然后通过CPU内部的寄存器来处理。不同类型的CPU,其内部寄存器的数量,种类以及寄存器存储的数值范围都是不同的。根据功能的不同,我们可以将寄存器大致划分为八类。

累加寄存器:存储执行运算的数据和运算后的数据。

标志寄存器:存储运算处理后的CPU的状态。

程序计数器:存储下一条指令所在内存的地址。

基址寄存器:存储数据内存的起始地址。

变址寄存器:存储基址寄存器的相对地址。

通用寄存器:存储任意数据。

指令寄存器:存储指令。CPU内部使用,程序员无法通过程序对该寄存器进行读写操作。

栈寄存器:存储栈区域的起始地址。

其中,程序计数器,累加寄存器,标志寄存器,指令寄存器和栈寄存器都只有一个,其他的寄存器一般有多个。

1.3 决定程序流程的程序计数器

地址0100是程序运行的开始位置。Windows等操作系统把程序从硬盘复制到内存后,会将程序计数器(CPU寄存器的一种)设定为0100,然后程序开始运行。CPU每执行一个指令,程序计数器的值就会自动加1。例如,CPU执行0100地址的指令后,程序计算器的值就变成0101(当执行的指令占据多个内存地址时,增加与指令长度相应的数值)。然后,CPU的控制器就会参照程序计数器的数值,从内存中读取命令并执行。也就是说,程序计数器决定着程序的流程。

1.4 条件分支和循环机制

程序的流程分为顺序执行, 条件分支和循环三种。顺序执行是指按照地址内容的顺序执行指令。条件分支是指根据条件执行任意地址的指令。循环是指重复执行同一地址的指令。

上图表示把内存中存储的数值的绝对值输出到显示器的程序的内存状态。程序运行的开始位置是0100地址。随着程序计数器数值的增加,当达到0102地址时,如果累加寄存器的值是正数,则执行跳转指令(jump指令)跳转到0104地址。此时,由于累加寄存器的数值是123,为正数,因此0103地址的指令被跳过,程序的流程直接跳转到0104地址。也就是说,“跳转到0104地址”这个指令间接执行了“将程序计数器设定成0104地址”这个操作。

条件分支和循环中使用的跳转指令,会参照当前执行的运算结果来判断是否跳转。无论当前累加寄存器的运算结果是负数,零还是正数,标志寄存器都会将其保存。CPU在进行运算时,标志寄存器的数值会根据运算结果自动设定。条件分支在跳转指令前会进行比较运算。至于是否执行跳转指令,则由CPU在参考标志寄存器的数值后进行判断。运算结果的正,零,负三种状态由标志寄存器的三个位表示。如图:

标志寄存器的第一个字节位,第二个字节位和第三个字节位的值为1时,表示运算结果分别为正数、零和负数。

CPU执行比较的机制很有意思,因此请大家务必牢记。例如,假设要比较累加寄存器中存储的XXX值和通用寄存器中存储的YYY值,执行比较的指令后,CPU的运算装置就会在内部(暗中)进行XXX-YYY的减法运算。而无论减法运算的结果是正数、零还是负数,都会保存在标志寄存器中。程序中的比较指令,就是在CPU内部做减法运算。

1.5函数的调用机制

哪怕是高级语言编写的程序,函数调用处理也是通过把程序计数器的值设定成函数的存储地址来实现的。

 上图是给变量a和b分别代入123和456后,将其赋值给参数(parameter)来调用MyFunc函数的C语言程序。图中地址是将C语言编译成机器语言后运行的地址。由于1行C语言程序在编译后通常会变成多行的机器语言,所以图中的地址是离散的。

此外,通过跳转指令把程序计数器的值设定成0260也可实现调用MyFunc函数。函数的调用原点(0132地址)和被调用函数(0260地址)之间的数据传递,可以通过内存或寄存器来实现。

机器语言的call指令和return指令能够解决这个问题。函数调用使用的是call指令,而不是跳转指令。在将函数的入口地址设定到程序计数器之前,call指令会把调用函数后要执行的指令地址存储在名为栈的主存内。函数处理完毕后,再通过函数的出口来执行return命令。return的功能是把保持在栈中的地址设定到程序计数器中。如图所示,MyFunc函数被调用之前,0514地址保持在栈中。MyFunc函数的处理完毕后,栈中的0514地址就会被读取出来,然后再被设定到程序计数器中。

1.6 通过地址和索引实现数组

如图所示,出现的基址寄存器和变址寄存器。通过这两个寄存器,我们可以对主内存上特定的内存区域进行划分,从而实现类似于数组的操作。

首先,用十六进制数将计算机内存上00000000~FFFFFFFF的地址分出来。那么,凡是该范围的内存区域,只要是有一个32位的寄存器,即可查看全部的内存地址。但如果想要像数组那样分割特定的内存区域以达到连续查看的目的,使用两个寄存器会更方便些。例如查看10000000地址~1000FFFF地址时,可以将10000000存入基址寄存器,并使变址寄存器的值在0000000~0000FFFF变化。CPU则会把基址寄存器+变址寄存器的值解释为实际查看的内存地址。变址寄存器的值就相当于高级编程语言程序中数组的索引功能。

猜你喜欢

转载自www.cnblogs.com/mylearning-log/p/10932053.html