简析
分频器
- 偶数分频器。VL13 时钟分频(偶数)。
- 奇数分频器。VL18 无占空比要求的奇数分频,VL16 占空比50%的奇数分频。
- 小数分频器。VL17 任意小数分频。
小数分频器是分频器中最难的一种,而且不能像整数分频那样得到均匀且占空比为50%的分频输出。
小数分频
假设输出clk_out
是输入clk_in
的分频。首先要将分频系数化为分数形式,比如,。本题中,可以化为。这意味着在87个clk_in
周期内输出10个clk_out
周期就可以实现分频。
然后采用若干种(一般是两种)整数分频在87个原周期clk_in
内产生10个新时钟周期clk_out
。整数分频的分频系数有很多种选择,但要尽可能接近,提高clk_out
的均匀度。一般推荐在小数分频系数的附近选取。因为,所以两个整数分频系数是8和9。接着要计算87个clk_out
周期分别有多少个是8分频和9分频的。设每10个clk_out
中有个8分频输出和个9分频输出,则可列出如下方程:
可得,。也就是3个8分频和7个9分频一组,循环输出,就等效于8.7分频。
最后安排组内8分频和9分频的位置。这里的方法也不固定,不过本题要求3个8分频先输出,再输出7个9分频,如下图。
参数介绍
题目提供的:
- M_N=87。一组
clk_out
输出需要的clk_in
时钟数量。 - c89=24。切换分频系数的时间点。从这里可以看出,本题要求先输出3个8分频。
- div_e=8。分频系数1。
- div_o=9。分频系数2。
自定义的:
- cyc_cnt。对
clk_in
进行计数,达到M_N后清零。 - div_flag。8/9分频标志。当
div_flag==0
时是8分频;当div_flag==1
时是9分频。cyc_cnt==M_N-1
或者cyc_cnt==c89-1
时该标志位翻转。 - clk_cnt。用于产生分频输出。当
div_flag==0
时,计数最大值是div_e-1
;当div_flag==1
时,计数最大值是div_o-1
。 - clk_out_r。根据
clk_cnt
和div_flag
产生分频输出。
代码
`timescale 1ns/1ns
module div_M_N(
input wire clk_in,
input wire rst,
output wire clk_out
);
parameter M_N = 8'd87;
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
reg [3:0] clk_cnt;
reg [6:0] cyc_cnt;
reg div_flag;
reg clk_out_r;
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_cnt <= 0;
else if(~div_flag)
clk_cnt <= clk_cnt==(div_e-1)? 0: clk_cnt+1;
else
clk_cnt <= clk_cnt==(div_o-1)? 0: clk_cnt+1;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
cyc_cnt <= 0;
else
cyc_cnt <= cyc_cnt==(M_N-1)? 0: cyc_cnt+1;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
div_flag <= 0;
else
div_flag <= cyc_cnt==(M_N-1)||cyc_cnt==(c89-1)? ~div_flag: div_flag;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_out_r <= 0;
else if(~div_flag)
clk_out_r <= clk_cnt<=((div_e>>2)+1);
else
clk_out_r <= clk_cnt<=((div_o>>2)+1);
end
assign clk_out = clk_out_r;
//*************code***********//
endmodule