第二章 数字电路基础:晶体管与逻辑门、组合逻辑电路、时序逻辑电路、时钟与复位
各位同学,欢迎来到第二章。这一章是数字芯片的「细胞级」解剖课。你想想看,无论多复杂的服务器CPU,拆到最底层,无非就是一堆晶体管在那开关开关。我当年刚入行时,总觉得架构设计高大上,看不上这些基础。结果第一次做时钟树综合,复位信号没处理好,整个芯片上电就乱跳——嗯,从那以后,我再也不敢小瞧这些「基本功」了。
2.1 晶体管:数字世界的开关
数字电路的核心就两个东西:导通和截止。说白了,就是0和1。实现这个功能的,就是晶体管。
我们最常用的是CMOS(互补金属氧化物半导体)工艺。它由一对MOS管组成:NMOS和PMOS。
- 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 本章小结
这一章我们走完了从晶体管到系统的基础链路。记住几个核心点:
- 晶体管是开关,CMOS是互补对。
- 逻辑门用NAND/NOR更快。
- 组合逻辑无记忆,时序逻辑有记忆。
- 时钟是心跳,复位是重启键。
- 异步复位同步释放,是工程上的最佳实践。
下一章,我们会进入硬件描述语言的世界。到时候,我会教你怎么用Verilog把这些电路「写」出来。嗯,那才是真正开始动手的时候。