任意分数分频器的verilog实现

这篇博文是关于分频器最后的讲解了,主要是要实现nume/deno倍的分频。对于nume/deno倍的分频,实质上就是要在nume个输入的时钟周期里,输出deno个脉冲。因此这里需要通过简单的数学运算来保证deno个脉冲的输出。nume,deno,quot和remd满足下面的式子:nume = quot*deno + remd,从这个式子中我们可以得到quot=nume/deno,即nume和deno相除向下取整;remd ==nume%deno,即nume和deno相除得到的余数。这样要实现nume/deno的分频,就需要remd个quot+1的分频和deno-remd个quot分频,这样算下来这个分频的个数为remd + (deno-remd)=deno,也就是需要deno个脉冲,而这deno个脉冲正好是在remd*(quot+1) +(deno-remd)*quot=remd + demo*quot=nume个时钟周期产生的,也就是我们一开始提到的在nume个时钟周期里输出deno个脉冲。以上便是实现任意分数分频的原理,下面利于verilog进行实现。上面的原理可以转化为以下的几个模块:

任意分数分频器的verilog实现_第1张图片

这里整数分频1实现的是quot+1分频器,整数分频2实现的是quot分频,根据前面两篇博文的介绍,这两个整数分频器实现起来并没有什么难度。但需要注意的是,在整数分频过程中需要加入同步信号sync,因为当整数分频1和整数分频2互相切换的时候,并不一定以这两个整数分频器的上升沿开始的,因此这里加入sync信号强制整数分频重新由上升沿开始输出分频时钟。clk_sel这个控制信号用于选择两个整数分频,控制模块的设计也比较简单,由计数器的值去确定clk_sel和sync。相应的verilog代码如下:

这里实现的是68/9的分频,根据介绍的原理需要5个8分频和4个7分频电路。

module div #(parameter WIDTH = 32)(
input clk_in,
input rst,
input [WIDTH-1:0] nume,//indicate numerator
input [WIDTH-1:0] deno,//indicate denominator
output clk_out);

wire [WIDTH-1:0] quot;//indicate quotient
wire [WIDTH-1:0] quot1;//indicate quot + 1
wire [WIDTH-1:0] remd;//indicate remainder
wire [WIDTH-1:0] clk_num1;
wire [WIDTH-1:0] clk_num2;
wire [WIDTH-1:0] clk_num;


reg clk_sel;
wire clk1;
wire clk2;
wire sync1,sync2;
reg [WIDTH-1:0] cnt;


assign quot = nume / deno;
assign remd = nume % deno;
assign clk_num1 = remd * (quot + 1);
assign clk_num2 = quot * (deno - remd);
assign clk_num = clk_num1 + clk_num2;
assign quot1 = quot + 1;

//整数分频模块1
Random_div #(32) u_div1(
.clk_in(clk_in),
.rst(rst),
.sync(sync1),
.N(quot1),
.clk_out(clk1));

//整数分频模块2
Random_div #(32) u_div2(
.clk_in(clk_in),
.rst(rst),
.sync(sync2),
.N(quot),
.clk_out(clk2));

//计数器
always@(posedge clk_in or negedge rst)
begin
  if(!rst)
  begin
    cnt <= 0;
  end
  else 
  begin
    cnt <= cnt + 1;
    if( cnt == clk_num-1)
	cnt <= 0;
  end
end

//用于两个整数模块切换的时候重新由上升沿开始输出
assign sync1 = (cnt < clk_num1);
assign sync2 = ~sync1;

//用于选择整数模块
always@(posedge clk_in or negedge rst)
begin
  if(!rst)
  clk_sel <= 0;
  else 
  clk_sel = sync1;
end

assign clk_out = clk_sel ? clk1 : clk2;

endmodule

//整数分频模块
module Random_div #( parameter WIDTH=32)(
input clk_in,
input rst,
input sync,
input [WIDTH-1:0] N,
output clk_out);

reg [WIDTH-1:0] cnt;
wire [WIDTH-1:0] half_n;
reg div;

assign half_n = N/2;
always@(posedge clk_in or negedge rst)
begin
  if(!rst)
  begin
    cnt <= 0;
	div <= 0;
  end
  else if(!sync)
    cnt <= N-1;//同步信号
  else
  begin
    cnt <= cnt + 1;
	if(cnt==N-1)
	begin
	  cnt <= 0;
	  div <= ~div;
	end
	else if(cnt == half_n - 1)
	begin
	   div = ~div;
	end
  end
end

assign clk_out = sync ? div : 1'b0;
endmodule

 

你可能感兴趣的:(verilog,IC模块设计)