当前位置:   article > 正文

Verilog 任意整数分频器_分频器verilog

分频器verilog

Foreword

距离上一篇CSDN又有两个月了,这两个月学了好多,感觉这半年我还是有很大进步了的,没有一开始那么心力憔悴了。但是水管依旧到处漏……

最近和老虞还有刘同学吃饭,两个不同领域下的大佬,一个做考古,一个做AI,虽然聊的内容差异巨大,但两个人给我的感触都是,他们好厉害,小汤要好好努力!同时也让我想到了,世界可以分为哲学和数学,但最后都会归结于美学。我身边几个特别厉害的程序员,往往审美也是很好的,可能不是那么艺术,但做出来的东西一定是让人看着舒服的。

分频原理

首先推荐一个画波形原理图的在线网站WaveDrom Online Editor,他们家也有软件可以下载WaveDrom Download Github,使用方法在他家官网上也有介绍Tutorial,可以保存多种格式: json/png/svg,很好用。

在时序电路里,一般系统时钟都是高频的,不同外设对时钟频率的要求不同,所以需要通过分频来获得相应的时钟频率,一般都是将高频的时钟转换为低频的时钟。最简单的分频就是2分频,也就是把时钟频率减半,输出时钟和输入时钟上升沿对齐,波形图是这样的:

div2
当然也会有遇到需要奇数分频的时候,这时候上升沿和下降沿都需要用到,3分频波形图是这样的:

3div50

上面两张图都是50%占空比的,有的时候我们只需要用输出时钟的上升沿,不需要考虑下降沿,这样的话我们的输出时钟只需要是单脉冲的就可以了,设计的时候会简单很多,单脉冲的3分频波形图是这样的:

3div1

50%占空比的偶数分频方法

偶数分频又可以分成两种,一种是2的倍数,一种是2的次方。当分频系数是2的次方时,分频的方法会简单很多。这里还是要吐槽一下,CSDN为什么不支持verilog语法!!!

  • 2的倍数分频

    原理:

    1. 计数器在时钟上升沿+1,加到对应分频系数后,清零
    2. clkOut在计数器记到(N-1)/2和N-1的地方翻转
    3. 当分频系数为0或1时,clkOut = clkIn
    `define __DIVEVEN_V__
    
    module DivEven #(
    parameter PRRWIDTH = 4
    )(
    input  wire					clk,
    input  wire					rst,	// negetive valid
    input  wire					en,
    input  wire	[PRRWIDTH-1:0]	prr,
    
    output reg					clkOut
    );
    
    reg  [PRRWIDTH-1:0]			cnt;
    wire [PRRWIDTH-1:0]			cntValue;
    wire						direct;
    
    // when prr is 0 or 1, clkOut = clk directly
    assign	direct = (prr == {PRRWIDTH{1'b0}}) | (prr == {{(PRRWIDTH-1){1'b0}}, 1'b1});
    assign	cntValue = direct ? {PRRWIDTH{1'b0}} : (prr - 1'b1);
    
    // positive edge count
    always @(posedge clk or negedge rst) begin
    	if (!rst) begin
    		cnt <= {PRRWIDTH{1'b0}};
    	end
    	else if (!en) begin
    		cnt <= {PRRWIDTH{1'b0}};
    	end
    	else if (cnt == cntValue) begin
    		cnt <= {PRRWIDTH{1'b0}};
    	end
    	else begin
    		cnt <= cnt + 1'b1;
    	end
    end
    
    // overturn clkOut when cnt = (cntValue - 1) / 2 or cntValue
    always @(posedge clk or negedge rst) begin
    	if (!rst) begin
    		clkOut <= 1'b0;
    	end
    	else if (!en) begin
    		clkOut <= 1'b0;
    	end
    	else if (direct) begin
    		clkOut <= clk;
    	end
    	else if ((cnt == (cntValue >> 1)) || (cnt == cntValue)) begin
    		clkOut <= !clkOut;
    	end
    end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 2的次方分频

    原理:

    1. 计数器在时钟上升沿+1,加到全1后,清零
    2. cnt[0]的值是2分频,cnt[1]的值是4分频,cnt[2]的值是8分频
    3. 例如4分频,每两个clkIn上升沿,cnt[1]翻转一次,所以得到4分频后的clkOut
    `define __DIVEVEN_V__
    
    module DivEven (
    input  wire					clk,
    input  wire					rst,	// negetive valid
    input  wire					en,
    input  wire	[1:0]			div,
      // div = 0 means prr = 0;
      // div = 1 means prr = 2;
      // div = 2 means prr = 4;
      // div = 3 means prr = 8;
    
    output wire					clkOut
    );
    
    reg  [2:0]	cnt;
    
    assign clkOut = (!rst | !en)	? 1'b0		:
    				div == 2'b00	? clk		:
    				div == 2'b01	? cnt[0]	: // prr = 2
    				div == 2'b10	? cnt[1]	: // prr = 4
    				div == 2'b11	? cnt[2]	: // prr = 8
    				1'b0;
    
    // positive edge count
    always @(posedge clk or negedge rst) begin
    	if (!rst) begin
    		cnt <= 3'b000;
    	end
    	else if (!en) begin
    		cnt <= 3'b000;
    	end
    	else if (cnt == 3'b111) begin
    		cnt <= 3'b000;
    	end
    	else begin
    		cnt <= cnt + 1'b1;
    	end
    end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

50%占空比的任意整数分频方法

原理:

  1. 偶数的时候只用上升沿得到的时钟,奇数的时候将上升沿得到的时钟和下降沿得到的时钟并起来
  2. 上升沿得到的时钟和下降沿得到的时钟都是在计数器记到(N-1)/2和N-1的地方翻转
  3. 当分频系数为0或1时,clkOut = clkIn

code

`define __DIV50PCT_V__

module Div50Pct #(
	parameter PRRWIDTH = 4
)(
	input  wire					clk,
	input  wire					rst,	// negetive valid
	input  wire					en,
	input  wire	[PRRWIDTH-1:0]	prr,

	output wire					clkOut
);

	reg  [PRRWIDTH-1:0]			cntP;
	reg  [PRRWIDTH-1:0]			cntN;
	reg							clkP;
	reg							clkN;
	wire [PRRWIDTH-1:0]			cntValue;
	wire						direct;

	// when prr is 0 or 1, clkOut = clk directly
	assign	direct = (prr == {PRRWIDTH{1'b0}}) | (prr == {{(PRRWIDTH-1){1'b0}}, 1'b1});
	assign	cntValue = direct ? {PRRWIDTH{1'b0}} : (prr - 1'b1);

	// when prr is odd, clkOut = clkP || clkN
	// when prr is even, clkOut = clkP
	assign	clkOut = direct ? clk : (prr[0] ? (clkP | clkN) : clkP);

	// positive edge count
	always @(posedge clk or negedge rst) begin
		if (!rst) begin
			cntP <= {PRRWIDTH{1'b0}};
		end
		else if (!en) begin
			cntP <= {PRRWIDTH{1'b0}};
		end
		else if (cntP == cntValue) begin
			cntP <= {PRRWIDTH{1'b0}};
		end
		else begin
			cntP <= cntP + 1'b1;
		end
	end

	// positive edge clock
	// overturn clkP when cntP = (cntValue - 1) / 2 or cntValue
	always @(posedge clk or negedge rst) begin
		if (!rst) begin
			clkP <= 1'b0;
		end
		else if (!en) begin
			clkP <= 1'b0;
		end
		else if (direct) begin
			clkP <= 1'b0;
		end
		else if ((cntP == (cntValue >> 1)) || (cntP == cntValue)) begin
			clkP <= !clkP;
		end
	end

	// negetive edge count for odd prr
	always @(negedge clk or negedge rst) begin
		if (!rst) begin
			cntN <= {PRRWIDTH{1'b0}};
		end
		else if (!en) begin
			cntN <= {PRRWIDTH{1'b0}};
		end
		else if (prr[0]) begin
			if (cntN == cntValue) begin
				cntN <= {PRRWIDTH{1'b0}};
			end
			else if (cntP != {PRRWIDTH{1'b0}})begin
				cntN <= cntN + 1'b1;
			end
		end
		else begin
			cntN <= {PRRWIDTH{1'b0}};
		end
	end

	// negetive edge clock for odd prr
	// overturn clkN when cntN = (cntValue - 1) / 2 or cntValue
	always @(negedge clk or negedge rst) begin
		if (!rst) begin
			clkN <= 1'b0;
		end
		else if (!en) begin
			clkN <= 1'b0;
		end
		else if (direct) begin
			clkN <= 1'b0;
		end
		else if (prr[0]) begin
			clkN <= ((cntN == (cntValue >> 1)) || (cntN == cntValue)) ? !clkN : clkN;
		end
		else begin
			clkN <= 1'b0;
		end
	end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

单脉冲的任意整数分频方法

思路:

  1. 计数器在时钟上升沿+1,加到对应分频值后,clkOutReg拉高,计数器清零
  2. 计数器清零后,clkOutReg拉低
  3. 当clkOutReg和clk都为高时,clkOut为高
  4. 当分频系数为0或1时,clkOut = clkIn
`define __DIVSINGLEPULSE_V__

module DivSinglePulse #(
	parameter PRRWIDTH = 4
)(
	input  wire					clk,
	input  wire					rst,	// negetive valid
	input  wire					en,
	input  wire	[PRRWIDTH-1:0]	prr,

	output wire					clkOut
);

    reg							clkOutReg;
	reg  [PRRWIDTH-1:0]			cnt;
	wire [PRRWIDTH-1:0]			cntValue;
	wire						direct;

	// when prr is 0 or 1, clkOut = clk directly
	assign	direct = (prr == {PRRWIDTH{1'b0}}) | (prr == {{(PRRWIDTH-1){1'b0}}, 1'b1});
	assign	cntValue = direct ? {PRRWIDTH{1'b0}} : (prr - 1'b1);

	assign	clkOut = direct ? clk : clkOutReg & clk;

	// positive edge count
	always @(posedge clk or negedge rst) begin
		if (!rst) begin
			cnt <= {PRRWIDTH{1'b0}};
		end
		else if (!en) begin
			cnt <= {PRRWIDTH{1'b0}};
		end
		else if (cnt == cntValue) begin
			cnt <= {PRRWIDTH{1'b0}};
		end
		else begin
			cnt <= cnt + 1'b1;
		end
	end

	// clkOut is high when cnt == cntValue
	always @(posedge clk or negedge rst) begin
		if (!rst) begin
			clkOutReg <= 1'b0;
		end
		else if (!en) begin
			clkOutReg <= 1'b0;
		end
		else if (direct) begin
			clkOutReg <= 1'b0;
		end
        else if (cnt == cntValue) begin
			clkOutReg <= 1'b1;
		end
		else begin
			clkOutReg <= 1'b0;
		end
	end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

代码下载

以上代码及testbench都可以在verilog任意整数分频及测试.zip中下载噢!

Conclusion

12月到处都是节日的氛围,相信圣诞老人,相信爱、童话和魔法。

昨晚听了Westlife线上演唱会,感觉回到了初中的时候,Seasons in the Sun可能是我最早接触的英文歌。十多年过去了,我工作了,西城男孩也有了岁月的痕迹。They have raised me up and hope to see them once again.

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/623894
推荐阅读
相关标签
  

闽ICP备14008679号