CPU 的工作原理
CPU的最重要的功能是计算,但是计算是CPU整个功能的其中之一,叫做逻辑计算模块(ALU)。基于整个CPU的功能,他还有寄存器
缓存
内存寻址
等功能模块。整体来讲分为两部分 1. 计算 2. 寄存器存储
1. 计算
CPU是通过集成电路完成的计算,且在计算机中使用的是同意二进制进行对数字的表达与计算,这是由于二进制的计算简单,越简单越通用。之前分析过计算机电路中大量采用的三极管,三极管可当作一个开关,这个开关的 开 闭 状态可以通过一根导线来控制,这个特性来表达二进制是再好不过的了。
1.1 二进制
我们常用的是十进制,要理解二进制就需要理解数学上的 进制
。比如十进制,表达不同数字的符号有0-9
十个符号,没有位的情况下不能表达更多的数字,对数字进行扩展 增加数字的位数,则可以使数字符号所能表达的情况倍增。数字的变化过程需要一个映射关系,也就是 1+1 = 2
,这样数字就可以进行计算了,当遇到 位数上的计算不能用 单个位上的 符号表示的时候就需要进位。
这是十进制的表达 计算的基础。单个位的数学符号订单,多个位实现数学符号扩展,增加数学符号可表达的容量,1+1=2
定义计算规则,结合进位 实现了计算功能。
同样的原理可用于 二进制 八进制 十六进制等…
计算机在早期的确有使用三进制 五进制 之类的形式,但是二进制是最简单的形式,使用电路电流来表达起来会简单一些,也不易出错。
1.2 逻辑门
在计算机中使用二进制进行计算,困难在于,如何让机器实现加这个操作。其实这些操作是基于 布尔逻辑
来实现的,布尔逻辑
定义个一个新增的 数字间的映射关系 或
且
非
,在二进制中的布尔计算结果如下
A | B | 或 | 且 |
---|---|---|---|
1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 |
1 | 1 | 1 | 1 |
0 | 0 | 0 | 0 |
A | 非 |
---|---|
1 | 0 |
0 | 1 |
或(|): 两个值中有一个为 真(1) 则结果为真(1),且(&): 两个值都为真(1) 则结果为真,非(^): 若值为真 则 结果为 假(0) 若值为假 则结果为真(1),这样的计算映射过程可以使用电路来很好的表达,如下图:
晶体管中的实现形式是通过输入电流来控制电流大小,其对应的元器件表达方式如下图:
1.3 逻辑运算
基于以上的功能,可以考虑计算二进制的事情了,在计算中存在两个重要的事情 当前位的值
进位
。二进制在这方面就简单很多很多了,可以分析下二进制的加法运算中的一些规律,这里仅仅关注其中一位的变化
A | B | 结果 | Sum 当前位余数 | Carry 进位 |
---|---|---|---|---|
00 | 00 | 00 | 0 | 0 |
01 | 00 | 01 | 1 | 0 |
01 | 01 | 10 | 0 | 1 |
从以上结果中可看出规律,当前位(Sum)的值的结果是 若两个位的值相等则为 0 若两个位的值不相等则为 1。这个在我们熟悉的高级编程语言中是简单的 位运算中有 异
运算,但是这里的基本电器逻辑门中只有 或
且
非
三种门,为了不使问题复杂化,这里应该向办法在这三个门的基础上设计一个 异
门 。需要对这个映射过程进行分析
A | B | R |
---|---|---|
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
0 | 0 | 0 |
最总可以得到一个映射方式 R = (A & !B) | (B & !A)
基于这个规则 可以基于 基础的逻辑门来组成一个 异
门,其电路图如下
其次是进位 Carry的计算,Carry的计算相对简单,两个数进行 且
运算就可以了,最终我们的输出是 Sum
和 Carry
两个值,到这里实现的只是一个半加器
若要实现多位数字相加 的 全加器
则我们的模型是,输入 A B Carry 输出 Sum Carry 。
所以需要在半加器的电路中进行改造 将 进位的情况考虑进来。
先观察数据
|A|B|C(in)|<>|S(ab)|S(out)|–|C(ab)|C(out)|
|–|–|–|–|–|–|–|
|1|0|0|<>|1|1|–|0|0|
|1|1|0|<>|0|0|–|1|1|
|0|0|0|<>|0|0|–|0|0|
|0|1|0|<>|1|1|–|0|0|
|1|0|1|<>|1|0|–|0|1|
|1|1|1|<>|0|1|–|1|1|
|0|0|1|<>|0|1|–|0|0|
|0|1|1|<>|1|0|–|0|1|
在增加了 进位的数值后 Sum 的值会受其影响,经过观察 S(ab) C(in) 与 S(out) 的值可以得出以下规律 S(out) = S(ab) ^ C(in)
展开S(ab) 也就是 S(out) = A ^ B ^ C(in)
对于进位 Carray 其值受 C(in) C(ab) 以及 S(ab) 的影响,(进位只有是否进位的情况 不存在在一个位上需要近两位的情况),其中重要的是 C(ab) 他是当前位的进位结果,C(in) 是上一位的进位,这里其相当于一个被加数,与 S(ab) 共同决定是否进位。观察数据 不难发现,如果 C(ab) 需要进位 则一定有进位,若C(ab) 不需要进位,则是否进位由 S(ab) 与 C(in) 决定是否进位,最终得出规律 C(out) = C(ab) | C(in) & S(ab)
展开得到 C(out) = A & B | C(in) & (A ^ B)
得到最终的结果,先用流程图进行表示如下
可以基于这个流程来实现 全加器
的电路图
以上实现的一个 CPU
的加法计算,上面的电路仅表示了一个位,将其扩大到多位 比如 i7 的64位,下图是一个支持4位的二进制数计算的运算单元。
3. 寄存器
寄存器作为CPU的组成部分,也是一个比较大的知识领域,目前并没有研究其细节,只能笼统的概括下 对其有一个形象的认识。
程序的运行本质是计算过程,CPU完成了计算部分,计算需要数据 这个数据存储在内存中,CPU对内存进行读写。CPU通过内存寻址的方式访问内存,他们之间通过北桥芯片的电路进行通信。寄存器是集成在CPU内部的,CPU从寄存器中读写数据比内存中读写数据要快的多,寄存器在这里充当了内存的缓存作用,数据从内存读到寄存器提供给CPU进行计算。一般CPU还存在 一个三级缓存 (L1 L2 L3 cache),这个是内存与寄存器之间的一个缓冲区域,用来弥补CPU 与 内存 间的速度差异。
一般常用寄存器根据功能划分为 数据寄存器
变址寄存器
指针寄存器
段寄存器
数据寄存器 主要提供给程序使用,累加寄存器:用于计算中的乘除操作;计数寄存器 控制程序中的循环次数;数据寄存器 :;基地址寄存器:;
指针寄存器 主要存放 内存堆栈偏移量,其数据主要用于 内存堆栈的访问。
汇编代码 可以直观的查看CPU的数据变化过程
1 | MOV AX,12 # 将数字 12 写入寄存器 AX |
参考链接中有一个在线的简单汇编代码执行器,可以直观的感受到汇编对寄存器的操作过程。
接下来要研究下内存的结构,以及CPU是如何进行寻址的,进一步理解C语言。
关于CPU对内存的寻址过程
CPU对内存数据的读写主要通过 地址总线
指令总线
数据总线
来完成的。通过地址总线
与内存通信 先确定内存数据的存储地址 指令总线
用来确定操作是读数据 还是写数据,内存根据接收的指令信息确定操作,如果是读数据,根据地址读取数据并通过地址总线
返回数据,如果是些数据 通过地址总线
接收数据 并通过地址将数据写入,具体的电路实现可以参考 内存 的工作原理
TODO CPU时钟
其实CPU在进行一次计算做了很多事情,这些事情还要在规定的时间内完成,这就需要CPU时钟 进行控制 也就是我们常看到的CPU的频率 ,比如目前的电脑CPU频率是 2.2GHz