赞
踩
Tsu:是指在触发器的时钟信号上升沿到来以前,数据稳定不变的时间,如果建立时间不够,数据将不能在这个时钟上升沿被稳定的打入触发器,Tsu就是指这个最小的稳定时间
Th:是指在触发器的时钟信号上升沿到来以后,数据稳定不变的时间,如果保持时间不够,数据同样不能被稳定的打入触发器,Th就是指这个最小的保持时间
产生原因:简单来说,就是当时钟信号上升沿到来的时候正好采样的数据也在发生变化,但是对于采样的时钟信号,如果想要采样得到一个稳定值,在clk的上升沿的前一段时间有一个建立时间TSU和在clk的上升沿的后一段时间有一个保持时间Th,如果在这两个时间段内采样的信号D发生跳变的话,输出的信号Q就会出现0,1之间跳变的不稳定、不确定状态,从而对采样结果产生干扰,这就是亚稳态。
解决方法:
仅仅适用于 慢时钟域到快时钟域
由上图可知,采样信号sig是慢时钟域的信号,正好当第一个clk上升沿建立时间和保持时间内采样信号发生了变化,reg1及出现了一个亚稳态的状态,当第二个采样时钟对reg1进行采样时,在第二个clk上升沿的建立时间和保持时间的范围内 reg1保持在稳定的概率要比第一个时刻大得多,相应的发生亚稳态的概率也会减小,一般来说,第一级寄存器的发生亚稳态的之后稳定的概率为70%,第二次寄存器发生亚稳态之后稳定的概率为99%
就是说在绝大多数时候,第一级寄存器即使出现亚稳态,也会在一个时钟周期内稳定下来,这样第二级寄存器就会采到的就是一个稳定的值。并不是说第二级寄存器所输出的第一个状态 就是输入的第一个状态,只能说第二个寄存器输出第一个的状态是稳定的,之后的状态是跟输入的状态保持一致的
2.打拍子
在FPGA中,常见病的打拍子 :我们可以理解为把某个信号延迟了一个时钟周期,推而广之:“打两拍”就是延迟两个时钟周期,“打n拍”就是延迟n个时钟周期。
其实不是每个信号都需要打拍子,打两拍是为了消除亚稳态。
(1)在全同步设计中,如果信号来自同一时钟域,各模块的输入不需要寄存。
(2)如果这个输入信号来自异步时钟域(比如FPGA芯片外部的输入),必须寄存两拍。第一拍将输入信号同步化,同步化后的输出可能带来建立/保持时间的冲突,产生亚稳态。需要再寄存一拍,减少(注意是减少)亚稳态带来的影响。
3.异步复位跟同步复位
同步复位:(缺点:复位信号的有效时长必须大于时钟周期,才能真正被系统识别并完成复位任务)
复位信号只有在时钟上升沿到来时才能有效。
verilog中表现形式:
always@(posedge sys_clk)
3.异步复位:(缺点:复位信号容易受到毛刺的影响或者亚稳态)
无论时钟沿是否到来,只要复位信号有效,就进行复位。
verilog中表现形式:
always@(posedge sys_clk or negedge rst_n)
推荐使用异步复位,同步释放的方式,而且复位信号低电平有效。
所谓异步复位同步释放,就是在rst_n信号为低时,立刻进行复位,而rst_n信号由低到高释放时,为了防止亚稳态的出现,将rst_n信号用DFF向后延一周期,达到与时钟clk边沿同步的目的。
在这里插入代码片 module asyn_reset( clk , rst_n , rst_s2 ); input clk ; input rst_n ; output reg rst_s2; reg rst_s1; always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin rst_s1 <= 1'b0; rst_s2 <= 1'b0; end else begin rst_s1 <= 1'b1 ; rst_s2 <= rst_s1 ; end end endmodule
具体可以参考这个:
在这里插入代码片
https://blog.csdn.net/zhangduang_KHKW/article/details/122308445?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165580279416781435434710%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165580279416781435434710&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-10-122308445-null-null.142^v20^control,157^v15^new_3&utm_term=%E5%BC%82%E6%AD%A5%E5%A4%8D%E4%BD%8D%EF%BC%8C%E5%90%8C%E6%AD%A5%E9%87%8A%E6%94%BE&spm=1018.2226.3001.4187
之前按照CSDN在vivado中试过三段式状态机,踩过一些坑。比如按照网上教程,仿真中没有任何问题,下载到开发板中状态切换不成功。下面是我做的一个乒乓FIFO三段式状态机
在这里插入代码片 //第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器 always @ (posedge clk or negedge rst_n) //异步复位 if(!rst_n) current_state <= IDLE; else current_state <= next_state;//注意,使用的是非阻塞赋值 //第二个进程,组合逻辑always模块,描述状态转移条件判断 always @ (current_state) //电平触发 begin next_state = x; //要初始化,使得系统复位后能进入正确的状态 case(current_state) S1: if(...) next_state = S2; //阻塞赋值 ... endcase end //第三个进程,同步时序always模块,格式化描述次态寄存器输出 always @ (posedge clk or negedge rst_n) //初始化 .... case(next_state) S1: out1 <= 1'b1; //注意是非阻塞逻辑 S2: out2 <= 1'b1; default:... //default的作用是免除综合工具综合出锁存器。 endcase end
三段式:状态切换用时序逻辑,次态输出用组合逻辑,信号输出用时序逻辑。
其中有个坑: 第二段的条件,如果使用仿真always @ (current_state) 或者 always@(*)或者always@(posedge clk)都是正确的,但是当你下载到开发板中,你会发现always@(posedge clk)切换状态不成功,前面两种都可以。
当然,还需要注意的是:组合逻辑跟时序逻辑的非阻塞赋值跟阻塞赋值。第二段状态机是时序逻辑,用的阻塞赋值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。