Skip to content
Published on

数字逻辑设计完全指南:从布尔代数到 CPU 设计

分享
Authors

1. 数字系统概述

模拟 vs 数字

模拟信号携带连续的取值,而数字信号只使用离散状态——0 和 1。现代电子系统之所以普遍采用数字方式,主要有以下几个原因:

  • 抗噪性:只需区分 0 和 1,因而对噪声有很强的抵抗力。
  • 完美复制:复制数字数据不会引入信号劣化。
  • 逻辑处理:布尔代数为其提供了严谨的数学基础。
  • 存储能力:触发器和存储单元能够可靠且长期地保持状态。

进制转换

数字系统中经常使用二进制(Binary)、八进制(Octal)、十六进制(Hexadecimal)表示法。

十进制转二进制——不断除以 2:
  45 ÷ 2 = 221
  22 ÷ 2 = 110
  11 ÷ 2 =  51
   5 ÷ 2 =  21
   2 ÷ 2 =  10
   1 ÷ 2 =  01
  结果: 101101(二进制)
十进制二进制八进制十六进制
0000000
5010155
10101012A
15111117F
16100002010

有符号数的表示

二进制补码(Two's Complement) 是现代计算机中表示负整数的通用标准。

+50000 0101
-5:
  一的补码:  1111 1010
1:      1111 1011-5 的二进制补码表示

8 位二进制补码的表示范围:-128 到 +127。

BCD 与格雷码

  • BCD(二-十进制编码):每个十进制位用 4 位二进制表示。例如:29 = 0010 1001。
  • 格雷码:相邻码字之间只有 1 位不同 → 将误差降到最低,应用于编码器。

2. 布尔代数(Boolean Algebra)

基本运算

布尔代数由三种基本运算构成:

  • AND(逻辑与):A · B——两个输入都为 1 时,输出才为 1。
  • OR(逻辑或):A + B——至少一个输入为 1 时,输出即为 1。
  • NOT(取反):A'、NOT A。0↔1 反转。

布尔代数定律

交换律:   A + B = B + A,      A · B = B · A
结合律:   A + (B+C) = (A+B) + C
分配律:   A · (B+C) = AB + AC
恒等律:   A + 0 = A,  A · 1 = A
互补律:   A + A' = 1, A · A' = 0
幂等律:   A + A = A,  A · A = A

德摩根定理(De Morgan's Theorems)——对基于 NAND/NOR 的实现至关重要:

(A · B)' = A' + B'
(A + B)' = A' · B'

标准形式

  • SOP(积之和,Sum of Products):最小项之和。例如:F = AB' + A'B + AB
  • POS(和之积,Product of Sums):最大项之积。例如:F = (A+B)(A'+C)

3. 逻辑门

全部基本门的真值表

AND :              OR :               NOT :
A  B  A·B            A  B  A+B            A  A'
0  0   0             0  0   0             0   1
0  1   0             0  1   1             1   0
1  0   0             1  0   1
1  1   1             1  1   1

NAND :             NOR :
A  B  (A·B)'         A  B  (A+B)'
0  0    1            0  0    1
0  1    1            0  1    0
1  0    1            1  0    0
1  1    0            1  1    0

XOR :              XNOR :
A  B  AB            A  B  (AB)'
0  0   0             0  0    1
0  1   1             0  1    0
1  0   1             1  0    0
1  1   0             1  1    1

万能门(Universal Gate,NAND 与 NOR)

仅用 NAND 一种门就能实现任意布尔函数:

NOT A   = A NAND A
A AND B = (A NAND B) NAND (A NAND B)
A OR B  = (A NAND A) NAND (B NAND B)

得益于这一特性,实际芯片制造时只需 NAND 门就能实现全部逻辑,从而简化生产流程。NOR 门同样具有相同的万能性。

CMOS 实现概述

现代数字集成电路大多采用 CMOS(互补金属氧化物半导体)技术实现:

  • NMOS 晶体管:栅极为 HIGH 时导通(下拉网络)。
  • PMOS 晶体管:栅极为 LOW 时导通(上拉网络)。
  • CMOS 反相器:PMOS 与 NMOS 在 VDD 与 GND 之间串联构成。
  • 静态功耗接近于 0 → 低功耗优势。

4. 卡诺图(Karnaugh Map)

卡诺图是通过将相邻单元格分组(按格雷码顺序排列)来直观简化布尔表达式的工具。

4 变量卡诺图示例

          CD
AB      00  01  11  10
00  [    1   0   1   1  ]
01  [    1   1   1   0  ]
11  [    0   1   1   0  ]
10  [    0   0   1   1  ]

分组规则

  1. 分组的大小必须是 2 的幂:1、2、4、8 或 16。
  2. 分组必须呈矩形(含正方形)。
  3. 卡诺图的上下左右是相互连通的(环面拓扑)。
  4. 分组数量尽量少、每组尽量大。
  5. 无关项(Don't-care,X)可以被纳入分组以扩大分组范围。

素蕴含项(Prime Implicant)

素蕴含项是指无法再扩大的分组。必要素蕴含项是指至少覆盖了一个不被任何其他素蕴含项覆盖的最小项的分组——它必须出现在最小化后的 SOP 表达式中。


5. 组合逻辑电路

组合电路的输出仅取决于当前输入——不存在内部状态或记忆。

半加器与全加器

半加器(Half Adder):
  (Sum)   S = AB
  进位(Carry) C = A · B

全加器(Full Adder):
  (Sum)    S    = ABCin
  进位(Carry) Cout = AB + Cin(AB)

将全加器级联即构成行波进位加法器(Ripple Carry Adder)——结构简单,但由于进位是逐级串行传播的,速度较慢。高速运算则使用超前进位加法器(Carry Lookahead Adder,CLA),并行计算各位的进位。

多路选择器(MUX)

用 n 个选择信号从 2ⁿ 个输入中选择一个并输出。

41 MUX(选择线 S1S0):
  S1=0, S0=0Y = I0
  S1=0, S0=1Y = I1
  S1=1, S0=0Y = I2
  S1=1, S0=1Y = I3

一个 2ⁿ 选 1 的 MUX 可以直接实现任意 n 变量布尔函数。

编码器与译码器

  • 编码器:把 2ⁿ 条输入转换为 n 位二进制编码(例如:10 转 4 优先级编码器)。
  • 译码器:把一个 n 位编码转换为最多 2ⁿ 条输出线(例如:3 转 8 译码器)。

译码器与 OR 门组合,可以直接实现任意最小项之和(SOP)表达式。


6. 时序逻辑电路

时序电路的输出既取决于当前输入,也取决于内部状态(记忆)。它们是寄存器、计数器和处理器的基础构件。

锁存器(Latch)

SR 锁存器是通过置位(Set)与复位(Reset)输入来保存状态的最基本存储元件。

SR 锁存器真值表:
S  R  Q(次态)
0  0  Q(保持)
1  0  1(置位)
0  1  0(复位)
1  1  不确定(禁止)

D 锁存器是消除了 SR 锁存器禁止状态的版本,当 Enable 信号为 HIGH 时,会将 D 输入原样保存。

触发器(Flip-Flop)

触发器是边沿触发(edge-triggered) 的——状态仅在时钟的上升沿或下降沿发生变化。

D 触发器:   Q(次态) = D

JK 触发器:
  J=0, K=0Q(保持)
  J=1, K=0Q=1(置位)
  J=0, K=1Q=0(复位)
  J=1, K=1Q'(翻转)

T 触发器:
  T=0Q(保持)
  T=1Q'(翻转)

JK 触发器没有未定义的输入组合。T 触发器是计数器设计的自然选择。


7. 寄存器与计数器

移位寄存器

移位寄存器将多个触发器级联,使数据在每个时钟周期沿链移动(移位)。

  • SISO(串入串出):数据以串行方式进出。
  • SIPO(串入并出):以串行方式载入数据,然后所有位被同时读出。
  • PISO(并入串出):以并行方式载入数据,然后逐位发送。
  • PIPO(并入并出):完整的并行载入与并行读出。

应用场景:串并转换、CRC 生成、伪随机数生成器(LFSR),以及按 2 的幂做乘除法。

计数器

3 位异步(行波)计数器:
  三个 T 触发器串联。
  012345670 ...
  缺点:会产生进位传播延迟(行波延迟)
3 位同步计数器:
  所有触发器共用同一个时钟。
  优点:输出同时变化,可实现高速运行。

模 N 计数器在 0 到 N-1 之间循环。例如:十进制计数器(Decade Counter)在 0 到 9 之间循环。


8. 有限状态机(FSM)

FSM 是时序电路的抽象模型,是数字系统设计的核心。

摩尔机(Moore) vs 米利机(Mealy)

  • 摩尔机(Moore Machine):输出仅取决于当前状态。状态图中,输出标示在状态气泡内部。
  • 米利机(Mealy Machine):输出取决于当前状态 + 输入。输入/输出标示在转移(transition)线上。

自动售货机 FSM 示例

状态: S0(0 韩元), S1(100 韩元), S2(200 韩元), S3(300 韩元 → 出饮料)
输入: 100 韩元(A), 200 韩元(B)

状态转移:
  S0 --A--> S1
  S0 --B--> S2
  S1 --A--> S2
  S1 --B--> S3(出货)
  S2 --A--> S3(出货)
  S2 --B--> S3(出货,找零 100 韩元)

FSM 设计流程

  1. 分析问题,定义全部状态。
  2. 绘制状态图。
  3. 构建状态表(次态与输出)。
  4. 为各状态分配二进制编码(状态编码)。
  5. 推导次态函数与输出函数。
  6. 用卡诺图化简。
  7. 用触发器与组合门实现。

9. Verilog HDL 基础

Verilog HDL(硬件描述语言)是一种能像描述软件一样描述数字电路的语言。

模块结构

module module_name (
    input  wire        clk,
    input  wire        reset,
    input  wire [3:0]  data_in,
    output reg  [3:0]  data_out
);
    wire [3:0] temp;

    // 组合逻辑 —— assign
    assign temp = data_in & 4'b1111;

    // 时序逻辑 —— always
    always @(posedge clk or posedge reset) begin
        if (reset)
            data_out <= 4'b0000;
        else
            data_out <= temp;
    end
endmodule

D 触发器

module d_ff (
    input  wire clk,
    input  wire reset,
    input  wire d,
    output reg  q
);
    always @(posedge clk or posedge reset) begin
        if (reset)
            q <= 1'b0;
        else
            q <= d;
    end
endmodule

4 位同步计数器

module counter_4bit (
    input  wire       clk,
    input  wire       reset,
    output reg  [3:0] count
);
    always @(posedge clk or posedge reset) begin
        if (reset)
            count <= 4'b0000;
        else
            count <= count + 1'b1;
    end
endmodule

测试平台(Testbench)

module tb_counter;
    reg        clk, reset;
    wire [3:0] count;

    counter_4bit uut (
        .clk(clk),
        .reset(reset),
        .count(count)
    );

    // 10 ns 时钟周期
    initial clk = 0;
    always #5 clk = ~clk;

    initial begin
        reset = 1;
        #20 reset = 0;
        #200 $finish;
    end

    initial begin
        $monitor("t=%0t reset=%b count=%b", $time, reset, count);
    end
endmodule

Verilog 数据类型汇总

类型说明常见用途
wire连接线,保持驱动值assign、端口连接
reg可保存取值的变量always 块内部
integer整数类型仿真、循环
parameter常量对模块参数化

10. FPGA 基础

FPGA vs ASIC vs 微处理器

区分FPGAASICMCU/CPU
可重构可以不可以可通过软件变更
性能中到高性能最高通用
开发成本中等非常高
大批量生产成本
并行处理优秀优秀有限
用途原型开发、中小批量大批量生产通用控制

FPGA 内部架构

  • CLB(可配置逻辑块):由 LUT、触发器和 MUX 组合而成。
  • LUT(查找表):n 输入 LUT 可以直接存储真值表,从而实现任意 n 变量函数。
  • IOB(I/O 块):与外部引脚的接口,支持多种电压/协议。
  • 块 RAM(BRAM):内置存储块。
  • DSP 块:高速乘法器/加法器,专用于信号处理。
  • PLL/DCM:时钟管理、频率合成。

FPGA 设计流程

1. 设计输入(编写 HDL 代码 / 原理图)
2. 综合(Synthesis)→ 门级网表
3. 实现(Implementation)
   ├── 映射(Map)→ 分配到 FPGA 资源
   ├── 布局(Place)→ 确定物理位置
   └── 布线(Route)→ 确定连接线
4. 时序分析(Timing Analysis)
5. 生成比特流(Bitstream Generation)
6. FPGA 编程

主要 FPGA 厂商

  • AMD-Xilinx:Spartan(低价)、Artix、Kintex、Virtex(高性能)、Zynq(ARM+FPGA)。
  • Intel(Altera):Cyclone(低价)、Arria、Stratix(高性能)。
  • Lattice Semiconductor:iCE40(超低功耗,提供开源工具支持)。

11. CPU 基础设计

ALU(算术逻辑单元)

ALU 是 CPU 的核心,负责执行算术运算与逻辑运算。

ALU 输入:
  A, B      —— n 位操作数
  OpCode    —— 选择运算类型

ALU 输出:
  Result    —— n 位运算结果
  Zero      —— 结果为 0 时为 1
  Carry     —— 发生进位时为 1
  Overflow  —— 发生溢出时为 1
  Negative  —— 结果为负数时为 1

运算示例:
  000A + B(加法)
  001A - B(减法)
  010A AND B
  011A OR B
  100A XOR B
  101NOT A
  110A << 1(逻辑左移)
  111A >> 1(逻辑右移)

寄存器堆

寄存器堆是通用寄存器的集合,拥有两个读端口和一个写端口。

module register_file (
    input  wire        clk,
    input  wire        we,
    input  wire [4:0]  rs1, rs2, rd,
    input  wire [31:0] write_data,
    output wire [31:0] read_data1,
    output wire [31:0] read_data2
);
    reg [31:0] regs [0:31];

    assign read_data1 = regs[rs1];
    assign read_data2 = regs[rs2];

    always @(posedge clk) begin
        if (we && rd != 0)
            regs[rd] <= write_data;
    end
endmodule

简单 CPU 数据通路

IF  —— 取指:PC 指向的地址读出指令
ID  —— 译码:读取寄存器,生成控制信号
EX  —— 执行:ALU 完成运算
MEM —— 访存:读写数据存储器
WB  —— 写回:将结果写入寄存器堆

流水线

5 级流水线通过重叠执行多条指令来提高吞吐量:

时钟:      1   2   3   4   5   6   7   8   9
指令 1:   IF  ID  EX  ME  WB
指令 2:       IF  ID  EX  ME  WB
指令 3:           IF  ID  EX  ME  WB
指令 4:               IF  ID  EX  ME  WB
指令 5:                   IF  ID  EX  ME  WB

流水线冒险(Hazard) 会破坏理想的吞吐量:

  • 结构冒险:两条指令同时需要同一硬件资源。
  • 数据冒险(RAW/WAR/WAW):某条指令要读取的值,尚未被前一条指令写回。通过转发、停顿或编译器调度来解决。
  • 控制冒险:分支结果要到流水线较靠后的阶段才能确定。通过分支预测、延迟分支或推测执行来解决。

12. 与 AI 硬件的连接

GPU 的数字逻辑架构

现代 GPU 包含数以千计的小型 ALU 核心(CUDA 核心、SIMD 通道),并行运行。这种大规模并行性正好契合深度学习中占主导地位的矩阵乘法运算。

  • NVIDIA Tensor Core:在单个时钟周期内执行混合精度(FP16 × FP16 累加到 FP32)矩阵运算。
  • SIMT 执行模型:数千个线程对不同数据同时执行同一条指令。

TPU 与 NPU

  • TPU(张量处理单元):Google 设计的矩阵运算专用 ASIC。采用脉动阵列(Systolic Array)结构,将 MAC(乘累加)运算大规模并行化。
  • NPU(神经处理单元):面向移动/边缘设备的 AI 加速器。例如:Apple Neural Engine、高通 Hexagon DSP 等。

基于 FPGA 的 AI 加速

FPGA 被用于加速神经网络推理(inference)。

  • 低延迟:适合有实时处理需求的系统。
  • 灵活性:模型变化时,通过重新加载比特流来应对。
  • 例如:数据中心内的 FPGA 推理加速(Microsoft Project Brainwave)。

神经形态计算

神经形态计算是用硬件直接模仿大脑神经元-突触结构的计算范式。

  • Intel Loihi:脉冲神经网络(SNN)专用芯片。
  • IBM TrueNorth:单芯片实现 100 万个神经元、2.56 亿个突触。
  • 超低功耗 / 事件驱动处理 → 在边缘 AI 领域大有可为。

13. 学习路线图

【基础】
  布尔代数 → 逻辑门 → 卡诺图
【组合电路】
  加法器, MUX, 译码器, 编码器
【时序电路】
  锁存器 → 触发器 → 寄存器 → 计数器
【系统级设计】
  FSM → 数据通路 → 控制单元
HDLFPGA  Verilog → 仿真 → FPGA 实现
【处理器架构】
  ALU → 流水线 → 存储层次
AI 硬件】
  GPU 架构 → TPU/NPUFPGA 加速

小测验

Q1. 为什么 NAND 被称为万能门?

答案:因为仅用 NAND 就能实现 NOT、AND 和 OR,从而只用 NAND 门就能构建出任意布尔函数。

说明:

  • NOT A = A NAND A
  • A AND B = (A NAND B) NAND (A NAND B)
  • A OR B = (A NAND A) NAND (B NAND B)

由于 NOT、AND、OR 构成了一个功能完备集,任何逻辑电路都可以仅用 NAND 门实现。NOR 门同样具有这一性质。

Q2. 二进制补码方式下,8 位能表示的最小负数是多少?

答案:-128(即 10000000(2))

说明:8 位二进制补码的表示范围是 -128 ~ +127。最高有效位(MSB)为 1 时表示负数,-128 用 10000000(2)表示。+128 无法表示,因此范围是不对称的。

Q3. D 锁存器与 D 触发器的关键区别是什么?

答案:D 锁存器是电平触发的——只要 Enable 为 HIGH,就持续把 D 传递给 Q。D 触发器是边沿触发的——只在时钟边沿对 D 采样一次,并保持该值直到下一个边沿。

说明:锁存器在 Enable=1 期间以透明(transparent)方式工作。触发器只在边沿采样,因此时序控制严格,是同步电路设计中的标准做法。

Q4. 卡诺图中的无关项(Don't-care)条件是什么?什么时候使用它?

答案:无关项(X)是指某个输入组合要么不可能出现,要么其输出值对系统而言无关紧要。设计者可以自由地将它赋值为 0 或 1,以便让分组尽量大、让最终表达式尽量简化。

说明:例如,在 BCD 输入(0~9)中,1010~1111 不会被使用。把这 6 个组合作为无关项(X)处理,就能在卡诺图中形成更大的分组,使门数量减少、电路更简单。

Q5. 流水线 CPU 中的数据冒险是什么?主要的解决办法有哪些?

答案:数据冒险是指某条指令需要使用一个值,而这个值尚未被流水线中还在执行的前一条指令写回(即一次先读后写,RAW,依赖)。

解决方法:

  • 转发(旁路,Forwarding/Bypassing):把 ALU 的输出直接接到下一条指令的 ALU 输入,跳过寄存器堆的写回步骤。可以在不停顿的情况下解决大多数 RAW 冒险。
  • 停顿(流水线气泡,Stall):插入空操作周期,直到所依赖的值可用为止。做法简单,但会降低吞吐量。
  • 编译器调度:把没有依赖关系的指令重新排列,填补生产者与消费者之间的空当,在不依赖硬件转发的情况下避免冒险。

参考资料