第二讲:RTL代码风格基础——命名规范、缩进对齐与注释规范
各位同学好,今天我们聊聊RTL代码的“门面”——代码风格。
你可能觉得这东西虚,不就是起个名字、对齐一下嘛?我告诉你,真不是。我在项目里见过太多因为命名混乱导致的低级bug,也见过因为注释误导让接手的人骂娘的情况。代码风格,说白了就是你的专业素养。
一、命名规范:让信号自己会说话
好的命名,能让代码像读文章一样顺畅。坏的命名,嗯…就像看天书。
1. 模块命名
我个人习惯用“模块名_功能”的格式。比如:
// 好的命名
uart_rx
uart_tx
fifo_wr_ctrl
spi_master
// 不好的命名
module1
ctrl
top_top
模块名要体现它的功能。你想想看,如果别人看到你的模块叫“ctrl”,他得花多少时间去猜你到底控制什么?
2. 信号命名
这里我有一套自己的规则,用了十几年了:
| 信号类型 | 命名规则 | 示例 |
|---|---|---|
| 时钟 | clk_前缀 | clk_sys, clk_100m |
| 复位 | rst_n后缀(低有效) | rst_n, rst_sys_n |
| 使能 | _en后缀 | wr_en, rd_en |
| 有效指示 | _vld后缀 | data_vld, addr_vld |
| 准备好 | _rdy后缀 | data_rdy, fifo_rdy |
3. 参数命名
参数用大写字母加下划线,这是业界共识:
parameter DATA_WIDTH = 32;
parameter FIFO_DEPTH = 1024;
parameter ADDR_BITS = 10;
我曾经见过有人把参数写成小写,结果和信号混在一起,查了半天才发现是参数赋值错了。从那以后,我坚持参数全大写。
二、缩进与对齐:让代码有呼吸感
缩进这件事,看似简单,但做不好真的很要命。
1. 缩进规则
我建议用2个空格缩进。为什么不是4个?因为RTL代码嵌套层次多,4个空格会让代码很快跑到屏幕右边去。
// 好的缩进
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 8'b0;
end else if (en) begin
cnt <= cnt + 1'b1;
end else begin
cnt <= cnt;
end
end
// 不好的缩进
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 8'b0;
end else if (en) begin
cnt <= cnt + 1'b1;
end else begin
cnt <= cnt;
end
end
你看,第二种写法,眼睛扫过去根本分不清逻辑层次。调试的时候,这种代码就是噩梦。
2. 对齐规则
赋值语句的对齐,我习惯这样:
// 好的对齐
assign data_out = (sel) ? data_a : data_b;
assign addr_out = addr_in + offset;
assign wr_en = wr_req & fifo_full_n;
// 不好的对齐
assign data_out = (sel) ? data_a : data_b;
assign addr_out = addr_in + offset;
assign wr_en = wr_req & fifo_full_n;
对齐后的代码,一眼就能看出哪些信号是同一类操作。嗯,这里要注意,对齐不是强制要求,但能极大提升可读性。
三、注释规范:写给未来的自己
注释这件事,我最有发言权。因为我自己就吃过亏。
1. 模块头注释
每个模块开头,必须有一个注释块,说明这个模块是干什么的:
//==================================================
// 模块名称:fifo_wr_ctrl
// 功能描述:FIFO写控制逻辑,处理写请求和满标志
// 输入:clk, rst_n, wr_req, fifo_full
// 输出:wr_en, wr_addr
// 作者:张三
// 日期:2024-01-15
// 修改记录:
// v1.0 - 初始版本
// v1.1 - 修复满标志延迟问题
//==================================================
这个注释块,说白了就是模块的“身份证”。别人拿到你的代码,第一眼就看这个。
2. 行内注释
行内注释要解释“为什么”,而不是“是什么”:
// 好的注释
cnt <= cnt + 1'b1; // 每拍加1,用于生成读地址
// 不好的注释
cnt <= cnt + 1'b1; // cnt加1
你想想看,代码本身已经说明了“cnt加1”,注释再说一遍就是废话。注释要告诉别人“为什么加1”。
3. 复杂逻辑注释
遇到复杂的状态机或者算法,一定要写注释说明状态转移条件:
// 状态机:FIFO写控制
// IDLE: 等待写请求
// WRITE: 执行写操作,持续1拍
// FULL: FIFO已满,等待读操作释放空间
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
end else begin
case (state)
IDLE: begin
// 有写请求且FIFO未满,进入写状态
if (wr_req & !fifo_full) begin
state <= WRITE;
end
end
// ... 其他状态
endcase
end
end
四、知识体系总览
下面这张图,是我对RTL代码风格核心要点的总结:
这张图把三大核心要素串起来了。命名规范解决“叫什么”,缩进对齐解决“怎么摆”,注释规范解决“为什么”。三者缺一不可。
好了,这一讲就到这里。记住,代码风格不是给别人看的,是给未来的自己看的。你三个月后回头看自己的代码,如果能一眼看懂,说明你的风格合格了。
可可精品资料库