这篇帖子用于记录学习Verilog过程中的一些syntax的问题,会不断更新,有不正确的地方请各位帮忙指正:D
一.Verilog 语法中的可综合性
 Verilog HDL 真的很强大,如果程序只用于仿真,那么几乎所有的语法和编程语句都可以使用。但如果程序是用于硬件实现,那么我们就必须保证程序的可综合性,即所编写的程序能被综合器 转化为相应的电路结构。不可综合的HDL语句在用综合工具综合时将被忽略或者报错。作为设计者,应该对可综合模型的结构有所了解。
 虽然不同的综合工具对Verilog HDL语法结构的支持不尽相同,但Verilog HDL中某些典型的结构是很明确地被所有综合工具支持或不支持的。
 (1)所有综合工具都支持的结构:
 always,assign,begin,end,case,wire,tri,aupply0,supply1,reg,integer,default,for,
 function,and,nand,or,nor,xor,xnor,buf,not,bufif0,bufif1,notif0,notif1,if,inout,
 input,instantitation,module,negedge,posedge,operators,output,parameter。
 (2)所有综合工具都不支持的结构:time,defparam,$finish,fork,join,initial,delays,UDP,wait。
 (3)有些工具支持有些工具不支持的结构:casex,casez,wand,triand,wor,trior,real,disable,forever,arrays,memories,repeat,
 task,while。
 看到一些资料上说其实Verilog HDL的产生是为了写testbench,而编程设计只用到了其中的很少的部分。Verilog有人说很好学,很容易入手,但是我觉得仅仅入手是没有用的,充其量就鸡肋一根,一定要仔细深入研究语法和结构,这样才能写出高效率的代码,否则基本的代码一塌糊涂的话后面的功能仿真,时序仿真都是浮云。
 |
 |
 二.避免锁存器
   在 always 块的 if..else 语句中如果所列的条件不完整,综合时则会产生锁存器。
 example:
 always @(action) 
if(action) out1 <= 1'b1;
 if(action) out1 <= 1'b1;
没有考虑到 !action 的情况,默认out1保持不变,这就产生了锁存器。
优化方法:1.列出 !action 的情况,2.对out1赋初始值
 1.always @(action) 
if(action) out1 <= 1'b1;
 if(action) out1 <= 1'b1;
else    out1 <= 1'b0;
 |
 2.always @(action)  begin
 out <= 1'b0;
 if(action)  out1 <= 1'b1;
 end
  但是,在描述时序逻辑的时候,也通常利用 if 语句的隐式条件对带时钟使能的 D 触发器建模
 example:
 always@(posedge clk, negedge rst_n)  begin
 if(!rst_n)  sum <= 0;
 else if(EN)  sum <= a+b;
 表示在时钟正沿来临时,如果 EN 为 1 ,则将 a+b 的值赋给 sum, 言下之意是如果 EN 为 0, 那么 sum 保持原值不变。这里综合工具会把代码综合成一个带时钟使能的 D 触发器。
  三.产生占空比不等于50%的波形 (状态机的巧用)
 在面试的时候常常看到一些对verilog用得不熟的同学,在被要求写出可综合的RTL代码并产生占空比不同的输出脉冲时,选择用很多计数器来对输入的脉冲进行计数,而且还分别对输入脉冲的上升沿和下降沿进行计数,非常的糟糕,因为输入的脉冲一般只能保证一个触发沿是稳定的
 如果要产生占空比相同的波形,那么计数器可以很简单的搞定。
 例如:将一个200kHz的时钟做2分频,4分频,8分频,这时候你也许会想到用PLL,但是这里的时钟速率是kHz级别,很低,无法使用PLL。
 可以这样设计:
 reg [2:0] cnt;
always @(posedge clk_200k, negedge rst_n)
if(!rst_n)
cnt <= 3'b000;
else
cnt <= cnt + 1'b1;
assign clk_100k = cnt[0];
assign clk_50k = cnt[1];
assign clk_25k = cnt[2];
如要要求产生一个占空比为1:4的波形,用计数器实现的话就很麻烦了,在这种时候就可以用一个简单的状态机来实现。
 000->001->110->100->010->
 |               |
 <----<----<----<----<----<-
 利用状态机就很简单的实现了占空比不同的波形的产生。
 代码如下:
  1   reg [2:0] state;
2
3 always @(posedge clk, negedge rst_n)
4 if(!rst_n)
5 state <=3'b000;
6 else
7 case (state)
8 3'b000: state <= 3'b001;
9 3'b001: state <= 3'b110;
10 3'b110: state <= 3'b100;
11 3'b100: state <= 3'b010;
12 3'b010: state <= 3'b000;
13 default : state <=3'b000;
14 endcase
15
16 assign clk_out = state[0];
17
 2
3 always @(posedge clk, negedge rst_n)
4 if(!rst_n)
5 state <=3'b000;
6 else
7 case (state)
8 3'b000: state <= 3'b001;
9 3'b001: state <= 3'b110;
10 3'b110: state <= 3'b100;
11 3'b100: state <= 3'b010;
12 3'b010: state <= 3'b000;
13 default : state <=3'b000;
14 endcase
15
16 assign clk_out = state[0];
17
仿真波形:
  状态机的设计水平直接反映了工程师的逻辑功底,要写好状态机就一定要多练习。