一、基本模块结构
Verilog 代码以 模块(Module) 为单位,每个模块对应一个硬件功能单元(如逻辑门、寄存器等)。
基本格式:
module 模块名 (
// 输入输出端口声明
input 端口1,
input 端口2,
output 端口3
);
// 内部信号或变量声明
wire 信号1;
reg 信号2;
// 逻辑描述(组合逻辑或时序逻辑)
assign 信号1 = 端口1 & 端口2; // 组合逻辑
always @(posedge clk) begin // 时序逻辑
信号2 <= 端口1;
end
endmodule
二、端口声明
-
输入端口 :
input
-
输出端口 :
output
-
双向端口 :
inout
示例:module example (
input a, // 单比特输入
input [7:0] b, // 8位宽输入
output c // 单比特输出
);
三、数据类型
-
线网类型(Net) :表示电路中的物理连接(如导线),常用
wire
。wire data; // 单比特线网 wire [3:0] bus; // 4位宽总线
-
寄存器类型(Register) :表示存储单元,常用
reg
。reg counter; // 单比特寄存器 reg [31:0] data; // 32位宽寄存器
-
其他类型:
integer
:整数类型(仿真用)。parameter
:常量参数(类似宏定义)。real
:浮点数(仿真用)。
四、基本语法
1. 赋值语句
-
连续赋值(组合逻辑) :用
assign
关键字。assign out = a & b; // 与门逻辑
-
过程赋值(时序逻辑) :在
always
块中使用。always @(posedge clk) begin q <= d; // D触发器,非阻塞赋值 end
2. 条件语句
-
if-else
:always @(*) begin if (sel == 1'b0) out = a; else out = b; end
-
case
:always @(*) begin case (sel) 2'b00: out = a; 2'b01: out = b; default: out = 0; endcase end
3. 循环语句
-
for
循环:integer i; always @(*) begin for (i=0; i<4; i=i+1) out[i] = a[i] & b[i]; end
-
while
和repeat
(较少用,多用于仿真)。
五、命名规则
- 合法字符 :字母、数字、下划线
_
,区分大小写。 - 首字符:必须是字母或下划线(不能是数字)。
- 保留字 :不可使用 Verilog 关键字(如
module
,input
,always
)。 - 命名建议 :
- 使用有意义的名字(如
clk
,reset
,data_in
)。 - 总线命名:
data[7:0]
表示 8 位数据。 - 避免混淆:如
l
(小写 L)和1
(数字 1)。
- 使用有意义的名字(如
示例:
reg [3:0] counter; // 合法
wire _enable; // 合法
reg 4bit_data; // 非法(首字符是数字)
六、注释
-
单行注释 :
//
-
多行注释 :
/* ... */
// 这是单行注释
/*
这是
多行注释
*/
七、示例代码
1. 与门模块
module and_gate (
input a,
input b,
output c
);
assign c = a & b;
endmodule
2. D 触发器
module d_flipflop (
input clk,
input reset,
input d,
output reg q
);
always @(posedge clk or posedge reset) begin
if (reset)
q <= 1'b0; // 复位时清零
else
q <= d; // 时钟上升沿采样
end
endmodule
八、测试模块(Testbench)
用于验证设计功能的仿真代码:
module testbench;
reg a, b;
wire c;
// 实例化被测试模块
and_gate u1 (.a(a), .b(b), .c(c));
initial begin
a = 0; b = 0;
#10 a = 1;
#10 b = 1;
#10 $finish;
end
endmodule
九、注意事项
- 阻塞赋值(
=
) vs 非阻塞赋值(<=
) :- 组合逻辑用阻塞赋值(
=
)。 - 时序逻辑用非阻塞赋值(
<=
)。
- 组合逻辑用阻塞赋值(
- 敏感列表 :
always @(*)
用于组合逻辑,always @(posedge clk)
用于时序逻辑。 - 避免锁存器 :组合逻辑中需覆盖所有条件分支(如
if-else
必须有else
)。