在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 5821|回复: 2

[转贴] 时钟切换电路

[复制链接]
发表于 2019-7-14 12:15:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
时钟切换电路其实就是两个clockgate电路

本文讨论了时钟切换的两种基本情况以及两种基本电路结构,讨论了一些问题:下图是一个时钟选择的简单实现以及时序图,使用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
---------------------
作者:poirot12
来源:CSDN
原文:https://blog.csdn.net/u010668547/article/details/80250997
版权声明:本文为博主原创文章,转载请附上博文链接!

发表于 2019-7-15 09:04:00 | 显示全部楼层
dingiexian
发表于 3 天前 | 显示全部楼层
学习一下!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条


小黑屋| 手机版| 关于我们| 联系我们| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-12-28 14:05 , Processed in 0.014701 second(s), 6 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表