美文网首页
一些Verilog的小东西

一些Verilog的小东西

作者: 今日你学左米啊 | 来源:发表于2019-07-23 17:10 被阅读0次

    一些Verilog的小东西

    [TOC]

    常用小模块

    1. 奇数次分频
    
    module fdiv5(input clk,output k_or,k1,k2);
    reg [2:0] c1,c2;
    reg M1,M2;
    
    always @ (posedge clk )
        begin 
        if(c1 == 4) c1<=0 ; else c1<=c1+1;
        if(c1 == 1) M1<=~M1; else if(c1 ==3) M1<=~M1; 
        end
    always @ (negedge clk )
        begin 
        if(c2 == 4) c2<=0; else c2 <=c2+1;
        if(c2 == 1)  M2<=~M2 ; else if (c2 == 3) M2<=~M2;
        end
        
    assign k1 = M1; assign k2=M2;
    assign k_or = k1|k2;
    
    endmodule
    
    
    1. PWM的FPGA控制
    module PWM_Generator_Verilog
     (
     clk, // 100MHz clock input 
     increase_duty, // input to increase 10% duty cycle 
     decrease_duty, // input to decrease 10% duty cycle 
     PWM_OUT // 10MHz PWM output signal 
        );
     input clk;
     input increase_duty;
     input decrease_duty;
     output PWM_OUT;
     wire slow_clk_enable; // slow clock enable signal for debouncing FFs
     reg[27:0] counter_debounce=0;// counter for creating slow clock enable signals 
     wire tmp1,tmp2,duty_inc;// temporary flip-flop signals for debouncing the increasing button
     wire tmp3,tmp4,duty_dec;// temporary flip-flop signals for debouncing the decreasing button
     reg[3:0] counter_PWM=0;// counter for creating 10Mhz PWM signal
     reg[3:0] DUTY_CYCLE=5; // initial duty cycle is 50%
      // Debouncing 2 buttons for inc/dec duty cycle 
      // Firstly generate slow clock enable for debouncing flip-flop (4Hz)
     always @(posedge clk)
     begin
       counter_debounce <= counter_debounce + 1;
       //if(counter_debounce>=25000000) then  
       // for running on FPGA -- comment when running simulation
       if(counter_debounce>=1) 
       // for running simulation -- comment when running on FPGA
        counter_debounce <= 0;
     end
     // assign slow_clk_enable = counter_debounce == 25000000 ?1:0;
     // for running on FPGA -- comment when running simulation 
     assign slow_clk_enable = counter_debounce == 1 ?1:0;
     // for running simulation -- comment when running on FPGA
     // debouncing FFs for increasing button
     DFF_PWM PWM_DFF1(clk,slow_clk_enable,increase_duty,tmp1);
     DFF_PWM PWM_DFF2(clk,slow_clk_enable,tmp1, tmp2); 
     assign duty_inc =  tmp1 & (~ tmp2) & slow_clk_enable;
     // debouncing FFs for decreasing button
     DFF_PWM PWM_DFF3(clk,slow_clk_enable,decrease_duty, tmp3);
     DFF_PWM PWM_DFF4(clk,slow_clk_enable,tmp3, tmp4); 
     assign duty_dec =  tmp3 & (~ tmp4) & slow_clk_enable;
     // vary the duty cycle using the debounced buttons above
     always @(posedge clk)
     begin
       if(duty_inc==1 && DUTY_CYCLE <= 9) 
        DUTY_CYCLE <= DUTY_CYCLE + 1;// increase duty cycle by 10%
       else if(duty_dec==1 && DUTY_CYCLE>=1) 
        DUTY_CYCLE <= DUTY_CYCLE - 1;//decrease duty cycle by 10%
     end 
    // Create 10MHz PWM signal with variable duty cycle controlled by 2 buttons 
     always @(posedge clk)
     begin
       counter_PWM <= counter_PWM + 1;
       if(counter_PWM>=9) 
        counter_PWM <= 0;
     end
     assign PWM_OUT = counter_PWM < DUTY_CYCLE ? 1:0;
    endmodule
    // Debouncing DFFs for push buttons on FPGA
    module DFF_PWM(clk,en,D,Q);
    input clk,en,D;
    output reg Q;
    always @(posedge clk)
    begin 
     if(en==1) // slow clock enable signal 
      Q <= D;
    end 
    endmodule
    
    1. 任意时钟分频
    // --------------------------------------------------------------------
    // Module Function:任意整数时钟分频
     
    module clkdiv ( clk,rst_n,clkout);
     
            input   clk,rst_n;                       //输入信号,其中clk连接到FPGA的C1脚,频率为12MHz
            output  clkout;                          //输出信号,可以连接到LED观察分频的时钟
            //parameter是verilog里常数语句
        parameter   WIDTH   = 3;             //计数器的位数,计数的最大值为 2**WIDTH-1
        parameter   N   = 5;             //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出
     
        reg     [WIDTH-1:0] cnt_p,cnt_n;     //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
        reg         clk_p,clk_n;     //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟
     
        //上升沿触发时计数器的控制
        always @ (posedge clk or negedge rst_n )         //posedge和negedge是verilog表示信号上升沿和下降沿
        begin
            if(!rst_n)
                cnt_p<=0;
            else if (cnt_p==(N-1))
                cnt_p<=0;
            else cnt_p<=cnt_p+1;             //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器
        end
     
            //上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
        always @ (posedge clk or negedge rst_n)
            begin
                if(!rst_n)
                    clk_p<=0;
                else if (cnt_p<(N>>1))          //N>>1表示右移一位,相当于除以2去掉余数
                    clk_p<=0;
                else 
                    clk_p<=1;               //得到的分频时钟正周期比负周期多一个clk时钟
            end
    
        //下降沿触发时计数器的控制          
    always @ (negedge clk or negedge rst_n)
        begin
            if(!rst_n)
                cnt_n<=0;
            else if (cnt_n==(N-1))
                cnt_n<=0;
            else cnt_n<=cnt_n+1;
        end
    
        //下降沿触发的分频时钟输出,和clk_p相差半个时钟
    always @ (negedge clk)
        begin
            if(!rst_n)
                clk_n<=0;
            else if (cnt_n<(N>>1))  
                clk_n<=0;
            else 
                clk_n<=1;                //得到的分频时钟正周期比负周期多一个clk时钟
        end
     
            assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p;      //条件判断表达式
                                                                        //当N=1时,直接输出clk
                                                                        //当N为偶数也就是N的最低位为0,N(0)=0,输出clk_p
                                                                        //当N为奇数也就是N最低位为1,N(0)=1,输出clk_p&clk_n。正周期多所以是相与
    endmodule     
    
    1. 格雷码计数器
    module GrayCounter(
      input clk,
      output [3:0] cnt_gray
    );
    
    reg [3:0] cnt = 0;
    always @(posedge clk) cnt <= cnt+1;  // 4bit binary counter
    
    assign cnt_gray = cnt ^ cnt[3:1];  // then convert to gray
    endmodule
    
    
    
    module GrayCounter(
      input clk,
      output reg [3:0] cnt_gray = 0
    );
    
    wire [3:0] cnt_cc = {cnt_cc[2:1] & ~cnt_gray[1:0], ^cnt_gray, 1'b1};  // carry-chain type logic
    always @(posedge clk) cnt_gray <= cnt_gray ^ cnt_cc ^ cnt_cc[3:1];
    
    endmodule
    
    1. 软件按键消抖
    module GrayCounter(
      input clk,
      output [3:0] cnt_gray
    );
    
    reg [3:0] cnt = 0;
    always @(posedge clk) cnt <= cnt+1;  // 4bit binary counter
    
    assign cnt_gray = cnt ^ cnt[3:1];  // then convert to gray
    endmodule
    
    
    
    module GrayCounter(
      input clk,
      output reg [3:0] cnt_gray = 0
    );
    
    wire [3:0] cnt_cc = {cnt_cc[2:1] & ~cnt_gray[1:0], ^cnt_gray, 1'b1};  // carry-chain type logic
    always @(posedge clk) cnt_gray <= cnt_gray ^ cnt_cc ^ cnt_cc[3:1];
    
    endmodule
    
    1. 正交信号解码
    module quad(clk,
                quadA,
                quadB,
                count);
        input clk, quadA, quadB;
        output [7:0] count;
        
        reg [2:0] quadA_delayed, quadB_delayed;
        always @( posedge clk ) quadA_delayed <= {quadA_delayed[1:0], quadA};
        always @( posedge clk ) quadB_delayed <= {quadB_delayed[1:0], quadB};
        
        wire count_enable    = quadA_delayed[1] ^ quadA_delayed[2] ^ quadB_delayed[1] ^ quadB_delayed[2];
        wire count_direction = quadA_delayed[1] ^ quadB_delayed[2];
        
        reg [7:0] count;
        always @( posedge clk )
        begin
            if ( count_enable )
            begin
                if ( count_direction ) count <= count+1; else count <= count-1;
            end
        end
        
    endmodule
    

    状态机

    这里给两种比较常见的写法
    a.

    module fsm(
    input x,
    input rst,
    input clk,
    
    output reg [1:0] y
    );
    parameter state_A = 3'd0 , state_B = 3'd1 , 
                 state_C = 3'd2 , state_D = 3'd3 , 
                 state_E = 3'd4 ;
    reg [2:0] state;
    
    always @(posedge clk or posedge rst)
    begin 
    if(rst)
        begin
        state <= state_A;
        y   <= 2'b00;
        end
    else
        case(state)
        state_A : begin
                        if(!x) state <= state_B; else state <= state_C;
                        y <= 2'b00;
                     end
        state_B : begin
                        if(!x) state <= state_D; else state <= state_C;
                        y <= 2'b00;
                     end
        state_C : begin
                        if(!x) state <= state_E; else state <= state_B;
                        y <= 2'b00;
                    end
        state_D : begin
                        if(!x) state <= state_D; else state <= state_C;
                        y <= 2'b01;
                    end
        state_E : begin
                        if(!x) state <= state_B; else state <= state_E;
                        y <= 2'b10;
                    end
        default : begin
                         state <= state_A; y <= 2'b00;
                     end
        endcase
    end
    
    endmodule
    
    

    b.

    module fsm2(
    input [3:0] row,
    input srow,
    input reset,
    input clk,
    output reg [3:0] col
    );
    
    parameter  S0 = 3'd0 , S1 = 3'd1 , 
                  S2 = 3'd2 , S3 = 3'd3 , 
                  S4 = 3'd4 , S5 = 3'd5 ;
    
    reg [3:0] current_state , next_state;
    
    always @(posedge clk or posedge reset)
    begin
        if(reset)
            current_state <= S0;
        else
            current_state <= next_state;
    end
    
    always @(*)
    begin
        case(current_state)
            S0:begin
                    next_state = (srow==1'b1) ? S1 : S0;
                    col       = 4'd15;
                end
            S1:begin
                    next_state = (row==4'd0) ? S2 : S5;
                    col       = 4'd1;
                end
            S2:begin
                    next_state =(row==4'd0) ? S3 : S5;
                    col       = 4'd2;
                end
            S3:begin
                    next_state = (row==4'd0) ? S4 : S5;
                    col       = 4'd3;
                end
            S4:begin
                    next_state = (row==4'd0) ? S0 : S5;
                    col       = 4'd4;
                end
            S5:begin
                    next_state = S5;
                    col       = 4'd5;
                end
        endcase 
    end
    
    endmodule
    

    懂的人自然都懂.建议用quartus写,然后看看RTL会贴心地给出状态描述图

    仿真的 $display $monitor $strobe的区别

    1. $display
      相当于c语言的printf,一旦程序触发到就立即显示

    2. $monitor
      一直以一个格式在追踪某几个变量或者表达式的变化

    一个程序里面只能有一个monitor在跑

    1. $strobe
      用于观察非阻塞赋值,在所在的always块结束后才会改变

    task 和function的区别

    这里也是给上一个功能一样,但是分别用task和function实现的代码

    1. task_test
    module task_test(data_in,data_out); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    
    task BCD2Access3; 
    output [3:0] data_out; 
    input [3:0] data_in; 
    
        data_out = data_in + 4'd3; 
    endtask 
    
    
    always @(data_in) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  BCD2Access3(data_out,data_in); 
    end 
    
    endmodule
    
    1. function_test
    module function_test(data_in,data_out); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    
    function BCD2Access3; 
    input [3:0] data_in; 
        BCD2Access3 = data_in + 4'd3; 
    endfunction 
    
    
    always @(data_in) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  data_out = BCD2Access3(data_in); 
    end 
    
    endmodule
    

    务必要注意两点:
    1. task可以有很多输入输出,但是例化的顺序和task里面写的input,output顺序是一致的,不能搞反
    2. function虽说看起来很C语言,但是要注意返回值就是他的名字(,剩下的都是输入

    相关文章

      网友评论

          本文标题:一些Verilog的小东西

          本文链接:https://www.haomeiwen.com/subject/shualctx.html