Verilog Intro
Hardware Description Language
Hardware Description Language, a.k.a HDL, is a programming-like language that is used to describe hardware.
HDLs are synthesized (and optimized) to hardware primitives while software languages are sometimes compiled to primitive instructions.
Verilog Basics
Modules
In Verilog, designs are broken down into modules
A module is a container that the designer can use to encapsulate a unit of functionality.
Modules can contain code to describe hardware and also instances of other modules.
Good designs consist of sufficient (but not excessive) levels of hierarchy, with modules containing instances of modules, that contain instances of other modules.
At each level in the hierarchy, a module instance is treated as a "black-box" — the internals are unknown.

Verilog Module Declaration
Use the module keyword and a list of ports
The above declaration describes a module with 3 ports, each a single wire
Describe the direction of ports using input and output
The above describes a module with two inputs and one output.
endmodule keyword
The endmodule keyword indicates the end of statements that comprise the module description.
Gate-Level Primitives
Verilog provides us with basic primitives to model Boolean gates: and, nand, or, nor, not, xor, xnor.
Gate-Level Primitives Example
The following Verilog code represents an and gate with inputs connected to wires a and b, and output connected to wire y.

The single output is always the first argument.
Wires
We can declare internal wires in a module, using the wire keyword
This creates a named (1-bit) wire that can be used to connect gates together.
Examples with wire
To describe the following circuit,

The HDL we write will be
Module Instantiation
In Verilog, we can use existing modules within new modules through instantiation.
Ordered Instantiation
To instantiate a module, we can use the following syntax
where M1 is the name of this instance, and A, B, w1, w2, are four arguments.
This kind of instantiation is called ordered instantiation because the order of the arguments passed matters! Thus, it is error-prone and usually not recommended.
Named Instantiation
During module instantiation, we can specify the parameter that the argument will be passed in explicitly. For example,
where .a, .b, .sum and .Cout are the name of each parameter in the definition of module add_half.
Example: Implementing a full adder using two half adders

Verilog Assignments
Implementing larger circuits using individual gate, a.k.a Gate-Level Primitives can be tedious. For example, till now, to implement an AND gate, we use,
But Verilog allows us to use combinational logic expressions through the assign keyword. So, now, to implement an AND gate, we can use
This is called a continuous assignment. As it is always permanently assigned. It also allows us to assign the result of a Boolean expression to a signal.
Verilog Assignment Operators
&&
Logical AND
1 or 0 (1-bit)
Returns 1 if both operands are non-zero; otherwise 0.
&
Bitwise AND
Same width as the widest operand
Performs bitwise AND between corresponding bits.
||
Logical OR
1 or 0 (1-bit)
Returns 1 if either one of the operands is non-zero; otherwise 0.
|
Bitwise OR
Same width as the widest operand
Performs bitwise OR between corresponding bits.
!
Logical NOT
1 or 0 (1-bit)
Returns 1 if operand is zero; otherwise 0.
~
Bitwise NOT (Complement)
Same width as the widest operand
Inverts every bit in the operand.
^
Bitwise XOR
Same width as the widest operand
Performs bitwise XOR between operands.
~^ / ^~
Bitwise XNOR
Same width as the widest operand
Performs bitwise XNOR (inverse of XOR).
~& / &~
Bitwise NAND
Same width as the widest operand
Performs bitwise NAND
Example
The use of continuous assignment makes life much easier
To implement the following circuit using continuous assignment, we only need one line of code

And that is,
Remember that all assign statements happen concurrently (at the same time)
Use continuous assignment to implement a multiplexer
This can be done by conditional assignment (almost same as in C). So, to implement a 1-bit 2x1 multiplexer, we can use
The signal y will be connected to x1 if sel is 1, else it is connected to x0.
Vectors in Verilog
So far, we are only dealing with 1-bit signals. What happens if we want to use multi-bit signals?
Luckily, Verilog has a special construct for handling multi-bit signals (wire). Formed by specifying a range:
Vector is also supported when specifying multi-bit module ports (input, output)
Bit Selection in Vectors
We can select individual bit of the vector. For example,
We can also select a range of the vector. For example,
In Verilog, widths of vectors in assignments should match!
Miscs
Number Literals
Verilog allows us to use number literals to assign a fixed bit pattern to a signal. A number literal has the following structure,
<size>is the width in bits<radix>:bfor binary,ofor octal,hfor hex,dfor decimal<value>: the number you want, with as many optional underscores as needed (for readability)
Example
Concatenation
It is sometimes very useful to be able to concatenate a number of signals into a single signal. In Verilog, the concatenation is signified by curly brackets ({, }) enclosing a list. For example,
Examples
The second line of code utilises the replication feature of concatenation in Verilog
Parameters
A parameter in Verilog is a constant that is local to a module. It can be declared either in the module header or in the module body (we will not use the second paradigm).
This is different from the parameter of a function that we have learned in C, Java or other Programming language. Attention!
For example,
Notes
Structural Verilog
The process of using Verilog HDL to describe the gate-level circuit directly is called structural Verilog.
The order of statements doesn't matter in each Verilog module
In the Verilog module, the order of statements is unimportant. Each statement describes a piece of hardware. There is no sequence of steps when doing structural Verilog.

Note on wire
In the Verilog wire, usually there is no need to declare 1-bit wires for connecting modules. Tools will infer these wires automatically by matching names.

This only applies for 1-bit wires in instantiation.
Last updated