How are Verilog "always" statements implemented in hardware?

First, note that not all Verilog designs are synthesizable. Usually, only a very specific subset of constructs can be used in a design that is to be realized in hardware.

One important restriction that pops up is that every reg variable can only be assigned to in at most one always statement. In other words, regs have affinity to always blocks.

The following types of always blocks can generally be used.

always @(*) begin
    // combinational
end

always @(posedge clk) begin
    // sequential
end

In the former case, the * indicates that the block should be executed whenever any signal used in the block changes or, equivalently, that the block should be executed continuously. Therefore, regs that have affinity to combinational always blocks are implemented as signals computed from other signals using combinational logic, i.e. gates.

Registers that have affinity to always blocks of the latter type, on the other hand, are outputs of D flip-flops that are clocked on the rising edge of clk (falling edge if negedge is used). Inputs to the flip-flops are, again, computed with combinational logic from other signals.

Consider the following, somewhat contrived example.

reg out, out_n;
always @(*) begin
    out_n = !out;
end
always @(posedge clk) begin
    out <= !out;
end

Here, out_n is associated with the first always block, out with the second. out_n will be implemented with a single NOT gate that will drive out_n and be driven from out (note that it is a pure combinational logic). On the other hand, out will be driven by a flip-flop clocked from clk. The input to the flip-flop will again be computed by a NOT gate from out (which is driven by the aforementioned flip-flop). Optimizing synthesizers will combine the two NOT gates and use one NOT gate and one flip-flop.

Depending on the hardware you have available, other types of constructs can be used. For example, if the flip-flops have asynchronous resets, the following construct is also synthesizable.

always @(posedge clk or posedge rst) begin
    if (rst)
        // reset
    else
        // sequential
end

An always block is commonly used to describe a flip-flop, a latch, or a multiplexer. The code would be implemented with a flip-flop, a latch, or a multiplexer.

In an FPGA a flip-flop and a latch are generally just two different configurations of a more general-purpose register device. A multiplexer would be constructed from one or more general-purpose logic elements (LUTs).

In general, there's two ways to go about design with Verilog:

  1. Visualize the logic you want in terms of gates and registers, then figure out how to describe it in Verilog. The synthesis guide books from the FPGA vendors or synthesis tool vendors give boiler-plate for the most common structures you might want to work with.

  2. Just write Verilog and don't worry about what the underlying hardware looks like. However, even if you do this, you still have to know what is and what isn't synthesizable. So again, you will look to the boilerplate provided by your tool vendor and adapt it to your application.

EDIT

Avakar's answer is a much better one for your question, but this spurred some interesting discussion about the differences between Xilinx and Altera so I won't delete it.

Tags:

Verilog