微架构剖析与设计
超标量 CPU 是实现指令级并行形式的 CPU,相比于标量 CPU,通过同时向不同执行单元分发多条指令来在同一时钟周期执行多条指令,在给定频率下获得更多吞吐率。超标量 CPU 中,指令分发器 Dispatcher 决定了那些指令可以并行运算并将指令分发到执行单元。超标量的概念在于 CPU 核由更多细粒度的执行单元组成,如算术逻辑单元、乘法器、浮点运算单元。
流水线将每条指令的执行分为多个阶段,允许在不同阶段同时执行不同的指令,增加了指令级并行 ILP。流水线技术要求执行的任务相同或相似,不同类型指令的格式和执行差异保持在最低限度,因此 RISC 非常适合流水线设计。经典的 RISC 流水线分为 5 级:Instruction Fetch, Instruction Decode, Execute, Memory Access, Write Back。
经典流水线的弊端在于指令执行不是并行的,由于流水线需要静态调度,也不允许指令 Speculative 执行。也就是说,一条指令需要从流水线前面的指令中收集结果,并且确认前面的指令执行无误后才能执行。流水线由于 Pipelining hazards 会 stall。一般有几种情况会停顿:
- 数据冒险。
- 控制冒险:由于分支指令对流水线重定向造成延迟。
- 结构冒险:由于资源限制。
- 内存访问延迟。 超流水线
执行单元设计
CPU 在执行阶段执行多种类型的操作,包括算术运算;寄存器和存储通信的访存指令;更改 PC 的控制指令;其他对控制寄存器读写的指令。当代 CPU 会分为多个数据通路完成不同类型指令执行。ALU 执行算术和逻辑运算,FPU 执行浮点运算,AGU 计算访存指令的访存地址;分值单元计算控制指令的结果 PC 值;数据缓存用于提供内存快速访问,是 LSU 的重要部分。执行单元的另一个概念是旁路网络。旁路网络将指令的源和目标操作数在计算单元、寄存器、缓存之间传递。
算术逻辑单元
一个典型的 ALU 包括:加法单元,用来实现加减法;移位单元,逻辑、算数和循环移位;特殊运算,实现如前导零、前导 1 统计等特殊指令。预处理和后处理模块做一些公共操作,预处理如取反、按位屏蔽等;后处理如饱和处理、标志位处理。
有的 CPU 会定义状态标志来记录算术逻辑运算的状态,如 x 86 定义了以下:
- CF: Carry Flag,结果 MSB 发生进位或错位,置 1,否则 0
- PF: Parity Flag,结果的最低有效字节包含偶数个 1,置 1,否则 0
- AF: Adjust Flag,结果的第 3 位进位或错位,置 1,否则 0
- ZF: Zero Flag,结果为 0,置 1,否则 0
- SF: Sign Flag,有符号整型的最高有效位,0 为正,1 为负
- OF: Overflow Flag,结果大于目标操作数能表示的最大值,或小于能表示的最小值,置 1,否则 0
加减法与移位
减法 A-B 可以用 A+(-B)+1 实现。
算数移位填充符号位,逻辑以为填充 0,循环移位填充移出的位。移位的实现可以使用一个基础移位逻辑复用。以 8-bit 为例,移位数量 N 位宽 3-bit,位移范围 0-7,移位分三阶段,一阶段根据 N[0] 决定是否移 1-bit,二阶段根据 N[1] 判断是否移位 2-bit,三阶段根据 N[2] 是判断否移位 4-bit,整个移位逻辑延时为 3 个 MUX。对于 n-bit 移位,需要 级 MUX 逻辑.
基础逻辑实现右移,进行前处理和后处理后实现左移。根据操作码选择填充位为符号位、0 或被移出的数据。
前导零检测
CLZ/CLO 分别是检测输入操作数从 MSB 开始连续 0/1 的数量,CLS 是前导符号位检测指令,检测从符号位的下一位开始,数值等于符号位的连续位的位数。
以 16-bit 为例,给出一个方案,基本思路基于自底向上。考虑 2-bit 数据的前导零检测,可得真值表:
| 输入数据 | 前导零位数 cnt | vld |
|---|---|---|
| 00 | X | 0 |
| 01 | 1 | 1 |
| 10 | 0 | 1 |
| 11 | 0 | 1 |
定点乘法运算
基本的乘法器原理是被乘数与乘数每一位分别相乘,得到的部分积错位相加,这个过程称为部分积压缩。因此部分积生、部分积压缩、一级加法构成了乘法器的基本部分。
部分积生成
Booth 发现使用简单的加法和减法混合,可以得到相同的结果,如 6=-2+8。Booth 的要点是,将乘数中连续出现的 1 分成第一位、中间各位、最后一位。
部分积压缩
Wallace