参考自:http://guqian110.github.io/pages/2015/04/21/verilog_hdl_coding_style_guide.html
好的代码风格不仅便于理解和重用,也便于综合工具的优化,Good Coding Styles应当从设计之初就开始了,因为模块划分的好坏会直接影响到代码的可读性和重用性。
所以一开始我们就要遵循一定的规则对模块进行划分,然后编写设计文档,将设计细节描述清楚,使项目可控,然后才是Coding,Coding又包括Coding Styles、Naming和Format。
Naming和Format比较死,主要是针对代码的可读性,Coding Styles则主要针对代码的可移植性和综合性能,综合性能即代码映射后的电路性能,比如什么时候用if…else,什么时候用case,要不要复位?怎么复位?并且针对不同厂家,甚至同一厂家的不同器件也会有所不同(大部分方法还是一样的,主要针对器件的部分特性会有一定的改变,如触发器的结构、DSP硬核的结构等)。
具体的代码风格请参考上面的链接,下面只写一些我自己觉得比较重要又容易遗忘的东西。
- 一个模块最好在500行左右,不要太大,但也不要将模块划分得太细,需要权衡;
- 模块与模块之间低耦合,要更少的连线,且最好不要有逻辑关系,即不要因为修改一个模块影响到其他模块;
- 为了减少修改内容、避免出错、移植方便、创建可重用模块,在编写代码的时候使用 define、parameter、localparam 定义可重定义的参数(如 SIZE、WIDTH、DEPTH 等),一个参数只对本模块有影响时使用localparam,状态机的状态也使用localparam;
- 模块的输入信号尽量用 DFF 先锁存再使用(若输入是其他的寄存器输出则不必),模块的输出信号尽量用 DFF 先锁存再输出(便于综合和 STA,处理起来简单,Timing 更好);
- 代码要简洁,这一点非常重要,不必要的begin…end和注释就不写,因为会分散注意力,增加我们搜索有用信息的时间。
// code1
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
q <= 0;
end // end-if-begin
else
begin
q <= d;
end // end-else-begin
end // end-always-begin
// code2
always @(posedge clk or negedge rst_n)
if (!rst_n) q <= 0;
else q <= d;
不用拘泥于形式,始终要想着Coding Styles的目的。
附:
常用信号名缩写:
name | short | name | short | name | short |
---|---|---|---|---|---|
acknowledge | ack | error | err | ready | rdy |
adress | addr | enable | en | receive | rx |
arbiter | arb | frame | frm | request | req |
check | chk | generate | gen | resest | rst |
clock | clk | grant | gnt | segment | seg |
config | cfg | increase | inc | source | src |
control | ctrl | input | in | statistic | stat |
counter | cnt | length | len | switcher | sf |
data in | din | output | out | timer | tmr |
data out | dout | packet | pkt | tmporary | tmp |
decode | de | priority | pri | transmit | tx |
decrease | dec | pointer | ptr | valid | vld |
delay | dly | read | rd | write | wr |
disable | dis | read enbale | rd_en | write enable | wr_en |
一个简单的模板:
///////////////////////////////////////////////////////////////////////////////////
// Module Declaration //
///////////////////////////////////////////////////////////////////////////////////
module MODULE_NAME #(parameter PARAM1 = xxx, PARAM2 = xxx)
(
//----------------------------------
// Interface1
port_1, // comments
port_2,
...
//----------------------------------
// Interface2
port_n
);
///////////////////////////////////////////////////////////////////////////////////
// Parameter Declarations //
///////////////////////////////////////////////////////////////////////////////////
localparam DIN = 16,
DOUTA = 16,
DOUTE = 16,
DOUTCTR = 16;
///////////////////////////////////////////////////////////////////////////////////
// Main Body of Code //
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Instantiate sub module //
///////////////////////////////////////////////////////////
MODULE_NAMW_A U_MODULE_NAMW_A (
.A(A)
.B(B)
...
);
///////////////////////////////////////////////////////////
// Some Logic //
///////////////////////////////////////////////////////////
//----------------------------------------
// sequential logic
always @(posdge clk) begin
if (rst) begin
// reset
...
end
else begin
// do something
...
end
end
//---------------------------------------
// combinational logic
assign wire_1 = wire_2;
...
endmodule