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

如何在SystemVerilog中中断未完成的信号延迟?

问题:Verilog实现带中断功能的信号上升/下降延迟

问题背景

我尝试用以下代码为信号设置不同的上升和下降延迟:

timeunit            1ns;
timeprecision       1ps;
parameter   real    delay_en_rising_us  = 100.0;    // 上升延迟100us
parameter   real    delay_en_falling_us = 300.0;    // 下降延迟300us
logic en;
logic en_delayed;

always_comb
  if ($realtime == 0)
    en_delayed = en;
  else if (en)
    en_delayed <= #(delay_en_rising_us*1us) en;
  else
    en_delayed <= #(delay_en_falling_us*1us) en;
  • 场景1:使用上述参数时,仿真结果符合预期
    场景1仿真结果

  • 场景2:修改延迟参数为以下值时,仿真结果不符合预期

    parameter   real    delay_en_rising_us  = 100.0;      // 上升延迟100us
    parameter   real    delay_en_falling_us = 1500.0;     // 下降延迟1500us
    

    场景2仿真结果

实际需求

当信号en变为高电平时,需要立即取消en_delayed上未完成的下降延迟,预期行为如下:
预期仿真结果

完整仿真代码如下:

module top;
  
  timeunit            1ns;
  timeprecision       1ps;

  // 正常工作的参数
  parameter   real    delay_en_rising_us  = 100.0;    // 上升延迟100us
  parameter   real    delay_en_falling_us = 300.0;    // 下降延迟300us

  // 存在问题的参数
  //parameter   real    delay_en_rising_us  = 100.0;      // 上升延迟100us
  //parameter   real    delay_en_falling_us = 1500.0;     // 下降延迟1500us
  
  logic en;
  logic en_delayed;
  
  always_comb
    if ($realtime == 0)
      en_delayed = en;
    else if (en)
      en_delayed <= #(delay_en_rising_us*1us) en;
    else
      en_delayed <= #(delay_en_falling_us*1us) en;
  
  initial fork
    $dumpfile("dump.vcd"); $dumpvars;
    
    en = 1;
    #1000us en = 0;
    #2000us en = 1;
    
    #5000us $finish;

  join

endmodule

解决方案

原代码的核心问题是:always_comb中使用非阻塞延迟赋值时,每次en变化都会向仿真事件队列中添加新的延迟任务,但之前未完成的任务不会被自动取消,导致多个任务同时执行,出现不符合预期的输出。

方法1:任务+禁用任务实现延迟中断

module top;
  
  timeunit            1ns;
  timeprecision       1ps;

  // 测试存在问题的参数
  parameter   real    delay_en_rising_us  = 100.0;      // 上升延迟100us
  parameter   real    delay_en_falling_us = 1500.0;     // 下降延迟1500us
  
  logic en;
  logic en_delayed;

  // 定义自动任务,每次调用都会生成独立实例
  task automatic delay_update;
    if (en) begin
      #(delay_en_rising_us*1us);
      en_delayed = en;
    end else begin
      #(delay_en_falling_us*1us);
      en_delayed = en;
    end
  endtask

  // 当en变化时,取消之前的任务并启动新任务
  always @(en) begin
    disable delay_update;
    fork
      delay_update();
    join_none
  end

  // 仿真控制逻辑
  initial fork
    $dumpfile("dump.vcd"); 
    $dumpvars;
    
    en = 1;
    #1000us en = 0;
    #2000us en = 1;
    
    #5000us $finish;
  join

endmodule

方法2:带状态标记的事件控制实现

通过标记位跟踪未完成的延迟任务,在en变化时主动取消:

module top;
  
  timeunit            1ns;
  timeprecision       1ps;

  parameter   real    delay_en_rising_us  = 100.0;
  parameter   real    delay_en_falling_us = 1500.0;
  
  logic en;
  logic en_delayed;
  bit update_pending; // 标记是否有未完成的延迟任务

  always @(en) begin
    // 若存在未完成任务,立即取消
    if (update_pending) begin
      disable delayed_update;
      update_pending = 0;
    end
    // 启动新的延迟更新任务
    fork : delayed_update
      update_pending = 1;
      if (en) begin
        #(delay_en_rising_us*1us);
        en_delayed = en;
      end else begin
        #(delay_en_falling_us*1us);
        en_delayed = en;
      end
      update_pending = 0;
    join_none
  end

  // 仿真初始化
  initial fork
    $dumpfile("dump.vcd"); $dumpvars;
    
    en = 1;
    #1000us en = 0;
    #2000us en = 1;
    
    #5000us $finish;
  join

endmodule

核心原理

两种方法均通过disable关键字终止未完成的延迟任务,确保每次en变化时,只有最新的延迟逻辑在执行,从而实现“信号变化时中断未完成延迟”的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:02:10