Verilog功能模块——时钟分频

一. 模块功能与应用场景

模块功能:对输入时钟进行任意倍数分频。

应用场景:

  • 需要对时钟进行分频,而PLL不能满足要求或者使用起来不方便

  • 需要固定倍数关系的时钟


二. 模块框图与使用说明

通过参数DIV控制分频系数,输出div_clk = clk / DIV。

注意:

1.原始div_clk是门控时钟,一般不推荐使用。但Vivado软件综合时会自动给div_clk加BUFG,使其使用全局时钟资源变为全局时钟,故此处不在代码中加入BUFG原语,同时也保证了代码的通用性。

2.未在Quartus中测试过,不知道是否也会自动转为全局时钟,需要注意。


三. 模块代码

/*
 * @Author       : Xu Dakang
 * @Email        : [email protected]
 * @Date         : 2021-04-30 08:22:46
 * @LastEditors  : Xu Dakang
 * @LastEditTime : 2021-04-30 16:24:07
 * @Filename     : clkDivider.sv
 * @Description  : 时钟分频模块
*/

/*
! 模块功能: 将输入时钟根据参数DIV分频. DIV为正整数, 得到div_clk = clk / DIV
* 思路:
  1.当DIV为1时,时钟原样输出
  1.当DIV为偶数时, 直接生成占空比50%的方波即可
  2.当DIV为奇数时, 需要用到下降沿触发, 生成两个占空比不是50%的方波, 然后做或运算
*/



module clkDivider
#(
  parameter DIV = 2 // 时钟分频系数
)(
  output logic div_clk,

  input  logic clk,
  input  logic rstn
);



//< 分频计数 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
logic [$clog2(DIV)-1 : 0] div_cnt;
always_ff @(posedge clk, negedge rstn) begin
  if (~rstn)
    div_cnt <= '0;
  else if (div_cnt < (DIV - 1)) // 计数最大值:DIV-1
    div_cnt <= div_cnt + 1'b1;
  else
    div_cnt <= '0;
end
//< 分频计数 ------------------------------------------------------------



//> 生成分频时钟 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
logic div_clk_a;
always_ff @(posedge clk, negedge rstn) begin
  if (~rstn)
    div_clk_a <= 1'b0;
  else if (div_cnt < (DIV >> 1))
    div_clk_a <= 1'b1;
  else
    div_clk_a <= 1'b0;
end


logic div_clk_b;
always_ff @(negedge clk, negedge rstn) begin // 下降沿触发
  if (~rstn)
    div_clk_b <= 1'b0;
  else if (div_cnt < (DIV >> 1))
    div_clk_b <= 1'b1;
  else
    div_clk_b <= 1'b0;
end


always_comb begin
  if (DIV == 1)
    div_clk = clk;
  else if (DIV[0] == 0) // 分频系数为偶数
    div_clk = div_clk_a;
  else             // 分频系数为奇数
    div_clk = div_clk_a | div_clk_b;
end
//> 生成分频时钟 ------------------------------------------------------------



endmodule

四. testbench

/*
 * @Author       : Xu Dakang
 * @Email        : [email protected]
 * @Date         : 2021-04-29 22:55:32
 * @LastEditors  : Xu Dakang
 * @LastEditTime : 2021-04-30 16:22:07
 * @Filename     : clkDivider_tb.sv
 * @Description  : testbench of clkDivider
*/



module clkDivider_tb ();

timeunit 1ns;
timeprecision 1ps;

logic         div_clk;

logic         clk;
logic         rstn;

parameter DIV = 2;



clkDivider #(.DIV(DIV)) clkDivider_inst01 (.*);



// 生成时钟
localparam CLKT = 2;
initial begin
  clk = 0;
  forever #(CLKT / 2) clk = ~clk;
end



initial begin
  rstn=0;
  #(CLKT*2) rstn=1;

  #(DIV*CLKT*5) $stop;
end



endmodule

五. 仿真验证

仿真工具:Vivado 2020.2 Simulator。

  1. DIV = 1时:

    Verilog功能模块——时钟分频_第1张图片
  2. DIV = 2时:

    Verilog功能模块——时钟分频_第2张图片
  3. DIV = 5时:

    Verilog功能模块——时钟分频_第3张图片

六. 工程分享

clkDivider 时钟分频模块 vivado 2020.2工程.7z

欢迎大家关注我的公众号:徐晓康的博客,回复以下代码获取。

2369

建议复制过去不会码错字!


徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。

你可能感兴趣的:(Verilog,verilog,systemverilog,时钟,分频,功能模块)