How to interrupt an uncompleted delay in SystemVerilog

74 views Asked by At

I want to apply a different rising and falling delay to a signal using the following code:

  timeunit            1ns;
  timeprecision       1ps;
  parameter   real    delay_en_rising_us  = 100.0;    // means 100us
  parameter   real    delay_en_falling_us = 300.0;    // means 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;

The Scenario 1 shows the results which are looking good.

enter image description here

However, if I change the delays like this:

parameter   real    delay_en_rising_us  = 100.0;      // means 1000us
parameter   real    delay_en_falling_us = 1500.0;     // means 1500us

Then the results are like shown in Scenario 2 which are not what I was expecting and trying to achieve.

enter image description here

Actually, the falling delay of 1500us at signal "en_delayed" should be immediately canceled or interrupted if the signal "en" goes high. See following picture showing the expected behaviour.

enter image description here

In summary, if there is a delay which has not completed and the signal "en" suddenly changes then that uncompleted delay should be immediately interrupted.

Thank you very much for any suggestion.

Below is the code for simulation.

module top;
  
  timeunit            1ns;
  timeprecision       1ps;

  //--------------------------------------------------------  
  // This is working fine
  parameter   real    delay_en_rising_us  = 100.0;    // means 100us
  parameter   real    delay_en_falling_us = 300.0;    // means 300us

  // This is not working fine or as expected
  //parameter   real    delay_en_rising_us  = 100.0;      // means 1000us
  //parameter   real    delay_en_falling_us = 1500.0;     // means 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 begin
  initial fork
    $dumpfile("dump.vcd"); $dumpvars;
    
    //en = 0;
    //#100us  en = 1;       
    //#1000us en = 0; 
    //#3000us en = 1; 

    en = 1;
    #1000us en = 0;
    #2000us en = 1;
    
    #5000us $finish;

  join

 //------------------------------------------------------------------------------------------------ 

endmodule
1

There are 1 answers

0
Parth Pandya On

I think you need code like below. en_delayed will be 1'b0 at time 0ns in this.

always@(posedge en)
  begin   
     en_delayed <=0;
     en_delayed <= #(delay_en_rising_us*1us) 1'b1;
  end   
  always@(negedge en)
  begin
     en_delayed <= 1;
     en_delayed <= #(delay_en_falling_us*1us) 1'b0;
  end