always_latch is equivalent to always @(clk, d)

always_latch is equivalent to always @(clk, d) and is the preferred idiom for describing a latch in SystemVerilog. It evaluates whenever clk or d changes. always_comb reevaluates the statements inside the always statement whenever any of the signals on the right-hand side of <= or = in the always statement change.

always/process statements can also be used to describe combinational logic behaviorally if the sensitivity list is written to respond to changes in all of the inputs and the body prescribes the output value for every possible input combination.

A group of nonblocking assignments are evaluated concurrently; all of the statements are evaluated before any of the signals on the left-hand sides are updated.

case and if statements are convenient for modeling more complicated combinational logic. case and if statements must appear within always/process statements. The casez statement acts like a case statement except that it also recognizes ? as don't care.

module priority_casez(input logic [3:0] a, output logic [3:0] y);
always_comb
casez(a)
4'b1???: y = 4'b1000;
4'b01??: y = 4'b0100;
4'b001?: y = 4'b0010;
4'b0001: y = 4'b0001;
default: y = 4'b0000;
endcase
endmodule

1. Use always_ff @(posedge clk) and nonblocking assignments to model synchronous sequential logic.
2. Use continuous assignments to model simple combinational logic.
3. Use always_comb and blocking assignments to model more complicated combinational logic where the always statement is helpful.
4. Do not make assignments to the same signal in more than one always statement or continuous assignment statement.

Chisel好比过度的C++, ffmpeg, linux kernel等用C,遵循好的设计和编程风格,棒棒哒。

// nonblocking assignments (not recommended)
module fulladder(input logic a, b, cin, output logic s, cout);
logic p, g;
always_comb
begin
p <= a ^ b; // nonblocking
g <= a & b; // nonblocking
s <= p ^ cin;
cout <= g | (p & cin);
end
endmodule

Observe that s is computed concurrently with p. Hence, it uses the old value of p, not the new value. Therefore, s remains 0 rather than becoming 1. However, p does change from 0 to 1. This change triggers the always/process statement to evaluate a second time. This time, p is already 1, so s correctly changes to 1. The nonblocking assignments eventually reach the right answer, but the always/process statement had to evaluate twice. This makes simulation slower, though it synthesizes to the same hardware.

Another drawback of nonblocking assignments in modeling combinational logic is that the HDL will produce the wrong result if you forget to include the intermediate variables in the sensitivity list. 鄙人的玩具CPU always @(*) :-)

Worse yet, some synthesis tools will synthesize the correct hardware even when a faulty sensitivity list causes incorrect simulation. This leads to a mismatch between the simulation results and what the hardware actually does.

HDL Example 4.20 SYNCHRONIZER
module sync(input logic clk, input logic d, output logic q);
logic n1;
always_ff @(posedge clk)
begin
n1 <= d; // nonblocking
q <= n1; // nonblocking
end
endmodule

The synchronizer from HDL Example 4.20 is correctly modeled using nonblocking assignments. On the rising edge of the clock, d is copied to n1 at the same time that n1 is copied to q, so the code properly describes two registers. For example, suppose initially that d = 0, n1 = 1, and q = 0. On the rising edge of the clock, the following two assignments occur concurrently, so that after the clock edge, n1 = 0 and q = 1.

HDL Example 4.29 tries to describe the same module using blocking assignments. The assignments occur one after the other so that after the clock
edge, q = n1 = 0.

Because n1 is invisible to the outside world and does not influence the behavior of q, the synthesizer optimizes it away entirely, as shown in Figure 4.24. The moral of this illustration is to exclusively use nonblocking assignment in always/process statements when modeling sequential logic.

posted @ 2022-03-15 19:10  Fun_with_Words  阅读(85)  评论(0)    收藏  举报









 张牌。