Verilog describes hardware that all runs concurrently. Processes, instances and continuous assignments run together, while statements inside one begin end block run in the order written.
Simulation schedules concurrent processes in some order. Two process templates keep simulation and hardware in agreement.
6 lessons, about 26 min
always blocks in the same module both contain assignments. Which executes first?Neither is “first”. They are concurrent processes. The language does not define the order in which processes run within a time step, so a simulator may pick any order. Nonblocking assignments make a clocked design come out the same whatever that order is, which is why RTL must be written so the result never depends on it.
The whole topic on one page, taken from each lesson's Remember box. Read it before an interview, or print it.
Modules and Ports
Connect by name, not by position: a reordered port list still compiles and connects the wrong signals.
Give every parameter a default and override it by name.
A port with no range is 1 bit, so a forgotten width on an output silently drops the upper bits.
Rule of thumb: turn on default_nettype none at the top of every file.
Wire vs reg
reg only means a variable that a procedural block can assign.
An always @(*) block that assigns on every path is combinational, an incomplete one infers a latch, and @(posedge clk) describes a flop.
Keep one writer per RTL variable. Reserve a resolved net such as wire for shared buses.
Rule of thumb: the hardware comes from how you assign, not from the keyword.
assign vs always
Use @(*) or always_comb, blocking assignments, and assign every output on every path.
An incomplete sensitivity list gives stale simulation but ordinary synthesised hardware.
@(*) misses a module signal read only inside a called function; always_comb does not.
Rule of thumb: never write a sensitivity list for combinational logic by hand.
The Two Process Templates
Combinational: assign a default to every output first, use blocking assignments.
Sequential: use non-blocking assignments and one reset style across the design.
An asynchronous reset in the sensitivity list still releases asynchronously, so synchronise the release outside.
Rule of thumb: default first in combinational code, hold by omission in clocked code.
Blocking vs Non-blocking
A blocking assignment updates now. A non-blocking one reads now and updates in the NBA region of the same timestamp.
Use <= in clocked blocks and = in combinational blocks.
Blocking assignments between clocked processes make a race: the result depends on process order.
Rule of thumb: non-blocking in clocked blocks, blocking in combinational ones.
From Code to Hardware
Operators become gates, muxes or adders. Variables assigned in a clocked block become one flop per bit, with enable and reset pins taken from the code.
An always @(*) output that is not assigned on every path becomes a latch, and Yosys warns while it converts the process.
Before mapping, stat counts one cell per operator or register. After synth it counts one cell per gate or per bit.
Rule of thumb: write down the cell list before you synthesise; any cell you did not predict is a question about your code.
Mini project: a 4-bit ALU with flags and an exhaustive bench
Code lab: Build a full adder from half adders
Practice question: Synchronous D flip-flop with reset
Practice question: D flip-flop with asynchronous reset
Practice question: Blocking vs non-blocking in sequential logic
Interview: run a mock interview on this topic