异步信号场景下,采用与门阻断时钟的设计方案是否可接受?
问题描述
我需要判断异步的BLOCK信号是否早于5个clk周期到来,由于两者异步,无法使用如下经典结构:
always(posedge clk) if(cnt==4 && !BLOCK) flag<=1; else flag<=0; //只有当BLOCK信号未在5个clk周期前到来时,flag才会被置1 always(posedge clk) cnt <= cnt + 1;
我尝试通过在BLOCK信号到来时阻断clk,使其停止为flag模块提供时钟,避免flag被置1,对应的设计代码如下:
wire clk_flag = clk & !BLOCK; always(posedge clk_flag) if(cnt==4) flag<=1; else flag<=0; //只有当BLOCK信号未在5个clk周期前到来时,flag才会被置1 always(posedge clk) cnt <= cnt + 1;
请问这种通过与门组合信号作为时钟的设计方式是否可接受?
回答
这种用与门组合生成时钟的方式绝对不可接受,核心问题如下:
- 毛刺触发风险:BLOCK是异步信号,和clk通过与门组合时,极易产生时钟毛刺。这些毛刺会被寄存器识别为有效时钟沿,导致
flag出现无规律的错误翻转,直接破坏电路功能。 - 时序分析失效:FPGA/ASIC的时序分析工具无法对这类组合时钟进行准确的时序检查,建立时间、保持时间等关键参数无法验证,后期调试和时序收敛会陷入极大困境。
- 时钟树破坏:芯片内部的时钟树会对时钟信号做延迟均衡处理,保证时钟到达各寄存器的时间一致。而组合生成的时钟绕开了时钟树,会导致时钟偏移(skew)过大,进一步恶化时序问题。
正确的实现思路是:
- 先对异步的BLOCK信号做两级寄存器同步,将其纳入clk时钟域,避免亚稳态问题。
- 在clk域内用同步后的BLOCK信号控制计数器和flag逻辑,比如当同步后的BLOCK信号到来时,立即复位计数器或阻止flag置1。
参考代码如下:
// 异步BLOCK信号同步到clk域 reg BLOCK_sync1, BLOCK_sync2; always(posedge clk) begin BLOCK_sync1 <= BLOCK; BLOCK_sync2 <= BLOCK_sync1; end reg [2:0] cnt; reg flag; always(posedge clk) begin if(BLOCK_sync2) begin cnt <= 3'd0; flag <= 1'b0; end else begin if(cnt == 3'd4) begin flag <= 1'b1; cnt <= cnt; // 计数到5个周期后保持状态 end else begin cnt <= cnt + 1'b1; flag <= 1'b0; end end end
该方案既解决了异步信号的同步问题,又规避了组合时钟带来的各类风险,同时能被时序分析工具正常识别,便于后续调试和优化。
内容的提问来源于stack exchange,提问作者den251
相关产品推荐
相关产品推荐

