第 3 章 · 运算器与 ALU

核心是加法器(补码把减法变加法),沿「全加器→多位加法器→ALU→移位→乘除→标志位」推进。

3.1 一位全加器(Full Adder)

一位加法三个输入(加数位 a、b,低位进位 cin)、两个输出(和 s、进位 cout):

s    = a ⊕ b ⊕ cin
cout = (a ∧ b) ∨ (cin ∧ (a ⊕ b))     // 至少两个 1 就产生进位

半加器只处理 a、b 无低位进位;n 个全加器串联(cin 接上一级 cout)= n 位行波进位加法器(ripple-carry adder)。

3.2 行波进位 vs 超前进位

行波进位:进位从最低位逐级滚到最高位,第 i 位要等第 i-1 位进位。延迟 = n × 单级延迟,O(n);结构简单面积小,位数一大即成关键路径(第 1 章)。

超前进位(CLA):并行预计算所有进位。定义两个信号:

  • 生成 gᵢ = aᵢ ∧ bᵢ:本位自己能产生进位。
  • 传播 pᵢ = aᵢ ⊕ bᵢ:低位进位来了能传过去。

cᵢ₊₁ = gᵢ ∨ (pᵢ ∧ cᵢ),展开:

c1 = g0 ∨ (p0 ∧ c0)
c2 = g1 ∨ (p1 ∧ g0) ∨ (p1 ∧ p0 ∧ c0)
c3 = g2 ∨ (p2 ∧ g1) ∨ (p2 ∧ p1 ∧ g0) ∨ (p2 ∧ p1 ∧ p0 ∧ c0)
...

所有进位只依赖 g、p、c0,一层门同时算出,延迟 O(log n)。

对比:CLA 用「额外电路+高扇入」换延迟。工程折中是分组 CLA:组内 CLA、组间串行(或两级 CLA),不大面积爆炸又压低延迟。

加法器延迟面积/扇入适用
行波进位O(n)最小面积优先、位数短
全 CLAO(log n)大、高扇入延迟优先
分组 CLA介于两者折中主流

3.3 ALU:加法的「加强版」

ALU 在加法器外圈加选择逻辑,用功能选择线切出多种运算:

      ┌───────────┐
A ───▶│           │
B ───▶│   ALU     │──▶ 结果 F
op ──▶│           │──▶ 标志位 ZF/OF/CF/SF
      └───────────┘

n 位 ALU 至少支持:加、减(A+补码(B))、按位与/或/异或、非、比较(减但不写回、只置标志)、移位。减法 = B 取反 + cin=1:反相器取反 B、最低位进位置 1,恰等于加 B 的补码。

3.4 移位运算:逻辑 / 算术 / 循环

移位操作空位补用途
逻辑左移 SLL整体左移补 0x << 1 = 乘 2
逻辑右移 SRL整体右移补 0unsigned 除 2
算术右移 SRA右移补符号位signed 除 2(保符号)
循环移位 ROL/ROR移出的位补到另一端自身位旋转、密码学

注意:算术右移 vs 逻辑右移 = C 里 int >> 1unsigned >> 1 的机器级区别。有符号右移是「实现定义」,主流编译器对负数用算术右移(-5 >> 1 = -3);无符号一律逻辑右移;左移对负数溢出是 UB(第 2 章)。

移位器是组合逻辑,用桶形移位器一次移任意位;乘法里用移位+加法替代乘常数(x*10 = (x<<3)+(x<<1))。

3.5 乘法与除法

乘法 = 移位+累加:按乘数每位决定加被乘数或加 0,再左移一位:

  1101  (13)
×  1011  (11)
─────────────
  1101   ← 乘数最低位为 1,加
 1101    ← 左移 1 位再加
0000     ← 该位为 0,加 0
1101     ← 左移 3 位再加
─────────────
10001111 (143)

硬件用 Booth 算法处理有符号乘法:对补码同样有效,遇连续 1(…01110…)可一次跳过、减少加减次数。现代 CPU 用阵列乘法器或华莱士树并行压缩部分积,单周期或几周期出结果。

除法 = 移位+比较+减。恢复余数法:试减除数,够减商 1,不够商 0 并恢复(加回除数);不恢复余数法省掉恢复一步,用符号控制下一步加减,是硬件主流。

对比:乘除比加减慢得多——整数加法 1 周期、乘法 34 周期、除法 2090 周期(x86 div 极慢)。故编译器把「除以常数」优化成「乘倒数+移位」(x/10 ≈ (x × 0xCCCCCCCD) >> 35),避免真除法。

3.6 标志位:ZF / OF / CF / SF

ALU 运算后置一组条件码标志位(x86 的 EFLAGS),供条件跳转读取:

标志含义置位条件
ZF零标志结果为 0
SF符号标志结果最高位(符号位)为 1
CF进位/借位标志无符号运算产生进位或借位(C_out)
OF溢出标志有符号运算溢出(第 2.3 节 C_out ⊕ C_in

注意:CF/OF 分别服务无符号/有符号——1111 1111 + 0000 0001 作无符号是 255+1=256 进位(CF=1),作有符号是 -1+1=0 不溢出(OF=0)。CPU 同时置两个,由指令语义决定看哪个:ja/jb 看 CF,jg/jl 看 OF+SF——故 C 的 unsigned/signed 比较编译出不同跳转。

3.7 与指令集 / C 对照

  • 第 4 章:标志位是「隐式状态」,RISC-V 放弃标志位改用显式比较+分支,x86/ARM 保留条件码——CISC/RISC 分水岭。
  • Cx += y 可能是 add(改标志)也可能被优化成 lea(不碰标志);a < bint/unsigned 生成不同跳转——根子在 3.6 的 CF/OF。
  • 第 1 章主频:ALU 加法器关键路径直接决定主频——现代 CPU 用 CLA/树形进位把 64 位加法压进一个周期,才撑起 GHz。