Search code examples
eventsveriloghdlsynthesis

Can clock edge events be synthesized inside always blocks in verilog?


I have two clocks, clk0 and clk1. I want a counter to count on posedge of clk0 but reset at posedge of clk1. The important thing to note is that the reset should occur only on the posedge and not when clk1 is high. So the below code is not possible.

always @(posedge clk0 or posedge clk1)
begin
     if (clk1)
              count <= 0;
     else
              count <= count + 1;
end

We cannot drive the counter from two always blocks as well. So the below is not possible:

always @ (posedge clk0)
begin
     count <= count + 1;
end

always @ (posedge clk1)
begin
     count <= 0;
end

So my question: What offers a similar functionality like

always @(posedge clk0 or posedge clk1)
begin
     if (posedge clk1)
              count <= 0;
     else
              count <= count + 1;
end

And is synthesizable?

I want a counter which counts on posedge of clk0 and resets on posedge of clk1. clk0 is faster than clk1 by an order of magnitude. The design needs to be synthesizable.


Solution

  • You need to transfer the 'event' from clk1 to clk0. This is a clock domain crossing issue and thus requires synchronization.

    reg clk1_meta,clk1_sync,clk1_prev;
    always @(posedge clk0 or negedge reset_n) // async low reset as example
    begin
       if (!reset_n)
       begin
          clk1_meta <= 1'b0; 
          clk1_sync <= 1'b0; 
          clk1_prev <= 1'b0;
          counter   <= 'b0;       
       end
       else
       begin
          // transfer clk1 to clk0
          clk1_meta <= clk1;
          clk1_sync <= clk1_meta;
    
          // Now we have a safe signal: clk1_sync          
          clk1_prev <= clk1_sync;
          // A rising edge is when clk1_sync1 is high but previously it was low
          if (clk1_sync==1'b1 && clk1_prev==1'b0)
             counter <= 'b0;
          else
             counter <= counter + 1;
       end
    end
    

    There is an unavoidable delay of ~2 clk0 clock cycles before the clk1 arrives in the clk0 domain because of the synchronisation.