verilog任意小数分频的实现

  • 原理
  • 波形
  • module代码
  • testbench代码
  • 算法解析
  • 参考文档

原理

假设19/9分频,利用公式

(19/9) * (a+b)=2a+3b
===>
a=8
b=1

即可以由8个2分频+1个3分频,在8*2+1*3=19个参考时钟周期内,实现19/9分频。
优点是算法简单。
缺点是占空比不是50%,因为2分频和3分频交叉组合而成,所以周期性抖动较差。

总之,用于普通的数字逻辑实现基于频率的带宽精细微调,还是很有用处的。

波形

这里写图片描述

module代码

分频系数=分子/分母。

module clkFracDiv(
                  output reg   clkout,
                  input        rstn,
                  input        refclk,
                  input [31:0] fenzi,//fenzi/fenmu must equal or more than 2
                  input [31:0] fenmu //fenzi/fenmu must equal or more than 2
);
   reg [2:0]                   rstn_syn;
   reg [31:0]                  cnt;

   //1. reset synchronization;
   //2. indicate that refclk is already stable
   always @(posedge refclk) begin
      rstn_syn[0] <= rstn;
      rstn_syn[1] <= rstn_syn[0];
      rstn_syn[2] <= rstn_syn[1];
   end

   //1. main algorithm
   always @(posedge refclk or negedge rstn_syn[2]) begin
      if(!rstn_syn[2]) cnt <= 0;
      else begin
         if(cnt < fenzi) cnt <= cnt + fenmu;
         else cnt <= cnt + fenmu - fenzi;
      end
   end

   //1. base the above algorithm, deduce clkout
   always @(posedge refclk or negedge rstn_syn[2]) begin
      if(!rstn_syn[2]) clkout <= 0;
      else begin
         if(((cnt > (fenzi>>1)) || (cnt == (fenzi>>1))) && (cnt < fenzi)) clkout <= 1;
         else clkout <= 0;
      end
   end
endmodule

testbench代码

`timescale 1ns/10ps
module tb_top;
   reg refclk;
   initial begin
      refclk = 0;
   end
   always #0.2 refclk = !refclk;

   reg rstn;
   initial begin
      rstn = 0;
      #100;
      rstn = 1;
   end

   reg [31:0] fenzi;
   reg [31:0] fenmu;
   reg        enable_clkFracDiv;
   initial begin
      fenzi=32'd19;
      fenmu=32'd9;
      enable_clkFracDiv=0;
      #200;
      enable_clkFracDiv=1;
   end

   clkFracDiv clkFracDiv(
                         /*output reg   */.clkout (clkout),
                         /*input        */.rstn   (rstn && enable_clkFracDiv ),
                         /*input        */.refclk (refclk),
                         /*input [31:0] */.fenzi  (fenzi ),//fenzi/fenmu must equal or more than 2
                         /*input [31:0] */.fenmu  (fenmu ) //fenzi/fenmu must equal or more than 2
                         );
endmodule

算法解析

主要算法,在clkFracDiv.v的第二段实现代码里。
第三段实现代码,只是基于这个算法推演clkout波形而已。

基于实例说明,19/9分频。换个说法,即19个参考时钟refclk里,划分9段。
因为分母是9,所以计数器是+9计算的,如果超过19,意味着当前两个上升沿之间的周期大于期望周期值,余数需要考虑进下一个周期里。总共需要的周期数,就是前文的8*2+1*3=19个参考时钟周期内。

理论上,只要分频系数大于或者等于2的各种整数分频、小数分频,都是可以的。

参考文档

32任意分数分频Verilog实现
http://3y.uu456.com/bp-4ecb3facd1f346q3daef3e2e-1.html

你可能感兴趣的:(verilog)