verilogsystem-verilogicarus

why are icarus verilog specify times not respected?


My understanding of "specify" is that it controls the propagation delay from input to output.

So ..

I expect the code below to show 'o' changing at 118 - ie 10 time units after 108 when 'b' changed but instead the 'b' change is incorporated at 115 which is 10 units after a changed.

>A T=   0  a  0  b  0  o  x
>B T=   0  a  0  b  0  o  x
 O T=  10  a  0  b  0  o  0
>A T= 105  a  1  b  0  o  0
>B T= 108  a  1  b  1  o  0
 O T= 115  a  1  b  1  o  2

I expected this ....

>A T=   0  a  0  b  0  o  x
>B T=   0  a  0  b  0  o  x
 O T=  10  a  0  b  0  o  0
>A T= 105  a  1  b  0  o  0
>B T= 108  a  1  b  1  o  0
 O T= 115  a  1  b  1  o  1
 O T= 118  a  1  b  1  o  2

Have I misunderstood 'specify'?

See https://www.edaplayground.com/x/eBUY

module check(a,b,o);
  output wire [1:0] o;
  input [1:0]  a,b;

specify
    ( a => o ) = 10;
    ( b => o ) = 10;
endspecify

  assign o = a + b;

  always @ (a)
    $display (">A T=%4t  a %2d  b %2d  o %2d ", $time, a, b, o);
  always @ (b)
    $display (">B T=%4t  a %2d  b %2d  o %2d ", $time, a, b, o);
  always @ (o)
    $display (" O T=%4t  a %2d  b %2d  o %2d ", $time, a, b, o);

endmodule

module test;

  wire [1:0] o;
  logic [1:0] a,b;

  check t1(.a,.b,.o);


  initial begin
    a = 0;
    b = 0;
  end
  initial begin
    #105 a = 1;
  end
  initial begin
    #108 b = 1; // I EXPECT o TO CHANGE AS 108+10 BUT IT CHANGES AT 115
  end

endmodule

=========

Updated ...

Two alternatives that seem to work the way I expected See below and https://www.edaplayground.com/x/P7kB

module check(a,b,o);
  output reg [1:0] o;
  input [1:0]  a,b;

  // OPTION 1 - put the delays on the individual wires
  wire #10 a_delayed = a;
  wire #10 b_delayed = b;
  assign o = a_delayed + b_delayed;

  
  // OPTION 2
  // Use non-blocking with RHS delay as per https://www-inst.eecs.berkeley.edu/~cs152/fa06/handouts/CummingsHDLCON1999_BehavioralDelays_Rev1_1.pdf
  //  always @* 
  //    o <= #10 a + b;
  
  always @ (a)
    $display (">A T=%4t  a %2d  b %2d  o %2d ", $time, a, b, o);
  always @ (b)
    $display (">B T=%4t  a %2d  b %2d  o %2d ", $time, a, b, o);
  always @ (o)
    $display (" O T=%4t  a %2d  b %2d  o %2d ", $time, a, b, o);

endmodule

Both option 1 nd 2 produce the same output ...

>A T=   0  a  0  b  0  o  x 
>B T=   0  a  0  b  0  o  x 
 O T=  10  a  0  b  0  o  0 
>A T= 105  a  1  b  0  o  0 
>B T= 108  a  1  b  1  o  0 
 O T= 115  a  1  b  1  o  1 
 O T= 118  a  1  b  1  o  2 

Is there a better way to get the individual input to output propagation delays to work?

BTW This quesiton is actually part of a more complictated usecase that this question was motivated by. I am creating a timed model of a 74HCT151 and wanted the timings to be accurate as I want to generate the settling glitches that the published timing implies.

Should I create a separate question for that?


Solution

  • Specify path delays come in two forms; Parallel connection a=>o and Full connection a*>o. A parallel connection is the same as writing a[0] => o[0] and a[1] => o[1]. There is no path from a[0] => o[1], same for b[0]=>o[1].

    In your testcase, you are changing a[0] and b[0], but o[1] is changing, since there is no path, there is 0 delay. Also, the LRM section 30.7 says

    Two consecutive scheduled transitions closer together in time than the module path delay are deemed a pulse. By default, pulses on a module path output are rejected.

    That is why o goes directly from 0 to 2. You need use a Full connection.

    BTW, I could not get Icarus Verilog on EDAPlayground to match your results or give me the correct results when changing => to *>, but all the other simulators worked.


    Update

    Your option 1 filters input glitches. If a or b have glitches less than 10 time units, those get filtered out. Your option 2 passes all output glitches through, even 0 delay glitches. If you want realistic pulse filtering, you must use specify path delays with $PATHPULSE and apparently iverilog does not implement correctly.