Electronic – Sharing data in two different always @(posedge …) blocks

verilog

I have the following two signals A and B

      __________                                           __________
_____|          |_________________________________________|          |_____
 __                   __    __    __    __    __    __                  __
|  |_________________|  |__|  |__|  |__|  |__|  |__|  |________________|

Note that:

  • There is no common clock between them available
  • Signal B always changes when A is low and A always changes when B is low

I would like to create a 6-bit counter that increments its value every negative edge of signal A and then outputs its value bitwise in between, exactly at the positive edges of signal B.

The problem is I have to share a state between these two, for example:

wire bit_output;
reg [5:0] counter;
reg [5:0] current_value;
always @(posedge signalA) begin
  counter <= counter + 1;
  current_value <= counter;
end

always @(posedge signalB) begin
  current_value <= { current_value[4:0], 1'b0 };
end

assign bit_value = current_value[5];

Now this is unfortunately not a valid Verilog code, for example in Xilinx ISE I get:

Signal current_value[5] in unit test is connected to following multiple drivers:

I tried placing them into one always statement but this is not possible either:

Assignment under multiple single edges is not supported for synthesis

If I had a common clock I could use a conventional state machine but in this case I only have these two independent signals.

No matter with which solution I come up, I always need to share data somehow.

I do not want to run both paths independently; for example having a counter for SignalB and if it is zero, initialize with data from A because the initial condition would be undefined. I would like to ensure that the data that is spit out on the positive edges of signal B are always properly initialized at the falling edge of signal A even if, for example, only 3 positive signal B edges occur.

What is the easiest way to implement this?

(this is just a simplified example to keep things compact; the actual task is more complicated)

Best Answer

To do this in an FPGA, the usual way would be to introduce a new clock, running much faster than A or B. Clock your logic from this new clock and use A and B only as control signals, not as clocks.

The new clock must be fast enough to be guaranteed to have at least one edge for each change of value of the A and B inputs.

module weird_counter(A, B, CLK, Q);
input A, B;
input CLK;
output Q;

reg [2:0] Ad;  
reg [2:0] Bd; /* Delayed copies of A and B */
reg [5:0] ctr;
reg [5:0] obuf;

assign Q = obuf[5];

always @(posedge CLK) begin
    Ad <= {Ad[1:0], A};
    Bd <= {Bd[1:0], B};

always @(posedge CLK) begin
    if(Ad[1] & ~Ad[2]) begin /* We are seeing a rising edge on A */
         /* Do something with ctr and obuf*/
    end
    if(Bd[1] & ~Bd[2]) begin /*Rising edge on B */
         /* Do something else with ctr and obuf*/
    end
end

endmodule;

Edit: Added some stages to Ad and Bd at Tom Carpenter's suggestion to demonstrate syncronizing a signal across clock boundaries. This reduces the risk of a logic fault due to violating set-up and hold times.