The always block describes hardware behaviour sequentially in Verilog, similar to how software is written. Outputs will be registered (i.e., will not change) until the always block runs again via the reg command.

All signals assigned a value in always must be of type reg, but cannot be assigned outside of the block. If we have multiple statements in a block, then we must use the keywords begin and end. We cannot use wire within always. Modules can only be instantiated outside always blocks, not inside. A workaround is to call always within the sub-module.1

Take this module, describing a multiplexer.

// ...
output reg f;
always @(x,y,s)
begin // like a {
	if (s == 0)
		f = x;
	else
		f = y;
end // like a }
// ...

Sensitivity list

Whatever parameters are in the always statement describe a “sensitivity list”, i.e., where the code in the always block is sensitive to changes in the signals. We can also instead put an asterisk in the sensitivity list — what this means is that we let Verilog figure out the sensitivity list. For combinational circuits, we should only pass in an asterisk.

For sequential circuits, we want to be able to pass in a clock edge. Oftentimes we explicitly put in:

always@(posedge clock, negedge reset_n)

Enabled features

Certain language constructs are only enabled within always blocks.

  • Regular conditionals, like if and else statements.
  • case statements, analogous to switch statements

Footnotes

  1. There’s a really good explanation on StackOverflow on other possible things you can do.