1
votes

The statements in procedural blocks execute seqeuntially so why aren't any of the block1, block2 or block3 inferring a latch?

module testing(
    input  logic a, b, c,
    output logic x, y, z, v
    );

    logic tmp_ref, tmp1, tmp2, tmp3;

    //reference
    always_comb begin: ref_block
        tmp_ref = a & b;
        x = tmp_ref ^ c;
    end

    always_comb begin: block1
        y = tmp1 ^ c;
        tmp1 = a & b;
    end

    always @(*) begin: block2
        tmp2 <= a & b;
        z = tmp2 ^ c;
    end

    always @(c) begin: block3
        tmp3 = a & b;
        v = tmp3 ^ c;
    end
endmodule: testing

In block1 y is calculated using the blocking assignment before the new value of tmp1 is available.

In block2 tmp2 is calculated using a non-blocking assignment, which should postpone the assignment for when the always block finishes. Meanwhile, z is calculated using the blocking assignment and the new value of tmp2 is not yet available.

In block3 there is an incomplete sensitivity list and still no latch.

Here is the synthesis result from Quartus II 14.1: enter image description here

Only when I add this block a latch is inferred:

//infers a latch
always @(*) begin: block4
    if (c == 1'b1) begin
        tmp4 = a & b;
        w = tmp4 ^ c;
    end
end

Can someone please explain why incomplete sensitivity list or using a variable before the value is updated does not infer a latch in a combinatorial block?

1

1 Answers

4
votes

The type of assignment used in a combinatorial block will not effect synthesis. The use of non-blocking (<=) may result in RTL (pre-synthesis) to gates (post-synthesis) simulator mismatches.

The same is true for sensitivity lists, synthesis will give the behaviour of auto generated or complete list.

In a clocked process (@(posedge clk)) use non-blocking (<=) to get the simulation behaviour of a flip-flop. It is possible to use blocking (=) as well to have combinatorial code inside the clocked process but mixing styles is considered a bad coding practice. The combinatorial part code just be moved to a separate combinatorial block (always @*).

A latch is a basic memory element, if the circuit does not need memory then it will not be inferred.

For example:

always @* begin: 
    v = (a & b) ^ c;
end

v is completely defined by inputs, there is no memory involved. In comparison to :

always @* begin
  if (c == 1'b1) begin
    w = (a & b) ^ c;
  end
end

When c is 0 w must hold its value, therefore a latch is inferred.

It is worth noting that while latches are not bad, care must be taken with the timing of when the open and close to ensure they capture the correct data. Therefore inferred latch are typically seen as bad and are from poor coding.

SystemVerilog has the following syntax for semantically implying design intent:

always_latch begin
  if (c == 1'b1) begin
    w = (a & b) ^ c;
  end
end