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.

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;
	// ...

Much like we give values to variables in programming, we have parameters in Verilog that let us do conceptually similar work. The point of the parameter is to enable code reuse — sometimes we might need differently sized inputs for our modules.

// ..
parameter 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.

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