【笔记】关于整数分频的思考(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块的好处是,推荐这种代码风格。功能性更单一,便于阅

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

posted on 2010-09-26 20:43  yf.x  阅读(3215)  评论(3编辑  收藏  举报

导航