第二章 数字电路基础:晶体管与逻辑门、组合逻辑电路、时序逻辑电路、时钟与复位

各位同学,欢迎来到第二章。这一章是数字芯片的「细胞级」解剖课。你想想看,无论多复杂的服务器CPU,拆到最底层,无非就是一堆晶体管在那开关开关。我当年刚入行时,总觉得架构设计高大上,看不上这些基础。结果第一次做时钟树综合,复位信号没处理好,整个芯片上电就乱跳——嗯,从那以后,我再也不敢小瞧这些「基本功」了。

2.1 晶体管:数字世界的开关

数字电路的核心就两个东西:导通截止。说白了,就是0和1。实现这个功能的,就是晶体管。

我们最常用的是CMOS(互补金属氧化物半导体)工艺。它由一对MOS管组成:NMOSPMOS

  • NMOS:栅极电压为高(VDD)时导通,低(GND)时截止。
  • PMOS:栅极电压为低(GND)时导通,高(VDD)时截止。

我个人习惯把NMOS想象成「听话的小弟」——你给高电平,他就开门;PMOS则是「叛逆青年」——你给低电平,他才干活。两者互补,所以叫CMOS。

关键特性:CMOS电路静态时几乎不耗电。只有在开关切换的瞬间,才会有电流流过。这也是为什么数字芯片能集成几十亿晶体管,功耗还能控制住的原因。

我在项目中遇到过一个问题:某颗芯片的漏电流异常大。查了半天,发现是某个PMOS的阈值电压漂了。所以,做后端设计时,阈值电压的选择是个大学问——选高了速度慢,选低了漏电大。

2.2 逻辑门:从晶体管到布尔代数

有了晶体管这个开关,我们就可以搭出逻辑门了。最基本的三个门:与门、或门、非门

举个例子,一个两输入与非门(NAND)的晶体管级实现:

// 两输入NAND门的CMOS结构
// 两个PMOS并联,两个NMOS串联
// 输入A、B,输出Y

PMOS: 源极接VDD,漏极接Y,栅极接A
PMOS: 源极接VDD,漏极接Y,栅极接B
NMOS: 漏极接Y,源极接NMOS2的漏极,栅极接A
NMOS: 漏极接NMOS1的源极,源极接GND,栅极接B

// 真值表
// A=0, B=0 → Y=1
// A=0, B=1 → Y=1
// A=1, B=0 → Y=1
// A=1, B=1 → Y=0

你可能会问:「为什么服务器芯片里要用NAND门,而不是直接用AND门?」

原因很简单:NAND/NOR门比AND/OR门快。因为CMOS工艺中,串联的NMOS比并联的PMOS更容易驱动。所以,实际设计中,我们几乎都是用NAND和NOR来搭电路。我曾经优化过一个加法器,把关键路径上的AND门全部换成NAND+反相器,时序直接提升了15%。

2.3 组合逻辑电路:没有记忆的「直性子」

组合逻辑电路的特点是:输出只取决于当前输入,跟历史状态无关。说白了,就是一根筋,不记仇。

常见的组合逻辑模块有:

  • 加法器:全加器、超前进位加法器
  • 多路选择器:MUX
  • 译码器/编码器:地址译码
  • 比较器:数值比较

这里我重点说一下超前进位加法器。为什么服务器芯片里不用简单的行波进位加法器?因为慢!

行波进位加法器,进位信号像波浪一样逐级传递。32位的加法器,最坏情况下要等32个门延迟。而超前进位加法器,通过预计算进位生成信号(G)和进位传播信号(P),把关键路径缩短到3-4级门延迟。

我的经验:在做CPU的ALU设计时,加法器的速度直接决定了主频上限。我建议你在做RTL设计时,直接用综合工具的加法器宏单元(如DesignWare的DW_add),它们已经针对工艺库做了优化。自己手写加法器?除非你是做定制电路,否则别折腾。

2.4 时序逻辑电路:有记忆的「老江湖」

时序逻辑电路就不一样了。它的输出不仅取决于当前输入,还取决于之前的状态。核心元件就是触发器(Flip-Flop)锁存器(Latch)

在服务器芯片里,我们几乎只用边沿触发的D触发器。为什么?因为锁存器是电平敏感的,容易产生毛刺和时序问题。我见过一个团队,为了省面积用了大量锁存器,结果芯片在高温下频繁出错——这就是血的教训。

一个标准的D触发器结构:

// 上升沿触发的D触发器
// 输入:D, CLK
// 输出:Q

always @(posedge CLK) begin
    Q <= D;
end

// 带异步复位的D触发器
always @(posedge CLK or negedge RST_N) begin
    if (!RST_N)
        Q <= 1'b0;
    else
        Q <= D;
end

注意看,我用了非阻塞赋值(<=)。这是RTL设计的基本功——时序逻辑用非阻塞赋值,组合逻辑用阻塞赋值。混用了?仿真时可能看不出问题,但综合出来的电路绝对会让你头疼。

2.5 时钟与复位:芯片的「心跳」和「重启键」

时钟和复位,是整个数字系统的命脉。没有时钟,芯片就是一堆死电路;没有复位,芯片上电后状态未知,直接乱套。

2.5.1 时钟

时钟信号是一个周期性的方波。它的关键参数有三个:

参数 说明 典型值(服务器芯片)
频率 每秒的周期数 2-5 GHz
占空比 高电平时间占周期的比例 50%(理想情况)
抖动 时钟边沿的随机偏移 < 10 ps

时钟抖动是个大问题。我做过一个项目,PLL输出的时钟抖动偏大,导致高速接口的建立时间总是不够。最后不得不加了一级时钟缓冲器来整形。所以,时钟树综合是后端设计中最关键的一步——要保证时钟信号同时到达所有触发器,而且边沿要陡峭。

避坑指南:我曾经遇到过时钟门控(Clock Gating)导致的功能错误。当时为了省功耗,在RTL里手动插了时钟门控,结果门控信号没处理好,产生了毛刺,把触发器触发了两次。记住:时钟门控一定要用锁存器+与门的结构,确保门控信号只在时钟低电平时变化。

2.5.2 复位

复位信号分为两种:同步复位异步复位

  • 同步复位:只在时钟边沿有效。优点是不会产生亚稳态,缺点是需要时钟才能复位。
  • 异步复位:立即有效,不依赖时钟。优点是复位快,缺点是容易产生亚稳态。

我个人习惯用异步复位、同步释放的方式。既保证了复位速度,又避免了亚稳态问题。代码实现如下:

// 异步复位、同步释放
reg rst_sync1, rst_sync2;

always @(posedge CLK or negedge RST_N) begin
    if (!RST_N) begin
        rst_sync1 <= 1'b0;
        rst_sync2 <= 1'b0;
    end
    else begin
        rst_sync1 <= 1'b1;
        rst_sync2 <= rst_sync1;
    end
end

// 使用同步后的复位信号
always @(posedge CLK or negedge rst_sync2) begin
    if (!rst_sync2)
        Q <= 1'b0;
    else
        Q <= D;
end

这个结构,说白了就是两级触发器打拍。第一级可能亚稳态,但第二级基本就稳定了。我在多个项目里用过这个方案,从来没出过问题。

2.6 本章小结

这一章我们走完了从晶体管到系统的基础链路。记住几个核心点:

  1. 晶体管是开关,CMOS是互补对。
  2. 逻辑门用NAND/NOR更快。
  3. 组合逻辑无记忆,时序逻辑有记忆。
  4. 时钟是心跳,复位是重启键。
  5. 异步复位同步释放,是工程上的最佳实践。

下一章,我们会进入硬件描述语言的世界。到时候,我会教你怎么用Verilog把这些电路「写」出来。嗯,那才是真正开始动手的时候。