You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一模块中时钟正负沿always块的正确改写方案咨询

时钟正负沿触发模块的正确改写方法

问题背景

了解到同一模块中不要混用同一时钟的上升沿(posedge)和下降沿(negedge)触发(可综合但分析难度大),于是尝试将原有的分别使用always @(posedge clk)和always @(negedge clk)的代码,改写为单个always @(posedge clk)块内的逻辑,但改写后波形与原代码不一致。现附上相关代码,寻求正确改写方案。


原代码(正负沿混用版本)

`timescale 1ns / 1ps

module DEFF (
    input clk, reset, in,
    output out
);

    reg trig1 = 0, trig2 = 0;

    assign out = trig1 ^ trig2;

always @(posedge clk, posedge reset) begin
    if (reset) trig1 <= 0;
    trig1 <= in^trig2;
end

always @(negedge clk, posedge reset) begin
    if (reset) trig2 <= 0;
    trig2 <= in^trig1;
end

endmodule

改写后代码(存在问题)

module DEFF (
    input clk, reset, in,
    output out
);

reg clk_prev = 1'b0;
reg trig1 = 0, trig2 = 0;
reg pos_edge_detected = 0;
reg neg_edge_detected = 0;

assign out = trig1 ^ trig2;

always @(posedge clk, posedge reset) begin
    if (reset) begin
        trig1 <= 0;
        trig2 <= 0;
    end else begin
        trig1 <= in ^ trig2;
        if (!trig1) begin
            trig2 <= in ^ trig1;
        end
    end
end
endmodule

测试平台

`timescale 1ns / 1ps

module TB_DEFF;

    // Inputs
    reg clk;
    reg reset = 0;
    reg in;
    // Outputs
    wire out;

    // Instantiate the Unit Under Test (UUT)
    DEFF DUT (
        .clk(clk),
        .reset(reset),
        .in(in),
        .out(out)
    );

    always #5 clk = ~clk;

    // Toggle the clock and input
    initial begin
        clk = 0;
        reset = 1;
        in = 0;
        #10 reset = 0;
        #10 in = 1;
        #20 in = 0;
        #20 in = 1;
        #20 in = 0;
        #20 $finish;
    end

endmodule

正确改写方案

原代码核心是trig1在时钟上升沿更新、trig2在下降沿更新,且两者互相依赖。要合并到单个上升沿块中,关键是在上升沿逻辑中检测并模拟下降沿的时序行为,具体实现如下:

修正后的代码

`timescale 1ns / 1ps

module DEFF (
    input clk, reset, in,
    output out
);

reg trig1 = 0, trig2 = 0;
reg clk_prev = 1'b0; // 记录上一个时钟周期的电平,用于检测下降沿

assign out = trig1 ^ trig2;

always @(posedge clk, posedge reset) begin
    if (reset) begin
        trig1 <= 1'b0;
        trig2 <= 1'b0;
        clk_prev <= 1'b0;
    end else begin
        // 检测下降沿:上一个时钟为高、当前为低,说明两个上升沿之间发生了下降沿
        if (clk_prev == 1'b1 && clk == 1'b0) begin
            // 执行原下降沿逻辑:用当前trig1的值更新trig2
            trig2 <= in ^ trig1;
        end
        
        // 执行原上升沿逻辑:用当前trig2的值更新trig1
        trig1 <= in ^ trig2;
        
        // 更新上一个时钟的电平记录
        clk_prev <= clk;
    end
end

endmodule

关键说明

  1. 下降沿检测:通过clk_prev记录上一个上升沿时的时钟电平,当clk_prev=1且当前clk=0时,即可判断两个上升沿之间发生了下降沿。
  2. 时序匹配:先处理下降沿的trig2更新,再处理上升沿的trig1更新,完全匹配原代码中"上升沿更新trig1→下降沿更新trig2"的时序逻辑,确保波形一致。
  3. 可综合与易分析:这种写法仅使用时钟上升沿触发,避免了正负沿混用的问题,同时保持原有功能,更便于时序分析和维护。

内容的提问来源于stack exchange,提问作者kyw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 02:22:00