概述
本文讨论了时钟切换的两种基本情况以及两种基本电路结构,讨论了一些问题:
下图是一个时钟选择的简单实现以及时序图,使用AND-OR多路复用逻辑,其中SELECT信号为时钟选择信号,如图中所示,直接切换会产生毛刺(glitch)
时钟切换分为两种情况:(1)CLK0与CLK1为相关时钟源,即CLK0与CLK1成整数倍关系;(2)CLK0与CLK1之间没有关系;
(1)CLK0与CLK1为相关时钟源
(2)CLK0与CLK1为无关时钟源
时钟切换源代码:
`timescale 1ns/1ns
module clk_syn_tst (
rst_n,
clka,
clkb,
sel_clkb,
clk_o
);
input rst_n;
input clka;
input clkb;
input sel_clkb;
output clk_o;
reg sel_clka_d0;
reg sel_clka_d1;
reg sel_clka_dly1;
reg sel_clka_dly2 ;
reg sel_clka_dly3;
reg sel_clkb_d0;
reg sel_clkb_d1;
reg sel_clkb_dly1;
reg sel_clkb_dly2;
reg sel_clkb_dly3;
always @ (posedge clka or negedge rst_n)
begin
if (!rst_n)
begin
sel_clka_d0 <= 1'b0;
sel_clka_d1 <= 1'b0;
end
else
begin
sel_clka_d0 <= (~sel_clkb) & (~sel_clkb_dly3) ;
sel_clka_d1 <= sel_clka_d0 ;
end
end
// part2
//always @ (posedge clka_n or negedge rst_n)
always @ (negedge clka or negedge rst_n)
begin
if (!rst_n)
begin
sel_clka_dly1 <= 1'b0;
sel_clka_dly2 <= 1'b0;
sel_clka_dly3 <= 1'b0;
end
else
begin
sel_clka_dly1 <= sel_clka_d1;
sel_clka_dly2 <= sel_clka_dly1 ;
sel_clka_dly3 <= sel_clka_dly2 ;
end
end
// part3
//always @ (posedge clkb_n or negedge rst_n)
always @ (posedge clkb or negedge rst_n)
begin
if (!rst_n)
begin
sel_clkb_d0 <= 1'b1;
sel_clkb_d1 <= 1'b1;
end
else
begin
sel_clkb_d0 <= sel_clkb & (~sel_clka_dly3) ;
sel_clkb_d1 <= sel_clkb_d0 ;
end
end
// part4
//always @ (posedge clkb_n or negedge rst_n)
always @ (negedge clkb or negedge rst_n)
begin
if (!rst_n)
begin
sel_clkb_dly1 <= 1'b1;
sel_clkb_dly2 <= 1'b1;
sel_clkb_dly3 <= 1'b1;
end
else
begin
sel_clkb_dly1 <= sel_clkb_d1;
sel_clkb_dly2 <= sel_clkb_dly1 ;
sel_clkb_dly3 <= sel_clkb_dly2 ;
end
end
// part5
//clk_gate_xxx clk_gate_a ( .CP(clka), .EN(sel_clka_dly3), .Q(clka_g), .TE(1'b0) );
//clk_gate_xxx clk_gate_b ( .CP(clkb), .EN(sel_clkb_dly3), .Q(clkb_g), .TE(1'b0) );
assign clka_g = clka & sel_clka_dly3 ;
assign clkb_g = clkb & sel_clkb_dly3 ;
assign clk_o = clka_g | clkb_g ;
endmodule
时钟切换测试代码:
`timescale 1ns/1ns
module clk_syn_tb;
parameter DLY=1;
reg rst_n;
reg clka;
reg clkb;
reg sel_clkb;
wire clk_o;
clk_syn_tst test1(
//input
.rst_n (rst_n), //system reset
.clka (clka), //clock A
.clkb (clkb), //clock B
.sel_clkb (sel_clkb),//pulse input from clka
// output
.clk_o (clk_o)//pulse output in clkb
);
initial
begin
rst_n=0;
clka=0;
clkb=0;
sel_clkb=0;
#20 rst_n =1;
#500 sel_clkb=1;
#500 sel_clkb=0;
end
always #5 clka<=~clka;
always #20 clkb<=~clkb;
//always @(posedge clka or negedge rst_n)
//begin
//if(rst_n==1'b0)
//puls_a_in<=0;
//else
//puls_a_in<=# DLY $random %2;
//end
endmodule
本文代码部分中clka即为CLK0,clkb即为CLK1,sel_clkb即为SELECT,时钟切换的结构有些不同,
begin
sel_clkb_d0 <= sel_clkb & (~sel_clka_dly3) ;
sel_clkb_d1 <= sel_clkb_d0 ;
end
代码相当于将(sel_clkb)&(~sel_clka_dly3)之后,再打两拍在反馈回路上增加两个DFF,结合sel_clkb_d1之后经过了三拍延迟,
begin
sel_clkb_dly1 <= sel_clkb_d1;
sel_clkb_dly2 <= sel_clkb_dly1 ;
sel_clkb_dly3 <= sel_clkb_dly2 ;
end
故由sel_clkb由0变为1时,clk_o在经过5个clkb下降沿之后,才由clka切换至clkb。同时在这里需要考虑两个问题:
(1)为什么part4中,需要在下降沿(negedge)对sel_clkb_d1进行采样,假设采用上升沿(posedge)对sel_clkb_d1进行采样,结果又会怎样:
//always @ (posedge clka_n or negedge rst_n)
always @ (negedge clka or negedge rst_n)
begin
if (!rst_n)
begin
sel_clka_dly1 <= 1'b0;
sel_clka_dly2 <= 1'b0;
sel_clka_dly3 <= 1'b0;
end
else
begin
sel_clka_dly1 <= sel_clka_d1;
sel_clka_dly2 <= sel_clka_dly1 ;
sel_clka_dly3 <= sel_clka_dly2 ;
end
end
采用下降沿对sel_clkb_d1进行采样:
采用上升沿对sel_clkb_d1进行采样:
圆圈中的毛刺是由于在sel_clkb由0变为1时,需要5个clka时钟输出clk_o才关闭,但是由于是在clka上升沿进行采样,之后与clka进行&操作,&操作在clk上升沿之后,故进行与操作会产生毛刺。
(2)在对寄存器进行赋值时,为什么复位初始值都设置为0,这里面出于什么考虑:
// part2
//always @ (posedge clka_n or negedge rst_n)
always @ (negedge clka or negedge rst_n)
begin
if (!rst_n)
begin
sel_clka_dly1 <= 1'b0;
sel_clka_dly2 <= 1'b0;
sel_clka_dly3 <= 1'b0;
end
复位初始值设置为0:
此时sel_clka_dly3与sel_clkb_dly3都为0,即在复位时将clk_o锁住,输出为0,在rst_n被拉起后,经过5个clka,clka的使能信号sel_clkb(0)才被采到。
假设与clkb相关的寄存器复位状态都设置为1,与clka相关的寄存器复位状态都设置为0,则时序图为:
此时相当于clk_o由时钟clkb向clka进行了切换,因此在复位的时候进行了依次切换。
至于代码中part5部分,关于clock gating cell 的说明可以参考:
https://blog.csdn.net/github_33678609/article/details/54575442
本文参考EETimes文章,连接https://www.eetimes.com/document.asp?doc_id=1202359;
最后
以上就是糊涂高跟鞋为你收集整理的Verilog学习心得之一-----时钟无缝切换的全部内容,希望文章能够帮你解决Verilog学习心得之一-----时钟无缝切换所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复