Menu
CoddyTech

Verilog 速查表

最后更新

模块结构与端口

模块是最基本的构建单元,它有一个名字和一个端口列表。

语法含义
module adder(...); ... endmodule定义一个模块及其主体
input clk;输入端口
output q;输出端口
output reg q;由 always 块驱动的输出
input [7:0] data;8 位输入总线(向量)
inout sda;双向端口
adder u1 (.a(x), .b(y), .sum(s));按端口名例化一个模块

数据类型

wire 表示一条连线;reg 保存由过程代码赋的值。

元素作用
wire w;由 assign 或模块输出驱动的线网
reg r;保存在 always/initial 块中赋的值
wire [3:0] bus;4 位向量(从第 3 位到第 0 位)
reg [7:0] count;8 位寄存器
bus[2]选取单个位
bus[3:1]选取一段连续的位(部分选择)
reg mem [0:255];存储器:由寄存器组成的数组
parameter WIDTH = 8;模块中的命名常量

数字字面量

格式为 <size>'<base><value>:size 是位宽,base 可以是 b/o/d/h。

语法含义
4'b10104 位二进制,值为 10
8'hFF8 位十六进制,值为 255
8'hff同上,十六进制数字不区分大小写
16'd25516 位十进制,值为 255
3'o73 位八进制,值为 7
8'b1010_1100用下划线给数字分组,便于阅读
1'bx未知值(x)
1'bz高阻态(z)

运算符

按位、逻辑、比较和归约运算符。

运算符作用
& | ^ ~按位与、或、异或、非
&& || !逻辑与、或、非(结果为 1 位)
== != < > <= >=比较运算符
<< >>左移和右移
+ - * / %算术运算符
&bus归约与(所有位相与)
|bus归约或(所有位相或)
^bus归约异或(所有位的奇偶校验)
{a, b}位拼接;{4{1'b1}} 复制得到 4'b1111

连续赋值

assign 持续驱动一个 wire,用来描述组合逻辑。

语法含义
assign y = a & b;用 a 和 b 相与的结果驱动 y
assign sum = a + b;持续计算两数之和
assign y = sel ? a : b;三目运算:一个二选一多路选择器
assign {c, s} = a + b;同时得到进位和和
assign y = ~en;用取反后的信号驱动 wire

过程块

always 和 initial 用来执行语句,敏感列表决定何时执行。

语法含义
always @(*) begin ... end组合逻辑(任一输入变化时执行)
always @(posedge clk)每个时钟上升沿执行(时序逻辑)
always @(negedge clk)每个时钟下降沿执行
always @(posedge clk or posedge rst)带异步复位的时钟块
initial begin ... end在 0 时刻执行一次(测试平台,仅限仿真)
begin ... end把多条语句组合在一起
#10延迟 10 个时间单位(仅限仿真)

阻塞与非阻塞赋值

组合逻辑用 =,时钟驱动的时序逻辑用 <=。

语法含义
a = b;阻塞赋值:按顺序立即执行
a <= b;非阻塞赋值:先读取所有右侧表达式,再统一赋值
always @(*) y = a & b;组合逻辑:用阻塞赋值 =
always @(posedge clk) q <= d;触发器:用非阻塞赋值 <=
在同一个块中混用 = 和 <=不要这样做,这是常见的 bug 来源

控制流

过程块中的条件判断和多路分支。

语法含义
if (cond) ... else ...条件语句
if (a) x = 1; else x = 0;单行 if/else
case (sel) ... endcase根据一个值进行多路分支
2'b00: y = a;一个 case 分支
default: y = 0;默认分支
for (i = 0; i < 8; i = i + 1)循环(常用于 generate 或仿真中)
repeat (4) @(posedge clk);将一条语句重复 N 次

常用写法

反复会用到的基础电路,以及测试平台中的常用任务。

写法语法
D 触发器always @(posedge clk) q <= d;
带复位的寄存器always @(posedge clk) if (rst) q <= 0; else q <= d;
计数器always @(posedge clk) count <= count + 1;
状态机的状态寄存器always @(posedge clk) state <= next_state;
状态机的次态逻辑always @(*) case (state) ... endcase
打印一个值$display("q = %b", q);
值变化时打印$monitor("t=%0t q=%b", $time, q);
结束仿真$finish;

常用的 Verilog 语法都在这一页。这份 Verilog 速查表是这门硬件描述语言的快速参考:声明模块和端口、选择数据类型、编写组合逻辑和时序逻辑,以及描述真实电路的 always 块写法。

这里的语法是标准 Verilog(IEEE 1364),可以在 Icarus Verilog、Verilator 等常用仿真器中使用。需要什么就直接复制,也可以在 Verilog 在线编辑器里动手试试:写一个模块,运行仿真,在浏览器里直接看到输出。

Verilog 速查表常见问题

这份 Verilog 速查表免费吗?

免费。这份 Verilog 速查表完全免费,无需注册。收藏这一页,需要查语法、运算符或 always 块写法时随时回来看。

wire 和 reg 有什么区别?
wire 表示一条物理连线,必须被持续驱动(由 assign 语句或模块输出驱动),所以用于组合逻辑的线网。reg 会一直保持它的值,直到过程代码修改它,所以凡是在 always 或 initial 块中赋值的信号都用 reg。虽然名字叫 reg,但它不一定会综合成硬件寄存器,它只表示这个值是通过过程语句赋的。
阻塞赋值和非阻塞赋值有什么区别?
阻塞赋值(=)像普通的程序语句一样,按顺序立即执行,所以在 always @(*) 块中描述组合逻辑时使用它。非阻塞赋值(<=)先计算所有右侧表达式,再同时更新所有左侧变量,能正确地描述触发器,所以在时钟驱动的 always @(posedge clk) 块中使用它。在同一个块中混用两者,是仿真 bug 的经典来源。
可以在线练习 Verilog 吗?

可以。打开 Verilog 在线编辑器,写一个模块,运行仿真,就能在浏览器里看到输出,无需安装任何软件。想系统学习的话,Coddy 免费的互动式 Verilog 课程会一步步带你从模块和数据类型学到 always 块和有限状态机。

这份速查表适合初学者吗?

适合。它从基础内容(模块、端口和数据类型)开始,一直讲到时序逻辑和状态机写法,你可以从上面的部分学起,逐步学会描述真实的电路。

Coddy 编程语言插图

在 Coddy 学习 Verilog

开始