浅谈verilog语言编写规范

嵌入式技术

1378人已加入

描述

5.1.3 Net and Register

一个reg变量只能在一个always语句中赋值  。

向量有效位顺序的定义一般是从大数到小数。

尽管定义有效位的顺序很自由, 但如果采用毫无规则的定义势必会给作者和读代码的人带来困惑, 如Data[-4 :0] ,则LSB[0][-1][-2][-3][-4]MSB ,或 Data[0 :4] ,则LSB[4][3][2][1][0]MSB, 这两种情况的定义都不太好 ,推荐 Data[4 :0] 这种格式的定义。

对net和register类型的输出要做声明 (在PORT中)。如果一个信号名没做声明 Verilog将假定它为一位宽的wire变量。

线网的多种类型 。寄存器的类型。

5.1.4 Expressions

用括号来表示执行的优先级。尽管操作符本身有优先顺序, 但用括号来表示优先级对读者更清晰, 更有意义。


 If ((alpha < beta) && (gamma >= delta)).... 比下面的表达更合意 。  
If (alpha < beta && gamma >= delta)...

用一个函数(function)来代替表达式的多次重复

如果代码中发现多次使用一个特殊的表达式 ,那么就用一个函数来代替。这样在以后的版本升级时更便利 ,这种概念在做行为级的代码设计时同样使用 ,经常使用的一组描述可以写到一个任务(task)中 。

5.1.5 IF 语句

向量比较时 比较的向量要相等。

当比较向量时 ,verilog将对位数小的向量做 0 扩展以使它们的长度相匹配 ,它的自动扩展为隐式的。建议采用显示扩展 ,这个规律同样适用于向量同常量的比较。


 Reg Abc [7:0];  Reg Bca [3:0];  ......
 If (Abc = = {4’b0, Bca})begin  .......
 If (Abc = = 8’b0) begin

每一个If 都应有一个else 和它相对应。

在做硬件设计时 ,常要求条件为真时执行一种动作而条件为假时执行另一动作,即使认为条件为假不可能发生。没有else可能会使综合出的逻辑和RTL级的逻辑不同。如果条件为假时不进行任何操作,则用一条空语句.


 always @(Cond)  begin
 if (Cond)  DataOut <= DataIn;
 End  // Else  以上语句DataOut会综合成锁存器.

应注意If ..else if ...else if ...else 的优先级

如果变量在If-else 或case 语句中做非完全赋值, 则应给变量一个缺省值 ,即,


 V1 = 2’b00;  V2 = 2’b00;  V3 = 2’b00;
 If (a = = b) begin  V1 = 2’b01; //V3 is not assigned
 V2 = 2’b10;
 End Else if (a = = c) begin  
V2 = 2’b10; //V1 is not assigned  
V3 = 2’b11;
 End Else ;;

5.1.6 case 语句

case语句通常综合成一级多路复用器 (图的右边部分), 而if-then-else则综合成优先编码的串接的多个多路复用器, 如图的左边部分。通常 ,使用case 语句要比if语句快 ,优先编码器的结构仅在信号的到达有先后时使用。条件赋值语句也能综合成多路复用器, 而case 语句仿真要比条件赋值语句快。

寄存器

所有的Case 应该有一个default case 允许空语句 Default : ;

5.1.7 Writing functions

在function的最后给function赋值.


 Function CompareVectors; // (Vector1, Vector2, Length)  
Input [199:0] Vector1, Vector2;  
Input [31:0] Length;  //local variables
 Integer i;
 Reg Equal;
 Begin
  i = 0;  
 Equal = 1;  
 While ((i  If (Vector 2[i] !== 1’bx) begin     
If (Vector1[i] !== Vector2[i])   
  Equal = 0;  
  Else ;   
End
   i = i + 1;
  End   CompareVectors = Equal;
End Endfunction //compareVectors

函数中避免使用全局变量 否则容易引起HDL行为级仿真和门级仿真的差异 如


function ByteCompare  input [15:0] Vector1
 input [15:0] Vector2  input [7:0] Length  begin
 if (ByteSel)  // compare the upper byte
 else  // compare the lower byte  
 end endfunction // ByteCompare 中使用了全局变量ByteSel, 可能无意在别处修改了 ,导致错误结果。最好直接在端口加以定义 。注意 函数与任务的调用均为静态调用。

5.1.8 Assignment

Verilog 支持两种赋值 :过程赋值(procedural) 和连续赋值(continuous)。过程赋值用于过程代码 initial,   always, task or function)中给reg 和 integer变量 time ealtimereal赋值,   而连续赋值一般给wire 变量赋值。


 Always @(敏感表 敏感表要完整 如果不完整 将会引起仿真和综合结果不一致  always @(d or Clr)   if (Clr)    q = 1'b0;  else if (e)    q = d; 以上语句在行为级仿真时e的变化将不会使仿真器进入该进程,导致仿真结果错误

Assign/deassign 仅用于仿真加速 仅对寄存器有用  。

Force/release 仅用于debug 对寄存器和线网均有用 。

避免使用Disable。

对任何reg赋值用非阻塞赋值代替阻塞赋值 reg 的非阻塞赋值要加单位延迟 ,但异步复位可加可不加 。

=与 =的区别


 Always @(posedge Clk or negedge Rst_)  Begin   
If (!Rst_)  // prioritize the “if conditions” in if statement
   Begin    
 Rega <= 0; //non_blocking assignment     
Regb <= 0;   
 End   Else if (Soft_rst_all)
     Begin  
   Rega <= #u_dly 0; //add unit delay   
  Regb <= #u_dly 0;  
  End   Else if (Load_init)   
 Begin    
 Rega <= #u_dly init_rega;  
  Regb <= #u_dly init_regb;   
 End   Else    Begin  
   Rega <= #u_dly Rega << 1;    
 Regb <= #u_dly St_1;   
 End End // end Rega, Regb assignment.

5.1.9 Combinatorial Vs Sequential Logic

如果一个事件持续几个时钟周期 设计时就用时序逻辑代替组合逻辑 。如


Wire Ct_24_e4; //it ccarries info. Last over several clock cycles
 Assign Ct_24_e4 = (count8bit[7:0] >= 8’h24) 
& (count8bit[7:0] <= 8’he4); 那么这种设计将综合出两个8 比特的加法器 而且会产生毛刺 对于这样的电路 要采用时序设计 代码如下

 Reg Ct_24_e4;
 Always @(poseddge Clk or negedge Rst_)  Begin  
 If (!Rst_)    Ct_24_e4 <= 1’b0;
  Else if (count8bit[7:0] = = 8’he4)   
 Ct_24_e4 <= #u_dly 1’b0;  
 Else if (count8bit[7:0] = = 8’h23)  
  Ct_24_e4 <= #u_dly 1’b1;  
 Esle ;   //内部总线不要悬空 在default状态 要把它上拉或下拉.
  Wire OE_default;   
Assign OE_default = !(oe1 | oe2 | oe3);  
 Assign bus[31:0] =  oe1 ? Data1[31:0] :  
      oe2 ? Data2[31:0] :     
   oe3 ? Data3[31:0] :   
     oe_default ? 32’h0000_0000 :
       32’hzzzz_zzzz;

5.1.10Macros

为了保持代码的可读性 常用  “ `define ”   做常数声明。

把“define”放在一个独立的文件中 参数 parameter 必须在一个模块中定义 不要传替参数到模块 仿真测试向量例外 “define”可以在任何地方定义 要把所有的“define”定义在一个文件中 在编译原代码时首先要把这个文件读入 如果希望宏的作用域仅在一个模块中 就用参数来代替。

5.1.11Comments

对更新的内容更新要做注释。

在语法块的结尾做标记。


 //style 1  
If (~OE_ && (state != PENDING)) begin  ....  End // if enable = = ture and ready  //style 2 --- identical lables on begin and end
 If (~OE_ && (state != PENDING)) begin //drive data  
....  End //drive data  // Comment end with the name of the 
 Function Calcparity //Data, ParityErr  ....  Endfunction // Calcparity

每一个模块都应在模块开始处做模块级的注释 参考前面标准模块头 。

在模块端口列表中出现的端口信号 都应做简要的功能描述。

5.1.12 FSM

VerilogHDL状态机的状态分配 VerilogHDL描述状态机时必须由parameter分配好状态,这与VHDL不同 VHDL状态机状态可以在综合时分配产生。

组合逻辑和时序逻辑分开用不同的进程。组合逻辑包括状态译码和输出 时序逻辑则是状态寄存器的切换。

必须包括对所有状态都处理 不能出现无法处理的状态 使状态机失控  。

Mealy机的状态和输入有关,而Moore机的状态转换和输入无关。

Mealy 状态机的例子如下:

 ...  reg CurrentState, NextState, Out1;

 Parameter S0=0,S1=1;  always @(posedge Clk o
r negedge Rst_)  // state vector flip-flops (sequential)  
 if (!Reset)   CurrentState = S0;  
 else   CurrentState <= #u_dly NextState;
 always @(In1 or In2 or CurrentState)  
 // output and state vector decode (combinational)  
 case (CurrentState)
  S0: begin  
 NextState <= #u_dly S1;   
Out1 <= #u_dly 1'b0;  end  
 S1: if (In1) begin
  NextState <= #u_dly S0;
  Out1 <= #u_dly In2;  
 end   else begin
  NextState <= #u_dly S1;
  Out1 <= #u_dly !In2;
  end  
 endcase  endmodule

编辑:黄飞

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分