原创 我的Verilog 代码风格-供参考

2007-10-17 14:29 3480 8 6 分类: FPGA/CPLD

Description
本文主要是收集一些重要的Verilog coding style。一个好的coding style可以减少错误的发生,增加电路的效能,以及较好的可读性。


Text
The order of module signals
一个module signal顺序如下 (由左至右):


Input
clock signals(clk_*)
set/reset signals(set_*, rst_*)
enable/disble signals(en_*, dis_*)
read/write enable signals(we_*, re_*, rw_*)
control signals(i_*)
address signals(i_*)
data signals(i_*)
Output
clock signals(o_clk_*)
set/reset signals(o_set_*, o_rst_*)
enable/disable signals(o_en_*, o_dis_*)
control signals(o_*)
address signals(o_*)
data signals(o_*)
In/Out
control signals(io_*)
address signals(io_*)
data signals(io_*)
Naming Rule
以下的namign rule为个人使用的规则。


命名方式分类
底线分隔型:xxx_yyy_zzz
大写底线分隔型:XXX_YYY_ZZZ
首字大写型:AbcDefGhi
首字小写型:avcDefGhi
各种元素所使用的命名
文件名称:底线分隔型, Ex: xxx_yyy_zzz.v
module名称:底线分隔型, Ex: xxx_yyy_zzz
module instance名称:底线分隔型, Ex: xxx_yyy_zzz
local wire名称:底线分隔型:Ex: xxx_yyy_zzz
local reg名称:底线分隔型, Ex: xxx_yyy_zzz
input signal名称:前置i_的底线分隔型, Ex: i_xxx_yyy_zzz
output signal名称:前置o_的底线分隔型, Ex: o_xxx_yyy_zzz
input/output signal名称:前置io_的底线分隔型, Ex: io_xxx_yyy_zzz
常数名称:大写底线分隔型, `XXX_YYY_ZZZ
parameter参数名称:大写底线分隔型, Ex: XXX_YYY_ZZZ
block名称:大写底线分隔型, Ex: XXX_YYY_ZZZ
特殊讯号名称
单一的clock signal: clk
多个clock signal: clk_xxx
负缘触发的clock signal: clk_n, clk_xxx_n
单一的reset signal: rst
多个reset signal: rst_xxx
负缘触发的reset signal: rst_n , rst_xxx_n
单一的set signal: set
多个set signals: set_xxx
负缘触发的set signals: set_n, set_xxx_n
致能讯号: en_xxx
除能讯号: dis_xxx


Procedural Assignments
使用指引



在撰写sequential logic时,使用nonblocking assignment。
在撰写latches电路时,使用nonblocking assignment。
在always block中撰写conbinational logic时,使用blocking assignment。
在同一个always block中同时撰写sequential及combinational logic时,一律使用nonblocking assignment。
别在同一个always block中混合使用nonblocking及blocking assignment。
别在两个以上的always block中对同一个变量设定数值。
使用$strobe来显示由nonblocking assignment所给定的变量。
不要对assignment使用#0延迟设定。
在procedural assignment中,LHS一定要是reg型态。非procedural assignment一定是net的型态。
常用的style
Combination logic
在always block中,如果使用combination logic,应当使用blocking assignment.


// All inputs used within always block should be listed in sensitive list.
always @(in1 or in2 or in3)
begin
  xxx = in1 ^ in2 & in3;
end
Sequential logic
在always block中,如果使用sequential logic,应当使用nonblocking assignment.


// Synchronous reset. The rst_n is NOT in sensitive list.
always @(posedge clk)
  begin
    if (~rst_n)
        begin
      xxx <= `INIT_VAL;
        end
    else
        begin
      xxx <= yyy;
        end
  end


// Asynchronous reset. The rst_n IS in sensitive list.
always @(posedge clk or negedge rst_n)
  begin
    if (~rst_n)
      begin
        xxx <= `INIT_VAL;
      end
    else
      begin
        xxx <= yyy;
      end
  end
Delay的建模
Combination logic
建模没有delay时,使用blocking assignment(ex: a = b;)
建模有惯性(inertial) delay时(即glitch不会传到后面的电路中)。使用delayed evaluation blocking assignments(#10 a = b;).
建模传输(transport)delay时(即glitch也会一并传到后面的电路中)。使用delayed assignment nonblocking assignments(ex: a <= #10 b;).
Sequential logic
建模没有delay时,使用non-blocking assignments (ex: q <= d; ).
建模有delay时,使用delayed assignment nonblocking assignments(ex: q <= #10 d;).


Finite State Machine
Moore FSM: 输出与输入没有直接关系。
由两个always block构成,一个是sequential block用来处理状态的变化。另一个为combinational block用来处理状态与输入之间的关系。注意,在sequential block中应全部使用nonblocking assignment。在combinational block中应使用blocking assignment。在某些简单的case中,combinational block也可直接由continuous assignment来取代。下面的范例是一般简单的FSM。 


// Sequential always block.
always @(posedge clk or posedge rst)
  begin
    if (rst)
      state <= STATE_IDLE;
    else
      state <= next;
  end


// Combinational always block.
always @(state or input1 or input2 ... or inputN)
  begin
    next = STATE_IDLE;
    outputs = OUTPUT_IDLE:
    case (state)
      STATE_IDLE:
        begin
          ... // the logic to determine the next state.
          next = STATE_?????;
        end
      STATE_?????:
        begin
          ... // the logic to determine the next state.
          next = STATE_?????;       
          outputs = ?????; // The output of this state.
        end
    endcase
  end
针对simplified one-hot encoding的FSM范例:


// Sequential always block.
always @(posedge clk or posedge rst)
  begin
    if (rst)
      state <= n'b0;
      state[STATE_DEFAULT] <= 1'b0;
    else
      state <= next;
  end


// Combinational always block.
always @(state or input1 or input2 ... or inputN)
  begin
    next = n'b0;
    outputs = OUTPUT_DEFAULT:
    case (1'b1)  // synopsys full_case parallel_case
      state[STATE_DEFAULT]:
        begin
          ... // the logic to determine the next state.
          next[STATE_?????] = 1'b1;
        end
      state[STATE_?????]:
        begin
          ... // the logic to determine the next state.
          next[STATE_?????] = 1'b1;
          outputs = ?????; // The output of this state.
        end
      // synopsys translate_off
      default:
        $display("Bad state!!");
      // synopsys translate_on
    endcase
  end
针对simplified one-hot with zero-idle encoding的FSM:


// Sequential always block.
always @(posedge clk or posedge rst)
  begin
    if (rst)
      state <= n'b0;
    else
      state <= next;
  end


// Combinational always block.
always @(state or input1 or input2 ... or inputN)
  begin
    next = n'b0;
    outputs = OUTPUT_DEFAULT:
    case (1'b1)  // synopsys full_case parallel_case
      ~|state:  // IDLE
        begin
          ... // the logic to determine the next state.
          next[STATE_?????] = 1'b1;
        end
      state[STATE_?????]:
        begin
          ... // the logic to determine the next state.
          next[STATE_?????] = 1'b1;
          outputs = ?????; // The output of this state.
        end
      // synopsys translate_off
      default:
        $display("Bad state!!");
      // synopsys translate_on
    endcase
  end
Mealy FSM: 输出与输入有直接关系。
Mealy FSM的作法与上面的范例相类似。唯一的不同在于outputs的指定,需加上与input相关的逻辑判断。例如:


case(state)  // synopsys parallel_case full_case
  ...
  STATE_?????:
    begin
    ...
    if (input1 & input2)
      outputs = ?????;
    else
      outputs = ?????;
    end
  // synopsys translate_off
  default:
    $display("Bad FSM.");
  // synopsys translate_on
  default   
endcase
Datapath
参考:Coding Guidelines for Datapath Synthesis.


有号数的计算:若有需要关于有号数的计算,应当利用Verilog 2001所提供的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的implicity signed extension,避免手动进行转换。


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't do this: assign o = a * b;
// The $signed({1'b0, a}) can convert the unsigned number to signed number.
assign o = $signed({1'b0, a}) * b;


input  signed  [7:0]  a;
output  signed  [15:0]  o;


// Don't do this: assign o = a * 8'b10111111;
// Use $signed() system task
assign o = a * $signed(8'b10111111);
// or sb keyword.
assign o = a * 8'sb10111111;
part-select运算过后的操作数是无号数。就算是选择的范围包含整个register或wire。
input  signed  [7:0]  a;
input  signed  [7:0]  b;
output  signed  [15:0]  o1, o2;


// Don't do this: assign o1 = a[7:0];
assign  o1 = a;
// Don't do this: assign o2 = 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;


assign o = a + b;  // 9 bits.


对一个表示式而言,最大宽度的操作数决定了整体的宽度。
input  signed  [3:0]  a;
input  signed  [7:0]  b;
output    [11:0]  o;
wire  signed  [11:0]  o_sgn;


// Don't do this: assign o = $unsigned(a * b);  这将会是一个8 bit的运算。因为在刮号内的bits数是依据最大操作数b的宽度决定的。
assign   o_sgn = a * b;  // 12 bits。因为bit数是依据LHS宽度决定的。
assgign o = $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't do this: assign o = (a + b) > (c * d); 因为(a + b)及(c * d)都会是8 bit的结果。
assign  tmp1 = a + b;  // 16 bits.
assign  tmp2 = c * d;  // 16 bits.
assign  o = tmp1 > tmp2;  // 1 bit.

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户1846087 2015-10-9 08:45

非常有用

用户1182575 2012-5-20 12:01

用户1356205 2007-10-17 16:34

good,thx
相关推荐阅读
用户1113192 2011-02-09 17:26
2011 新的一年 共同进步
空间荒废了一年了,今天打开了 呵呵  还在。 真是对不起各位大侠了。有需求发我邮箱吧。wwh_nuaa@163.com.   明天开始上班了。祝大家心情愉快。大展宏图。...
用户1113192 2009-05-27 15:05
高级加密标准(AES)算法
高级加密标准(AES)算法...
用户1113192 2009-05-27 14:59
分组对称加密模式:ECB/CBC/CFB/OFB缺CTR- -
分组对称加密模式:ECB/CBC/CFB/OFB缺CTR- -                                       【虎.无名】一般的加密通常都是块加密,如果要加密超过块大小的...
用户1113192 2009-05-27 14:57
基于AES算法的WLAN安全机制分析
基于AES算法的WLAN安全机制分析Performance Analysis of AES-Based WLAN Security刘永元,张联峰,刘乃安摘要:高级加密标准(AES)加密算法Rijnda...
用户1113192 2009-05-23 14:27
工作日志
 xilinx 11.1 update pdf ...
用户1113192 2009-05-18 08:33
图文并茂VLAN全接触
https://static.assets-stash.eet-china.com/album/old-resources/2009/5/18/3f8b27e9-5417-46f5-897f-dc13...
EE直播间
更多
我要评论
2
8
关闭 站长推荐上一条 /3 下一条