[转帖]Verilog的语法及generate使用

verilog 单独文件调用 include

Verilog中可以使用预处理命令 `include "文件名" 来包含新文件。

`include "文件名"的位置需要在 module声明之后。

这里举个例子,param.h存放了参数LENTH,顶层mult.v使用了它。

mult.v代码如下

 1 module mult (
 2 input clk,
 3 input rst,
 4 input [LENTH-1:0] A,
 5 input [LENTH-1:0] B,
 6 output [LENTH-1:0] C
 7 );
 8 
 9 `include "param.h"
10 
11 reg [LENTH-1:0] c_reg;
12 
13 always@(posedge clk or negedge rst)
14 if(rst == 1'b0)begin
15     c_reg <= 32'b0;
16 end
17 else begin
18     c_reg <= A*B;
19 end
20 
21 assign C = c_reg;
22 
23 endmodule
aram.h代码如下
parameter LENTH = 32;

 



2014-04-10  15:39:17周四
verilog 条件编译命令`ifdef、`else、`endif 的应用(经常用于主程序中添加测试信息。。。)
通常在Verilog HDL程序中用到`ifdef、`else、`endif编译命令的情况有以下几种:
        •    选择一个模块的不同代表部分。 
        •    选择不同的时序或结构信息。
        •    对不同的EDA工具,选择不同的激励。
 1 module ifdef_test(out);
 2 output out;
 3 `define wow
 4 `define nest_one
 5 `define second_nest
 6 `define nest_two
 7 `ifdef wow
 8     initial $display("wow is defined");
 9     `ifdef nest_one
10         initial $display("nest_one is defined");
11         `ifdef nest_two
12             initial $display("nest_two is defined");
13         `else
14             initial $display("nest_two is not defined");
15         `endif
16     `else
17         initial $display("nest_one is not defined");
18     `endif
19 `else
20     initial $display("wow is not defined");
21     `ifdef second_nest
22         initial $display("second_nest is defined");
23     `else
24         initial $display("second_nest is not defined");
25     `endif
26 `endif
27 endmodule
View Code

 

 1 module ifdef_test(out);
 2 output out;
 3 `define wow
 4 `define nest_one
 5 `define second_nest
 6 `define nest_two
 7 `ifdef wow
 8     initial $display("wow is defined");
 9     `ifdef nest_one
10         initial $display("nest_one is defined");
11         `ifdef nest_two
12             initial $display("nest_two is defined");
13         `else
14             initial $display("nest_two is not defined");
15         `endif
16     `else
17         initial $display("nest_one is not defined");
18     `endif
19 `else
20     initial $display("wow is not defined");
21     `ifdef second_nest
22         initial $display("second_nest is defined");
23     `else
24         initial $display("second_nest is not defined");
25     `endif
26 `endif
27 endmodule

 

       运行结果为:

        # wow is defined
        # nest_one is defined
        # nest_two is defined

2013-06-28   08:32:40 周五
1、常量(constant)、参数(parameter)、块标号(block label)最好使用大写命名,变量(variable)、实例(instance)、结构
 代码1.1 模-m计数器(缺省为模-10计数器)
module mod_m_bin_counter 
#(parameter M=10) // mod-M 
( 
  // global clock and asyn reset 
  input clk, 
  input rst_n, 
  // counter interface 
  output max_tick, 
  output min_tick, 
  output [N-1:0] q 
); 
  
// signal declaration 
localparam N = log2(M); // number of bits in counter 
reg [N-1:0] r_reg; 
wire [N-1:0] r_next; 
  
// body 
// register 
always@(posedge clk, negedge rst_n) 
  if(!rst_n) 
    r_reg <= 0; 
  else
    r_reg <= r_next; 
     
// next-state logic 
assign r_next = (r_reg == (M-1)) ? 0 : r_reg + 1'b1; 
//output logic 
assign q = r_reg; 
assign max_tick = (r_reg == (M-1)) ? 1'b1 : 1'b0; 
  
  
// log2 constant function 
function integer log2(input integer n); 
  integer i; 
begin
  log2 = 1; 
  for(i=0; 2**i<n; i = i + 1) 
    log2 = i + 1; 
end
endfunction                 
endmodule 

根据这个模-m计数器,我们再写一个testbench。

使用动态索引的Verilog代码即用可变的索引或地址作为位选择或存储器元素 循环语句或算术运算符因为这些代码要被合并成大量难以优化的门。jitter抖动,skew倾斜。flip-flop触发器-边沿敏感,latch锁存器-电平敏感。阻塞赋值-值立即更新,含连续赋值和过程赋值。
offset补偿,preset预置。
 
1、可变索引位选择描述的多路开关
module BitSelect2(Din, BitSel, Dout);
input [3:0] Din;
input [1:0] BitSel;
output Dout;
reg Dout;
always @(Din or BitSel)
  Dout = Din[BitSel];
endmodule
2、可变索引位选择实现译码器
module BitSelectDecoder(Din, BitSel, Dout);
input Din;
input [1:0] BitSel;
output [3:0]Dout;
reg [3:0]Dout;
always @(Din or BitSel)
  Dout[BitSel] = Din;
endmodule
3、条件表达式的综合:assign Dout = (c1^c2) ? Din : 0;
4、always语句的综合
always语句中定义的变量都是临时变量。
对于纯组合逻辑,always语句中要使用完整的事件列表,而临时变量不需要列入。
5、if语句、case语句要采用完整的分支语句,否则会产生锁存器(电平敏感)。赋初值避免综合出锁存器。
用default分支语句避免综合出锁存器。使用"full_case"指令避免综合出锁存器。使用"parallel_case"指令避免综合出锁存器。
并行的case语句:
module parallelCase(key,decoder);
input [3:0] key;
output [1:0] decoder;
reg [1:0] decoder;
always @(key)
  casex(key) //synthesis parallel_case
    4'bxxx1: decoder = 0;//等价的if语句:if(key[0])  decoder = 0;
     4'bxx1x: decoder = 1;//if(key[1])  decoder = 1;
    4'bx1xx: decoder = 2;//if(key[2])  decoder = 2;
    4'b1xxx: decoder = 3;//if(key[3])  decoder = 3;
  endcase
endmodule//若不用 //synthesis parallel_case就会综合出优先级解码器。
将"full_case"综合指令用于条件表达式使用常量的case语句。
module parallelCase(key,decoder);
input [3:0] key;
output [1:0] decoder;
reg [1:0] decoder;
always @(key)
  casex(1) //synthesis full_case
    key[0]: decoder = 0;
     key[1]: decoder = 1;
    key[2]: decoder = 2;
    key[3]: decoder = 3;
  endcase
endmodule
//我想到的方法,用for循环。
module parallelCase(key,decoder);
input [3:0] key;
output [1:0] decoder;
reg [1:0] decoder;
always @(key)
begin: LOOP1
  integret i;
  decoder = 0;
  for(i=0,i<4,i=i+1)
    if(key[i]) decoder = i;
    else decoder = decoder;
end
endmodule
6、利用任务实现串行移位乘法器
module TaskMultiplier(clk, a, b, c)
input clk;
input [3:0] a, b;
output [7:0] c;
reg [7:0] c;
always @(posedge clk) begin
  multiply(a,b,c);
end
 
task multiply;
  input [3:0] a, b;
  output [7:0] c;
  begin: serialMult
           reg [3:0] tempa;
    reg [7:0] tempb, tempc;
    tempa = a;
    tempb = {4'b0, b};
    tempc = 0;
    repeat(4) begin//推荐使用,GOOD!
      if(tempa[0]) tempc = tempc+tempb;
       tempa = tempa>>1;
      tempb = tempb<<1;
    end
    c = tempc;
  end
endtask
或者用另外一种方法实现task功能,采用for语句静态循环描述的无符号乘法器。
task multiply;
  input [3:0] a, b;
  output [7:0] c;
  begin: serialMult
           integret i;
    reg [7:0] tempb, tempc;
    tempb = {4'b0, b};
    tempc = 0;//赋初值避免综合成锁存器。
    for(i=0;i<4;i=i+1) begin//不推荐
      if(a[i]) tempc = tempc+tempb;
      tempb = tempb<<1;
    end
    c = tempc;
  end
endtask
或者用优化的CODE,用while语句非静态循环描述无符号乘法器。非静态循环是指循环的次数是由运算中的某个变量决定,而不是编译器确定。但有的EDA不支持非静态循环。如QuartusII。好处是一旦a中的高位全为0,则整个乘法去处结束。这在数据字较长时有明显的效果。
task multiply;
  input [3:0] a, b;
  output [7:0] c;
  begin: serialMult
           reg [3:0] tempa;
    reg [7:0] tempb, tempc;
           reg [3:0] shift_cnt;
    tempa = a;
    tempb = {4'b0, b};
    tempc = 0;
    shift_cnt = 0;//calc the number of 1 in the tempa.
    while(|tempa) begin//推荐使用,GOOD!
      if(tempa[0]) tempc = tempc+tempb;
       tempa = tempa>>1;
      tempb = tempb<<1;
      shift_cnt = shift_cnt + 1;
    end
    c = tempc;
  end
endtask
endmodule
 
 
 
 
verilog之generate的使用 发布时间:2012-05-03 16:10:03
技术类别:CPLD/FPGA  

Verilog-2001添加了generate循环,允许产生module和primitive的多个实例化,同时也可以产生多个variable,net,tash,function,continous assignment ,initial和always。在generate语句中可以引入if-else和case语句,根据条件不同产生不同的实例。

为此,verilog-2001增加了以下关键字:generate, endgenerate, genvar, localparam。genvar为新增的数据类型,存储正的integer。在generate语句中使用的index必须定义成genvar类型。localparam与parameter有些类似,不过其不能通过redefinition改变值。除了可以在generate语句使用if-else,case外,还能使用for语句进行循环。

   实例1.generate-for循环:例化8-bit加法器

     generate

genvar i;

for (i=0; i<=7; i=i+1)

begin : for_name

adder add (a[8*i+7 : 8*i], b[8*i+7 : 8*i], ci[i], sum_for[8*i+7 : 8*i], c0_or[i+1]);

end

endgenerate

for循环以begin开始,end结束,begin后边必须有一个唯一的标识符。

在for循环里使用always语句:

generate

   genvar i;    

     //ant0

      for (i = 0; i < 11; i = i + 1) begin : carrier_iq_data_gen

           always @ (ul_a0_i_vld or ul_a0_q_vld) begin          

                  ul_a0_iq[i * 2]     = ul_a0_i_vld[i];               

                  ul_a0_iq[i * 2 + 1] = ul_a0_q_vld[i];                

           end

endgenerate

 

实例2.generate-if-else例化不同的实例:基于数据宽度,例化乘法器

generate

if (IF_WIDTH < 10)

begin : if_name

multiplier_imp1 # (IF_WIDTH) u1 (a, b, sum_if);

end

else

begin : else_name

multiplier_imp2 # (IF_WIDTH) u2 (a, b, sum_if);

end

endgenerate

 

实例3.generate-case例化不同的实例:基于数据宽度,例化加法器

generate

case (WIDTH)

1:

begin : case1_name

adder #(WIDTH*8) x1 (a, b, ci, sum_case, c0_case);

end

2:

begin : case2_name

adder #(WIDTH*4) x2 (a, b, ci, sum_case, c0_case);

end

default:

begin : d_case_name

adder x3 (a, b, ci, sum_case, c0_case);

end

endcase

endgenerate

2013-06-03  13:52:21 周一 阴
coeff多项式系数
parameter DYNAMIC_PREC = 16;
parameter DYNAMIC_LEVEL = 10;
parameter DYNAMIC_COEFF_0 = 0 * (2**DYNAMIC_PREC-1) / DYNAMIC_LEVEL;//the calculation is 0
parameter DYNAMIC_COEFF_1 = 1 * (2**DYNAMIC_PREC-1) / DYNAMIC_LEVEL;//the calculation is 6553
 2**DYNAMIC_PREC is 2^DYNAMIC_PREC
// log2 constant function
function integer log2(input integer n);
  integer i;
begin
  log2 = 1;
  for(i=0; 2**i<n; i = i + 1)
    log2 = i + 1;
end
endfunction
 
2013-05-31    09:51:10 周五 晴
Verilog中`include路径的设置  
在写Verilog的testbetch文件时,如果*.v文件中使用`include命令时,要特别的指名下路径,这是因为测试tb文件与代码rtl文件是在不同的目录下,只有指名调用路径才能跨目录仿真。例如:

project目录
---myproject(QuartusII 工程目录)
    |
    |---- comm  // 要include的文件存放的目录,文件为default_setting.v
    |
    |---- src     // 工程源代码(.v文件)存放目录
    |
    |---- sim(仿真工程目录)

按照上面的文档组织格式,如果src文件夹中的top.v文件中要include文件default_setting.v 则将下面的命令写入top.v文件
     `include "../comm/default_setting.v”

如果上面的形式不行,可以再加一级试下,我就再加一级可以。

     `include "../../comm/default_setting.v”

如果将所有的源码文件放在同一文件夹目录下,则可以直接使用`include "default_setting.v”命令,无需指定路径。

 
2012-11-12  周一 晴
 对于组合逻辑模式选择的写法可以有两种,一种是采用generate if  else  和 assign 语句实现的。另外一种是采用ifdef  else 和assign语句实现的。
对于时序逻辑可以采用case语句实现。
generate语句使用if-else,case外,还能使用for语句进行循环

语法
`ifdef MacroName
  VerilogCode...
[`else
  VerilogCode...]
`endif
规则
•  如果宏的名字已经用了`define 定义,那么只编译 Verilog 代码的第一个块。
•  如果没有定义宏的名字,而且出现`else 伪指令, 那么只编译第二个块。  
•  这些伪指令可以嵌套。
•  不被编译的代码都应是有效的 Verilog 代码。
`define primitiveModel

module Test;
...
`ifdef primitiveModel
  MyDesign_primitives UUT (...);
`else
  MyDesign_RTL UUT (...);
`endif
endmodule

 
 
 
 
来源:http://wenku.baidu.com/view/ab60218002d276a200292e51.html verilog中generate的用法。
 
格雷码与二进制的相互转换 Verilog实现:来源http://hi.baidu.com/hikyuu/item/297a050aa091cd026c9048aa
 
在红外线技术中使用的0.85或者0.95微米波段的谩射传输,它允许有两种速率:1M和2M速率,在1M速率上,采用的是格雷编码:它的编码原理是每四位一组,每个组被编码成一个16位的码字,任意两个相临位只有一个二进制数不同,它和奇偶校验码都属于可靠性编码.
    格雷码(Gray code)是由贝尔实验室的Frank Gray在1940年提出,用于在PCM(Pusle Code Modulation)方法传送讯号时防止出错,并于1953年三月十七日取得美国专利。格雷码是一个数列集合,相邻两数间只有一个位元改变,为无权数码,且格雷码的顺序不是唯一的。
直接排列
    以二进制为0值的格雷码为第零项,第一项改变最右边的位元,第二项改变右起第一个为1的位元的左边位元,第三、四项方法同第一、二项,如此反覆,即可排列出n个位元的格雷码。
    二进制数转格雷码
(假设以二进制为0的值做为格雷码的0)
格雷码第n位 = 二进制码第(n+1)位+二进制码第n位。不必理会进制。     Verilog 代码:gray=(binary>>1)^binary;
    格雷码转二进制数
二进制码第n位 = 二进制码第(n+1)位+格雷码第n位。因为二进制码和格雷码皆有相同位数,所以二进制码可从最高位的左边位元取0,以进行计算。      verilog 代码://------假设 reg [n-1] gray,binary;             integer i;             for(i=0;i<=n-1;i=i+1)              binary[i]= ^(gray>>i)//gray移位后,自身按位异或^(gray>>i)//第一次看到这样的用法,特意查了下verilog语法 Verilog 的位运算语法:  位逻辑运算符

在Verilog语言中有7种逻辑运算符:

1           ~   (非)

2           &   (与)

3           |   (或)

4           ^   (异或)

5           ^~  (同或)

6           ~&  (与非)

7           ~|  (或非)

位逻辑运算符对其自变量的每一位进行操作,例如,表达式A & B的结果是A和B的对应位相与的值。对具有不定值的位进行操作,视情况而定会得到不同的结果。例如:x和FALSE相与得结果x,x和TRUE相或得结果TURE。如果操作数的长度不相等,较短的操作数将用0来补位,逐位运算将返回一个与两个操作数中位宽较大的一个等宽的值。

在此需要注意的是,不要将逻辑运算符和位运算符相混淆,比如,!是逻辑非,而~是位操作的非,即按位取反,例如:对于前者!(5 = = 6)结果是TRUE,后者对位进行操作,~{1,0,1,1} = 0100。

 

 一元约简运算符

  约简运算符是单目运算符,也有与、或、非运算。其与、或、非运算规则类似于位运算符的与、或、非运算规则,但其运算过程不同。位运算是对操作数的相应位进行与、或、非运算,操作数是几位数则运算结果也是几位数。而约简运算则不同,约简运算是对单个操作数进行与、或、非递推运算,最后的运算结果是1位的二进制数。约简运算的具体运算过程是:1°先将操作数的第1位与第2位进行与、或、非运算;2°将运算结果与第3位进行与、或、非运算,依次类推,直至最后一位。

  例如:

      reg [3:0]  B;

      reg  C;

      C = &B;

  相当于:

      C = ( (B[0]&B[1]) & B[2] ) & B[3];

  一完整的模块举例如下:

  module reduction(a, out1, out2, out3, out4, out5, out6);

      input [3:0] a;

      output out1, out2, out3, out4, out5, out6;

      reg out1, out2, out3, out4, out5, out6;

     

    always @ (a)

    begin

      out1 = & a;     //与约简运算

      out2 = | a;         //或约简运算

      out3 = ~& a;        //与非约简运算

      out4 = ~| a;        //或非约简运算

      out5 = ^ a;     //异或约简运算

      out6 = ~^ a;        //同或约简运算

    end

 

  endmodule

    一. 自然二进制码转换为二进制格雷码
原理:若二进制码表示为: B[N-1]B[N-2]...B[2]B[1]B[0];相应地, 则二进制格雷码表示为: G[N-1]G[N-2]...G[2]G[1]G[0].其中最高位保留: G[N-1] = B[N-1];其他各位: G[i] = B[i+1] xor B[i]. (i = 0, 1, 2, ..., n-2) Binary_to_Gray.v / Verilog
module Binary_to_Gray (
  input       [N-1:0] B,
  output reg  [N-1:0] G
);
 
parameter N = N_bit_Binary; // 设置自然二进制码的位宽 integer i; always @ (B)
begin
  G[N-1] = B[N-1];
  for (i=0; i<N-1; i="i"+1)
    G[i] = B[i+1] ^ B[i];
end endmodule图2. N="4" 二. 二进制格雷码转换为自然二进制码
原理:若二进制格雷码表示为: G[N-1]G[N-2]...G[2]G[1]G[0];相应地, 则二进制码表示为: B[N-1]B[N-2]...B[2]B[1]B[0].其中最高位保留: B[N-1] = G[N-1];其他各位: B[i-1] = G[i-1] xor B[i]. (i = 1, 2, ..., n-1) Gray_to_Binary.v / Verilog
module Gray_to_Binary (
  input       [N-1:0] G,
  output reg  [N-1:0] B
); parameter N = B_bit_Gray; // 设置二进制格雷码的位宽 integer i; always @ (G)
begin
  B[N-1] = G[N-1];
  for (i=1; i<=N-1; i="i"+1)
    B[i-1] = G[i-1] ^ B[i];
end
 
endmodule

posted on 2012-09-26 16:29  zlh840  阅读(5171)  评论(1编辑  收藏  举报

导航