1

I made a basic example on eda playground of the issue I got. Let s say I have two clocks 1x and 2x. 2x is divided from 1x using flop divider.

I have two registers a and b. a is clocked on 1x, b is clocked in 2x.

b is sampling value of a.

When we have rising edge of 1x and 2x clocks, b is not taking the expected value of a but it s taking the next cycle value.

This is because of this clock divider scheme, if we make division using icgs and en it works fine. But is there a way to make it work using this clock divider scheme with flops ?

EDA playground link : https://www.edaplayground.com/x/map#

module race_test;

  logic clk1x = 0;
  logic clk2x = 0;

  always
    #5ns clk1x = !clk1x;

  int a, b;


  always @(posedge clk1x) begin
    a <= a+1;
    clk2x <= !clk2x;
  end

  // Problem here is that b will sample postpone value of a
  // clk2x is not triggering at the same time than clk1x but a bit later
  // This can be workaround by putting blocking assignment for clock divider
  always @(posedge clk2x) begin
    b <= a;
  end

  initial begin
    $dumpfile("test.vcd");
    $dumpvars;
    #1us
    $stop;
  end
endmodule
Matthew Taylor
  • 13,365
  • 3
  • 17
  • 44
Viktorinox
  • 120
  • 1
  • 9
  • 1
    See [here](https://books.google.de/books?id=_VGghBpoK6cC&pg=PA64&lpg=PA64&dq=verilog+race+condition+clock+divider&source=bl&ots=F5fLBRXVz1&sig=K7uY3Li9vc6m6pSj7i3xXEfS3_I&hl=de&sa=X&ved=2ahUKEwjL6MqCp_LdAhXMyIUKHU3QBMsQ6AEwAnoECAcQAQ#v=onepage&q=verilog%20race%20condition%20clock%20divider&f=false) – mkrieger1 Oct 06 '18 at 17:09
  • Thanks for the link, that s what I was expecting. It is working as intended using blocking assignment for clock divider. But is this correct if my clock divider is not a model but a real flop that will be in my chip ? In the book they say that synthesizers will be fine with that (hopefully) – Viktorinox Oct 06 '18 at 17:16
  • in general, rule of thumb is, that you **never** use NBAs for clocks to avoid the race. – Serge Oct 07 '18 at 14:40

2 Answers2

1

Digital clock dividers present problems with both simulation and physical timing.

Verilog's non-blocking assignment operator assumes that everyone reading and writing the same variables are synchronized to the same clock event. By using an NBA writing to clk2x, you have shifted the reading of a to another delta time*, and as you discovered, a has already been updated.

In real hardware, there are considerable propagation delays that usually avoid this situation. However, you are using the same D-flop to assign to clk2x, so there will be propagation delays there as well. You last always block now represents a clock domain crossing issue. So depending on the skews between the two clocks, you could still have a race condition.

One way of correcting this is using a clock generator module with an even higher frequency clock

always #2.5ns clk = !clk;

always @(posedge clk) begin
       clk1x <= !clk1x;
       if (clk1x == 1)
         clk2x = !clk2x;
dave_59
  • 39,096
  • 3
  • 24
  • 63
  • Hi Dave, the solution you provide is fine if the code is used for modeling or verification. In my case, the flop used for clock division is used in RTL, I want to be sure synthesizer correctly implements it. The cleanest way I found to fix it, is to replace divider scheme with ICG in case it is possible. But the only case where it s no possible it s when my generated clocks have to be 50/50 duty cycle. Is there a way to generate 50/50 clock with ICGs ? – Viktorinox Oct 07 '18 at 15:38
  • I think the answer depends on the technology you are using, and where the clk1x is coming from. Maybe a better question for https://electronics.stackexchange.com – dave_59 Oct 08 '18 at 01:17
0

Of course you have solved this problem, but I think there is a better way. The book says one can use blocking assignment to avoid race. But blocking assignemnt causes errors in synopsys lint check. So, one way to avoid race problem without lint error is to use dummy logic, like this

wire [31:0] a_logic;
wire dummy_sel;
assign dummy_sel = 1'b0;
assign a_logic = dummy_sel ? ~a : a;
always @(posedge clk2x) begin
  b <= a_logic;
end
Vito
  • 1