3. Verilog模块结构:模块定义、端口声明、模块实例化、`timescale与注释
各位同学,今天我们来聊聊Verilog设计中最基础、也最核心的东西——模块结构。说白了,一个Verilog模块就像一块芯片的“设计图纸”。你画好这张图,工具才能帮你把它变成真正的硬件。
我刚开始学Verilog那会儿,总觉得模块定义就是个形式,随便写写就行。后来在项目中吃过亏,才发现这里面的门道真不少。咱们一个一个来看。
3.1 模块定义——你的设计“外壳”
每个Verilog模块,都以 module 开头,以 endmodule 结尾。这是硬性规定,少一个都不行。
module 模块名 (端口列表);
// 内部逻辑
endmodule
模块名我建议用有意义的英文单词组合,比如 counter_8bit、uart_tx。别用 module1、test 这种名字,三个月后你自己都看不懂。
pwmGenerator。当然这不是强制规定,但团队里统一风格很重要。
3.2 端口声明——模块的“手脚”
端口就是模块跟外界打交道的通道。Verilog支持三种端口方向:
| 端口类型 | 关键字 | 说明 |
|---|---|---|
| 输入 | input |
数据流入模块,不能赋值 |
| 输出 | output |
数据流出模块,可以赋值 |
| 双向 | inout |
数据可进可出,常用于总线 |
端口声明有两种写法。我个人偏爱ANSI风格,简洁明了:
module counter (
input wire clk,
input wire rst_n,
input wire en,
output reg [7:0] count
);
// 逻辑代码
endmodule
另一种是传统风格,端口列表只写名字,方向在内部声明。嗯,这种写法现在用得少了,但老代码里还能见到。
input 写成了 inout。仿真没问题,但综合后多了一堆三态缓冲器,资源翻了一倍。所以端口方向一定要写对。
3.3 模块实例化——把图纸变成实物
模块定义好了,怎么用?实例化。就像你画好了一个芯片的版图,然后把它“贴”到更大的电路板上。
实例化有两种方式:
方式一:按端口顺序连接
counter u_counter (
clk, // 连接到顶层clk
rst_n, // 连接到顶层rst_n
en, // 连接到顶层en
count // 连接到顶层count
);
这种方式代码短,但容易出错。端口顺序一变,所有实例化都得改。我不推荐。
方式二:按端口名称连接(推荐)
counter u_counter (
.clk (clk),
.rst_n (rst_n),
.en (en),
.count (count)
);
这种方式清晰、可读性强,而且端口顺序随便调。你想想看,如果项目里有几十个模块实例化,用这种方式维护起来多省心。
.后面是模块定义的端口名,括号里是当前模块的信号名。别搞反了。
3.4 `timescale——仿真时间单位
`timescale 是编译器指令,用来定义仿真中的时间单位和精度。它长这样:
`timescale 1ns / 1ps
斜杠前面是时间单位,后面是时间精度。上面这行表示:时间单位是1ns,精度是1ps。
为什么要有这个?因为仿真器需要知道 #10 到底代表多长时间。没有 `timescale,仿真器就懵了。
`timescale。我曾经接手过一个项目,好几个文件没写,仿真结果对不上,查了两天才发现是时间单位不一致。这种坑,踩一次就够了。
常用的时间单位组合:
`timescale 1ns / 1ps—— 最常用,精度够用`timescale 10ns / 1ns—— 低频设计可以用`timescale 1ps / 1fs—— 高速设计,但仿真会慢
3.5 注释——写给未来的自己
注释分两种:
//单行注释:用于简短说明/* ... */多行注释:用于大段描述
我见过太多没有注释的代码了。说实话,三个月后你自己都看不懂当时写的逻辑。所以我的习惯是:
- 每个模块开头写一段功能描述
- 每个always块前面写清楚触发条件
- 关键信号旁边加注释
// 8位同步计数器,带使能和异步复位
// 计数范围:0 ~ 255
module counter (
input wire clk, // 系统时钟
input wire rst_n, // 异步复位,低有效
input wire en, // 计数使能
output reg [7:0] count // 计数值
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 8'd0;
else if (en)
count <= count + 1'b1;
end
endmodule
3.6 知识体系总览
下面这张图,把本章的核心内容串起来了。你可以把它当作一个快速参考。
好了,以上就是Verilog模块结构的全部核心内容。模块定义、端口声明、实例化、`timescale、注释——这五个点,是每个Verilog设计者必须烂熟于心的基本功。别觉得简单就跳过,我见过太多老手在这些基础问题上翻车了。
公众号:蓝海资料掘金营,微信deep3321