8. CPU的结构和功能
文章目录
- 本笔记参考哈工大刘宏伟老师的MOOC《计算机组成原理(上)_哈尔滨工业大学》、《计算机组成原理(下)_哈尔滨工业大学》。
- 或者是B站《计算机组成原理(哈工大刘宏伟)135讲(全)高清》,大家一起听比较热闹。
- 中文教材:《计算机组成原理(第二版)-唐朔飞.pdf》、《学习指导与习题解答(第2版)-唐朔飞.pdf》
- 本篇笔记对应课程第八章(下图加粗)。
8.1 CPU的结构
本章进一步分析机器语言指令是如何在计算机硬件系统上执行的。首先来根据CPU的功能,讨论出为实现这种功能而设计的结构。如下表所示,最终推导出下图所示的结构。其中,控制总线双向、数据总线双向、地址总线单向。并且除了下图所示,还有其他的辅助电路,以及各部分之间进行连接的CPU内部互联机构。如下:
CPU功能 | CPU结构 | ||
---|---|---|---|
功能细分 | 功能总结 | 结构细分 | 结构概括 |
取指令 | 指令控制 | 寄存器 | 控制器 |
分析指令 | 操作控制 | 控制单元CU (时序电路) |
|
执行指令 | |||
控制程序输入及结果输出 | 时间控制 | ||
总线管理 | |||
处理异常和特殊请求 | 处理中断 | 中断系统 | |
实现算逻运算 | 数据加工 | ALU、寄存器 | 运算器 |
寄存器:不同指令集、不同CPU对于寄存器的设置不同。这里给出寄存器的简单分类。
- 用户不可见寄存器:非常多,比如流水段之间的流水段寄存器。
- 用户可见寄存器
- 通用寄存器:存放操作数,也可作某种寻址方式所需的专用寄存器。
- 数据寄存器:存放操作数(满足各种数据类型),或者两个寄存器拼接存放双倍字长数据。
- 地址寄存器:存放地址,其位数应满足最大的地址范围,用于特殊的寻址方式,如段基值、栈指针。
- 条件码寄存器:存放条件码,可作程序分支的依据,如判断条件为正、负、零、溢出、进位等。
- 控制和状态寄存器
- 控制寄存器:控制CPU操作。比如从内存取一条指令 PC→MAR→M→MDR→IR(1.3节-计算机的工作步骤),其中MAR、MDR、IR用户不可见,PC用户可见。
- 状态寄存器:反应指令指令结果的情况,或者是软件、硬件的状态。“状态寄存器”存放条件码、“PSW寄存器”存放程序状态字。详见“微机原理”课程。
控制单元CU:产生全部指令执行时所需的微操作命令序列。有以下两种方式。
- 组合逻辑设计:使用硬连线逻辑,速度快,比如RISC。
- 微程序设计:使用存储逻辑,适用于复杂功能的指令,将在第九章、第十章介绍。
中断系统:参见下面的“8.4节-中断系统”。
ALU:参见“第6章-计算机的运算方法”。
【课后讨论】举例说明为什么64位的机器不一定比32位的机器速度更快?
【ChatGPT】很大程度上取决于特定的应用场景和工作负载。在处理大型数据库、科学计算和高性能计算任务时,64位架构的优势通常会比较明显。然而,对于那些不需要大量内存或依赖于特定CPU优化的应用,32位机器可能会提供相似甚至更好的性能。以下是一些具体情况:
- 应用程序和工作负载
- 数据宽度:对于不需要处理大量数据的应用程序或不依赖于大地址空间的任务,64位处理器提供的额外能力可能不会带来任何实质性的性能提升。在这种情况下,程序的执行速度可能主要取决于其他因素,如CPU的核心速度、缓存大小、内存速度等。
- 代码和数据的膨胀:64位程序可能因为更大的指针和某些数据类型而导致代码和数据占用更多的内存和缓存空间,这可能在某些情况下降低性能。
- 系统资源和配置
- 内存资源:如果一个64位系统配备的物理内存量不足以支撑其运行更大的应用程序和数据集,可能会导致频繁的页面交换(swap),反而降低性能。而一个32位系统由于其较小的内存地址空间限制,可能不会那么容易遇到这个问题。
- 兼容性层:在一些64位系统上运行32位应用程序时,可能需要通过某种形式的兼容性层(如WOW64在Windows上)。这种转换层可能会引入额外的开销,影响到运行32位应用程序的性能。
- CPU设计和优化
- CPU设计差异:不同的CPU架构和设计可能会在相同的工艺节点和频率下展现出不同的性能表现。例如,一个设计优化的32位CPU可能在某些工作负载下超过一个设计较差的64位CPU。
- 指令集优化:在一些特定的应用场景中,32位应用程序可能更好地利用了特定的CPU指令集优化,而这些优化在对应的64位版本中可能没有得到同样的关注。
8.2 指令周期
本节简单的讲解指令的执行过程。“指令周期”指的是取出并执行一条指令所需的全部时间,如下图分成取值周期、间址周期、执行周期、中断周期,当然还有很多其他的分段方法。当然不同的指令所包含的周期分段不同,比如 NOP 指令只包含取指周期,表示计算机系统无需任何操作;ADD 加法指令的取指周期和执行周期都只访存一次,所以时间相当;MUL 乘法指令的执行周期则明显大于取指周期。如下:
- 取指周期:取指、分析。某些指令可能只有取值周期,比如NOP。
- 执行周期:执行。
- 间址周期:具有间接寻址的指令周期
- 中断周期:执行阶段结束时确认是否有中断请求,并响应中断,也就是“保存断点”、“形成中断程序的入口地址”、“关中断”。
上右流程图假设至少包含取值周期、执行周期。
在指令周期的不同阶段,虽然都需要读写操作,但是不同周期的读写功能不同,控制器给出的控制命令也不同,于是控制器需要知道当前处于控制周期的所处阶段,如上图,于是使用D触发器对不同的阶段进行标记。下面给出在工作周期的不同阶段,指令周期的数据流:
取指周期数据流:从 PC 开始,将指令地址存放在 MAR 中,通过地址总线传输给 存储器,CU再通过控制总线给 存储器 传输读信号。于是存储器通过数据总线返回所存储的指令到 MDR 中,最后送入 IR、CU 控制 PC+1。
间址周期数据流:从 MDR 开始(也可以是IR),将间接地址通过 MAR→地址总线 发送给存储器,CU通过控制总线传输读信号。于是 存储器 读出数据(真正的地址)并将其传输到 数据总线→MDR。
执行周期数据流:不同指令的执行周期数据流不同,第九章专门介绍。
中断周期数据流:中断需要完成“保存断点”、“形成中断程序的入口地址”、“硬件关中断”,下图只给出前两个。CU 将断点的存储地址通过 MAR→地址总线 发送给存储器,然后CU发送写命令到控制总线。同时 PC 将断点地址通过 MDR→数据总线 发送给存储器,存储器在相应的地址保存断点地址。最后 CU 将中断程序的入口地址发送给 PC,开始执行中断程序。“8.4节-中断系统”会详细介绍。
注:PC程序计数器、CU控制单元、MAR存储器地址寄存器、MDR存储器数据寄存器、IR指令寄存器,见“1.3节-计算机的工作步骤”。
8.3 指令流水
8.3.1 指令流水原理
如何提高机器速度:
- 提高访存速度:高速芯片、常用指令放Cache、多体并行(低位交叉)。见“4.2.7节-提高访存速度的措施”。
- 提高I/O和主机之间的传送速度:中断、DMA→通道→I/O处理机、多总线。见“第5章-输入输出系统”。
- 提高运算器速度:高速芯片、改进算法、快速进位链(见“6.5.2节-快速进位链”)。
流水线技术是现代处理器最常用、最有效的提高指令解释速度的方法,从嵌入式处理器到高性能处理器都用到了该技术。上面给出了我们前面学过的“提高机器速度”的方法,但除了方法外,还可以改进系统的结构,开发系统的并行性。下面给出“并行”的基本概念:
- 并行的概念
- 并发:两个或两个以上事件在同一时间段发生。不是在同一时刻。
- 同时:两个或两个以上事件在同一时刻发生,时间上互相重叠。真正的“并行”,下面“流水线”用到。
- 并行性的等级
- 过程级并行:也称为程序级并行、进程级并行,通常使用软件(操作系统)实现,粗粒度。
- 指令级并行(ILP):可以是指令之间同时解释,也可以是指令内部的操作或微操作同时执行,使用硬件实现,细粒度。
于是根据上述“并行”的启发,显然我们可以将指令由“串行执行”,改进成“流水线执行”,进而复用不同的部件。理想状况下, n n n 级流水线可以将指令解释速度提高 n n n 倍!下图给出了流水技术可以提高指令的解释速度的原因:
- 指令的串行执行:所有指令串行执行,各个阶段的部件(取指令部件、执行指令部件)也串行执行,总会有一部分部件处于空闲状态。
- 指令的二级流水:假设工作周期只包含“取指周期”、“执行周期”。重叠执行,没有部件处于空闲状态。
- 指令的六级流水:若将工作周期分为 取指令FI、指令译码DI、形成操作数的地址CO、取操作数FO、执行EI、写回结果WO,就是上右图所示的六级流水线。假设每段时间都是相同的。
分段原则:每段操作时间尽量一致。
注意上述流水段之间都会添加锁存器,保存上一段状态,并为下一段提供数据。但实际上,不是所有流水线都是理想的流水线,并且指令之间也存在一定的相关性,所以流水线很难一直处于满负荷状态。
8.3.2 影响流水线性能的因素
本小节介绍3个影响流水线性能的因素:
- 结构相关:不同指令争用同一功能部件产生资源冲突。比如FI、FO、WO阶段都需要访存(下左图),或者都需要读写同一寄存器,都需要使用ALU,就会冲突。解决方法如下三种。
- 停顿:也成为“加入气泡”,就是等待。
- 将指令Cache和数据Cache分开:也就是哈弗结构。
- 使用指令预取技术:如下右图,适用于访存较快的情况,取指部件利用空闲时间将多条指令放入缓冲区当中,执行部件一个个取出并执行。
- 数据相关:不同指令因重叠操作,可能改变操作数的读/写访问顺序。指令之间的关系有先写后读相关(RAW)、先读后写相关(WAR)、先写后写相关(WAW)。不管怎样,都要保证执行顺序和串行执行一致。
- 解决方法:后推法(推后读/推后写)、旁路技术。详见“计算机体系结构”课程。
- 控制相关:由“条件转移指令”引起,必须等上条指令执行结束,才能确定下条指令的地址,造成“转移损失”。如下图,指令3直到 WO 阶段才能判断已经满足条件,并跳转到指令15,于是指令4~指令7全部作废。现代程序中,基本上每3~5个指令就有1个条件转移指令,所以该指令对于流水线效率影响很大。
- 解决办法有很多,比如各种分支预测法。
8.3.3 流水线性能
有了指标才能分析流水线,进而设计出高性能流水线。设 m m m 段的流水线各段时间都等于 Δ t \Delta t Δt,给出如下三种性能:
- 吞吐率:单位时间内流水线所完成指令或输出结果的数量。
- 最大吞吐率: T p m a x = 1 Δ t T_{pmax}=\frac{1}{\Delta t} Tpmax=Δt1,流水线满负荷运行。
- 实际吞吐率:连续处理 n n n 条指令的吞吐率为 T p = n m Δ t + ( n − 1 ) Δ t T_{p}=\frac{n}{m\Delta t+(n-1)\Delta t} Tp=mΔt+(n−1)Δtn
- 最直接的方法:看某段时间内,有多少指令在执行。
- 加速比 S p S_p Sp: m m m 段的流水线的速度与等功能的非流水线的速度之比。
- 完成 n n n 条指令在 m m m 段流水线上共需 T = m Δ t + ( n − 1 ) Δ t T=m\Delta t +(n-1)\Delta t T=mΔt+(n−1)Δt,完成 n n n 条指令在等效的非流水线上共需 T ′ = n m Δ t T'=nm\Delta t T′=nmΔt,则 S p = 1 T / 1 T ′ = n m Δ t m Δ t + ( n − 1 ) Δ t = n m m + n − 1 S_p=\frac{1}{T}/\frac{1}{T'}=\frac{nm\Delta t}{m\Delta t+(n-1)\Delta t}=\frac{nm}{m+n-1} Sp=T1/T′1=mΔt+(n−1)ΔtnmΔt=m+n−1nm
- 效率:流水线中各功能段(硬件)的利用率。由于流水线有建立时间和排空时间,因此各功能段的设备不可能一直处于工作状态。
- 效率 E = 流水线各段处于工作时间的时空区 流水线中各段总的时空区 = m n Δ t m ( m + n − 1 ) Δ t E=\frac{流水线各段处于工作时间的时空区}{流水线中各段总的时空区}=\frac{mn\Delta t}{m(m+n-1)\Delta t} E=流水线中各段总的时空区流水线各段处于工作时间的时空区=m(m+n−1)ΔtmnΔt (理想流水线),也就是面积之比(如下图)。
8.3.4 流水线的多发技术
下面介绍在流水线的基础上,进一步提高指令解释速度的方法,也就是各种魔改流水线:
超标量技术:同时使用多个流水线。每个时钟周期内可并发多条独立指令,配置多个功能部件。执行过程中不能调整指令的执行顺序,所以通过编译优化技术,在执行前把可并行执行的指令搭配起来。
超流水线技术:进一步切割单个阶段(3段),于是在一个时钟周期内可以多次使用该功能部件(3次)。注意这些“小阶段”之间没有锁存器。同样靠编译程序解决优化问题。RISC使用了该技术。
超长指令字技术:根据计算机中执行部件的种类和数量,由编译程序挖掘出指令间潜在的并行性,将多条能并行操作的指令组合成一条具有多个操作码字段的超长指令字(可达几百位),可以大幅减少取指时间。“灰色”表示采用多个处理部件。在数字信号处理、多媒体信号处理等领域应用非常广。
8.3.5 流水线结构的扩展
最后需要说明的是,“流水线技术”是一种思想,不只能用于上面介绍的“指令流水线”,也可以是“运算流水线”:
指令流水线:将一条指令分6段,每段需一个时钟周期。若流水线不出现断流,理想情况下,1个时钟周期出1结果,6级流水的速度是不采用流水技术的6倍。
运算流水线:若运算过程比较复杂,也可以使用流水线技术提高运算速度。比如可以将浮点加减运算分成“对阶”、“尾数求和”、“规格化”三个部分。同样,每两个流水段之间一定要加上锁存器,保存上一段状态,为下一段提供数据。
分段原则:每段操作时间尽量一致。
8.4 中断系统
本节关心的问题:
- 各中断源如何向CPU提出请求?
- 各中断源同时提出请求怎么办?响应哪一个?
- CPU什么条件、什么时间、以什么方式响应中断?
- 如何保护现场?
- 如何寻找入口地址?
- 如何恢复现场,如何返回?
- 处理中断的过程中又出现新的中断怎么办?
本节介绍CPU的中断系统,上面是本节要回答的问题。总的来说,中断系统使用“硬件+软件”的方式解决上述问题。根据中断系统的响应速度、复杂性、灵活性等,不同计算机对于中断系统的软硬件功能划分不同。在前面的“5.4节-程序中断方式”已经介绍如何使用中断完成输入输出,实际上中断还可以用于程序调试、处理异常事件等,应用非常广泛。下面给出常见的引起中断的各种因素,也就是中断源:
- 人为设置的中断:如转管指令,也就是访问管理程序。
- 程序性事故:溢出、操作码不能识别、除法非法。
- 硬件故障:如存储器故障、硬盘坏道、掉电等。
- I/O设备:正常的输入输出都需要使用中断。
- 外部事件:用键盘中断现行程序。
- …
8.4.1 中断请求标记和中断判优逻辑
- 多个中断源如何提出中断请求,多个中断源同时提出请求,应该响应那个中断?——INTR
- 各中断源同时提出请求怎么办,响应哪一个?——中断判优逻辑
实际上,每个请求源都有一个 INTR(中断请求标记触发器),多个INTR就组成“中断请求标记寄存器”,如上图所示。INTR既可以分散在各个中断源的接口电路中,逻辑上组合在一起;也可以直接将所有的 INTR 集中在CPU的中断系统内。
当有多个中断源同时提出中断请求时,就需要“中断判优逻辑”,也就是“排队器”,原则上优先响应对系统影响最大、最重要的中断源。实现方式分为硬件和软件,如下图:
- 硬件排队器:现代计算机系统,大多数都是硬件实现。
- CPU外:INTR 分散在各个中断源的接口电路中,逻辑上组成链式排队器(5.5.2节-I/O中断的接口电路)。
- CPU内:INTR 全部集中在CPU内,构成排队器。
- 软件排队器:也就是程序查询。
8.4.2 寻找中断服务程序入口地址
- 如何找到中断服务程序的入口地址?硬件向量法、软件查询法
- 硬件向量法:用“向量地址形成部件”(内部结构见5.5.2节-I/O中断的接口电路)生成中断向量地址,然后找到要执行那个中断服务程序。优点是速度快,缺点是灵活性较低。
- 跳转指令:在中断向量地址的存储单元中存放一条跳转指令,执行该指令可跳转到“入口地址”。
- 向量地址表:所有中断向量地址所在的区域被设置为“向量地址表”,存储单元中直接保存的就是“入口地址”。
- 软件查询法:如上图“中断识别程序”(入口地址M),将八个中断源 1,2,…,8 按优先级降序排列,然后依次查找入口地址。显然非常灵活。
8.4.3 响应中断的条件
- CPU在任何条件下都要立即响应中断吗?——不是
- CPU在任何时间都能响应中断吗?——不是
- CPU在什么时间、什么条件下响应中断?
- 响应中断的条件:允许中断触发器 EINT=1。
- 响应中断的时间:指令执行周期结束时由CPU发查询信号,此时才会将中断源发送给排队器。只有极少数计算机的某个指令的执行时间非常长,可能会允许执行过程中响应中断。
- “硬件关中断”的RS触发器:[R,S]=[0,0]→Q=1;[R,S]=[0,1]→Q=0。我认为这不是标准的RS触发器,但是理解INT通过非门产生负跳变使 EINT=0 即可。
在“5.5.4节-中断服务程序的流程”中我们已经给出了单重中断、多重中断的程序流程,如下图。CPU在响应中断请求之后、进入“中断服务程序”之前,需要执行“中断隐指令”:
下面的三个操作都由硬件完成,并不是由计算机指令集的指令驱动,所以称之为“隐指令”。
- 保护程序断点:也就是保存程序运行的软硬件状态,该过程不允许发生中断。有两种方法。
- 保存在特定地址:具体见(8.4.5节-3.多重中断的断点保护)。
- 保存在堆栈:利用堆栈的先进后出特性。
- 寻找服务程序入口地址:上一小节给出两种方法,硬件向量法(向量地址→PC)、软件查询法(中断识别程序入口地址M→PC)。
- 硬件关中断:将中断允许触发器 EINT 置零。如上右图中蓝色线,排队器的输出结果只有一个高电平,一方面传输给“向量地址形成部件”;另一方面将 INT 拉高,再通过一个“非门”将 EINT 拉低,不再响应中断请求,即为“硬件关中断”。
【思考】为什么CPU在指令执行周期结束时刻发送查询信号,而不是其他时刻?
【CahtGPT】在指令执行周期结束时刻发送查询信号是一种平衡效率、性能、简化设计和兼容性考虑的结果。这种做法帮助处理器以可预测和高效的方式处理中断,同时保持对正在执行的任务的最小干扰。以下是几个关键原因和考虑因素:
- 确定性和同步
在指令执行周期的结束时刻发送查询信号可以确保CPU处于一种已知的、稳定的状态。此时,当前的指令已经完成执行,CPU寄存器和状态机等处于更新后的状态。这种同步机制简化了中断处理流程,因为处理器正好在两个指令周期之间的自然间隙进行中断检查,避免了执行过程中的不一致性。- 效率和性能
在周期结束时进行查询可以最大限度地减少对CPU主执行流程的干扰。如果在指令执行的中间阶段进行中断检查,可能会引入额外的复杂性和性能开销,因为这可能需要CPU在执行的非终点状态中保存和恢复更多的上下文信息。在周期结束时,处理器可以高效地处理中断,同时最小化对执行性能的影响。- 简化中断处理
通过在每个指令周期结束时统一检查中断请求,CPU可以简化中断管理逻辑。这种方法使得中断响应更加可预测,并且允许操作系统和硬件更容易地协调处理多个中断源。此外,这也为操作系统提供了一个清晰的时机来实现任务调度、上下文切换等高级功能。- 资源利用和管道执行
在现代CPU中,尤其是采用流水线技术的处理器,指令的执行被分解成多个阶段,而中断的检查通常安排在某个适当的阶段,以兼顾执行效率和响应时间。在流水线的末端检查中断允许CPU在不干扰当前执行流的情况下,准备接受新的指令或处理中断,从而优化资源利用和提高执行效率。- 兼容性和历史原因
许多处理器的设计遵循了一定的历史模式和兼容性考虑。在指令周期结束时检查中断是很多早期和现代处理器设计中的常见做法,部分原因是为了保持与现有软件的兼容性,以及遵循业界通用的设计原则。
8.4.4 保护现场和恢复现场
- 如果需要响应某个中断请求,CPU如何响应中断请求?——执行中断服务程序,为将来的中断返回做准备。
如下图所示,中断服务程序最重要的就是保护现场、恢复现场:
- 保护现场:包括“保护程序断点”、“保护CPU内部各寄存器内容”两个方面。前者由“中断隐指令”保存,后者由中断服务程序保存在堆栈或者内存某地址,比如下图的 PUSH、POP。
- 恢复现场:中断服务程序完成。
8.4.5 多重中断
1. 多重中断的执行流程
- 如果在执行中断服务程序的过程中,出现了更重要的,需要及时处理的新事件,怎么办呢?
若CPU在这执行中断服务程序时,有优先级更高的中断源产生了新的中断请求,显然就需要“多重中断”。如上图所示,多重中断会依次保存每一次中断的断点;如果多个中断同时请求,会优先执行优先级最高的中断,再执行其他中断。实现多重中断的条件:
- 提前设置开中断指令。也就是“保护现场”后立即开中断,而不是等待“恢复现场”后才开中断。
- 优先级别高的中断源,有权中断优先级别低的中断源。也就是下面的“中断屏蔽技术”。
2. 中断屏蔽技术
要允许CPU在执行某个中断服务程序时,响应新的中断请求,是不是任何一个新的中断请求,均能中断正在进行的中断服务?——显然不是,要根据响应优先级和屏蔽字进行判断。
INTR中断请求触发器、MASK中断屏蔽触发器。
“中断屏蔽技术”通过设置“中断屏蔽字”(中断屏蔽触发器)改变中断优先级,进而提高了中断响应的灵活性。如上左侧图,MASK=1 使得 中断源D 的中断请求无法产生,也就是说 MASK 用于屏蔽某个中断源的中断请求,使其无法进入排队器。用户通过设置“屏蔽字”可以改变上述 MASKi 的值,某中断源的“屏蔽字”表示该中断源可以屏蔽哪些中断源。
“屏蔽字”实际上并没有改变“响应优先级”,而只是通过屏蔽掉某个中断源,改变“处理优先级”。如下左图,每个中断源都有自己的屏蔽字,“原屏蔽字”按照“响应优先级”给出,MASK=1 表示屏蔽掉对应的中断源,于是“处理优先级”和“响应优先级”相同。“新屏蔽字”中,A、B均不影响原优先级,C则会屏蔽掉优先级更高的B、D则会屏蔽掉优先级更高的B/C,于是“处理优先级”就变为 A→D→C→B。右侧两图则给出不同屏蔽字设置下的程序处理流程:
再强调一下,“响应优先级”指的是“排队器”中的顺序,是硬件固定好的。而“中断屏蔽器”则是在“排队器”之前截胡,人为的屏蔽某个中断源的请求,这才有了“处理优先级”。
3. 多重中断的断点保护
- 三次中断,三个断点都存入“0”地址,如何保证断点不丢失?
上面介绍“中断隐指令”的第一步“保护程序断点”时提到可以将断点保存在特定地址中。下右图就给出了使用该方法的程序流程,注意进入每一重中断后,都会将该特定地址(0地址)转存到其他内存 RETURN,通过这种方式才使得多重中断的地址不会被覆盖。另外,注意途中“设置屏蔽字”、“恢复屏蔽字”的时机:
- 每个中断服务程序的的RETURN都不一样。
- CPU进入指令的中断周期:0地址→MAR、CU命令存储器写、PC→MDR(断点→MDR)、(MDR)→存入存储器