计算机科学基础_2 - CPU,指令

中央处理器CPU

  • RAM + 寄存器 + ALU 作个CPU
  • 解释“指令 -> 解释 -> 执行”这个循环
  • 时钟是什么,时钟速度和赫兹
  • 超频提高性能,降频省电

重点:python

  1. 拼个CPU出来。
  2. CPU怎么执行命令?

ALU:
做用:输出二进制,它会执行计算。算法

clipboard.png

两种内存:
寄存器: 很小的一块内存,能存一个值。
RAM: 是一大块内存,能在不一样地址存大量数字。 (寄存器增大后改形成RAM)编程

RAM, 寄存器, ALU放在一块儿,组件计算机的心脏CPU(中央处理单元)。缓存

拼个CPU

CPU: 四个寄存器 + 2个寄存器(指令寄存器和指令地址寄存器) + RAM + ALU(指令须要其功能才使用) + “时钟”架构

CPU做用: 负责执行程序。
程序由一个个操做组成,这些操做叫作“指令”,由于它们“指示”计算机要作什么。若是是数学指令,好比加/减,CPU会让ALU进行数学计算。也多是内存指令,CPU会和内存通讯,而后读/写值。
CPU里有不少组件。重点放在功能,而不是一根根线具体怎么连。当用一根线链接两个组件时,这条线只是全部必须线路的一个抽象。这种高层次视角叫“微体系架构”。性能

首先要内存,使用RAM,为了保持简单,假设它只有16个位置,每一个位置存8位。再来四个8位存储器,叫A, B, C, D。寄存器用来 临时存数据 和 操做数据。fetch

clipboard.png

数据是以二进制存在内存里。
程序也能够存在内存里。优化

能够给CPU支持的全部指令,分配一个ID:ui

clipboard.png

在这个假设的例子,用前四位存“操做代码”(operation code),简称“操做码”(opcode),后四位表明数据来自哪里,能够是寄存器或内存地址。加密

还须要两个寄存器,来完成CPU

  1. 一个寄存器追踪程序运行到哪里了,叫它“指令地址寄存器”。(存当前指令的内存地址)
  2. 另一个寄存器存当前指令, 叫“指令寄存器”。

clipboard.png

当启动计算机时,全部寄存器从0开始。

clipboard.png

CPU的第一个阶段叫“取指令阶段”(FETCH PHASE),负责拿到指令。

首先,将“指令地址寄存器”连到RAM,寄存器的值为0,所以RAM返回地址0的值,0010 1110会复制到“指令寄存器”里。

clipboard.png

如今指令拿到了,要弄清楚是什么指令,才能执行(execute),而不是杀死(kill)它,这是“解码阶段”。
前4位0010LODA A指令,意思是,把RAM的值放入寄存器A。
后4位1110RAM的地址,转成十进制是14。

clipboard.png

接下来,指令由“控制单元”进行解码,就像以前的全部东西,“控制单元”也是逻辑门组成的。

clipboard.png

clipboard.png

好比:为了识别“LOAD A”指令,须要一个电路,检查操做码是否是0010,能够用不多的逻辑门来实现。

clipboard.png

指令:

clipboard.png

知道了什么是指令,就能够开始执行了,开始“执行阶段”。

  1. 用“检查是否LOAD_A指令的电路”,能够打开RAM的“容许读取线”,把地址14传过去,RAM拿到值,0000 0011,十进制的3。
  2. 由于是LOAD_A指令,想把这个值只放到寄存器A,其它寄存器不受影响,因此须要一根线,把RAM链接到4个寄存器,用“检查是否LOAD_A指令的电路”启用寄存器A的“容许写入线”。

成功把RAM地址14的值,是十进制的3,放到了寄存器A:

clipboard.png

CPU怎么执行命令?
“取指令 -> 解码 -> 执行”

指令完成了,能够关掉全部线路:

clipboard.png

去拿下一条指令,“指令地址寄存器”+1,“执行阶段”结束。

LOAD_A只是CPU能够执行的各类指令之一,不一样指令由不一样逻辑电路解码,这些逻辑电路会配置CPU内的组件来执行对应操做。
如今计算机支持更多指令,直接操做内存,但原理上是如此。

复杂的逻辑电路解码,把它封装成一个总体的“控制单元”。

clipboard.png

汇编指令与机器指令就是一一对应。

控制单元就像管弦乐队的指挥,“指挥”CPU的全部组件。“取指令 -> 解码 -> 执行”完成。
后续能够再从“取指令”开始:

  1. “指令地址寄存器”如今值是1,因此RAM返回地址1里的值:0001 1111
  2. 到了“解码”阶段,0001LOAD_B指令,从RAM里把一个值复制到寄存器B,此次内存地址是1111,十进制的15。
  3. 如今到“执行阶段”,“控制单元”叫RAM读地址15,并配置寄存器B接受数据。
  4. 完成,把值0001 1110也就是十进制的14存到了寄存器B。
  5. 最后,再把“指令地址寄存器”+1。
  6. “执行阶段”结束。

clipboard.png

clipboard.png

后续能够再从“取指令”开始:

  1. “指令地址寄存器”如今值是2,因此RAM返回地址1里的值:1000 0100
  2. 1000是ADD指令,此次后面4位不是RAM地址,而是2位,2位,分别表明2个寄存器,2位能够表示4个值(00, 10, 01, 11),因此足够表示4个寄存器。
  3. 第一个地址是01,表明寄存器B,第二个地址是00,表明寄存器A。所以,1000 0100,表明把寄存器B,加到寄存器A里。
  4. 为了执行这个指令,要整合ALU。“控制单元”负责选择正确的寄存器做为输入,并配置ALU执行正确的操做。
  5. 对于ADD指令,“控制单元”会,启用寄存器B,做为ALU的第一个输入,还启用寄存器A,做为ALU的第二个输入。ALU能够执行不一样操做,因此控制单元必须传递ADD操做码告知ALU要作什么。
  6. 最后,结果应该存到寄存器A。但不能直接写入寄存器A,这样新值会进入ALU,不断和本身相加。所以,控制单元用本身的一个寄存器暂时保存结果,关闭ALU,而后把值写入正确的寄存器。这里3 + 14 = 17,二进制是0001 0001
  7. 最后,再把“指令地址寄存器”+1。
  8. ADD结束。

clipboard.png

clipboard.png

clipboard.png

后续能够再从“取指令”开始:

  1. “指令地址寄存器”如今值是3,因此RAM返回地址3里的值:0100 1101
  2. 解码得知是STORE A指令(把寄存器A的值放入到内存)RAM地址13中。
  3. 接下来,把地址传给RAM,但此次不是“容许读取”而是“容许写入”;同时,打开寄存器A的“容许读取”,这样就能够把寄存器A里的值,传给RAM

clipboard.png

clipboard.png

运行第一个电脑程序:
它从内存中加载两个值,相加,而后把它结果放回到内存中。

人工切换CPU的状态:“取指令 -> 解码 -> 执行”。

最后:
STORE_A 13指令执行完以后,再执行HALT指令。不然CPU会不停运行下去,处理后面的0。由于0不是操做码,因此电脑会崩掉。
通常来讲RAM没写的话,里面会储存乱码而不是0(不HALT就会崩掉)。

时钟

是“时钟”来负责管理CPU的节奏,时钟以精确的间隔,触发电信号,“控制单元”会用这个信号,推动CPU的内部操做。就像罗马帆船的船头,有一我的负责按节奏的击鼓,让全部划船的人同步。就像节拍器同样。

clipboard.png

节奏不能太快,由于就算是电也要必定时间来传输,CPU“取指令 -> 解码 -> 执行”的速度叫“时钟速度”。单位是赫兹,赫兹是用来表示频率的单位。1赫兹表明一秒1个周期。

前面的步骤:
读取 -> 读取 -> 相加 -> 存储时钟速度大概是0.03赫兹,(1/360 = 0.03Hz)。

第一个单芯片CPU是“英特尔 4004”1971年发布的4位CPU。
它的微架构:

clipboard.png

虽然是第一个单芯片的处理器,但它的时钟速度达到了740千赫兹 - 每秒74万次。

一兆赫兹是1秒1百万个时钟周期,如今的电脑或手机,确定有几千兆赫兹。1秒10亿次时钟周期。

计算机超频,意思是修改时钟速度,加快CPU的速度。芯片制造商常常会给CPU留一点余地,能够接受一点超频。但超频太多会让CPU过热,或产生乱码,由于信号跟不上时钟(超频通常不会让计算机起火)。
降频,有时候没有必要让处理器全速运行,可能用户走开了,或者在跑一个性能要求较低的程序,把CPU的速度降下来,能够省不少电。省电对用户电池的设备很重要,好比笔记本和手机。
为了尽量省电,不少现代处理器能够按需求,加快或减慢时钟速度。这叫“动态调整频率”。加上时钟后,CPU才是完整的。

寄存器ALU时钟封装在一块儿:

clipboard.png

RAM,是在CPU外边的独立组件。
CPURAM之间用“地址线”“数据线”“容许读/写线”进行通讯。

指令和程序

重点:运行一遍程序。

  • 介绍“指令集”。LOAD_A, LOAD_B, SUB, JUMP, ADD, HALT等指令。
  • 带条件跳转,JUMP NEGATIVE是负数才跳转,还有其余类型的JUMP
  • 真正如今CPU用更多指令集。位数更长。
  • 1971年的英特尔4004处理器,有46个指令。
  • 现在英特尔酷睿i7,有上千条指令。

ALU, 控制单元, RAM, 时钟结合在一块儿,作了一个基本,但可用的“中央处理单元”,简称CPU。它是计算机的核心。CPU之因此强大,是由于它是可编程的,若是写入不一样指令,就会执行不一样任务。CPU是一块硬件,能够被软件控制。

介绍指令集
  • LOAD_A寄存器A
  • LOAD_B寄存器B
  • ADD相加。
  • STORE_A存储寄存器A,并写入RAM中。
  • SUB减法,和ADD同样也要2个寄存器来操做。
  • JUMP(跳转),让程序跳转到新位置。若是想改变指令顺序,或跳过一些指令,这个就很实用。例如:JUMP 0,能够调回开头。JUMP在底层的实现方式是:把指令后4位表明的内存地址的值覆盖掉“指令地址寄存器”里的值。
  • JUMP_NEGATIVE,它只在ALU的“负数标志”为真时,进行JUMP。算数结果为负,“负数标志”才是真,结果不是负数时,“负数标志”为假,若是是假,JUMP_NEGATIVE就不会执行程序照常运行。
  • HALT(中止),计算机还须要知道何时该停下来。
条件跳转

clipboard.png

指令和数据都是存在同一个内存里的。它们在根本层面上毫无区别,都是二进制数HALT很重要,能区分指令和数据。

JUMP让程序更完整一些:
如今从CPU的视角走一遍程序。

clipboard.png

  • 首先LOAD_A 14,把1存入寄存器A(地址14里值是1)。
  • 而后LOAD_B 15,把1存入寄存器B(地址15里值是1)。
  • 而后ADD B A把寄存器B和A相加,结果放到寄存器A里。如今寄存器A的值是2,(以二进制存储的)
  • 而后STORE_A 13指令,把寄存器A的值存入内存地址13。
  • JUMP 2指令,CPU会把“指令寄存器”的值,如今的“4”,改为“2”。所以下一步不是HALT
  • 再读内存地址2里的指令,也就是ADD B A,寄存器A里的2,寄存器B里的1。1+2=3,寄存器A变成3。存入内存。又碰到JUMP 2,回到ADD B A,1+3=4。每次循环都+1,不断增多。若是按照这样执行下去,永远不会碰到HALT,老是会碰到JUMP 2。这个叫无限循环(INFINITE LOOP)∞

clipboard.png

JUMP 2指令:
clipboard.png

为了中止下来,须要有条件的JUMP,只有特定条件知足了,才执行JUMP
好比:JUMP NEGATIVE就是条件跳转的一个例子。
还有其它类型的条件跳转,好比,JUMP IF EQUAL(若是相等)JUMP IF GREATER(若是更大)

for循环是有个数限制,while和python里的repeat是无限循环。

执行下图程序:

clipboard.png

  • 程序先把内存值放入寄存器A和B。寄存器A是11,寄存器B是5。
  • SUB B A,用A减B,11-5=6。如今寄存器A的值是6
  • JUMP_NEG 5,ALU上次计算的是6,是正数,因此“负数标志”是假。所以处理器不会执行JUMP,继续下一条指令。
  • JUMP 2JUMP 2没有条件,直接执行SUB B A, 6-5=1。如今寄存器A的值是1。
  • JUMP_NEG 5,由于1仍是正数,所以JUMP NEGATIVE不会执行,来到下一条指令。
  • JUMP 2,直接执行SUB B A, 1-5=-4。如今寄存器A的值是-4。此次ALU的“负数标志”是真。如今寄存器A的值是-4。
  • JUMP_NEG 5, CPU的执行跳转到内存地址5的指令ADD B A。跳出了无限循环。
  • ADD B A,-4+5=1,存入寄存器A,如今寄存器A的值是1。
  • STORE_A 13,存入内存地址13
  • HALT指令,中止程序。

clipboard.png

指令顺序:

  1. LOAD_A 14 值是11
  2. LOAD_B 15 值是5
  3. SUB B A 寄存器A值6(11-5)
  4. JUMP_NEG 5 "负数标志"false
  5. JUMP 2 跳转会地址2再次依次执行
  6. SUB B A 寄存器A值1(6-5)
  7. JUMP_NEG 5 "负数标志"false
  8. JUMP 2 跳转会地址2再次依次执行
  9. SUB B A 寄存器A值-4(1-5)
  10. JUMP_NEG 5 "负数标志"true
  11. ADD B A 寄存器A值1(-4+5)
  12. STORE_A 13 存入内存地址13
  13. HALT指令,程序结束

这段程序只有7个指令,但CPU执行了13个指令。由于在内部循环了2次。
这段代码是算余数,11除5余1 -> 11-5-5-5+5 = 1

软件能够作到硬件作不到的事。
ALU可没有除法功能,是程序给了除法这个功能。

假设的CPU很基础,全部指令都是8位,操做码只占了前4位,即使用尽4位,也只能表明16个指令。并且有几条指令,是用后4位来指定内存地址。只能表示16个指令,并很少,甚至不用使用JUMP 17,由于4位二进制没法表示数字17,所以,真正的现代CPU用两种策略。

  1. 最直接的方法是用更多位来表明指令,好比32位或64位。这叫 “指令长度”
  2. “可变指令长度”,例如:某个CPU用8位长度的操做码,若是看到HALT指令,HALT不须要额外数据,那么会立刻执行。若是看到JUMP,它得知道位置值,这个值在JUMP的后边。这个叫“当即值”,这样设计,指令能够是任意长度。但会让读取阶段复杂一些。

某些指令不须要操做内存因此能够省下内存那四位。
可是JUMP也须要4位操做码,这样仍是只有4位来表示内存地址。
通常来讲 (指令=操做码+操做值地址)。当(指令=操做码+操做值)时,这个操做值就是当即值。
这样大于8位的地址,能够经过屡次重复读取的方式得到,这也是读取阶段相对麻烦的地方。
当即值是指令+位置

英特尔4004处理器

1971年,英特尔发布了4004处理器。这是第一次把CPU作成一个芯片,给后来的英特尔处理器打下基础。

  • 支持46个指令。足够作一台可以用的电脑。
  • 使用了前面使用过的指令。好比JUMP, ADD, SUB, LOAD
  • 也用8位的“当即值”来执行JUMP,以表示更多内存地址。

处理器从1971年到如今发展巨大,现代CPU,好比英特尔酷睿i7,有上千个指令和指令变种。长度从1到15个字节。
例如:光ADD指令就不少变种。
指令愈来愈多,是由于给CPU设计了愈来愈多功能。

高级CPU设计

  • 早期是加快晶体管切换速度,来提高CPU速度。
  • 给CPU专门的除法电路+其它电路来作复杂操做,好比游戏,视频解码。
  • 给CPU加缓存,提升数据存取速度。
  • 脏位(Dirty bit)
  • 流水线设计
  • 并行处理(parallelize)
  • 乱序执行(out-of-order execuition)
  • 推测执行(speculative execution)
  • 分支预测(branch prediction)
  • 多个ALU
  • 多核(Code)
  • 多个独立CPU
  • 超级计算机,中国的“神威 太湖之光”

从1秒1次运算,到如今千兆赫甚至兆赫的CPU。如今看视频的设备也有GHz速度。
1秒10亿条指令,这是很大的计算量。

减小晶体管切换时间

早期计算机的提速方式是,减小晶体管的切换时间。
晶体管组成了逻辑门,ALU以及其它计算机组件。

这种提速方法最终会碰到瓶颈,因此处理器厂商,发明了各类新技术来提高性能,不但让简单指令运行更快,也让它能进行更复杂的运算。

除法的程序,给CPU执行,方法是作一连串减法。好比16除4会变成。16-4-4-4-4,碰到0或负数才停下来。这种方法要多个时钟周期,很低效。因此现代CPU直接在硬件层面设计了除法,能够直接给ALU除法指令。

除法电路

拥有除法的ALU更大也更复杂一些。但也更厉害,复杂度vs速度 的平衡在计算机发展史上常常出现。
例如:现代处理器有专门电路来处理图形操做,解码压缩视频,加密文档等等。若是用标准操做来实现,要不少个时钟周期。可能据说过处理器MMX, 3DNOW, SEE。它们有额外电路作更复杂的操做。用于游戏和加密等场景。

指令不断增长,一旦习惯了它的便利就很难删掉,因此为了兼容旧指令集,指令数量愈来愈多。

英特尔4004,第一个集成CPU,有46条指令,足够作一台能用的计算机。但现代处理器有上千条指令,有各类巧妙复杂的电路。

超高的时钟速度带来另一个问题: 如何快速传递数据给CPU。就像有强大的蒸汽机,但没法快速加煤。RAM成了瓶颈。

RAM是CPU以外的独立组件,意味着数据要用线来传递,叫“总线”。
总线可能只有几厘米,别忘了电信号的传输接近光速。但CPU每秒能够处理上亿条指令。很小的延迟也会形成问题。

clipboard.png

给CPU加缓存

RAM还须要时间找地址,取数据,配置,输出数据。一条“从内存读数据”的指令可能要多个时钟周期,CPU空等数据。解决延迟的方法之一是:给CPU加一点RAM,叫“缓存”
由于处理器里空间不大,因此缓存通常只有KBMB,而RAM都是GB起步。
缓存提升了速度,CPU从RAM拿数据时,RAM不用传一个,能够传一批。虽然花的时间久一点,但数据能够存在缓存。

clipboard.png

这很实用,由于数据经常是一个个按顺序处理。
例如:算餐厅的当日收入。先取RAM地址100的交易额,RAM与其只给1个值,直接给一批值。把地址100到200都复制到缓存,当处理器要下一个交易额时,地址101,缓存会说:“我有下一个交易额的值”,而不用向RAM取数据。

clipboard.png

由于缓存离CPU近,一个时钟周期就能给数据,CPU不用空等
比反复去RAM拿数据快得多,若是想要的数据已经在缓存,叫“缓存命中”。若是想要的数据不在缓存,叫“缓存未命中”。
缓存也能够当临时空间,存一些中间值,适合长/复杂的运算。

若是计算完餐厅一天销售额,想把结果存到地址150,就像以前,数据不是直接存到RAM,而是存在缓存,这样不但存起来快一些,若是还要接着算,取值也快一些。
但这样带来一个问题,缓存和RAM不一致了,这种不一致必须记录下来,以后要同步。所以缓存里每块空间,有一个特殊标记,叫“脏位(Dirty bit)”。

同步通常发生在,当缓存满了而CPU又要缓存时,在清理缓存腾出空间以前,会先检查“脏位”,若是是“脏”的,在加载新内容以前,会把数据写会到RAM

clipboard.png

流水线设计

提高性能方法叫“指令流水线”。
例如:洗一整个酒店的床单,但只有1个洗衣机, 1个干燥机。

选择1: 按顺序来,放洗衣机等30分钟洗完,而后拿出湿床单,放进干燥机等30分钟烘干。这样1小时洗一批。

须要用“并行处理”进一步提升效率,先放一批床单到洗衣机,等30分钟洗完,而后湿床单放进干燥机,但此次,与其干等30分钟烘干,能够放另外一批进洗衣机。让两台机器同时工做,30分钟后,一批床单完成,另外一批完成一半,另外一批准备开始,效率是翻倍的。

clipboard.png

处理器也能够这样子设计,CPU是按序处理,取指令(fetch) -> 解码(decode) -> 执行(execute),不断重复。这种设计,三个时钟周期执行1条指令。

clipboard.png

并行处理

但由于每一个阶段用的是CPU的不一样部分,意味着能够并行处理,“执行”一个指令时,同时能够“解码”下一个指令,“读取”下下个指令。不一样任务重叠进行,同时用上CPU里全部部分。这样的流水线,每一个时钟周期执行1个指令,吞吐量*3。

clipboard.png

和缓存同样,这也会带来一些问题:

  • 指令之间的依赖关系。例如:在读某个数据,而正在执行的指令会改这个数据。也就是说拿是旧数据,所以流水线处理器,要先弄清数据依赖性,必要时中止流水线,避免出问题。
    高端CPU,好比笔记本和手机里的,会更进一步,动态排序 有依赖关系的指令。 最小化流水线的停工时间。这叫“乱序执行(out-of-order execuition)”。
    这种电路很是复杂,但由于很是高效,几乎全部现代处理器都有流水线。
  • “条件跳转”,好比“JUMP NEGATIVE”,这些指令会改变程序的执行流,简单的流水线处理器,看到JUMP指令会停一下子等待条件值肯定下来,一旦JUMP的结果出来了,处理器就继续流水线。但由于空等会形成延迟,因此高端处理器会用一些技巧(调度算法,冒险分支)。
    能够把JUMP想象成是“岔路口”,高端CPU会猜哪条路的可能性大一些,而后提早把指令放进流水线,这叫“推测执行(speculative execution)”。当JUMP的结果出了,若是CPU猜对了,流水线已经塞满正确能够执行的指令,能够立刻运行。若是CPU猜错了,就要清空流水线,就像走错路掉头。
    为了尽量减小清空流水线的次数,CPU厂商开发了复杂的方法,来猜想哪条分支更有可能,叫作“分支预测(branch prediction)”。现代CPU的正确率超过90%。
多个ALU

理想状况下,流水线一个时钟周期完成1个指令,而后“超标量处理器”出现了,一个时钟周期完成多个指令。即使有“流水线设计”,在指令执行阶段,处理器里有些区域仍是可能会空闲,好比,执行一个“从内存取值”指令期间ALU会闲置。因此一次性处理多条指令(取指令+解码)会更好。

能够再进一步,加多几个相同的电路,执行出现频次很高的指令。(一核有难,多核围观)
例如:不少CPU有四个,八个甚至更多彻底相同的ALU。能够同时执行多个数学运算。

clipboard.png

目前说过的方法:“缓存”,“指令流水线”,“多个ALU”,都是优化1个指令流的吞吐量。

多核(Code)

另一个提高性能的方法是:同时运行多个指令流,用多核处理器。(七核看戏)

双核或四核处理器,意思是一个CPU芯片里,有多个独立处理单元。很像是有多个独立CPU,但由于它们整合紧密,能够共享一些资源。好比缓存,使得多核能够合做运算。但多核不够时,能够用多个CPU。

clipboard.png

高端计算机,视频观看的计算机,须要更多的马力,让上百人以上可以同时流畅的观看,2个或4个CPU是最多见的,但有时有更高的性能需求,因此造了超级计算机。
好比模拟宇宙的造成,须要强大的计算能力。给普通的台式机加几个CPU没什么用,须要更多的处理器。目前为止,最快的计算机在中国无锡的“神威 太湖之光”,有40960个CPU,每一个CPU有256和核心,总共超过1千万个核心,每一个核心的频率是1.45GHz,每秒能够进行9.3亿亿次浮点运算。

现代的处理器不但大大的提升了速度,并且也变得更复杂,用各类技巧,榨干每一个时钟周期,作尽量多的运算。

相关文章
相关标签/搜索