SystemVerilog Bridge
logic, always_comb, and always_ff
How SystemVerilog logic, always_comb, and always_ff map onto the Verilog wire, reg, always @(*), and always @(posedge clk) you already know.
2 min read · Updated
SystemVerilog's logic type replaces the wire-versus-reg distinction Course 1 spent real time teaching,
for the common case: a signal with exactly one driver. Lesson 2.2's rule tied the type to the driver (assign
drives a wire, an always block needs a reg); a logic signal accepts either. Its limit is the number of
drivers: it can take one assign or be written by procedural code, but not several continuous drivers and not
a mix of the two. That limitation is why plain wire has not gone away. Nets that genuinely need more than one
driver (a shared bus, a tri-state line) still use wire, so "just use logic everywhere" is a useful
starting habit, not an absolute rule.
Two always variants replace the general-purpose ones:
always_combis the explicit form ofalways @(*). It exists only to describe combinational logic. Underalways @(*), a path that leaves an output unassigned is legal Verilog that infers a latch; a tool may warn, as in Lesson 6.6, but it cannot know you wanted no storage. Underalways_combyou have declared that you did not, so the SystemVerilog standard asks tools to warn about the latch.always_ffis the explicit form ofalways @(posedge clk). It exists only to describe clocked logic, so a tool warns when the block has no clock edge to act on (for examplealways_ff @(*)).
Both keywords add one more rule: a variable written inside an always_comb or always_ff block may not be
written by any other block, so two blocks fighting over one signal becomes a compile error.
Nothing about the discipline changes: default-at-top inside always_comb, non-blocking assignment inside
always_ff. Only the keywords get more specific about what each block is allowed to contain.