题解 | #任意小数分频#

任意小数分频

https://www.nowcoder.com/practice/24c56c17ebb0472caf2693d5d965eabb

`timescale 1ns/1ns

module div_M_N(
    input  wire clk_in,
    input  wire rst,
    output wire clk_out
);

    parameter M_N = 8'd87; 
    parameter c89 = 8'd24; // 8/9时钟切换点
    parameter DIV_E = 5'd8; //偶数周期
    parameter DIV_O = 5'd9; //奇数周期

// ==================================================================================================
    // 关于Verilog编写小数分频电路,最开始确实没有头绪。牛客上本题的解析还是很到位的,第一个题解教会了我如何思考,
    // 第二个题解教会了我这题如何编码:

    //1 https://blog.nowcoder.net/n/a4d81838e9d24ceca35797c4754b7fe8
    //2 https://blog.nowcoder.net/n/7d57a3086a6448f69637cf284b492f3b

    // Verilog不可能精确地实现小数的分频,只能通过多个周期,以及不同的整数分频数来模拟小数分频的效果。
    // 这里需要实现8.7分频,即频率上 clk_in:clk_out=8.7:1=87:10,也就是说,8.7分频相当于87个clk_in内输出10个clk_out。
    // 然后对于小数分频,采用小数的上下限整数来设置分频,因为8<8.7<9,所以8.7分频需要通过clk_in的8分频和9分频共同来模拟。
    // 设10个clk_out周期中,有x个是clk_in的8分频时钟,有y个是clk_in的9分频时钟。
    // 由方程
    // x+y = 10 ①
    // 和
    // 8x+9y = 87 ②
    // 解得:
    // x=3, y=7
    // 即,对clk_in进行三次8分频和7次9分频,可以得到8.7分频的效果。
    // 根据题目中已有的要求,c98=24=3×8 知,本题需要先进行8分频。
// ==================================================================================================

//*************code***********//

    wire        rst_n   ;
    assign  rst_n = rst ;

    reg [6:0]   cnt_total;
    always @(posedge clk_in or negedge rst_n) 
    begin
        if(~rst_n)
            cnt_total <= 'd0;
        else
            cnt_total <= (cnt_total==M_N-1'd1)? 'd0 : cnt_total+1'd1;
    end

    reg [3:0] cnt_div_8; // 8分频的计数器
    reg [3:0] cnt_div_9; // 9分频的计数器
    // 8,9分频的计数器逻辑
    always @(posedge clk_in or negedge rst_n) 
    begin
        if(~rst_n) begin
            cnt_div_8 <= 'd0;
            cnt_div_9 <= 'd0;
        end
        else begin
            if(cnt_total <= c89-1) begin
                cnt_div_8 <= (cnt_div_8==DIV_E-1)? 'd0 : cnt_div_8+1'd1;
                cnt_div_9 <= 'd0;
            end
            else if(cnt_total > c89-1) begin
                cnt_div_9 <= (cnt_div_9==DIV_O-1)? 'd0 : cnt_div_9+1'd1;
                cnt_div_8 <= 'd0;
            end
            else begin
                cnt_div_8 <= 'd0;
                cnt_div_9 <= 'd0;
            end
        end
    end

    reg     clk_out_r;
    assign  clk_out = clk_out_r;
    // 输出逻辑
    always @(posedge clk_in or negedge rst_n) 
    begin
        if(~rst_n)
            clk_out_r <= 1'b0;
        else begin
            if(cnt_total <= c89-1)
            // 执行 8 分频输出
                clk_out_r <= (cnt_div_8==((DIV_E>>1)) || cnt_div_8=='d0)? ~clk_out_r : clk_out_r;
            else if(cnt_total > c89-1)
            // 执行 9 分频输出
                clk_out_r <= (cnt_div_9==((DIV_O>>1)) || cnt_div_9=='d0)? ~clk_out_r : clk_out_r;
            else
                clk_out_r <= clk_out_r;
        end
    end

//*************code***********//
endmodule

全部评论

相关推荐

给我发了笔试链接,想着等晚上回去做,结果还没做流程就终止了
伟大的小黄鸭在学习:我猜就是笔试几乎没用,就是用来给用人部门拖时间复筛简历的,可能用人部门筛到你简历觉得不合适就提前挂了
投递小鹏汽车等公司10个岗位
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务