基于Verilog的奇数偶数小数分频器设计

来源:转载

      今天呢,由泡泡鱼工作室发布的微信公共号“硬件为王”(微信号:king_hardware)正式上线啦,关注有惊喜哦。在这个普天同庆的美好日子里,小编脑洞大开,决定写一首诗赞美一下我们背后伟大的团队,虽然连上我只有两个人,但丝毫不影响我们的工作热情和创业野心。合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下!

      首先小编在这里分享一个基于Verilog语言的分频器设计,该分频器实现了奇数、偶数、小数(0.5)分频,可综合,能跑700M左右的时钟,基本能够满足大部分应用需求。

一:背景

      前天,组长交待一个任务,关于光纤通道时钟同步模块的设计。里面需要用到一个10M的时钟,而我的PCIe时钟为125M,所以需要一个12.5分频的分频器。小编偷懒从网上搜了一个,代码简洁,行为仿真也没问题,直接就用上了。昨天组长调用我的设计,发现综合出现了问题,一查代码,把我批了一通,还暂时取消了我带小弟的资格,原因就出在这分频器上。

二:问题代码分析

 1 module divf #

2 ( parameter N = 12 , // 分频数

3 parameter state=1 //奇偶分频为0,半分频为1

4 )

5 (

6 input clr,

7 input clk,

8 output clkout

9 );

10

11 reg [5:0] M;

12 reg [24:0] count;

13

14 always@(posedge clk or negedge clk)

15 begin

16 case(state)

17 0:begin

18 if(!clr) count<=2*N-1;

19 else if(count==2*N-1)

20 begin

21 count<=0;

22 M<=2; //只on一个clk

23 end

24 else count<=count+1;

25 end

26

27 1:begin

28 if(!clr) count<=2*N;

29 else if(count==2*N)

30 begin

31 count<=0;

32 M<=N+1;

33 end

34 else count<=count+1;

35 end

36

37 default:;

38 endcase

39 end

40

41 assign clkout=(count<M)?1:0;

42

43 endmodule

看到这样的代码,像我一样的菜鸟见了都会怦然心动,但仔细分析,问题就出来了。

[email protected](posedge clk or negedge clk)

      触发器(FF)一般是上升沿触发,我做过实验,即使想要下降沿触发,布局布线后也会有一个反相器反相后用上升沿去触发。若同时使用上升沿和下降沿触发,例如[email protected](posedge clk or negedge clk),布局布线后等效于[email protected](posedge clk)。所以上面这种写法,若不是采用特定器件如ODDR,是很难完成上下时钟沿都采数据的(应该还有别的方法,请大牛不吝赐教)。所以如果用在高速时钟上,建议不要采用这种写法。

 assign clkout=(count<M)?1:0;

      组合逻辑输出问题,如果时钟频率较高,100M以上,组合逻辑的延时很有可能超过时钟的建立时间,会产生毛刺,所以我们一般都要求寄存器打一拍输出。上面这个例子中,clkout=(count<M)?1:0; 比较器是个延时比较多的器件,所以对时钟要求高的情况下不能使用。

 

三:解决方案

使用两个always块,但两个always块不能对同一变量进行操作。

[email protected](posedge clk) begin  … end

[email protected](negedge clk) begin  … end

或者使用锁相环产生两个频率相同,相位差180度的clk,然后在每个上升沿输出

[email protected](posedge clk1) begin  … end

[email protected](negedge clk2) begin  … end

针对组合逻辑输出问题,能避免使用则避免使用,如果非要使用,也只能使用足够简单的组合逻辑,比如与或非逻辑。

 

四:代码示例

说明:用一个大case分三类讨论,看上去很挫,实际是为了裁剪方便。

代码功能:完成奇数分频和偶数分频,占空比50%。完成n+0.5分频,占空比无要求。

 1 module divf #

2 ( parameter Div_num = 12 , // 分频数

3 parameter state=0 //半分频为0,奇数分频为1,偶数分频为2

4 )

5 (

6 input clr,

7 input clk,

8 output Div_clk

9 );

10 reg [24:0] count;

11

12 case(state)

13 1: begin //ji_shu

14 reg pos_clk;

15 reg neg_clk;

16

17 always@(posedge clk or negedge clr)

18 if(!clr) count<=0;

19 else if(count==0 & pos_clk) count<=Div_num/2-1;

20 else if(count==0) count<=Div_num/2;

21 else count<=count-1;

22

23 always@(posedge clk or negedge clr)

24 if(!clr) pos_clk<=0;

25 else if(count==0) pos_clk<=~pos_clk;

26 else pos_clk<=pos_clk;

27

28 always@(negedge clk or negedge clr)

29 if(!clr) neg_clk<=0;

30 else neg_clk<=pos_clk;

31

32 assign Div_clk = pos_clk & neg_clk;

33 end

34

35 2: begin //ou_shu

36 reg Div_clk1;

37

38 always@(posedge clk or negedge clr)

39 if(!clr) count<=0;

40 else if(count==0) count<=Div_num/2-1;

41 else count<=count-1;

42

43 always@(posedge clk or negedge clr)

44 if(!clr) Div_clk1<=0;

45 else if(count==0) Div_clk1<=~Div_clk1;

46

47 assign Div_clk = Div_clk1;

48 end

49

50

51 0: begin //ban_fen_pin

52 reg count_div;

53 reg count_div2;

54 wire clk_half;

55

56 assign clk_half = clk^count_div2;

57 always@(posedge clk_half or negedge clr) //模Div_num 计数

58 if(!clr) count<=0;

59 else if(count== Div_num-1) count<=0;

60 else count<=count+1;

61

62 always@(posedge clk_half or negedge clr) //模Div_num 计数

63 if(!clr) count_div<=0;

64 else if(count== Div_num-1) count_div<=1;

65 else count_div<=0;

66

67 always@(posedge count_div or negedge clr) //对count_div二分频

68 if(!clr) count_div2<=0;

69 else count_div2<=~count_div2;

70

71 assign Div_clk = count_div;

72 end

73 endcase

74

75 endmodule

五:仿真代码及结果

 1 module test_divf;

2 reg clk;

3 reg clr;

4 wire Div_clk;

5

6 always #1 clk=~clk;

7

8 initial

9 begin

10 #0 clr=0;clk=1;

11 #99 clr=1;

12 //#1000 $stop;

13 end

14

15 divf #

16 (

17 .Div_num ( 5 ),

18 .state ( 1 )

19 )divf(

20 .clr ( clr ),

21 .clk ( clk ),

22 .Div_clk ( Div_clk )

23 );

24

25 endmodule

仿真结果

Div_num=5,state=1,实现5分频

Div_num=6,state=2,实现6分频

Div_num=6,state=0,实现5.5分频

六:总结

      看到这个时候,如果您还记得我在开头说过要作一首诗,那么请您一定要关注“硬件为王”这个微信公共号(二维码见最下方),因为您是不折不扣的逻辑设计分析师。如果您已经忘了这个事了,很可能您只是百度进来抄代码的,那也请您关注“硬件为王”,因为我们会定期放出一些有用的代码和相关知识,上百度找总不如直接推送到手机上来的方便吧。

      谢谢各位看官,请求大家多多支持并随时给我们提出宝贵意见!

 


分享给朋友:
您可能感兴趣的文章:
随机阅读: