Verilog is a hardware description language. We write code, which is translated into a logic circuit on an FPGA through a CAD tool like Quartus Prime. Quartus will simplify logic expressions such that the gates will always be in the simplest configuration.

There is no real reason not to use SystemVerilog, except in legacy codebases.

Language features

The basics

Each discrete physical chip in Verilog is represented as a module. These can be replicated, i.e., instantiated into a larger circuit as needed.

For a multiple value-wide input, we can do:

module mux2to1_2bit(x,y,s,m);
	input s;
	input [1:0] x,y;
	output [1:0] m;
 
	assign s = 1'b1;
	// ...

We have parameters in Verilog that let us enable code reuse — sometimes we might need differently sized inputs for our modules.

localparam N = 4;
input wire [N-1:0] x, y;

We can concatenate signals like the following:

assign d = {a, b};

Reduction operations are bitwise, i.e., they operate bit by bit. Their output is -bit wide, where the least significant bit is the result. If at least one OR operation evaluates to true, or if all AND operations evaluate to true, then the LSB is 1.

assign q =| z; // bitwise OR
assign q =& z; // bitwise AND

The begin and end keywords are like curly brackets in C/C++. We use them when multiple statements are necessary.

Verilog has multiple key signal types:

  • localparam denotes definable constants that are within the module’s scope.
  • parameter denotes more general parameters. We can use them to enable code reuse for dynamically sized module/signal instantiation.
  • reg denotes a registered type. In practice, this is usually used within always blocks for assigning to flip-flops.
  • wire represents a physical connection, often between modules.

Debugging

Never put a semi-colon after an always block! This will cause funky behaviour. Also never assert signals in two different always blocks — this causes the compiler to think we’re asserting a signal from two different sources.

For if statements, a corresponding else statement should be used to prevent ambiguity and actually get the signals we want. I’ve run into this problem so many times because it’s never a problem in programming.

Resources

Extra reading

See also