|
| |
|---|---|---|
Driven by |
| Procedural assignment in an |
Holds a value? | No: it carries whatever drives it | Yes, in simulation, until assigned again |
Multiple drivers | Allowed (resolved), as for a bus | Only one process should assign it |
Becomes hardware as | A wire (or the output of a gate) | A flip-flop or plain combinational logic, depending on the code |
module reg_is_not_a_flop (
input wire a, b,
output reg y_comb // declared 'reg' ...
);
always @(*) y_comb = a & b; // ... but this is pure combinational logic (an AND gate)
endmodule
module reg_is_a_flop (
input wire clk, d,
output reg q // same keyword ...
);
always @(posedge clk) q <= d; // ... but here it IS a flip-flop (edge-triggered)
endmoduleBoth outputs are declared reg, but only the second is a flip-flop. The first is pure combinational logic, an AND gate.
Read each row from the code on the left to the hardware on the right; the orange reg marks the keyword that does not decide anything.
Rows one and two build the same AND gate. Only the declaration changes, because assign needs a net and always needs a variable.
Row three is the only one with an edge in its event control, so it is the only one with storage.
The sensitivity list decides when the block runs, but only full assignment cover keeps it combinational. @(*) with every output assigned on every path describes logic, while @(posedge clk) describes a clocked element. An incomplete @(*) block infers a latch.
Signals assigned with assign or driven by instance outputs: declare as wire.
Signals assigned inside an always or initial block: declare as reg.
Never mix the two on one signal (no assign plus an always assignment).
SystemVerilog adds logic, a 4-state data type for nearly every RTL variable. Such a variable accepts one continuous assignment or port, or procedural assignments. The type alone does not limit ordinary procedural writers to one process.
Keep one writer per RTL variable. always_ff and always_comb impose writer restrictions, and lint checks ownership; two plain always blocks can otherwise write the same variable and race. Reserve a resolved net such as wire for shared buses.
module logic_demo (
input logic clk, a, b,
output logic y_comb,
output logic q
);
assign y_comb = a & b; // driven continuously: fine for logic
always_ff @(posedge clk) q <= a; // driven procedurally: also fine
endmodulereg [3:0] count; and assigned on every path inside always @(*) with a full case statement. Is it a register in the hardware?No. A combinational always @(*) that assigns the variable on every path produces pure combinational logic. Only an edge-triggered block (or an incomplete combinational block that infers a latch) creates storage.