CPU的内部结构
❝CPU是中央处理器Central Processing Unit的缩写,相当于计算机的大脑,它的内部由数百万至数亿个 「晶体管」 构成。
❞
在 「程序运行流程」 中,CPU
所负责的就是 「解释和运行」 最终转换成 「机器语言」 的程序内容。
程序运行流程
CPU
和内存是由许多晶体管组成的 「电子部件」 ,通常成为集成电路Integrated Circuit。
❝从功能方面来看,
CPU
的内部是由 「寄存器」 、 「控制器」 、 「运算器」 、 「时钟」 等四个部分组成,各个部分之间由 「电流信号」 相互连通。❞
CPU的四个组成部分
- 「寄存器」
- 用来 「缓存」 指令、数据等处理对象,可以将其看作是**「内存的一种」**
- 根据种类的不同,一个
CPU
内部户有20~100
个寄存器
- 「控制器」
- 负责把 「内存」 上的指令、数据等读入**「寄存器」**
- 并根据指令的执行结果来 「控制」 整个计算机
- 「运算器」
- 负责运算**「从内存读入寄存器的数据」**
- 「时钟」
- 负责发出
CPU
开始计时的**「时钟信号」**
- 负责发出
内存
❝通常所说的 「内存」 指的是计算机的主要存储器Main Memory,简称 「主存」 。
❞
主存
通过 「控制芯片」 等与CPU
相连,主要负责 「存储指令和数据」 。主存由 「可读写」 的元素构成,每个字节(1字节=8位
)都带有一个 「地址编号」 。CPU
可以通过该地址 「读取」 主存中的指令和数据,当然也可以 「写入」 数据。
程序运行机制
程序启动后,根据 「时钟信号」 , 「控制器」 会从 「内存」 中读取指令和数据。通过对这些指令加以解释和运行, 「运算器」 就会对数据进行运算, 「控制器」 根据该运算结果来控制计算机。
CPU是寄存器的集合体
CPU
的四个构成部分中,我们只需要了解寄存器即可。这是因为, 「程序是把寄存器作为对象来描述的」 。
假设,我们存在如下用汇编语言编写的代码。
❝ 「汇编语言」 采用助记符Memonic来编写程序,每一个原本是 「电气信号」 的 「机器语言指令」 都有有一个与其 「相对应的助记符」 。
助记符通常为指令功能的英语单词的缩写。
❞
汇编代码
例如,mov
和add
分别是数据的存储和相加的简写。
❝「汇编语言和机器语言基本上是一一对应的」
❞
- 通常我们将 「汇编语言」 编写的程序转化成 「机器语言」 的过程称为**「汇编」**
- 反之, 「机器语言」 程序转化成 「汇编语言」 的程序的过程称为**「反汇编」**
从上述的 「汇编代码」 中,我们可以看出, 「机器语言级别的程序是通过寄存器来处理的」 ,也就是说, 「CPU是寄存器的集合体」 。eax
和ebp
表示的都是寄存器。并且,内存的存储场所 「通过地址编号来区分」 ,而寄存器的种类 「通过名字来区分」 。
CPU
处理程序的大致过程如下:
❝使用 「高级语言」 编写的程序会在 「编译」 后转化成 「机器语言」 ,然后再通过
CPU
内部的寄存器来处理。❞
寄存器的种类
❝不同类型的
CPU
,其内部寄存器的数量、种类以及寄存器存储的数值范围都是不同的。❞
不过,根据功能的不同,我们可以将寄存器大致分为 「8类」 。
寄存器的主要种类和功能
可以看出,寄存器中存储的内容既 「可以是指令也可以是数据」 。其中,数据分为 「用于运算的数据」 和**「表示内存地址的数据」**
CPU是寄存器的集合体
决定程序流程的程序计数器
只有1行的有用程序是很少见的,机器语言的程序也是如此。接下来,我们看一下程序是如何按照流程运行的。
下图是程序启动后的内存内容的模型。
❝用户发出启动程序的指示后, 「操作系统」 会把 「硬盘」 中保存的程序 「复制」 到 「内存」 中。
❞
实例中的程序实现的是将123
和456
两个数值相加,并将结果输出到显示器上。
前面我们已经介绍过,存储指令和数据的内存,是通过地址来划分的。由于使用机器语言难以清晰地表明各地址存储的内容,因此我们对各地址的存储内容添加注释。实际上, 「一个命令和数据通常被存储在多个地址上」 ,但是为了便于说明,上面的图例中,把指令、数据分配到一个地址中。
大致流程如下:
- 地址
0100
是程序运行的开始位置。 - 操作系统把程序从 「硬盘」 复制到 「内存」 后,会将 「程序计数器」 (
CPU
寄存器的一种)设定为0100
,然后程序便开始运行。 - 「
CPU
每执行一个指令,程序计数器的值就会自动加1」 - 然后,
CPU
的 「控制器」 就会参照程序计数器的数值,从内存中读取命令并执行。
❝程序计数器决定着程序的流程
❞
条件分支和循环机制
程序的流程分为 「顺序执行」 、 「条件分支」 和 「循环」 三种。
- 「顺序执行」 是指按照地址内容的顺序执行指令
- 「条件分支」 是指根据条件执行任意地址的指令
- 「循环」 是指重复执行同一地址的指令
「顺序执行」 的情况比较简单,每执行一个指令 「程序计数器」 的值就 「自动加1」 .但若程序中存在 「条件分支」 和 「循环」 ,机器语言的指令就可以将 「程序计数器」 的值设定为 「任意地址」 (不是加1)。这样一来,程序便可以返回到上一个地址来重复执行同一个指令,或者跳转到任意地址。
条件分支运行流程
上图表示把内存中存储的数值(示例中是123)的绝对值输出到显示器的程序的内存状态。
大致流程如下:
- 程序运行的开始位置是
0100
地址 - 随着 「程序计数器」 数值的增加
- 当到达
0102
地址时,如果 「累加寄存器」 的值是 「正数」 ,则执行 「跳转指令」 (jump
指令)跳转到0104
地址 - 此时,由于 「累加寄存器」 的值是
123
,为 「正数」 ,因此0103
地址的指令被跳过,程序的流程 「直接」 跳转到了0104
地址
❝ 「条件分支」 和 「循环」 中使用的 「跳转指令」 ,会参照当前执行的 「运算结果」 来判断是否跳转。
❞
前面我们提到过 「标志寄存器」 。无论当前 「累加寄存器」 的运算结果是负数、零还是正数, 「标志寄存器」 都会将其保存。
CPU
在进行运算时, 「标志寄存器」 的数值会根据运算结果 「自动设定」 。至于是否执行 「跳转指令」 ,则由CPU
在参考 「标志寄存器」 的数值后进行判断。运算结果的正、零、负 「三个状态」 由 「标志寄存器」 的三个位表示。
32位CPU(寄存器的长度是32位)的标志寄存器的示例
「标志寄存器」 的第一个字节位、第二个字节位和第三个字节位的值为1时,表示的运算结果分别为正数、零和负数。
CPU比较机制
假设要比较 「累加寄存器」 中存储的XXX
值和 「通用寄存器」 中存储的YYY
值,执行比较的指令后,CPU
的运算装置就会在内部进行XXX-YYY
的 「减法运行」 。
无论减法运算的结果是正数、零还是负数,都会被保存到 「标志寄存器」 中。
- 结果为 「正」 表示
XXX
比YYY
大 - 结果为 「零」 表示
XXX
和YYY
相等 - 结果为 「负」 表示
XXX
和YYY
小
❝程序中的比较指令,就是在
CPU
内部做减法运算❞
函数的调用机制
❝函数调用处理也是通过把 「程序计数器」 的值设定成函数的存储地址来实现的
❞
和 「条件分支」 、 「循环」 的机制不同,因为单纯的跳转指令无法实现函数的调用。
❝函数的调用需要在完成函数内部的处理后,处理流程再返回到函数调用点( 「函数调用指令的下一个地址」 )
❞
上图的示例为 变量a
和b
分别代入123
和456
后,将其赋值给参数来调用MyFunc
函数的C
语言程序。图中的地址是将C
语言编译成机器语言后运行时的地址。由于1行C
语言程序在编译后通常会变成多行的机器语言,所以图中的地址是 「离散」 的。
此外,通过 「跳转指令」 把 「程序计数器」 的值设定为0260
也可以实现调用MyFunc
函数。函数的 「调用原点」 (0132
地址)和 「被调用函数」 (0260
地址)之间的数据传递,可以通过内存或寄存器来实现。
当函数处理进行到最后的0354
地址时,我们应该将 「程序计数器」 的值设定成函数调用后要执行的0154
地址。我们通过机器语言的call
指令和return
指令能实现该功能。
call 指令和return 指令
❝函数调用使用的是
call
指令,而不是跳转指令。❞
在将函数的入口地址设定到 「程序计数器」 之前, 「call指令」 会把调用函数后要执行的指令地址存储在名为 「栈」 的内存内。 「return 指令」 的功能是把保存在栈中的地址设定到 「程序计数器」 中。
通过地址和索引实现数组
❝通过 「基址寄存器」 和 「变址寄存器」 可以对 「主内存」 上特定的内存区域进行划分,从而实现类似于数组的操作
❞
- 用 「十六进制数」 将计算机内存上
00000000~FFFFFFFF
的地址划分出来- 凡是该范围的内存区域,只要有一个32位的寄存器,即可查看全部的内存地址
- 如果想要像数组那样分割特定的内存区域以达到连续查看的目的,使用两个寄存器会更方便
❝
CPU
会把 「基址寄存器」 + 「变址寄存器」 的值解释为实际查看的内存地址。❞
「变址寄存器」 的值相当于高级程序语言程序中数组的**「索引功能」**
-
cpu
+关注
关注
68文章
10824浏览量
211086 -
计算机
+关注
关注
19文章
7409浏览量
87690 -
晶体管
+关注
关注
77文章
9629浏览量
137807
发布评论请先 登录
相关推荐
评论