Electronic – HDL code convention for register resets

hdlregisterresetverilog

When it comes to (synchronously) resetting registers in HDL (I'll use Verilog), is it considered bad practice to code the reset combinatorially? As far as I can tell, the following two snippets are functionally equivalent.

Behavioral:

always @ (posedge clk) begin
    if (rst) current_val <= 1'b0;
    else     current_val <= din;
end

Structural:

assign next_val = (rst == 1'b0) ? din : 1'b0;
always @ (posedge clk) begin
    current_val <= next_val;
end

I learned to write the logic the behavioral way, and only recently came across the second. In terms of HDL convention/best practices, is one preferrable to the other? Also, would they be mapped to different hardware?

Best Answer

There is no guarantee that the logic in the "Structural" example would be recognised by standard synthesis tools. It is entirely possible that you wouldn't get a register with synchronous reset. To understand why that is we need to consider exactly how the code is translated into the technology of the device being used.

Below is a diagram of half an Intel FPGA Cyclone V Adaptive Logic Module (image copyright Intel FPGA).

enter image description here

At the top of the image a series of signals called syncload, sclr and aclr can be seen. These are the control signals for the registers in the block. Other device families will have different dedicated signals. Correctly written code will infer use of these dedicated control signals. If the desired dedicated control signals are not available, or are inferred incorrectly, then inputs to the LUTs will be used instead. At best this will waste resources, at worst this could cause functionality to split across multiple ALMs and cause timing failure. We have no direct control over this, only the ability to infer through HDL. A good read on this can be found in the white paper here: https://www.xilinx.com/support/documentation/white_papers/wp275.pdf

Also, inspection of your code shows that it is not functionally equivalent to the "Behavioural" example. Next_val is being updated asynchronously to Current_val which has all sorts of implications for routing, timing and meta-stability. However, in simulation you would see none of that and both sets of code would be superficially identical.

HDL convention is to use recognised patterns for such low level constructs as this to ensure the synthesis tools will recognise them. These are provided by the synthesis tool designers. An example from Intel FPGA's Quartus Prime User Guide: Design Recommendations (https://www.intel.com/content/www/us/en/programmable/products/design-software/fpga-design/quartus-prime/user-guides.html) :

always @ (posedge clock)
begin
  if (!rst_n)
  begin
    reg1 <= 1’bo;
    reg2 <= 1’b0;
  end
  else
  begin
    reg1 <= data_a;
    reg2 <= data_b;
  end
end

Also, the general principle of readability in code would suggest that your "Structural" example is not to be favoured.