Verilog 入门指南
发布: (2026年2月4日 GMT+8 15:26)
7 min read
原文: Dev.to
Source: Dev.to

本文重点关注两件事
- 必须理解的核心 Verilog 语法
- 实际设计中使用的三种主要建模风格
如果你来自软件背景,请把 Verilog 看作是一种随时间描述硬件行为的方式,而不是逐行运行的程序。
什么是 Verilog?
Verilog 用于建模数字系统,例如
- 组合逻辑
- 时序逻辑
- 有限状态机
- 完整的 SoC 和 ASIC 设计
Verilog 代码可以
- 仿真以验证功能
- 综合以生成实际硬件
基本 Verilog 程序结构
每个 Verilog 设计都是由 模块 构成的。
module example_module (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
关键点
module和endmodule定义了一个硬件块。- 输入和输出描述了接口。
- 内部逻辑描述了输出如何依赖于输入。
常见数据类型
Wire
用于连续连接。
wire sum;
assign sum = a ^ b;
Reg
用于在过程块内部存储值。
reg q;
尽管名字叫
reg,但它并不总是表示触发器。它仅表示信号在always块内部被赋值。
常用运算符
- Arithmetic : + - * /
- Logical : &&
- Bitwise : &
- Comparison : == !=
- Assignment : = (blocking) <= (non‑blocking)
Verilog 建模风格
Verilog 支持三种主要的建模风格。选择合适的风格取决于你正在设计的内容以及希望描述的抽象程度。
1. 行为建模
关注电路 做什么,而不是 如何构建。
示例:2:1 多路复用器
module mux2_behavioral (
input wire a,
input wire b,
input wire sel,
output reg y
);
always @(*) begin
if (sel)
y = b;
else
y = a;
end
endmodule
特性
- 使用
always块。 - 易于阅读和编写。
- 适用于控制逻辑和有限状态机(FSM)。
- 在谨慎编写时可综合。
2. 数据流建模
使用连续赋值和表达式描述逻辑。
示例:全加器
module full_adder_dataflow (
input wire a,
input wire b,
input wire cin,
output wire sum,
output wire cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (b & cin) | (a & cin);
endmodule
特性
- 使用
assign语句。 - 与布尔方程非常接近。
- 最适合组合逻辑。
- 简洁明了。
3. 结构化建模
将低层模块相互连接,类似于原理图。
示例:使用两个半加器实现全加器
module half_adder (
input wire a,
input wire b,
output wire sum,
output wire carry
);
assign sum = a ^ b;
assign carry = a & b;
endmodule
module full_adder_structural (
input wire a,
input wire b,
input wire cin,
output wire sum,
output wire cout
);
wire s1, c1, c2;
half_adder ha1 (a, b, s1, c1);
half_adder ha2 (s1, cin, sum, c2);
assign cout = c1 | c2;
endmodule
特性
- 层次化设计。
- 反映真实硬件连接。
- 在大型设计中常用。
- 提高可复用性和清晰度。
4. 门级建模
直接使用 Verilog 原语。
示例:半加器
module half_adder (
input wire a,
input wire b,
output wire sum,
output wire carry
);
xor (sum, a, b);
and (carry, a, b);
endmodule
特性
- 纯门级描述。
- 对于大型设计非常繁琐。
阻塞与非阻塞赋值
这在 Verilog 中至关重要。
阻塞 (=)
用于组合逻辑。
always @(*) begin
x = a & b;
y = x | c;
end
非阻塞 (<=)
用于时序逻辑。
always @(posedge clk) begin
q <= d;
end
经验法则
- 在组合逻辑中使用
=。 - 在时钟触发的(顺序)逻辑中使用
<=。
建模顺序逻辑
示例:具有低电平有效复位的 D 触发器
module dff (
input wire clk,
input wire rst,
input wire d,
output reg q
);
always @(posedge clk or negedge rst) begin
if (!rst)
q <= 1'b0;
else
q <= d;
end
endmodule
所有代码片段均采用 Verilog‑2001 语法编写,除另有说明外均可综合。
Verilog 触发器示例
module dff (
input wire clk,
input wire rst,
input wire d,
output reg q
);
always @(posedge clk or negedge rst) begin
if (!rst)
q <= 1'b0;
else
q <= d;
end
endmodule
这种写法是可综合的,并且可以直接映射到硬件触发器。
何时使用每种建模风格
- 行为建模 – 最适合用于控制逻辑和有限状态机,关注电路做什么而不是怎么做。对于复杂的决策逻辑,代码更易阅读和维护。
- 数据流建模 – 适用于组合逻辑。它与布尔方程紧密对应,常用于算术电路、多路复用器以及输出直接由输入推导的简单逻辑块。
- 结构建模 – 用于大型层次化设计。它将较小的模块连接起来形成更大的系统,反映实际硬件结构,适合可复用和可扩展的设计。
- 门级建模 – 主要用于演示和学习。由于依赖 Verilog 门原语,代码冗长且难以管理,在现代大规模设计中很少使用,因此不适合构建可复用或可扩展的设计。
在实际项目中,通常会在同一个设计中混合使用三种风格(行为、数据流、结构)。
最终思考
Verilog 强大之处在于它允许你在不同抽象层次上对硬件进行建模。理解语法很重要,但掌握各种建模风格才是让你的设计保持整洁、可扩展且可综合的关键。
