zoukankan      html  css  js  c++  java
  • 【笔记】关于整数分频的思考(Verilog HDL)(Digital Logic)

     

    Instruction

    本文主要讨论整数分频器的原理以及实现。关键的问题就是分频的时钟什么时候翻转。

    Design

    1. 偶数倍分频

    原理:比如4分频,需要一个模4的计数器,占空比50%,计数为0~3循环,当计数到一半时,即计数输出cnt<2时翻转。

    代码如下:div4

    1 //四分频
    2  module div4(clk,rst_n,o_clk);
    3 input clk,rst_n;
    4 output o_clk;
    5 reg o_clk;
    6
    7 reg [1:0]cnt;
    8
    9 always @(posedge clk or negedge rst_n)
    10 begin
    11 if(!rst_n)
    12 cnt<=0;
    13 else if(cnt==3)
    14 cnt<=0;
    15 else
    16 cnt<=cnt+1;
    17 end
    18
    19 always @(posedge clk or negedge rst_n)
    20 begin
    21 if(!rst_n)
    22 o_clk<=0;
    23 else if(cnt<2)
    24 o_clk<=1;
    25 else
    26 o_clk<=0;
    27 end
    28
    29  endmodule
    30  

    仿真结果

    001

    2. 奇数倍分频

    原理:比如3分频,需要一个模3的计数器,占空比50%,即计数到一半(非整数)时翻转。方法是用2个模3的计数器,一个

    在时钟的上升沿计数,一个在下降沿计数。对这2个计数分别分频,然后相或。利用上升沿河下降沿刚好相差半个时钟周期来

    实现翻转,注意的是,1|0=1,所以设为1的部分占得部分较少,确切的说为cnt<1,即0。

    代码如下:div3

    1 //三分频
    2  module div3(clk,rst_n,o_clk);
    3 input clk,rst_n; //输入时钟和复位
    4   output o_clk; //输出时钟
    5  
    6 reg [1:0]cnt_p; //上升沿计数
    7   reg [1:0]cnt_n; //下降沿计数
    8   reg clk_p; //上升沿分频的时钟
    9   reg clk_n; //下降沿分频的时钟
    10  
    11 assign o_clk=clk_p|clk_n; //分频得到的两时钟相或得到输出时钟
    12
    13 //上升沿计数
    14   always @(posedge clk or negedge rst_n)
    15 begin
    16 if(!rst_n)
    17 cnt_p<=0;
    18 else if(cnt_p==2) //模3的计数器
    19   cnt_p<=0;
    20 else
    21 cnt_p<=cnt_p+1;
    22 end
    23 //上升沿分频
    24   always @(posedge clk or negedge rst_n)
    25 begin
    26 if(!rst_n)
    27 clk_p<=0;
    28 else if(cnt_p<1) //cnt=0
    29   clk_p<=1;
    30 else //cnt=1,2
    31   clk_p<=0;
    32 end
    33
    34 //下降沿计数
    35   always @(negedge clk or negedge rst_n)
    36 begin
    37 if(!rst_n)
    38 cnt_n<=0;
    39 else if(cnt_n==2)
    40 cnt_n<=0;
    41 else
    42 cnt_n<=cnt_n+1;
    43 end
    44 //下降沿分频
    45   always @(negedge clk or negedge rst_n)
    46 begin
    47 if(!rst_n)
    48 clk_n<=0;
    49 else if(cnt_n<1) //cnt_n=0
    50 clk_n<=1;
    51 else
    52 clk_n<=0; //cnt_n=1,2
    53 end
    54
    55 endmodule
    56

    仿真结果

    001

    3. 任意整数分频

    原理:总结1和2,设整数位N,当N为偶数时,cnt<N/2就翻转,当N为奇数时,cnt<(N-1)/2翻转。不论N为奇数、偶数,翻

    转的条件都可以表示为cnt<(N>>1)。这是一个编程的技巧,无它,也是看别人的代码,学到的。

    代码如下:divn

    1 //任意整数分频
    2 module divn(clk,rst_n,o_clk);
    3 input clk,rst_n;
    4 output o_clk;
    5
    6 parameter WIDTH=3; //计数器的位宽
    7 parameter N=6; //要分频的整数
    8
    9 reg [WIDTH-1:0]cnt_p;
    10 reg [WIDTH-1:0]cnt_n;
    11 reg clk_p;
    12 reg clk_n;
    13
    14 assign o_clk=(N==1)?clk:(N[0]?(clk_p|clk_n):clk_p);
    15
    16 always @(posedge clk or negedge rst_n)
    17 begin
    18 if(!rst_n)
    19 cnt_p<=0;
    20 else if(cnt_p==(N-1))
    21 cnt_p<=0;
    22 else
    23 cnt_p<=cnt_p+1;
    24 end
    25
    26 always @(posedge clk or negedge rst_n)
    27 begin
    28 if(!rst_n)
    29 clk_p<=0;
    30 else if(cnt_p<(N>>1))
    31 clk_p<=1;
    32 else
    33 clk_p<=0;
    34 end
    35
    36 always @(negedge clk or negedge rst_n)
    37 begin
    38 if(!rst_n)
    39 cnt_n<=0;
    40 else if(cnt_n==(N-1))
    41 cnt_n<=0;
    42 else
    43 cnt_n<=cnt_n+1;
    44 end
    45
    46 always @(negedge clk or negedge rst_n)
    47 begin
    48 if(!rst_n)
    49 clk_n<=0;
    50 else if(cnt_n<(N>>1))
    51 clk_n<=1;
    52 else
    53 clk_n<=0;
    54 end
    55
    56 endmodule
    57

    仿真结果

    001

    这里有2个技巧:

    1. 14 assign o_clk=(N==1)?clk:(N[0]?(clk_p|clk_n):clk_p);这行决定分频输出的类型;

    2.30 else if(cnt_p<(N>>1)),这里的(N>>1)比N/2好用多了,同样的表达方式通吃奇偶。

       比如在50 else if(cnt_n<(N>>1)),这里就等价于(N-1)/2.

    Result & Analysis

    前两个看懂了,任意整数分频就不难理解。关键还是奇数分频的算法,分别分频再求或,太奇妙了。至于3里的编程技巧,都是模

    仿无双的代码。(无双是谁?^_^)。细节部分,每个分频用2个always块的好处是,推荐这种代码风格。功能性更单一,便于阅

    读,也算是人都能读懂、综合的代码,综合器去综合应该没什么意外。

  • 相关阅读:
    makefile中的wildcard和patsubst
    makefile中=,:=,?=,+=区别
    hash函数查找和ASL计算
    ubuntu apt-get提示no dependencys怎么办
    增广贤文是不多的古典珍宝之一
    如何打印查看c++stack<..>中的内容(不使用pop,top)
    c/c++标准IO重定向
    c/c++使用#define,#ifdef,#endif将debug代码分离
    未完待续
    c++重载覆盖重定义多态其他别名区别
  • 原文地址:https://www.cnblogs.com/halflife/p/1836251.html
Copyright © 2011-2022 走看看