# Trying to understand how to design properly asynchronous signals in SystemVerilog

I have implemented a serial-in parallel-out register implemented in SystemVerilog:

module sipo_reg(
input   wire        in_data,
output  wire [7:0]  out_data,
output  wire        rdy,
input   wire        rst,
input   wire        clk
);
reg [7:0] buff;
reg [2:0] i;
reg was_enabled;

always @(posedge clk, posedge rst) begin
if (rst) begin
buff <= 0;
i <= 7;
was_enabled <= 0;
end else begin
was_enabled <= 1;
buff[i] <= in_data;
i <= i == 3'd0 ? 3'd7 : (i - 3'd1);
end
end

assign rdy = (i == 3'd7) & was_enabled;
assign out_data = {8{rdy}} & buff;
endmodule


I'm wondering if this is not a very good design because it might happen that rdy goes high before out_data has settled, leading to an incorrect read.

For instance, in the following code:

always @(posedge clk) begin
if (rdy)
my_data <= out_data;
end


It could happen that rdy reaches the positive edge before out_data has settled.

However, given that rdy changes some small delay after (posedge clk), one would say that rdy is asynchronous with respect to clk and can't just be read on the clock edge, since it could not respect the flip-flop setup-and-hold times. It would need to be synchronized to some clock signal, by passing it through two back-to-back flip flops (as explained here). Is this correct?:

cell_sync cs(clk, rst, rdy, rdy_sync); // rdy_sync synchronized with clk

always @(posedge clk) begin
if (rdy_sync)
my_data <= out_data;
end


However, in the code above, the problem no longer exists since rdy_sync will go high almost two clocks later than rdy does. As long as the clock period is slow enough to assure that all combinational logic in the design will have time to settle, out_data will necessarily have settled before it is read, am I right?

I have tried this on my simulation, and it works, yet I wonder if my reasoning is correct specially when implementing this design in a physical FPGA.

Finally, the most problematic scenario I can think about is:

always @(posedge rdy)
my_ff <= out_data;


This already fails in my simulations, so I have replace the last two continuous assignments by:

wire _rdy;

assign _rdy = (i == 3'd7) & was_enabled;
assign rdy = ~(~(~(~_rdy)));
assign out_data = {8{_rdy}} & buff;


The above works in my simulation, but I'm not very sure about the physical FPGA:

Having that out_data only needs 8 and gates in parallel, and rdy needs 4 not gates in series, assuming that the delay of the and and or gates are the same (by and and or gates I mean whatever logic the fpga actually uses to implement then), out_data should settle way before rdy does. Still, this still looks a bad design to me, because seems unsafe. Would I be right trying to avoid this solution? Can I be sure the synthesizer will not optimize out those not gates?

In addition, it seems bad to me to do @(posedge x), where x is anything other than a clock or a reset signal. Is this true?

For instance, in the following code:

always @(posedge clk) begin
if (rdy)
my_data <= out_data;
end


It doesn't matter whether rdy or out_data arrives at the input to this block first. It only matters that both of them arrive and are stable before the posedge clk event occurs.

If there is so much delay uncertainty that either one will be delayed so much that this could not be guaranteed, then the synthesis tool will indicate a timing violation.

However, given that rdy changes some small delay after (posedge clk), one would say that rdy is asynchronous with respect to clk

You wouldn't say that. rdy only changes in response to a clock edge, so it is a synchronous signal.

If one of the signals used to compute rdy (in the assign statement) originated off-chip, then we would consider it an asynchronous signal, because we'd have no control of the timing of that signal.