6

Following code in systemverilog fails:

module test_dly;
  reg clk = 0;
  wire w_clk_d;

  always #1ns  clk <= ~clk;
  assign #1400ps w_clk_d = clk;
endmodule

I expected that w_clk_d will be delayed version of clk, but it is not. Seems that # not working if new event arrived before delay expired. I wrote code to deal with this, but is there way to make # work as expected? Thanks,

dave_59
  • 39,096
  • 3
  • 24
  • 63
Albert Waissman
  • 71
  • 1
  • 1
  • 5

2 Answers2

9

assign #1400ps w_clk_d = clk; acts as a delay and filter. When clk changes wait 1400ps then then apply the current value (not original value) to w_clk_d. If the input changes faster than the delay intimidated values are lost. A similar behavior can also be observed with delay cells in physical circuits.

Filtering can be reduced by chaining smaller delays; the same strategy is used with physical delay cells.

wire   #700ps clk_d = clk;
assign #700ps w_clk_d = clk_d;

A delay only without filtering can be achieved with a transport delay, which samples the value of clk when it toggles, then applies the sampled value to w_clk_d 1400ps latter

logic w_clk_d;
always @* w_clk_d <= #1400ps clk;

To keep the assignment in the schedulers active region then extra code is needed

logic w_clk_d;
always @(clk) fork
  begin
    automatic logic sample_clk; // visible only locally with in the fork thread
    sample_clk = clk; // local copy of clk
    #1400ps;
    w_clk_d = sample_clk;
  end
join_none // non-blocking, allows detection of next @(clk)
Greg
  • 18,111
  • 5
  • 46
  • 68
  • Thanks a lot, I was not aware of filtering. I implement my delay similar to your sample code, but your sample code more friendly and I will use it. – Albert Waissman Jul 29 '16 at 06:32
5

The problem here is that the continuous assign statement can only schedule one active assignment at a time. If the RHS of the assignment changes faster than what's known as the inertial delay of the continuous assignment, then the previous assignment on the LHS gets canceled or filtered.

What you want is what called transport delay: every change on the RHS will get propagated to the LHS. You can do this with a non-blocking assignment (NBA) operator.

module test_dly;
  reg clk = 0;
  wire w_clk_d;

  always #1ns  clk = ~clk;
  always @clk  w_clk_d <= #1400ps clk;
endmodule
dave_59
  • 39,096
  • 3
  • 24
  • 63