Verilog 代码风格总结供参考.docx
《Verilog 代码风格总结供参考.docx》由会员分享,可在线阅读,更多相关《Verilog 代码风格总结供参考.docx(13页珍藏版)》请在冰豆网上搜索。
![Verilog 代码风格总结供参考.docx](https://file1.bdocx.com/fileroot1/2022-11/25/feab4eb0-e8dd-42eb-a7a4-6b6fa98f788b/feab4eb0-e8dd-42eb-a7a4-6b6fa98f788b1.gif)
Verilog代码风格总结供参考
窗体顶端
[转]Verilog代码风格-供参考
Description
本文主要是收集一些重要的Verilogcodingstyle。
一个好的codingstyle可以减少错误的发生,增加电路的效能,以及较好的可读性。
Text
Theorderofmodulesignals
一个modulesignal顺序如下(由左至右):
Input
clocksignals(clk_*)
set/resetsignals(set_*,rst_*)
enable/disblesignals(en_*,dis_*)
read/writeenablesignals(we_*,re_*,rw_*)
controlsignals(i_*)
addresssignals(i_*)
datasignals(i_*)
Output
clocksignals(o_clk_*)
set/resetsignals(o_set_*,o_rst_*)
enable/disablesignals(o_en_*,o_dis_*)
controlsignals(o_*)
addresssignals(o_*)
datasignals(o_*)
In/Out
controlsignals(io_*)
addresssignals(io_*)
datasignals(io_*)
NamingRule
以下的namignrule为个人使用的规则。
命名方式分类
底线分隔型:
xxx_yyy_zzz
大写底线分隔型:
XXX_YYY_ZZZ
首字大写型:
AbcDefGhi
首字小写型:
avcDefGhi
各种元素所使用的命名
文件名称:
底线分隔型,Ex:
xxx_yyy_zzz.v
module名称:
底线分隔型,Ex:
xxx_yyy_zzz
moduleinstance名称:
底线分隔型,Ex:
xxx_yyy_zzz
localwire名称:
底线分隔型:
Ex:
xxx_yyy_zzz
localreg名称:
底线分隔型,Ex:
xxx_yyy_zzz
inputsignal名称:
前置i_的底线分隔型,Ex:
i_xxx_yyy_zzz
outputsignal名称:
前置o_的底线分隔型,Ex:
o_xxx_yyy_zzz
input/outputsignal名称:
前置io_的底线分隔型,Ex:
io_xxx_yyy_zzz
常数名称:
大写底线分隔型,`XXX_YYY_ZZZ
parameter参数名称:
大写底线分隔型,Ex:
XXX_YYY_ZZZ
block名称:
大写底线分隔型,Ex:
XXX_YYY_ZZZ
特殊讯号名称
单一的clocksignal:
clk
多个clocksignal:
clk_xxx
负缘触发的clocksignal:
clk_n,clk_xxx_n
单一的resetsignal:
rst
多个resetsignal:
rst_xxx
负缘触发的resetsignal:
rst_n,rst_xxx_n
单一的setsignal:
set
多个setsignals:
set_xxx
负缘触发的setsignals:
set_n,set_xxx_n
致能讯号:
en_xxx
除能讯号:
dis_xxx
ProceduralAssignments
使用指引
在撰写sequentiallogic时,使用nonblockingassignment。
在撰写latches电路时,使用nonblockingassignment。
在alwaysblock中撰写conbinationallogic时,使用blockingassignment。
在同一个alwaysblock中同时撰写sequential及combinationallogic时,一律使用nonblockingassignment。
别在同一个alwaysblock中混合使用nonblocking及blockingassignment。
别在两个以上的alwaysblock中对同一个变量设定数值。
使用$strobe来显示由nonblockingassignment所给定的变量。
不要对assignment使用#0延迟设定。
在proceduralassignment中,LHS(等式的左边LeftHandSide?
)一定要是reg型态。
非proceduralassignment一定是net的型态。
常用的style
Combinationlogic
在alwaysblock中,如果使用combinationlogic,应当使用blockingassignment.
//Allinputsusedwithinalwaysblockshouldbelistedinsensitivelist.
always@(in1orin2orin3)
begin
xxx=in1^in2&in3;
end
Sequentiallogic
在alwaysblock中,如果使用sequentiallogic,应当使用nonblockingassignment.
//Synchronousreset.Therst_nisNOTinsensitivelist.
always@(posedgeclk)
begin
if(~rst_n)
begin
xxx<=`INIT_VAL;
end
else
begin
xxx<=yyy;
end
end
//Asynchronousreset.Therst_nISinsensitivelist.
always@(posedgeclkornegedgerst_n)
begin
if(~rst_n)
begin
xxx<=`INIT_VAL;
end
else
begin
xxx<=yyy;
end
end
Delay的建模
Combinationlogic
建模没有delay时,使用blockingassignment(ex:
a=b;)
建模有惯性(inertial)delay时(即glitch不会传到后面的电路中)。
使用delayedevaluationblockingassignments(#10a=b;).
建模传输(transport)delay时(即glitch也会一并传到后面的电路中)。
使用delayedassignmentnonblockingassignments(ex:
a<=#10b;).
Sequentiallogic
建模没有delay时,使用non-blockingassignments(ex:
q<=d;).
建模有delay时,使用delayedassignmentnonblockingassignments(ex:
q<=#10d;).
FiniteStateMachine
MooreFSM:
输出与输入没有直接关系。
由两个alwaysblock构成,一个是sequentialblock用来处理状态的变化。
另一个为combinationalblock用来处理状态与输入之间的关系。
注意,在sequentialblock中应全部使用nonblockingassignment。
在combinationalblock中应使用blockingassignment。
在某些简单的case中,combinationalblock也可直接由continuousassignment来取代。
下面的范例是一般简单的FSM。
//Sequentialalwaysblock.
always@(posedgeclkorposedgerst)
begin
if(rst)
state<=STATE_IDLE;
else
state<=next;
end
//Combinationalalwaysblock.
always@(stateorinput1orinput2...orinputN)
begin
next=STATE_IDLE;
outputs=OUTPUT_IDLE:
case(state)
STATE_IDLE:
begin
...//thelogictodeterminethenextstate.
next=STATE_?
?
?
?
?
;
end
STATE_?
?
?
?
?
:
begin
...//thelogictodeterminethenextstate.
next=STATE_?
?
?
?
?
;
outputs=?
?
?
?
?
;//Theoutputofthisstate.
end
endcase
end
针对simplifiedone-hotencoding的FSM范例:
//Sequentialalwaysblock.
always@(posedgeclkorposedgerst)
begin
if(rst)
state<=n'b0;
state[STATE_DEFAULT]<=1'b0;
else
state<=next;
end
//Combinationalalwaysblock.
always@(stateorinput1orinput2...orinputN)
begin
next=n'b0;
outputs=OUTPUT_DEFAULT:
case(1'b1) //synopsysfull_caseparallel_case
state[STATE_DEFAULT]:
begin
...//thelogictodeterminethenextstate.
next[STATE_?
?
?
?
?
]=1'b1;
end
state[STATE_?
?
?
?
?
]:
begin
...//thelogictodeterminethenextstate.
next[STATE_?
?
?
?
?
]=1'b1;
outputs=?
?
?
?
?
;//Theoutputofthisstate.
end
//synopsystranslate_off
default:
$display("Badstate!
!
");
//synopsystranslate_on
endcase
end
针对simplifiedone-hotwithzero-idleencoding的FSM:
//Sequentialalwaysblock.
always@(posedgeclkorposedgerst)
begin
if(rst)
state<=n'b0;
else
state<=next;
end
//Combinationalalwaysblock.
always@(stateorinput1orinput2...orinputN)
begin
next=n'b0;
outputs=OUTPUT_DEFAULT:
case(1'b1) //synopsysfull_caseparallel_case
~|state:
//IDLE
begin
...//thelogictodeterminethenextstate.
next[STATE_?
?
?
?
?
]=1'b1;
end
state[STATE_?
?
?
?
?
]:
begin
...//thelogictodeterminethenextstate.
next[STATE_?
?
?
?
?
]=1'b1;
outputs=?
?
?
?
?
;//Theoutputofthisstate.
end
//synopsystranslate_off
default:
$display("Badstate!
!
");
//synopsystranslate_on
endcase
end
MealyFSM:
输出与输入有直接关系。
MealyFSM的作法与上面的范例相类似。
唯一的不同在于outputs的指定,需加上与input相关的逻辑判断。
例如:
case(state) //synopsysparallel_casefull_case
...
STATE_?
?
?
?
?
:
begin
...
if(input1&input2)
outputs=?
?
?
?
?
;
else
outputs=?
?
?
?
?
;
end
//synopsystranslate_off
default:
$display("BadFSM.");
//synopsystranslate_on
default
endcase
Datapath
参考:
CodingGuidelinesforDatapathSynthesis.
有号数的计算:
若有需要关于有号数的计算,应当利用Verilog2001所提供的signed及$signed()机制。
input signed[7:
0] a,b;
output signed[15:
0] o;
assign o=a*b;
or
input [7:
0] a,b;
output [15:
0] o;
wire signed[15:
0] o_sgn;
assugb o_sgn=$signed(a)*$signed(b);
assign o=$unsigned(o_sgn);
正负号的扩展:
应多加利用Verilog的implicitysignedextension,避免手动进行转换。
input signed[7:
0] a,b;
input signed[8:
0] o;
assign o=a+b; //Verilog会自动进行符号的扩展。
有号数与无号数的混合计算:
不要在同一个verilog叙述中进行有号数与无号数的计算。
应该要分成个别独立的叙述。
在一个verilog叙述中只要有一个无号数的操作数,整个算式将被当成无号数进行计算。
input [7:
0] a;
input signed [7:
0] b;
output signed [15:
0] o;
//Don'tdothis:
assigno=a*b;
//The$signed({1'b0,a})canconverttheunsignednumbertosignednumber.
assigno=$signed({1'b0,a})*b;
input signed [7:
0] a;
output signed [15:
0] o;
//Don'tdothis:
assigno=a*8'b10111111;
//Use$signed()systemtask
assigno=a*$signed(8'b10111111);
//orsbkeyword.
assigno=a*8'sb10111111;
part-select运算过后的操作数是无号数。
就算是选择的范围包含整个register或wire。
input signed [7:
0] a;
input signed [7:
0] b;
output signed [15:
0] o1,o2;
//Don'tdothis:
assigno1=a[7:
0];
assign o1=a;
//Don'tdothis:
assigno2=a[6:
0]*b;
assign o2=$signed(a[6:
0])+b;
Verilog的位宽度规则:
技巧就是要善用LHS来限制位宽度。
利用中介的讯号线来作为限制宽度用的LHS操作数。
在没有特别设定的状况下,Verilog会依据LHS的操作数宽度来决定RHS操作数的宽度。
input [7:
0] a;
input [7:
0] b;
output [8:
0] o;
assigno=a+b; //9bits.
对一个表示式而言,最大宽度的操作数决定了整体的宽度。
input signed [3:
0] a;
input signed [7:
0] b;
output [11:
0] o;
wire signed [11:
0] o_sgn;
//Don'tdothis:
assigno=$unsigned(a*b); 这将会是一个8bit的运算。
因为在刮号内的bits数是依据最大操作数b的宽度决定的。
assign o_sgn=a*b; //12bits。
因为bit数是依据LHS宽度决定的。
assgigno=$unsigned(o_sgn);
input [7:
0] a;
input [7:
0] b;
input [7:
0] c;
input [7:
0] d;
output o;
wire [15:
0] tmp1;
wire [15:
0] tmp2;
//Don'tdothis:
assigno=(a+b)>(c*d);因为(a+b)及(c*d)都会是8bit的结果。
assign tmp1=a+b; //16bits.
assign tmp2=c*d; //16bits.
assign o=tmp1>tmp2; //1bit.
一.文件命名
规则1:
每个文件中只包含一个设计单元
理由:
便于修正.
规则2:
文件命名协定
<设计单元名称>.<扩展名>
理由:
便于理解设计单元constructs及文件内容.
如:
spooler.v //spooler模块的同步Verilog代码描述
规则3.模拟和数字Verilog文件
每个单一文件必须包含:
(1)模拟(analog)Verilog(用.va文件后缀);或
(2)数字Verilog(用.v文件后缀);或(3)清晰的模\数混合Verilog(用.va文件后缀).
理由:
模拟的编译器也许不能操纵数字的架构;反之亦然.
二.HDL编码项目命名
规则4:
允许的字符集
命名中必须包含字母,数字或下划线[A-Z,a-z,_](见规则5)
例外:
不允许使用连续的下划线.
理由:
双下划线在硬件竞争中是不工作的.
规则5:
命名的首字符
命名必须以字母开头,而不是数字或下划线(见规则4)
理由:
以数字或下划线开头的命名,可能会引起工具冲突.
规则6:
所有命名必须是唯一的无关项
理由:
在Verilog(语法敏感)和VHDL(语法不敏感)中的设计转换中,很可能受语法不敏感的设计风格影响.
规则7:
信号的一致性
理由:
和VHDL相比,Verilog和许多支持VHDL的工具都一样是语法敏感.及时辨别信号的类型(如:
低电平有效的信号或时钟)有助于调试.
规则8:
常量,参数和标签区块要大写
理由:
提供了一种可以辨别那些在仿真中不需要经过数据转换的实体的机制.
规则9:
信号,constructs和实例化标签要小写
理由:
从在仿真中数据不变化的实体中区别信号和constructs,以及在设计中保持一致的视觉和感觉.
规则10:
有意义的信号和变量名称
小写的名称必须包含信号和变量的意图.
理由:
描述是什么,而不是怎样去做,有助于理解设计.
如:
data_bus,set_priority
规则11:
有意义的常量名称
常量名称一定要描述常量的意图.根据意图可以很明显地看出常量的类型,及不是端口的名称.常量需大写.
理由:
有意义的名称对于常量来说,非常重要.
如:
好的名称:
SBUS_DATA_BITS,MEMORY_WIDTH,CLK_PERIOD
如:
差的名称:
ADDRESS_SIZE并不明晰,当它指的是数的位宽或地址空间的长度
规则12:
有意义的construct名称
construct的名称如functions,modules,tasks等,必须根据它们要做什么而不是怎么样去做来命名.construct名称必须小写.
理由:
描述是什么,而不是怎样去做,有助于理解设计.
规则13:
有意义的实例化标签
实例化标签要根据construct指定的要实现什么,而不是怎样去做来命名.
理由:
描述是什么,而不是怎样去做,有助于理解设计.
如:
addr_decode,bit_stuff,sbus_if
规则14:
用下划线分隔包含许多单词的名称
理由:
增加可读性
如:
ram_addr
规则15: