zoukankan      html  css  js  c++  java
  • [转帖]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
  • 相关阅读:
    Nginx 服务器安装及配置文件详解
    Linux 之 压缩解压缩
    RPM方式安装MySQL5.6
    Linux 之 搜索
    zabbix客户端安装
    JAVA输出指定目录下的子目录和子文件
    LoadRunner 11 安装破解
    SVN合并操作实践
    (转)SVN分支/合并原理及最佳实践
    MYSQL 免安装版(windows 7/64)
  • 原文地址:https://www.cnblogs.com/zlh840/p/2704221.html
Copyright © 2011-2022 走看看