Verilog基本电路设计(转)收藏
(帖子链接:bbs.eetop.cn/thread-605419-1-1.html)
看到坛子里不少朋友,对于基本数字电路存在这样那样的疑惑,本人决定开贴,介绍数字电路最常见的模块单元,希望给初学者带来帮助,也欢迎大佬们前来拍砖。如果想要做数字设计,下面这些电路是一定会碰到的,也是所有大型IP,SOC设计必不可少的基础,主要包括异步信号的同步处理,同步FIFO,异步FIFO,时钟无缝切换,信号滤波debounce等等,后面会根据大家反馈情况再介绍新电路。
首先介绍异步信号的跨时钟域同步问题。一般分为单bit的控制信号同步,以及多bit的数据信号同步。多bit的信号同步会使用异步FIFO完成,而单bit的信号同步,又是时钟无缝切换电路以及异步FIFO电路的设计基础,这里先介绍单bit信号同步处理。
clka域下的信号signal_a,向异步的clkb域传递时,会产生亚稳态问题。所有的亚稳态,归根结底就是setup/hold时间不满足导致。在同一个时钟域下的信号,综合以及布线工具可以在data路径或者clock路径上插入buffer使得每一个DFF的setup/hold时间都满足;但是当signal_a在clkb域下使用时,由于clka与clkb异步,它们的相位关系不确定,那么在clkb的时钟沿到来时,无法确定signal_a此时是否处于稳定无变化状态,也即setup/hold时间无法确定,从而产生亚稳态。这种异步信号在前后端流程里面是无法做时序分析的,也就是静态时序分析里常说的false_path。
消除亚稳态,就是采用多级DFF来采样来自另一个时钟域的信号,级数越多,同步过来的信号越稳定。对于频率很高的设计,建议至少用三级DFF,而两级DFF同步则是所有异步信号处理的最基本要求。
单bit的信号跨时钟域同步,又分成电平信号同步以及脉冲信号同步。电平信号,就是说clka下的信号signal_a在clkb看来,是一个很宽的信号,会保持多个clkb的时钟周期,一定能被clkb采到。这种情况,只需要使用clkb用至少两级DFF连续抓signal_a即可,特别需要强调的是,此时signal_a必须是clka下的寄存器信号,如果signal_a是clka下的组合逻辑信号,一定要先在clka下用DFF抓一拍,再使用两级DFF向clkb传递。这是因为clka下的组合逻辑信号会有毛刺,在clka下使用时会由setup/hold时间保证毛刺不会被clka采到,但由于异步相位不确定,组合逻辑的毛刺却极有可能被clkb采到。电平信号的同步处理,一般用于知道确定的时钟频率大小关系或者极慢时钟下的信号向极快时钟域传递时使用,简单处理如下:
always @ (posedge clkb or negedge rst_n)begin
if (!rst_n) begin
levl_b_d1 > 1) ^ nxt_wptr_wclk ;
always @ (posedge af_wclk or negedge rst_n)
begin
if (rst_n == 1'b0) begin
wptr_wclk > 1) ^ nxt_rptr_rclk ;
always @ (posedge af_rclk or negedge rst_n)
begin
if (rst_n == 1'b0) begin
rptr_rclk = 5'h7) ;
endmodule
上面给出的是深度16,宽度32的示例,大家可以使用parameter参数化定义深度和宽度,方便不同需求下的调用。除了空满信号标志,也可以根据需要做出半空半满之类信号。上面需要注意的一点就是,格雷码必须在本时钟域下DFF输出,再往另一个时钟域同步。同步FIFO呢,就不用有格雷码转换,设计更加简单,就不专门开贴描述了。
?
Verilog基本电路设计之四: 去抖滤波
(帖子链接:http://bbs.eetop.cn/thread-605729-1-1.html)
debounce电路,就是常说的去抖滤波,主要用在芯片的PAD输入信号,或者模拟电路输出给数字电路的信号上。
parameter BIT_NUM = 4 ;
reg [BIT_NUM-1 : 0] signal_deb ; //
always @ (posedge clk or negedge rst_n)
begin
if (rst_n == 1'b0)
signal_deb <= {BIT_NUM{1'b0}} ;
else
signal_deb <= # DLY {signal_deb[BIT_NUM-2:0],signal_i} ;
end
always @ (posedge clk or negedge rst_n)
begin
if (rst_n == 1'b0)
signal_o <= 1'b1 ;
else if (signal_deb[3:1]==3'b111)
signal_o <= # DLY 1'b1 ;
else if (signal_deb[3:1]==3'b000)
signal_o <= # DLY 1'b0 ;
else ;
end
上面的电路,第一个always,还兼顾了去亚稳态作用。它可以滤掉的宽度是两个clk的cycle,对于大于两个cycle而小于三个cycle的信号,有些可以滤掉,有些不能滤掉,这与signal_i相对clk的相位有关。
根据希望滤除的宽度相关,换算到clk下是多少个cycle数,从而决定使用多少级DFF。如果希望滤除的宽度相对 cycle数而言较大,可以先在clk下做一个计数器,产生固定间隔的脉冲,再在脉冲信号有效时使用多级DFF去抓signal_i;或者直接将clk分频后再使用。
谢谢小编无私的奉献