• 手撕代码——任意奇数分频


    手撕代码——任意奇数分频

    一、奇数分频器原理与设计

      在上文《手撕代码——任意偶数分频》中,我们编写任意偶数分频的Verilog代码,对时钟进行偶数分频,只需要用到时钟的上升沿或者下降沿即可,而要进行N倍奇数分频,需要同时用到时钟的上升沿和下降沿。对上升沿和下降沿分别设计一个上升沿计数器posedge_cnt和一个下降沿计数器negedge_cnt,计数器的位宽为 l o g 2 N log_2N log2N

    //上升沿计数器
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            posedge_cnt <= 'd0;
        else if(posedge_cnt == DIV_PARAM-1)
            posedge_cnt <= 'd0;
        else
            posedge_cnt <= posedge_cnt + 1'b1;
    end
    
    //下降沿计数器
    always @(negedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            negedge_cnt <= 'd0;
        else if(negedge_cnt == DIV_PARAM-1)
            negedge_cnt <= 'd0;
        else
            negedge_cnt <= negedge_cnt + 1'b1;
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

      同时根据上升沿计数器和下降沿计数器得到两个不同的时钟信号clk_1和clk_2,对这两个时钟信号clk_1和clk_2进行运算,得到目的分频时钟信号。在这里,可以通过或操作得到目的时钟信号。

    //或操作
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_1 <= 1'b0;
        else if(posedge_cnt > (DIV_PARAM>>1))
            clk_1 <= 1'b1;
        else
            clk_1 <= 1'b0;
    end
    
    always @(negedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_2 <= 1'b0;
        else if(negedge_cnt > (DIV_PARAM>>1))
            clk_2 <= 1'b1;
        else
            clk_2 <= 1'b0;
    end
    
    assign clk_o = clk_1 || clk_2;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

      同样的,也可以通过与操作得到目的分频时钟信号。

    //与操作
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_1 <= 1'b0;
        else if(posedge_cnt > (DIV_PARAM>>1)-1)
            clk_1 <= 1'b1;
        else
            clk_1 <= 1'b0;
    end
    
    always @(negedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_2 <= 1'b0;
        else if(negedge_cnt > (DIV_PARAM>>1)-1)
            clk_2 <= 1'b1;
        else
            clk_2 <= 1'b0;
    end
    
    assign clk_o = clk_1 && clk_2;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

      也可以通过异或操作得到目的分频时钟信号。

    //异或操作
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_1 <= 1'b0;
        else if(posedge_cnt == DIV_PARAM-1)
            clk_1 <= ~clk_1;
        else
            clk_1 <= clk_1;
    end
    
    always @(negedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_2 <= 1'b0;
        else if(negedge_cnt == (DIV_PARAM>>1))
            clk_2 <= ~clk_2;
        else
            clk_2 <= clk_2;
    end
    
    assign clk_o = clk_1 ^ clk_2;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    二、完整代码与仿真文件

      任意奇数分频器代码如下:

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2023/05/22 11:37:51
    // Design Name: 
    // Module Name: clk_divide_odd
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module clk_divide_odd
    #(
        parameter DIV_PARAM = 3 //分频系数(奇数)
    )
    (
        input   sys_clk  ,
        input   sys_rst_n,
        output  clk_o     
    );
    
    parameter   CNT_WIDTH = $clog2(DIV_PARAM); //计数器位宽
    
    reg     [CNT_WIDTH-1:0]     posedge_cnt; //上升沿计数器
    reg     [CNT_WIDTH-1:0]     negedge_cnt; //下降沿计数器
    reg                         clk_1; //时钟1
    reg                         clk_2; //时钟2
    
    //上升沿计数器
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            posedge_cnt <= 'd0;
        else if(posedge_cnt == DIV_PARAM-1)
            posedge_cnt <= 'd0;
        else
            posedge_cnt <= posedge_cnt + 1'b1;
    end
    
    //下降沿计数器
    always @(negedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            negedge_cnt <= 'd0;
        else if(negedge_cnt == DIV_PARAM-1)
            negedge_cnt <= 'd0;
        else
            negedge_cnt <= negedge_cnt + 1'b1;
    end
    
    //---------------------------------------------------------//
    //或操作
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_1 <= 1'b0;
        else if(posedge_cnt > (DIV_PARAM>>1))
            clk_1 <= 1'b1;
        else
            clk_1 <= 1'b0;
    end
    
    always @(negedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            clk_2 <= 1'b0;
        else if(negedge_cnt > (DIV_PARAM>>1))
            clk_2 <= 1'b1;
        else
            clk_2 <= 1'b0;
    end
    
    assign clk_o = clk_1 || clk_2; 
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

      仿真代码如下:

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2023/05/22 14:13:28
    // Design Name: 
    // Module Name: tb_clk_divide_odd
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module tb_clk_divide_odd();
    
    parameter DIV_PARAM = 5; //分频系数(奇数)
    
    reg   sys_clk  ;
    reg   sys_rst_n;
    wire  clk_o    ;
    
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    
    end
    
    always #5 sys_clk = ~sys_clk;
    
    clk_divide_odd
    #(
        .DIV_PARAM(DIV_PARAM) //分频系数(奇数)
    )
    clk_divide_odd
    (
        .sys_clk  (sys_clk  ),
        .sys_rst_n(sys_rst_n),
        .clk_o    (clk_o    ) 
    );
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    三、仿真结果

      分别对使用或操作、与操作、异或操作的奇数分频器进行仿真。

    (1)或操作奇数分频

    在这里插入图片描述
    (2)与操作奇数分频

    在这里插入图片描述
    (3)异或操作奇数分频

    在这里插入图片描述
      仿真通过。

  • 相关阅读:
    2173. 最多连胜的次数
    编译后的go程序无法在alpine基础镜像创建的容器运行问题
    【Go】格式化字符串指令大全 && Redis常用命令
    内网穿透的应用-Cloudreve搭建云盘系统,并实现随时访问
    计算机毕业设计——网络游戏虚拟交易平台的设计与实现
    PHP8的数据封装(数据隐藏)-PHP8知识详解
    使用Docker-Java监听Docker容器的信息
    未来科技中的云计算之路
    分布式文件存储——分块上传和断点续传
    XMl发展前景及相关领域
  • 原文地址:https://blog.csdn.net/qq_42224089/article/details/130807227