1. RTL设计基础:数字电路抽象、硬件描述语言概览、组合逻辑与时序逻辑核心区别
各位同学,欢迎来到《RTL设计与上板联调指南》的第一课。
我是你们的讲师,一个在FPGA和ASIC设计领域摸爬滚打了十几年的老工程师。今天咱们聊点最基础,但也最核心的东西。说白了,就是数字电路的“世界观”和“语言”。
你想想看,我们写的每一行RTL代码,最终都会变成实实在在的硅片上的晶体管。这中间到底发生了什么?嗯,这就是我们今天要搞明白的事。
1.1 数字电路抽象:从沙子到系统
数字电路设计,其实是一个不断“抽象”的过程。我们不需要关心每个晶体管怎么开关,我们只需要关心“0”和“1”。
我个人习惯把数字电路的抽象层次分成五层,就像盖楼一样:
- 系统级(System Level):最顶层,描述整个芯片是干什么的。比如“这是一个视频编解码器”。
- 寄存器传输级(RTL Level):我们工程师的主战场。描述数据如何在寄存器之间流动,以及经过什么逻辑运算。这就是我们写Verilog/VHDL的层次。
- 门级(Gate Level):RTL代码综合后的结果。由与门、或门、非门、触发器这些基本单元组成。
- 晶体管级(Transistor Level):用MOS管搭出来的电路。模拟工程师和版图设计师关心这个。
- 物理级(Physical Level):光刻掩膜版上的几何图形。这是芯片制造的最后一步。
核心观点:RTL设计,就是我们在“寄存器传输级”这个抽象层次上,用硬件描述语言来描述数字电路的行为。我们不需要管底层晶体管怎么工作,但必须清楚我们写的代码会综合成什么样的门级电路。
为了让你更直观地理解,我画了一张图:
1.2 硬件描述语言概览:Verilog与VHDL
有了抽象层次,我们还需要一种“语言”来描述它。这就是硬件描述语言(HDL)。
目前主流的就是两种:Verilog 和 VHDL。
| 特性 | Verilog | VHDL |
|---|---|---|
| 语法风格 | 类似C语言,简洁灵活 | 类似Ada/Pascal,严谨冗长 |
| 数据类型 | reg, wire, integer等,相对简单 | std_logic, std_logic_vector等,类型系统强大 |
| 设计粒度 | 适合从底层到顶层的设计 | 适合大型系统级设计 |
| 学习曲线 | 较平缓,上手快 | 较陡峭,但严谨 |
| 市场占有率 | 约70-80%(尤其在中国和美国) | 约20-30%(欧洲军工、航天领域较多) |
我的建议:如果你是初学者,我强烈建议从Verilog入手。原因很简单——资源多、社区活跃、找工作容易。我在项目中遇到过很多从VHDL转Verilog的同事,基本上一两周就能适应。反过来,从Verilog转VHDL的,往往要痛苦一两个月。
不过,语言只是工具。真正重要的是你脑子里有没有“电路感”。
1.3 组合逻辑与时序逻辑:核心区别
好,到了今天最关键的部分。很多初学者写RTL代码,写着写着就乱了,根本原因就是没搞清楚组合逻辑和时序逻辑的区别。
1.3.1 组合逻辑
定义:输出只取决于当前的输入。没有记忆功能。
特点:
- 输入一变,输出立刻变(不考虑门延迟)
- 没有时钟参与
- 由与门、或门、非门、多路选择器等构成
- 在Verilog中,用
assign或always @(*)描述
举个最简单的例子——一个2输入与门:
// 组合逻辑:与门
module and_gate (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
这段代码综合出来,就是三个晶体管组成的一个与门。没有时钟,没有存储。
1.3.2 时序逻辑
定义:输出不仅取决于当前输入,还取决于之前的状态。有记忆功能。
特点:
- 在时钟边沿(上升沿或下降沿)采样输入,更新输出
- 由触发器(Flip-Flop)或锁存器(Latch)构成
- 在Verilog中,用
always @(posedge clk)描述
再看一个D触发器的例子:
// 时序逻辑:D触发器
module dff (
input wire clk,
input wire rst_n,
input wire d,
output reg q
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0; // 异步复位
else
q <= d; // 时钟上升沿采样
end
endmodule
⚠️ 避坑指南:我曾经见过一个新手,在 always @(posedge clk) 块里用了阻塞赋值 = 而不是非阻塞赋值 <=。结果仿真没问题,上板就跑飞了。记住:时序逻辑用非阻塞赋值 <=,组合逻辑用阻塞赋值 =。这是铁律,别问为什么,先记住。
1.3.3 核心区别对比
| 对比项 | 组合逻辑 | 时序逻辑 |
|---|---|---|
| 记忆能力 | 无 | 有(靠触发器) |
| 时钟依赖 | 不依赖 | 依赖时钟边沿 |
| 输出变化 | 输入变化后立即变化 | 时钟边沿到来时变化 |
| Verilog描述 | assign 或 always @(*) |
always @(posedge clk) |
| 赋值方式 | 阻塞赋值 = |
非阻塞赋值 <= |
| 综合结果 | 门电路(与或非等) | 触发器 + 组合逻辑 |
| 典型应用 | 加法器、译码器、多路选择器 | 计数器、状态机、寄存器 |
1.3.4 一个混合的例子
实际设计中,组合逻辑和时序逻辑往往是混在一起的。比如一个简单的计数器:
// 4位计数器(时序 + 组合)
module counter (
input wire clk,
input wire rst_n,
input wire en,
output reg [3:0] count
);
// 时序部分:在每个时钟上升沿更新计数值
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 4'b0;
else if (en)
count <= count + 1'b1; // 这里用了加法器(组合逻辑)
end
endmodule
你看,count + 1'b1 这个加法操作,综合出来就是一个4位加法器(组合逻辑)。而 count <= ... 这个赋值,综合出来就是4个D触发器(时序逻辑)。两者配合,才构成了一个完整的计数器。
记住这句话:时序逻辑负责“记住”状态,组合逻辑负责“计算”下一个状态。两者缺一不可。
1.4 本章小结
好,第一课的内容就到这里。我们讲了三个核心概念:
- 数字电路抽象:从系统级到物理级,我们工作在RTL级
- 硬件描述语言:Verilog和VHDL,我推荐你先学Verilog
- 组合逻辑 vs 时序逻辑:一个没记忆,一个有记忆;一个用
=,一个用<=
这些东西看起来简单,但真的非常重要。我见过太多工程师,写了几年RTL代码,还在纠结“为什么我的寄存器没更新”、“为什么仿真和上板结果不一样”。说白了,就是基础没打牢。
嗯,今天就到这里。下一节课,我们会深入讲讲Verilog的语法细节,以及如何写出“可综合”的代码。