verilog基础tips

时间:2021-02-23
本文章向大家介绍verilog基础tips,主要包括verilog基础tips使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1、阻塞赋值和非阻塞赋值

阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句

非阻塞:当前语句的执行不会阻塞下一语句的执【非阻塞相对于阻塞赋值多出一个触发器,时序逻辑中要用非阻塞赋值<=】

阻塞赋值:在复位信号无效后第一个时钟周期a=0,b=0,c=0

    always@(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
             a=0;
             b=1;
             c=2;
        end
        else begin
             b=a;
             c=b;
        end 
    end

 非阻塞赋值:在复位信号无效后第一个时钟周期a=0;b=1;c=2;

    always@(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
             a<=0;
             b<=1;
             c<=2;
        end
        else begin
             b<=a;
             c<=b;
        end 
    end

2、if else 语句

具有优先级的if else 语句过多会造成时钟频率的下降


3、时钟分频

参考:偶数分频,奇数分频,半整数分频,小数分频

参考:小数分频

参考:任意小数分频

在一般情况下,应用到时钟分频尽量用IP核,因为这样的时钟偏斜比较小。(时钟偏斜:同一时钟到达不同寄存器的延时不同)

尽量不用自己分频出来的信号直接作为时钟,可以加入标志信号,在利用源时钟的情况下加入标志信号实现原本的功能

module cnt(
    input   clk,
    input   rst_n,
    output  [ 3 : 0]         cnt
);
    always@(posedge clk or negedge rst_n)begin //进行四分频
        if(rst_n == 1'b0)
            div_cnt <= 'h0;
        else 
            div_cnt <= div_cnt + 1'b1;
    end

    always@(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)
            clk_4 <= 'h0;
        else if(div_cnt == 2'd1)
            clk_4 <= 'h1;
        else if(div_cnt == 2'd3)
            clk_4 <= 'h0;
    end
    
/*------\/--------  by $Tyz  2021-02-20  --------\/--------{{{
* 需要避免的写法,不用自己分频的信号直接作为时钟使用
    always@(posedge clk_4 or negedge rst_n)begin
        if(rst_n == 1'b0)
            cnt <= 'h0;
        else 
            cnt <= cnt + 1'b1;
    end
--------/\--------  by $Tyz  2021-02-20  --------/\------}}}*/

    always@(posedge clk or negedge rst_n)begin //建议使用的方式,利用flag信号
        if(rst_n == 1'b0)
            clk_flag <= 'h0;
        else if(div_cnt == 2'd1)
            clk_flag <= 'h1;
        else 
            clk_flag <= 'h0;
    end

    always@(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)
            cnt <= 'h0;
        else if(clk_flag)
            cnt <= cnt + 1'b1; 
    end


endmodule

3.1 偶数分频

经常用到的就是偶数分频

`timescale 1ns / 1ns
/********** 任意偶数分频器************/


module divider_even    #(parameter DIV = 4)(                    
    input            sys_clk,            
    input            sys_rst_n,
    input    [7:0]    M_N,            // 取代DIV了

    output     reg        div_clk            // 任意偶数数分频输出时钟
    
);
    
    reg        [7:0]    cnt;
    
    always@(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            cnt <= 0;
        else if(cnt == M_N-1)
            cnt <= 0;
        else 
            cnt <= cnt + 1;
    end
    
    always@(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            div_clk <= 1'b0;
        else if((cnt == 0) || (cnt == (M_N/2)))
            div_clk <= ~div_clk;
        else
            div_clk <= div_clk;
    end
        
endmodule

3.2 奇数分频:

3.2.1 奇数分频可以直接采用计数器进行得到,如5分频就可以进行模5计数,在等于5的时候拉高,否则拉低信号,则可得到占空比为1/5的分频信号

3.2.2 奇数分频要要求占空比为50%。

    首先进行模5计数

    而后利用clk的上升沿连续拉低pos_clk三个时钟,而后连续拉高两个时钟周期。

    之后再利用clk的下降沿连续拉低neg_clk三个时钟,而后拉高两个时钟周期。

    最后对pos_clk 和neg_clk 进行或运算得到输出的分频时钟

    tips:上面的拉高拉低可以互换,最后的结果都是相同的(但此时最后的输出为pos_clk和neg_clk与运算

//奇数分频 N分频

//  .   .   .   1       2       3       4       5       6       7       8       9      10      11      12      13      14      15      16    
//          +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +
// clk      |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
//          +   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+   +---+

//          - ------- ------- ------- ------- ------- ---------------------------------------------------------------------------------------
// bus       X   0   X   1   X   2   X   3   X   4   X                                                                                       
//          - ------- ------- ------- ------- ------- ---------------------------------------------------------------------------------------

//                                  +---------------+                                                                                       
// pos_clk                          |               |                                                                                          
//          ------------------------+               +---------------------------------------------------------------------------------------
          
//          --+                         +---------------+                                                                                       
// neg_clk    |                         |               |                                                                                           
//            +-------------------------+               +---------------------------------------------------------------------------------------

//          --+                     +-------------------+                                                                                          
// clk_out    |                     |                   |                                                                                            
//            +---------------------+                   +-------------------------------------------------------------------------------------------
module even_divider(
    clk,
    rst_n,
    clk_out
);

    input                                   clk;
    input                                   rst_n;
    output                                  clk_out;

    reg                                     pos_clk;
    reg                                     neg_clk;
    reg               [ 7 : 0]              div_cnt;
    
    parameter   DIV_NUM = 5; //其中N为奇数

    always@(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)
            div_cnt <= 'h0;
        else if(div_cnt == DIV_NUM-1)
            div_cnt <= 'h0;
        else 
            div_cnt <= div_cnt + 1'b1;
    end

    //pos_clk
    always@(posedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)
            pos_clk <= 'h0;
        else if((div_cnt >= (DIV_NUM-1)/2) && (div_cnt <= DIV_NUM-1))
            pos_clk <= 'h0;
        else
            pos_clk <= 'h1;
    end

    //neg_clk
    always@(negedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)
            neg_clk <= 'h0;
        else if((div_cnt >= (DIV_NUM-1)/2) && (div_cnt <= DIV_NUM-1))
            neg_clk <= 'h0;
        else 
            neg_clk <= 'h1;
    end

    assign clk_out = pos_clk | neg_clk;

endmodule

3.2.3 小数分频

  tips:一般情况下,自己设计的小数分频对时序要求很高的电路并不使用,可以使用软件自带的IP进行小数分频的设计


4、状态机

状态机可分为mealy型和moore型:

按照写法状态机可分为一段式,二段式,三段式:

二段式状态机可以避免三段式状态机中由于组合逻辑而产生的的竞争冒险现象,同时减少代码复杂度。

而时钟采到毛刺的概率较低,可以有效消除毛刺影响


原文地址:https://www.cnblogs.com/tianyuzh/p/14412412.html