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的计算相对简单,两个数进行 运算就可以了,最终我们的输出是 SumCarry 两个值,到这里实现的只是一个半加器 若要实现多位数字相加 的 全加器 则我们的模型是,输入 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
2
3
4
MOV AX,12 # 将数字 12 写入寄存器 AX
ADD BX,AX # 将寄存器AX 中的数据与 寄存器BX中的数据相加 并存储在 BX寄存器中
INC AX # 使AX寄存器中的数据累加
MOV [0x0a2e23], BX # 将寄存器BX中的数据写入内存地址 0x0a2e23

参考链接中有一个在线的简单汇编代码执行器,可以直观的感受到汇编对寄存器的操作过程。

接下来要研究下内存的结构,以及CPU是如何进行寻址的,进一步理解C语言。

关于CPU对内存的寻址过程
CPU对内存数据的读写主要通过 地址总线 指令总线 数据总线 来完成的。通过地址总线与内存通信 先确定内存数据的存储地址 指令总线 用来确定操作是读数据 还是写数据,内存根据接收的指令信息确定操作,如果是读数据,根据地址读取数据并通过地址总线返回数据,如果是些数据 通过地址总线接收数据 并通过地址将数据写入,具体的电路实现可以参考 内存 的工作原理

TODO CPU时钟

其实CPU在进行一次计算做了很多事情,这些事情还要在规定的时间内完成,这就需要CPU时钟 进行控制 也就是我们常看到的CPU的频率 ,比如目前的电脑CPU频率是 2.2GHz

参考链接
四位计算机的原理及其实现
一个简单的在线汇编执行器
寄存器