13
\$\begingroup\$

I have a piece of code in Verilog which needs to assign the value of shift register to an output register when the shifting has finished, and I want to reset the value of the shift register in the same clock cycle. Like the following:

[shift register processing during several clock cycles...]

output_buffer <= shift_register;
shift_register <= 0;

I'm aware of non blocking assignments are done in parallel, meaning that they are done 'at the same time'. Having that on mind, the above piece of code should have an undefined behaviour: if both assignments happen 'in parallel', because in the end nothing can happen literally at the same time.

I have tried this on a simulator and it works as I expect, that is, output_buffer gets the shift reg. value and the latter is reset. However, in general, is it safe to execute this on a real FPGA?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You can put shift_register <= 0 ; above, and still you get the same behaviour in the hardware. \$\endgroup\$
    – Mitu Raj
    Commented Nov 12, 2021 at 15:26

3 Answers 3

14
\$\begingroup\$

Yes, you should get the same behavior in an FPGA as you do in simulation, assuming the Verilog code looks something like this:

always @(posedge clk) begin
    if (load) begin
        output_buffer  <= shift_register;
        shift_register <= 0;
    end else ...
    ...
end

This code does have defined behavior. At the rising edge of the clock, the Verilog simulator first reads the values on the RHS of the nonblocking assignments before it updates the LHS values. This means that output_buffer is guaranteed to get the previous value of shift_register, not 0.

Similarly, the FPGA synthesis tool should create a set of flip flops with the proper timing to guarantee that output_buffer gets the previous value of shift_register, assuming proper timing constraints are applied.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ The key is that FPGAs are designed to have "0 hold time". \$\endgroup\$
    – The Photon
    Commented Nov 12, 2021 at 15:16
  • 3
    \$\begingroup\$ Also note this will behave in the same way if the statements are swapped around. \$\endgroup\$
    – stanri
    Commented Nov 13, 2021 at 5:21
13
\$\begingroup\$

While I can't get into the heads of the original designers of Verilog, I suspect that 99% of engineers who use it will tell you that your code snippet exemplifies the whole point of non-blocking assignments.

Once you get your head wrapped around it, a non-blocking assignment is basically saying "put a register here". If you have a block of code that is all non-blocking assignments, then everything on the right side of the assignments are the values that exist in those signals immediately* before the clock edge; the values on the left side are the values assigned immediately after the clock edge.

So your code says "set the output buffer to the value of the shift register and zero out the shift register", all in one clock.

* In simulation-land. Really there's all the setup and hold business that you'll need to pay attention to if you're trying to go fast.

\$\endgroup\$
2
\$\begingroup\$

Things become much clearer if you draw the logic diagram for toolic’s code example:

logic diagram

The input of output_buffer mustn’t change too quickly after the rising clock edge (it’s called the hold time requirement). If shift_register changes really quickly to 0 and this change reaches output_buffer within the hold time it will violate the hold time requirement and can lead to metastability and all kinds of issues.

The synthesis tool makes sure that all timing requirements are met. In FPGAs meeting the hold time requirement is rarely an issue. If it is, the synthesis tool can introduce “dummy logic” from shift_register to output_buffer just to slow down the signal change.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.