极客时间已完结课程限时免费阅读

17 | 建立数据通路(上):指令+运算=CPU

17 | 建立数据通路(上):指令+运算=CPU-极客时间

17 | 建立数据通路(上):指令+运算=CPU

讲述:徐文浩

时长09:53大小9.03M

前面几讲里,我从两个不同的部分为你讲解了 CPU 的功能。
在“指令”部分,我为你讲解了计算机的“指令”是怎么运行的,也就是我们撰写的代码,是怎么变成一条条的机器能够理解的指令的,以及是按照什么样的顺序运行的。
在“计算”部分,我为你讲解了计算机的“计算”部分是怎么执行的,数据的二进制表示是怎么样的,我们执行的加法和乘法又是通过什么样的电路来实现的。
然而,光知道这两部分还不能算是真正揭开了 CPU 的秘密,只有把“指令”和“计算”这两部分功能连通起来,我们才能构成一个真正完整的 CPU。这一讲,我们就在前面知识的基础上,来看一个完整的 CPU 是怎么运转起来的。

指令周期(Instruction Cycle)

前面讲计算机机器码的时候,我向你介绍过 PC 寄存器、指令寄存器,还介绍过 MIPS 体系结构的计算机所用到的 R、I、J 类指令。如果我们仔细看一看,可以发现,计算机每执行一条指令的过程,可以分解成这样几个步骤。
1.Fetch取得指令),也就是从 PC 寄存器里找到对应的指令地址,根据指令地址从内存里把具体的指令,加载到指令寄存器中,然后把 PC 寄存器自增,好在未来执行下一条指令。
2.Decode指令译码),也就是根据指令寄存器里面的指令,解析成要进行什么样的操作,是 R、I、J 中的哪一种指令,具体要操作哪些寄存器、数据或者内存地址。
3.Execute执行指令),也就是实际运行对应的 R、I、J 这些特定的指令,进行算术逻辑操作、数据传输或者直接的地址跳转。
4. 重复进行 1~3 的步骤。
这样的步骤,其实就是一个永不停歇的“Fetch - Decode - Execute”的循环,我们把这个循环称之为指令周期(Instruction Cycle)。
指令周期(Instruction Cycle)
在这个循环过程中,不同部分其实是由计算机中的不同组件完成的。不知道你还记不记得,我们在专栏一开始讲的计算机组成的五大组件?
在取指令的阶段,我们的指令是放在存储器里的,实际上,通过 PC 寄存器和指令寄存器取出指令的过程,是由控制器(Control Unit)操作的。指令的解码过程,也是由控制器进行的。一旦到了执行指令阶段,无论是进行算术操作、逻辑操作的 R 型指令,还是进行数据传输、条件分支的 I 型指令,都是由算术逻辑单元(ALU)操作的,也就是由运算器处理的。不过,如果是一个简单的无条件地址跳转,那么我们可以直接在控制器里面完成,不需要用到运算器。
不同步骤在不同组件之内完成
除了 Instruction Cycle 这个指令周期,在 CPU 里面我们还会提到另外两个常见的 Cycle。一个叫 Machine Cycle机器周期或者 CPU 周期。CPU 内部的操作速度很快,但是访问内存的速度却要慢很多。每一条指令都需要从内存里面加载而来,所以我们一般把从内存里面读取一条指令的最短时间,称为 CPU 周期。
还有一个是我们之前提过的 Clock Cycle,也就是时钟周期以及我们机器的主频。一个 CPU 周期,通常会由几个时钟周期累积起来。一个 CPU 周期的时间,就是这几个 Clock Cycle 的总和。
对于一个指令周期来说,我们取出一条指令,然后执行它,至少需要两个 CPU 周期。取出指令至少需要一个 CPU 周期,执行至少也需要一个 CPU 周期,复杂的指令则需要更多的 CPU 周期。
三个周期(Cycle)之间的关系
所以,我们说一个指令周期,包含多个 CPU 周期,而一个 CPU 周期包含多个时钟周期。

建立数据通路

在专栏一开始,不少同学留言问到,ALU 就是运算器吗?在讨论计算机五大组件的运算器的时候,我们提到过好几个不同的相关名词,比如 ALU、运算器、处理器单元、数据通路,它们之间到底是什么关系呢?
名字是什么其实并不重要,一般来说,我们可以认为,数据通路就是我们的处理器单元。它通常由两类原件组成。
第一类叫操作元件,也叫组合逻辑元件(Combinational Element),其实就是我们的 ALU。在前面讲 ALU 的过程中可以看到,它们的功能就是在特定的输入下,根据下面的组合电路的逻辑,生成特定的输出。
第二类叫存储元件,也有叫状态元件(State Element)的。比如我们在计算过程中需要用到的寄存器,无论是通用寄存器还是状态寄存器,其实都是存储元件。
我们通过数据总线的方式,把它们连接起来,就可以完成数据的存储、处理和传输了,这就是所谓的建立数据通路了。
下面我们来说控制器。它的逻辑就没那么复杂了。我们可以把它看成只是机械地重复“Fetch - Decode - Execute“循环中的前两个步骤,然后把最后一个步骤,通过控制器产生的控制信号,交给 ALU 去处理。
听起来是不是很简单?实际上,控制器的电路特别复杂。下面我给你详细解析一下。
一方面,所有 CPU 支持的指令,都会在控制器里面,被解析成不同的输出信号。我们之前说过,现在的 Intel CPU 支持 2000 个以上的指令。这意味着,控制器输出的控制信号,至少有 2000 种不同的组合。
运算器里的 ALU 和各种组合逻辑电路,可以认为是一个固定功能的电路。控制器“翻译”出来的,就是不同的控制信号。这些控制信号,告诉 ALU 去做不同的计算。可以说正是控制器的存在,让我们可以“编程”来实现功能,能让我们的“存储程序型计算机”名副其实。
指令译码器将输入的机器码,解析成不同的操作码和操作数,然后传输给 ALU 进行计算

CPU 所需要的硬件电路

那么,要想搭建出来整个 CPU,我们需要在数字电路层面,实现这样一些功能。
首先,自然是我们之前已经讲解过的 ALU 了,它实际就是一个没有状态的,根据输入计算输出结果的第一个电路。
第二,我们需要有一个能够进行状态读写的电路元件,也就是我们的寄存器。我们需要有一个电路,能够存储到上一次的计算结果。这个计算结果并不一定要立刻拿到电路的下游去使用,但是可以在需要的时候拿出来用。常见的能够进行状态读写的电路,就有锁存器(Latch),以及我们后面要讲的 D 触发器(Data/Delay Flip-flop)的电路。
第三,我们需要有一个“自动”的电路,按照固定的周期,不停地实现 PC 寄存器自增,自动地去执行“Fetch - Decode - Execute“的步骤。我们的程序执行,并不是靠人去拨动开关来执行指令的。我们希望有一个“自动”的电路,不停地去一条条执行指令。
我们看似写了各种复杂的高级程序进行各种函数调用、条件跳转。其实只是修改 PC 寄存器里面的地址。PC 寄存器里面的地址一修改,计算机就可以加载一条指令新指令,往下运行。实际上,PC 寄存器还有一个名字,就叫作程序计数器。顾名思义,就是随着时间变化,不断去数数。数的数字变大了,就去执行一条新指令。所以,我们需要的就是一个自动数数的电路。
第四,我们需要有一个“译码”的电路。无论是对于指令进行 decode,还是对于拿到的内存地址去获取对应的数据或者指令,我们都需要通过一个电路找到对应的数据。这个对应的自然就是“译码器”的电路了。
好了,现在我们把这四类电路,通过各种方式组合在一起,就能最终组成功能强大的 CPU 了。但是,要实现这四种电路中的中间两种,我们还需要时钟电路的配合。下一节,我们一起来看一看,这些基础的电路功能是怎么实现的,以及怎么把这些电路组合起来变成一个 CPU。

总结延伸

好了,到这里,我们已经把 CPU 运转需要的数据通路和控制器介绍完了,也找出了需要完成这些功能,需要的 4 种基本电路。它们分别是,ALU 这样的组合逻辑电路、用来存储数据的锁存器和 D 触发器电路、用来实现 PC 寄存器的计数器电路,以及用来解码和寻址的译码器电路。
虽然 CPU 已经是由几十亿个晶体管组成的及其复杂的电路,但是它仍然是由这样一个个基本功能的电路组成的。只要搞清楚这些电路的运作原理,你自然也就弄明白了 CPU 的工作原理。

推荐阅读

如果想要了解数据通路,可以参看《计算机组成与设计 硬件软件接口》的第 5 版的 4.1 到 4.4 节。专栏里的内容是从更高一层的抽象逻辑来解释这些问题,而教科书里包含了更多电路的技术细节。这两者结合起来学习,能够帮助你更深入地去理解数据通路。

课后思考

这一讲,我们说 CPU 好像一个永不停歇的机器,一直在不停地读取下一条指令去运行。那为什么 CPU 还会有满载运行和 Idle 闲置的状态呢?请你自己搜索研究一下这是为什么,并在留言区写下你的思考和答案。
欢迎你留言和我分享,你也可以把今天的文章分享给你的朋友,和他一起学习和进步。
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 34

提建议

上一篇
16 | 浮点数和定点数(下):深入理解浮点数到底有什么用?
下一篇
18 | 建立数据通路(中):指令+运算=CPU
unpreview
 写留言

精选留言(38)

  • LDxy
    2019-06-04
    CPU在空闲状态就会停止执行,具体来说就是切断时钟信号,CPU的主频就会瞬间降低为0,功耗也会瞬间降低为0。由于这个空闲状态是十分短暂的,所以你在任务管理器里面也只会看到CPU频率下降,不会看到降低为0。当CPU从空闲状态中恢复时,就会接通时钟信号,这样CPU频率就会上升。所以你会在任务管理器里面看到CPU的频率起伏变化。这个知识也是我找工作面试时才学到的。
    共 5 条评论
    150
  • Akizuki
    2019-06-05
    操作系统内核有 idle 进程,优先级最低,仅当其他进程都阻塞时被调度器选中。idle 进程循环执行 HLT 指令,关闭 CPU 大部分功能以降低功耗,收到中断信号时 CPU 恢复正常状态。
    57
  • 黄马
    2019-10-21
    uptime 命令查看平均负载 满载运行就是平均负载为1.0(一个一核心CPU) 定义为特定时间间隔内运行队列中的平均线程数。load average 表示机器一段时间内的平均load。 这个值越低越好。负载过高会导致机器无法处理其他请求及操作,甚至导致死机 当CUP执行完当前系统分配的任务,为了省电,系统将执行空闲任务(idle task),这个任务循环执行HLT指令,CPU就会停止指令的执行,并且让CPU处于HALT状态,CPU虽然停止指令执行,并且CPU的部分功能模块将会被关闭(达到降低功耗的目的),但是CPU的LAPIC(Local Advanced Programmable Interrupt Controller)并不会停止工作,即CPU将会继续接收外部中断、异常等外部事件(事实上,CPU HALT状态的退出将由外部事件触发).当CPU接收到这些外部事件的时候,将会从HALT状态恢复回来,执行中断服务函数,并且当中断服务函数执行完毕后,指令寄存器(CS:EIP)将会指向HLT指令的下一条指令,即CPU继续执行HLT指令之后的程序
    展开
    39
  • 活的潇洒
    2019-08-21
    要想成功三个动作很重要 1、做出来 2、写出来 3、讲出来 三个非常重要,缺一不可 day17 笔记:https://www.cnblogs.com/luoahong/p/11330406.html
    展开
    共 1 条评论
    25
  • roger
    2019-08-12
    程序计数器一直在变化,就是满载吧,持续不变就是idle。CPU密集型任务需要CPU大量计算的任务,这个时候CPU负载就很高,IO密集型任务,CPU一直在等待IO,就会有idle。
    19
  • 旺旺
    2019-06-04
    cpu执行速度非常快,消耗性能资源也比较快。但实际上,电脑并不是时刻都需要进行大量运算。 所以,CPU需要一种“闲置”状态,来平衡这种矛盾(需要忙时,可以全速奔跑;暂无事务时,又可节能地随时待命。) “Idle 闲置”是一种低功耗的状态,cpu在执行最低功耗的循环指令。实际上并非啥都没干,而是一直在干最最轻松的事儿。
    展开
    共 1 条评论
    12
  • A君
    2020-06-25
    所谓构建数据通路,就是把各种组建通过线路组合起来,让他们可以完成数据存储、处理和传输的操作。数据处理部分自然是交给ALU组合逻辑计算元件,它是由大量运算器组合而成;数据存储自然是交给各种寄存器,存储的数据除了有计算数据外,还有各种状态,以及指令的地址;负责读取指令,将指令转换成电信号的就是译码器;为了让fetch-decode-execute这个循环体运作下去,还需要一个自动设备。
    7
  • 九云
    2019-11-15
    指令周期、时钟周期2个概念就够了。引入CPU周期这个概念,要解释什么问题呢?
    共 3 条评论
    6
  • kdb_reboot
    2019-06-06
    很喜欢这几章;大二时学数电,期末考了93分,但是仍然不知道它能做什么用,内心有困惑,但是也没更多的坚持这个问题;感谢你

    作者回复: 👍一起加油

    6
  • djfhchdh
    2019-06-18
    cpu满载和空闲的分别主要是操作系统调度任务导致的,如果操作系统调度了一个高优先级的任务,那么cpu就优先执行这个任务即满载,如果操作系统调度了一个低优先级的idle任务,那么cpu就执行这个idle任务,显示为空闲状态,空闲即假装“没事做”,其实当有其他更高优先级的任务调度时,就可以抢占它,去执行更高优先级的任务
    5
  • 北风一叶
    2020-03-03
    指令周期由:取得指令,指令译码,执行指令三个步骤的不断循环组成,其中取指令和指令译码由控制器负责,执行指令由运算器负责。一个指令周期由多个CPU周期构成,而一个CPU周期又由多个时钟周期构成,这一部分感觉说的有点混乱。
    共 2 条评论
    3
  • thomas
    2021-07-19
    每一条指令都需要从内存里面加载而来,所以我们一般把从内存里面读取一条指令的最短时间,称为 CPU 周期 ------------------------------------> 为什么要加上最短?
    2
  • A君
    2020-06-25
    因为cpu访问寄存器、cache、内存、硬盘的速度不同,为了不让宝贵的cpu资源浪费在数据传输过程中,因此引入中断,当cpu在访问硬盘等低速设备时可以将任务切换去,执行其他任务。如果不考虑进程调度策略、进程优先级等因素,如果几乎所有任务都是在做计算,那么cpu就会处在满载状态,如果当下没有任务在进行,操作系统就会切换ideal进程,该进程会主动挂起自己,所以说,虽然cpu当前在处理ideal任务,但并不会真正在读取处理传输数据。
    展开
    2
  • chengzise
    2019-06-03
    CPU 还会有满载运行和 Idle 闲置的状态, 指的系统层面的状态。即使是idle空闲状态,cpu也在执行循环指令
    2
  • Nuvole Bianche
    2022-10-17 来自上海
    又一个疑问,原文:“我们通过数据总线的方式,把它们连接起来,就可以完成数据的存储、处理和传输了“,请问其中“数据总线的方式”具体是什么方式或者怎么理解吗?
    1
  • once
    2019-11-27
    老师 前面你说了 访问内存很慢 从内存中取出指令至少需要一个cpu周期 但是执行指令相对于从内存中取出指令应该会快很多吧 为什么也要至少一个cpu周期呢
    共 2 条评论
    1
  • Ronnyz
    2019-11-25
    满载就是执行高优先级任务,不会被中断;空闲就是执行的任务优先级较低,可以被中断
    1
  • Lion
    2022-12-29 来自河北
    cpu密集型和io密集型
  • 第一装甲集群司令克莱...
    2022-12-20 来自北京
    学起来!
  • Geek_b0d83e
    2022-10-20 来自浙江
    指令周期(取指令+执行)>=2*CPU周期>时钟周期