如何用SystemVerilog设计延迟2个时钟周期输出的触发器?
正确实现2个时钟周期同步延迟的SystemVerilog方法
首先得指出你原来代码的核心问题:用#60这种固定时间延迟的写法完全不适合同步逻辑设计。从你的时钟生成代码clk=0; forever #10 clk = ~clk;能看出来,时钟周期是20ns(高低电平各10ns),#60确实是3个完整周期,但这种硬编码延迟完全脱离时钟同步——一旦你调整了时钟周期,延迟就不再对应预期的时钟数,而且在仿真中这种写法很容易导致时序混乱,这就是你达不到预期效果的根本原因。
同步逻辑里要实现精确的N个时钟周期延迟,最规范、可靠的做法是用寄存器打拍——把输入数据依次存入多级寄存器,每一级寄存器对应一个时钟周期的延迟。要实现2个时钟周期的延迟,我们只需要两级寄存器即可。
正确的代码实现
module sync_delay_2cycles ( input logic clk, input logic rst_n, // 同步低电平复位,可根据需求改为高电平复位 input logic d, output logic q ); // 定义中间寄存器,存储第一级延迟的数据 logic d_delay1; // 同步逻辑块:所有赋值都在时钟上升沿触发,严格同步 always @(posedge clk) begin if (!rst_n) begin // 复位时将所有寄存器置0 d_delay1 <= 1'b0; q <= 1'b0; end else begin // 第一级延迟:输入d在时钟上升沿存入d_delay1(延迟1个周期) d_delay1 <= d; // 第二级延迟:d_delay1在时钟上升沿存入q(再延迟1个周期,总共2个周期) q <= d_delay1; end end endmodule
工作原理说明
假设在第N个时钟上升沿,输入d变为某个有效值:
- 第N个时钟上升沿:
d_delay1被更新为当前d的值(此时q还是之前的旧值,延迟1个周期) - 第N+1个时钟上升沿:
q被更新为d_delay1的值(也就是第N个周期的d,此时刚好延迟了2个时钟周期)
这种方法完全跟时钟同步,不管你后续怎么调整时钟周期,延迟始终是精确的2个时钟周期,而且符合同步设计的规范,不管是仿真还是综合实现都能正常工作。
为什么你原来的写法不行?
你在always @(posedge clk)块里用#60 q<=d,会导致:
- 时钟上升沿触发后,等待60ns再执行赋值,但这个赋值是异步的(不在时钟事件里),会打破同步逻辑的时序规则
- 如果后续修改时钟周期(比如把#10改成#5,周期变成10ns),#60就变成了6个周期,完全不符合你的延迟需求
- 综合工具根本无法识别这种固定延迟写法,实际硬件实现时会出错
内容的提问来源于stack exchange,提问作者Ansuman Mishra
相关产品推荐
相关产品推荐

