从门到CPU
参考资料
计算机的早期历史
美索不达米亚 1000 BC 算盘
time | area | Instance | 进制 |
---|---|---|---|
1000BC | 美索不达米亚 | 算盘 | 10 |
1694 | 德国 | 步进计算器 | 10 |
before 20 C | world | 计算表 | |
1822 | 英国(Charles Babbage) | 差分机(论文) | |
1822-1842 | 英国(Charles Babbage) | 分析机(general computer) | |
18X(8|9)? | 美国(Hollerith IBM 创始人) | 打孔卡片制表机 |
Ada Lovelace 给分析机写了假象程序(第一程序员)
Charles Babbage 设计了分析机,即通用计算机 (计算机之父)
电子计算机
机械继电器(开关),利用电磁线圈的磁场把开关吸下来,联通电路
二极管 (首先出现为热电子管)
三级真空管(二代继电器),每秒客开闭千次
1947 贝尔实验室 晶体管(半导体材料继电器),每秒万次开闭,加州硅谷,出现仙童半导体公司,仙童来变成了英特尔,目前的晶体管体积 50 纳米,每秒上百万次开闭,工作几十年,
time | area | instance | person | remarks |
---|---|---|---|---|
1944 | IBM | Mark II | IBM | 1947 pulled a bug |
1943.12 | 英国 Bletchley | Mark I | Tommy Flowers | 大规模使用真空管(1600),可编程,解密 Nazi |
1941 | 英国 Bletchley | Bombe | Alan Turing | designd to break Enigma code |
1946 | 美 | ENIAC | Pennsylvania | 积分,真正意义电子计算机 |
1958 | 美 | IBM608 | IBM | 使用晶体管 |
布尔逻辑与逻辑门
布尔代数
关于真值的逻辑运算称为布尔代数(Boolean Algebra),以它的创始人布尔命名。
在编程语言中表示 T 值和 F 值的数据类型叫做布尔类型,在 C
语言中通常用int
类型来表示,非 0 表示 T,0 表示
F。布尔逻辑是写程序的基本功之一,程序中的很多错误都可以归因于逻辑错误。
1 | 以下是一些布尔代数的基本定理,为了简洁易读,T和F用1和0表示,AND用*号表示,OR用+号表示(从真值表可以看出AND和OR运算确实有些类似*和+),NOT用¬表示,x、y、z的值可能是0也可能是1。 |
1 | ¬¬x=x |
逻辑门 and or not xor
VDD 就是电源的意思
and 与门
true | true | true |
---|---|---|
true | false | false |
false | true | false |
false | false | false |
or 或门
true | true | true |
---|---|---|
true | false | true |
false | true | true |
false | false | false |
not 非门
true | false |
---|---|
false | true |
xor 异或门
true | true | false |
---|---|---|
true | false | true |
false | true | true |
false | false | false |
二进制
二进制,逢二进一
27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 |
---|---|---|---|---|---|---|---|
1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
二进制中,
一个 0 或 1 表示一位(1bit)
8bit = 1byte(字节)
字符的表示
字符表示最简单的方法就是给字母一个编号,就有了 ASCII
为了表示 the world 的所有字符,后来就出现了 Unicode 和 ISO,之后他们俩兼容了,现在常用的编码实现位 utf-8,它是一种可变长的编码,utf-8 编码规则
unicode
1 | 正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。 |
unicode 的问题
1 | 需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。 |
utf-8
1 | 互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。 |
Unicode 符号范围(十六进制) | UTF-8 编码方式(二进制) |
---|---|
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
1 | 跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。 |
引用
算数逻辑单元 ALU (Arithmetic & Logic Unit)
计算单元
上面我们介绍了二进制和布尔代数,现在通过硬件保存和布尔运算二进制数,来实现计算单元
加法实现
a half adder 半加器
进行 1bit 运算, 没有进位(十进制满10进1,二进制满2进1),在使用半加器做加法时,两个输入,

全加器
full adder 使用两个 half adder 实现

8bit adder 8bit位加法


逻辑单元
进行布尔运算 and or not xor
对输入的信号,进行逻辑运算,结果符合真值表
ALU 抽象

寄存器和内存(Registers & RAM)
RAM (内存): Random Access Memory (随机访问存储,意思是可以直接访问到任意内存位置,而不是访问的时候是随机的) Registers (寄存器): 存储一个数字,如果计算机设计时时8位,那么一个寄存器就时一个8位数字存储器
sava 1
把或门输出与输入链接,可以形成一个 1 的永久存储,因为输入始终有一个1

sava 0
把与门输出与输入连接,可以形成一个 0 的永久存储,因为输入始终有一个0

锁存(AND-OR LATCH)
将上述两个电路结合起来就做成了一个锁存器

set 设为 1 后,无论 set 如何改变,输出一直为 1,即 set 将状态置为 1。
reset 设为 1 后,无论 reset 如何改变,输出一直为 0,即 reset 将状态置为 0。
set 和 reset 都为 0 的话,锁存器将会保存最后设置的状态,1bit 的记忆功能就实现了,记忆的结果取决于最后关闭的是谁。
门锁(GATED LATCH)
1bit 的可控制写入存储

允许写入线为 0 时,set,reset 恒为 0,不可写入,允许写入线为 1 时,输入 0 将 reset 锁存,存储0,输入 1 将 set 锁存,存储1
抽象出门锁组件

寄存器 register
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储 1 位二进制数,所以由 N 个锁存器或触发器可以构成 N 位寄存器。寄存器是中央处理器内的组成部分。寄存器是有限存储容量的高速存储部件,它们可用来暂存指令

16x16 门锁矩阵
更大位的寄存器

启用某个锁存的方式位激活相应的排线和列线,注意,排线和列线并无连接,可以想象他们交界处,排线像拱桥一样越过了列线,另外,排线会连接他对应的那一排的锁存组件,列线会连接他对应的那一列的锁存组件。

在允许写入线前加一个与门,与行线和列线相连,就可以具体指向某个锁存,比如第一排,第一列,那么第一排第一列所连接的锁存,它的读写控制线才能真正被启动

启用行列线,再启用写入操作线,就可以操作这个锁存,再因为没有行列线的锁存是关闭启用写入线,所以写入操作线就算公用的(1 条线连所有),也可以做到针对某个锁存操作,

启用行列线,再启用读取操作线,就可以打开门锁输出线的开关组件,而此时的写入操作线是关闭状态,所以可以放心启用数据输入输出线,来读取到这个锁存的输出

启用行列线,再启用写入操作线,就可以开启此所存的写入操作,此时操作数据输入输出线,可以设置锁存的值

地址
如何表示操作的是哪个锁存,(我们是使用 16x16 门锁矩阵)
4bit 可以表示 16 个数字(0-15)正好对应16根线,比如0100,意思就是4,就是第5根线(起始值是0000代表第一根线),1111是15代表第16根线。两个16线用8个bit就能表示,前4代表行,后4代表列;8 个 bit 就可以表示一个地址(行,列),例如 3 行 10 列(0011,1010)
多路复用器(multiplexer)
为了将行和列转换为地址,我们需要多路复用器(multiplexer) 多路复用器就是执行将 8bit的一个数字拆成两个4bit,在把4bit的数字,对应到那一根线,让那根线的开关闭合,连通电路

内存(memory)
现在这个内存是通过8根线,代表地址,1根线代表数据读写,1根控制可读,1根控制可写。

静态随机地址存储(SRAM)
我们将8个1bit的内存并联,操作同一个地址,8根数据线分别写入8个小内存里,另外两根是可读可写线。如此一来,一个可存8位数据的,地址范围是0到255的存储装置就做好了,这也就是RAM(内存)
存储 8bit 数据的方式,8 个比特位用相同的地址分别存储

这个是一个 SRAM (static random access memory)
把这个内存单元,看成拥有 256 个地址,每个地址能读写一个 8bit 值,这就是 RAM

The Center Processing Unit (CPU)
基础组件
将上面所封装的寄存器和内存拿下来使用,记住我们始终操作的是8位的数据,鉴于我们的设计,我们肯定是需要一个8位的寄存器来存储地址,鉴于我们的读写功能,可能需要多于1个的8位寄存器来存储读取的数据,在一下的内容中,我们希望实现一些计算功能,我们其实此时完成了图灵机的一部分,即,一个存储设备,读写存储设备,访问存储设备的任意位置,目前我们缺少的是程序,而接下来我们定义指令,并在计算时,使用到上面封装的计算单元(ALU)来完成我们的图灵计算机。

指令表
我们定义指令,指令由8bit组成,前4位代表操作,后四位代表操作对象(地址,或寄存器),在这个例子中,我们的地址只有4位,(这是为了简化举例,我们上面所组装的8位地址是有用的,现代计算机早已经是64位了,而64位就代表其能操作的数值是64位,能使用的地址远超我们现在的例子,所以当前使用4位的地址仅仅是方便举例)如图所示,LOAD_A的意思是把后四位代表内存位置的值,读取到A寄存器里。

cpu 基本架构
我们还需要两个寄存器来完成 CPU,一个用来存储指令地址(本例是 RAM),一个用来存储指令

cpu 执行流程
启动计算机,所有寄存器从零开始

为了举例我们在 RAM 放了一个程序
取指令
cpu 的第一个阶段叫做取指令阶段
FETCH PHASE
,负责拿到指令
- 指令地址寄存器连到 RAM,此时寄存器地址为0,因此 RAM 返回地址 0 的值,值会复制到指令寄存器里

解码指令
cpu 的第二个阶段叫做解码阶段
DECODE
FHASE,负责解析出要执行什么指令

在我们定义的指令中,一个 8 位值,前 4 位代表指令,后 4 位代表参数;对于指令寄存器的值我们需要使用一个控制单元来进行解码
- 检查指令是不是 LOAD_A,我们可以用很少的逻辑门实现

执行指令
知道了是什么指令,我们就可以进入执行阶段

- 电路的连接保证 LOAD_A 正确执行

- 关闭电路,指令地址寄存器+1

控制单元
分析完一个指令后,其他的指令也是类似的情况,所以将所有指令封装成一个控制单元

- 对于 ADD 指令我们需要使用 ALU

- 始终以精确的间隔触发电信号,控制单元会利用这个信号,推进 cpu 的内部操作,确保一切按步骤进行,cpu"取指令-->解码-->执行"的速度叫"时钟速度(CLOCK SPEED)" 通过时钟,计算机一步一步得执行,取指令,解码指令,执行指令,读指令... 计算机中运行的是电信号,电的传播速度在我们的认知上是光速,所以cpu的极限频率大概和光速有关吧。

CPU
我们把寄存器,ALU ,指令控制封装到一起,到中国人很喜欢提的芯片上,这个芯片就叫CPU

指令和程序(Instruction&Programs)
cpu 之所以强大,是因为它是可编程的,写入不同的指令就会执行不同的任务,CPU 是一个可以被软件控制的硬件
这是上一节的例子,四个指令形成了一个加法的操作
RA(register A)
- RAM 地址 14 的值 加载到 RA(寄存器A)
- RAM 地址 15 的值加载到 RB(寄存器B)
- ADD RB & RA ,将结果写入 RA(寄存器A)
- 将 RA 的值存到 RAM 的 13 地址

增加一些指令

负数跳JUMP是通过 ALU 的标志位实现的

没有 halt,cpu 就会继续执行下去,由于 0 不是指令所以电脑会崩,因为指令和数据都放在内存里,他们在根本上没有区别,都是二进制数,所以 halt 很重要,能区分指令和数据
循环的指令
INST(instruction)
- RAM14 LOAD RA
- RAM15 LOAD RB
- ADD RB & RA into RA
- JUMP 2 =>INST.ADDR.REGISTER(指令寄存器) change into 2=> EXECUTE RAM 2 INST(指令)
- ADD RB & RA into RA
- JUMP 2 =>INST.ADDR.REGISTER(指令寄存器) change into 2=> EXECUTE RAM 2 INST(指令
- ...
(INFINITE LOOP)

有条件的循环

SUB(subtract) ALU(Arithmetic & Logic Unit)
- RAM14 LOAD RA
- RAM15 LOAD RB
- SUB RA - RB into RA 11-5=6>0
- JUMP_NEG 5 => ALU RESULT >0 =>don't EXECUTE
- JUMP 2=>INST.ADDR.REGISTER change into 2=> EXECUTE RAM2 INST
- SUB RB RA into RA into RA 6-5=1>0
- JUMP_NEG 5 => ALU RESULT >0 =>don't EXECUTE
- JUMP 2=>INST.ADDR.REGISTER change into 2=> EXECUTE RAM2 INST
- SUB RA - RB into RA 1-5=-4>0
- JUMP_NEG 5 => ALU RESULT <0 =>INST.ADDR.REGISTER change into 5=> EXECUTE RAM5 INST
- ADD RB & RA into RA
- STORE RA into RAM 13
- HALT (结束)
ALU 没有除法,但是我们可以通过程序来实现,
扩展资料