“随机存取存储器”,简称“RAM”,只能在有电的情况下存储东西,比如游戏状态
另一种存储叫“持久存储”,电源关闭时数据也不会丢失
存1位(AND-OR Latch - 锁存器)
将输出值回流到输入值,其输出结果仍然保持不变,这便使得可以持久存储。结果就好像是被锁住一样,因此形象的称为“锁存”
放入数据的动作叫写入,拿出数据的动作叫读取
两条线:一条是数据输入,另一条是启用写入线
只有当写入线启用时,写入的数据才会存储到计算机里面,读取数据时才会更新为刚刚写入的值
存8位 (register - 寄存器)
位宽表示内存或显存一次能传输的数据量
随着存储位数的增加,需要的线也越来越多。矩阵便是解决这个问题的方法
16x16 的矩阵便可以存 256 位
数据选择器/多路复用器(Multiplexer)解码8位地址,定位到单个锁存器
4位代表行,4位代表列
如1100 1000 就代表12行8列的锁存器
再比如0000 0001就代表0行1列的锁存器
(行和列均由0开始)
可寻址的256字节 内存
一条1980年代的内存,1M大小
8个模块,每个模块有32个小方块,
每个小方块有4个小块,每个小块是128位x64位
RAM(一大块内存,能在不同地址存大量数据) + 寄存器(很小的一块内存,能存一个值) + ALU(算术逻辑单元)做成了计算机的心脏“中央处理单元”简称CPU
CPU负责执行程序
解释**“取指令–>解码–>执行”**这个循环
CPU完成“取指令–>解码–>执行”每一步的速度叫**“时钟速度”**
其中单位是赫兹–赫兹是用来表示频率的单位,1赫兹代表1秒1个周期
举个例子:6min执行了4条指令(读取–>读取–>相加–>存储)
而每条指令经历了“取指令–>解码–>执行”三个时钟速度
因此就是4(4条指令)*3(每条指令需要花费的时间速度)/3600s(四条指令总花费的时间),所以时钟速度大概是0.03赫兹
超频提升性能,降频省电
每个地址可以存8位数据
前四位是“操作码”,后四位是内存地址,或寄存器
例如00101110,其中前四位代表指令LOAD_A,后四位指定内存地址的值,放入寄存器A
后四位是1110,十进制过后是14。因此00101110可以看成LOAD_A 14指令,从地址14拿
到数字然后放入寄存器A(LOAD_B同理)
例如“ADD B A”告诉ALU把寄存器B和寄存器A里的数字加起来
特别注意:B和A的顺序很重要,因为结果会存在第二个寄存器。也就是这里会存在寄存器A里
例如:STORE_A 13就是把寄存器A的值存入内存地址13
实现减法操作,与ADD一致,也是两个寄存器进行操作
实现跳转,让程序跳转到新的位置
例如JUMP 0可以跳回开头
JUMP在底层的实现方式是把指令后四位代表的内存地址的值覆盖掉“指令地址寄存器”里的值
它只在ALU的“负数标志”为真时,进行JUMP
能够区分指令和数据 使计算机停下来
带条件的跳转,JUMP NEGATIVE是负数才跳转,还有其他类型的JUMP
因为这里的CPU是为了便于理解做的假设
其中四位2进制最多只能表示16个指令或者地址,但真正现代CPU需要用更多指令集。
两种策略
第一种策略是使位数更长,比如32位或者64位,这叫做指令长度
第二种策略是**“可变指令长度”**,长度可以是任意的,但读取相对复杂
1971年的英特尔 4004处理器,有46个指令
这是第一次把CPU做成了一个芯片,给后来的英特尔处理器带下了基础
如今英特尔酷睿i7,有上千条指令还增加了不少指令变种
早期是加快晶体管切换速度,来提升CPU速度
给CPU专门的除法电路(早期的除法相当是在做一个又一个的减法操作,比如16/4 在早期是16 - 4 - 4 - 4 - 4,直到碰到0或者负数才停下) + 其他电路来做复杂操作,比如游戏,视频解码
如果想要的数据已经在缓存,叫缓存命中
如果想要的数据不在缓存,叫缓存未命中
缓存与RAM同步一般发生在 当缓存满了而CPU又要缓存时
在清理缓存腾出空间时,会先检查“脏位”
如果是“脏”的,在加载新内容之前,会把数据写回RAM
另一种提升性能的方法叫**“指令流水线”**
流水线设计,用1个洗衣机和1个干燥机举例
例如:你要洗一整个酒店的床单,但只有1个洗衣机和1个干燥机
选择1:按顺序来,放洗衣机等30min洗完,然后拿出湿床单,放入干燥机等30min烘干
结果1:一批床单需要1个小时
并行处理–parallelize
同样的例子
选择2:洗衣机和干燥机同时进行
结果2:效率x2
同理,CPU也可以这样处理,之前是“取址–>解码–执行>”不断重复
这种设计,三个时钟周期执行1条指令
但因为每个阶段用的是CPU的不同部分,意味着可以并行处理
例如当“执行”一个指令时,同时“解码”下一个指令,“读取”下下个指令
结果就是不同的任务重叠进行,同时用上CPU里所有的部分。这样的流水线 每个时钟周期就可以执行1个指令,吞吐量x3
但这样做也会带来几个问题:
问题1:指令之间的依赖关系,比如“读取”A地址的数据,而此时“执行”是修改A地址的数据,那么读取到的数据就是执行修改后的数据。
因此流水线处理器就要先弄清数据依赖性,必要时停止流水线,避免出问题
而如今高端的CPU会进一步,动态排序 有依赖关系的指令最小化流水线的时间也就是乱序执行–out-of-order execution
问题2:“条件跳转”,比如之前说的JUMP NEGATIVE
这些指令会改变程序的执行流
简单的流水线处理器,看到JUMP指令会停一会儿 等待条件值确定下来,一旦JUMP的结果出了,处理器就会继续流水线
而空等会造成延迟,所以高端处理器就会用一些技巧
例如:将JUMP想成是“岔路口”,高端CPU会猜哪条路的可能性大一些,然后提前把指令放进流水线,这叫**“推测执行”**,当JUMP的结果出了,如果CPU猜对了,流水线已经塞满正确指令,可以马上运行;如果CPU猜错了,就要清空流水线
为了尽可能减少清空流水线的次数,CPU厂商开发了复杂的方法,来猜测哪条分支更有可能,叫**“分支预测”**,现代CPU的正确率超过90%
理想情况下,流水线一个时钟周期完成1个指令,然后“超标量处理器”出现了,一个时钟周期完成了多个指令
但即使有流水线设计,在指令执行阶段,处理器有些区域还是可能会空闲
比如,执行一个“从内存取值”指令期间,ALU会闲置,所以一次性处理多条指令(取指令+解码)会更好
超级计算机,中国的“神威 太湖之光”
有40960个CPU,每个CPU有256个核心
给机器编程的需求远在计算机出现前就有了
例如如果你只想织一块红色大桌布,可以直接放红线进织布机,但如果是图案,工人则要每隔一会儿,调整一次织布机。因此非常消耗劳动力,导致图案纺织品很贵
由此约瑟夫·玛丽·雅卡尔 发明了可编程纺织机,于1801年首次亮相
每一行的图案由可穿孔纸卡决定,特定位置有没有穿孔,决定了线是高是低
打孔纸卡–Punched card,便宜、可靠、也易懂
并且在1890年用于美国人口普查
插线板–Plugboard
插线板不同意味着执行不同的程序,比如一个插线板算销售税,另一个算工资单
但插线板十分复杂,而人们急需更快、更灵活的新方式来编程
冯诺依曼架构
程序和数据都存在这里
冯诺依曼计算机的标志是:一个处理器(有算术逻辑单元)+数据寄存器+指令寄存器+指令地址寄存器+内存(负责存数据和指令)
面板编程
比起插线板用到大量的线,面板编程可以用一大堆开关和按钮,做到相同的效果
第一款取得商业成功的家用计算机Altair 8800
编程依然很困难,人们需要更友好更简单的方式编程–编程语言