jjzjj

【数字IC手撕代码】Verilog无毛刺时钟切换电路|题目|原理|设计|仿真

myhhhhhhhh 2024-02-21 原文
芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球
四社区联合力荐!近500篇数字IC精品文章收录
【数字IC精品文章收录】学习路线·基础知识·总线·脚本语言·芯片求职·EDA工具·低功耗设计Verilog·STA·设计·验证·FPGA·架构·AMBA·书籍


Verilog无毛刺时钟切换电路

一、前言

本系列旨在提供100%准确的数字IC设计/验证手撕代码环节的题目,原理,RTL设计,Testbench和参考仿真波形,每篇文章的内容都经过仿真核对。快速导航链接如下:

1.奇数分频
2.偶数分频
3.半整数分批
4.小数/分数分频
5.序列检测器
6.模三检测器
7.饮料机
8.异步复位,同步释放
9.边沿检测(上升沿,下降沿,双边沿)
10.全加器,半加器
11.格雷码转二进制
12.单bit跨时钟域(打两拍,边沿同步,脉冲同步)
13.奇偶校验
14.伪随机数生成器[线性反馈移位寄存器]
15.同步FIFO
16.无毛刺时钟切换电路

应当说,手撕代码环节是面试流程中既重要又简单的一个环节,跟软件类的岗位相比起来,数字IC的手撕代码题目固定,数量有限,属于整个面试中必得分的一个环节,在这个系列以外,笔者同样推荐数字IC求职者使用“HdlBits”进行代码的训练
链接如下
HDLBits — Verilog Practice

二、题目

为了SOC设计的低功耗性,多时钟域的划分是常用手段之一,有两个时钟,A为50Mhz,B为100Mhz,请设计无毛刺时钟切换电路,根据控制信号control,输出所需时钟信号

三、原理

3.1 有毛刺时钟切换

想要切换时钟电路,最简单的方法肯定是使用一个MUX,control作为控制信号
control=1,clk_output = clk_50M,
control=0,clk_output =clk_100M,

但是这种做法会存在毛刺问题,如图所示,当control信号转换的边缘时,假如clk_50M与clk_100M的边沿没对准,就有可能出现毛刺,影响时钟质量

因此我们需要无毛刺时钟切换电路的帮助,进入下一节

3.2 无毛刺时钟切换

首先我们需要明确的是,毛刺发生的原因

control信号至少对一个时钟信号为异步信号,导致了毛刺的出现,假如control,clk_50M,还是clk_100M都是边沿完全同步的理想信号话,应该是不会出现毛刺的

所以避免毛刺发生的方法顺理成章地过渡到了“异步信号同步化”这个理论上面,如何做同步呢?

毫无疑问,肯定是需要打拍/采样的方式

上升沿同步还是下降沿同步呢?

这里是上升沿打拍还是下降沿打拍其实是因电路而异的一个问题,我们假如希望最终用与门处理时钟信号和控制信号
即:当control信号为1时,按照时钟输出,control信号为0,输出为0(即相与逻辑)
没有电路会是完全理想的边沿完全同步的信号
假如是上升沿同步control信号,同步的control会比clk的边沿稍微慢一点点,二者相与,肯定会出现毛刺
假如是下降沿同步control有效信号,下降沿到来时,control被同步后为1,clk此时为0,二者相与为0,上升沿到来时,control保持,clk为1,二者相与为1,无毛刺出现,所以用与逻辑的时候,需要采用下降沿去做触发

只打一拍,够吗?

不够,若control信号的改变恰好在采样边沿,会存在出现亚稳态的风险,所以我们可以打两拍第一拍可以采用上升沿,第二拍可以采用下降沿。

那只打拍,够吗?

不够,为什么不够呢?
因为只打拍,只能保证各自的控制信号是同步的,无毛刺,但是不能保证切换不产生毛刺,所以我们还需要增加电路来处理切换的过程,假如我们可以在切换的时候排除相邻时钟的影响,是不是就可以完美确保无毛刺的出现了?

所以以下这张图片可以登场

  1. control信号无论是从上面通过还是从下面通过,都经过两级采样,避免了亚稳态的出现
  2. 后一级的DFF用下降沿采样,避免了采样毛刺的出现
  3. 第二级DFF的not Q的逻辑以负反馈的形式接回了输入,取了与逻辑,构建起50M时钟和100M时钟的关系,代表着切换前时钟等待一阵子后,才会转换到切换后时钟,避免了切换毛刺的出现
  4. 最终上面的电路和下面的电路,以或的逻辑相取,输出clk_output.

四、RTL设计

module free_glitch(clk_50M,clk_100M,control,rst_n,clk_output);
input clk_50M; // clock with 50M frequency
input clk_100M; // clock with 100M frequency
input control; // control signal
input rst_n; // reset signal
output clk_output; // output clock

reg clk_50_r1; // register for 50M clock
reg clk_50_r2;
reg clk_100_r1;// register for 100M clock
reg clk_100_r2;

wire logic_50_ctl; // logic "and" before DFF_r1 for 50M clock
wire logic_100_ctl; // logic "and" before DFF_r2 for 100M clock

assign logic_50_ctl  =  control & !clk_100_r2; // generate logic
assign logic_100_ctl = !control & !clk_50_r2; // generate logic


always@(posedge clk_50M or negedge rst_n)
	if(!rst_n)
		clk_50_r1 <= 1'b0;
	else
		clk_50_r1 <= logic_50_ctl;
		
always@(negedge clk_50M or negedge rst_n)
	if(!rst_n)
		clk_50_r2 <= 1'b0;
	else
		clk_50_r2 <= clk_50_r1;

always@(posedge clk_100M or negedge rst_n)
	if(!rst_n)
		clk_100_r1 <= 1'b0;
	else		
		clk_100_r1 <= logic_100_ctl;


		
always@(negedge clk_100M or negedge rst_n)
	if(!rst_n)
		clk_100_r2 <= 1'b0;
	else
		clk_100_r2 <= clk_100_r1;

assign clk_output = (clk_100_r2&clk_100M) | (clk_50_r2&clk_50M ); // generate final signal clock output

endmodule

五、仿真

`timescale 1ns / 1ps
module free_glitch_tb();
reg clk_50M;
reg clk_100M;
reg control;
reg rst_n;
wire clk_output;

free_glitch u1(clk_50M,clk_100M,control,rst_n,clk_output);

always #5 clk_100M = !clk_100M;
always #10 clk_50M = !clk_50M;

initial
begin
clk_100M = 0;
clk_50M = 1;
rst_n = 1;
control = 1;
#100
rst_n = 0;
#50
rst_n = 1;
#100
control =0;
#100
control =1;
#128
control = 0;

end


endmodule

六、仿真分析

我们可以发现,当control变化后,有一段时间的时,时钟信号才切换至目标的时钟处,就是这段延时的出现,确保了没有毛刺的出现,设计符合需求

有关【数字IC手撕代码】Verilog无毛刺时钟切换电路|题目|原理|设计|仿真的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  3. ruby-on-rails - Ruby on Rails with Haml - 如何从 erb 切换 - 2

    我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h

  4. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  5. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  6. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  7. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  8. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  9. 程序员如何提高代码能力? - 2

    前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源

  10. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

随机推荐