This conditional statement is used to make a decision on whether the statements within the if
block should be executed or not.
- If the expression evaluates to true (i.e. any non-zero value), all statements within that particular
if
block will be executed - If it evaluates to false (zero or 'x' or 'z'), the statements inside
if
block will not be executed - If there is an else statement and expression is false then statements within the
else
block will be executed.
Syntax
If multiple statements need to be placed inside the if or else part, it needs to be enclosed within begin
and end
.
if ([expression])
Single statement
// Use "begin" and "end" blocks for more than 1 statements
if ([expression]) begin
Multiple statements
end
// Use else to execute statements for which expression is false
if ([expression]) begin
Multiple statements
end else begin
Multiple statements
end
// if-else-if style to check for more expressions if the previous one doesn't match
if ([expression 1])
Single statement
else if ([expression 2]) begin
Multiple Statements
end else
Single statement
Hardware Implementation
if without else
if
without an else
part implies that the value remain unchanged for any condition that does not satisfy the expression inside if
.
module des ( input en,
input d,
output reg q);
always @ (en or d)
if (en)
q = d;
endmodule
Value of output q is updated whenever d or en changes in value.

if with else
Output q will get the value of input d at the positive edge of clock if rstn is high and describes the behavior of a D flop.
module dff ( input clk,
input rstn,
input d,
output reg q);
always @ (posedge clk) begin
if (! rstn)
q <= 0;
else
q <= d;
end
endmodule
Note that the synthesized output indicates a flop with an output q.

if else if
In the following example, the design module has a 4-bit output q that is incremented when mode is 1 and decrements when mode is 2 with if else
construct. Note that the description does not specify what has to be done if mode is 0 or 3 which are valid values for a 2-bit variable. It is assumed that the circuit does nothing when mode is 1 and 3, but maintain exiting value of q. It is not recommended to leave such ambiguity in real design code, but is shown here to highlight the possibility.
module des ( input [1:0] mode,
input clk,
input rstn,
output reg [3:0] q);
always @ (posedge clk) begin
if (! rstn)
q <= 0;
else begin
if (mode == 1)
q <= q + 1;
else if (mode == 2)
q <= q - 1;
end
end
endmodule
The synthesized output may differ with availability of cells for a given technology library
Shown below is the synthesized output and it is worth to note that q got implemented as a 4-bit flop which has a pin CE to enable the flop. Note that this flop is enabled only when mode is 1 or 2 and not for other values. Output q is fed back through an adder and subtractor block into the input of the same flop through a mux which is again controlled by mode.

Consider the same design from above with a 1-bit mode.
module des ( input mode,
input clk,
input rstn,
output reg [3:0] q);
always @ (posedge clk) begin
if (! rstn)
q <= 0;
else begin
if (mode)
q <= q + 1;
else
q <= q - 1;
end
end
endmodule
In this case, a regular flop without a CE pin is used along with a few multiplexers to choose the correct signal based on value of mode.

Examples
if without else for single statement
module tb;
int a = 10;
initial begin
if (a == 10) // if block can have only one statement in it
$display ("a is found to be 10");
$display ("Always executed regardless of value of a"); // This statement is outside if block because
end
endmodule
Simulation Log ncsim> run a is found to be 10 Always executed regardless of value of a ncsim: *W,RNQUIE: Simulation is complete.
if without else for multiple statements
module tb;
int a = 10;
initial begin
if (a == 10) begin // if block has begin end keywords, and can support multiple statements
$display ("a is found to be 10");
$display ("Its good to get 10");
// Anything else can be done here until the "end" keyword
end
$display ("Always executed regardless of value of a"); // Statement is outside the if block, because of the closing "end" for the "begin" in if
end
endmodule
Simulation Log ncsim> run a is found to be 10 Its good to get 10 Always executed regardless of value of a ncsim: *W,RNQUIE: Simulation is complete.
if-else for single statement
module tb;
int a = 9;
initial begin
if (a == 10)
$display ("a is found to be 10"); // Is executed when "if" expression is True
else
$display ("a is NOT 10 :("); // Is executed when "if" expression is false
end
endmodule
Simulation Log ncsim> run a is NOT 10 :( ncsim: *W,RNQUIE: Simulation is complete.
if-else for multiple statements
module tb;
int a = 9;
initial begin
if (a == 10) begin
$display ("a is found to be 10"); // Is executed when "if" expression is True
// Can have more additional statements here
end else begin
$display ("a is NOT 10 :("); // Is executed when "if" expression is false
$display ("Why is a not 10 ?");
// Can have more additional statements here
end
end
endmodule
Simulation Log ncsim> run a is NOT 10 :( Why is a not 10 ? ncsim: *W,RNQUIE: Simulation is complete.
All behavioral code is written inside module
and endmodule
. So, whatever digital design that you intend to create, it'll go inside a module
block. It may or may not have ports defined - allow signals to enter the block as input
or escape the block as output
.
Module
The empty module in the example below is called testbench. You can name it whatever you like, except that it should be alphanumeric, and can contain '_'.

module testbench;
endmodule
In the early days of integrated circuits, engineers had to sit down and physically draw transistors and their connections on paper to design them such that it can be fabricated on silicon. Bigger and complex circuits demanded more engineers, time and other resources and soon enough there was a need to have a better way of designing integrated circuits.
VHDL was soon developed to enhance the design process by allowing engineers to describe functionality of the desired hardware and let automation tools convert that behavior into actual hardware elements like combinational gates and sequential logic. Verilog was developed to simplify the process and make the Hardware Description Language (HDL) more robust and flexible. Today, Verilog is the most popular HDL used and practiced throughout the semiconductor industry.
How is Verilog useful ?
Verilog creates a level of abstraction that helps hide away the details of its implementation and technology.
For example, the design of a D flip-flop would require the knowledge of how the transistors need to be arranged to achieve a positive-edge triggered FF and what the rise, fall and clk-Q times required to latch the value onto a flop among many other technology oriented details. Power dissipation, timing and the ability to drive nets and other flops would also require a more thorough understanding of the physical characteristics of a transistor.
Verilog helps us to focus on the behavior and leave the rest to be sorted out later.
Example
The following code illustrates how a Verilog code looks like. We will delve into more details of the code in the next article. For the time being, let us simply understand that the behavior of a counter is described. The code essentially makes the counter count up if the up_down signal is 1, and down if its value is 0. It also resets the counter if the signal rstn becomes 0 making this an active-low reset.
module ctr (input up_down,
clk,
rstn,
output reg [2:0] out);
always @ (posedge clk)
if (!rstn)
out <= 0;
else begin
if (up_down)
out <= out + 1;
else
out <= out - 1;
end
endmodule
The simple example shown above illustrates how all the physical implementation details have been hidden while still providing a clear idea of how the counter functions.
ctr is a module
that represents an up/down counter, and it is possible to choose the actual physical implementation of the design from a wide variety of different styles of flops optimized for area, power and performance. They are usually compiled into libraries and will be available for us to select within EDA tools at a later stage in the design process.
Now that you know what Verilog is, let's start learning Verilog !
Design
module tff ( input clk,
input rstn,
input t,
output reg q);
always @ (posedge clk) begin
if (!rstn)
q <= 0;
else
if (t)
q <= ~q;
else
q <= q;
end
endmodule
Testbench
module tb;
reg clk;
reg rstn;
reg t;
tff u0 ( .clk(clk),
.rstn(rstn),
.t(t),
.q(q));
always #5 clk = ~clk;
initial begin
{rstn, clk, t} <= 0;
$monitor ("T=%0t rstn=%0b t=%0d q=%0d", $time, rstn, t, q);
repeat(2) @(posedge clk);
rstn <= 1;
for (integer i = 0; i < 20; i = i+1) begin
reg [4:0] dly = $random;
#(dly) t <= $random;
end
#20 $finish;
end
endmodule
Simulation Log ncsim> run T=0 rstn=0 t=0 q=x T=5 rstn=0 t=0 q=0 T=15 rstn=1 t=0 q=0 T=19 rstn=1 t=1 q=0 T=25 rstn=1 t=1 q=1 T=35 rstn=1 t=1 q=0 T=43 rstn=1 t=0 q=0 T=47 rstn=1 t=1 q=0 T=55 rstn=1 t=0 q=1 T=59 rstn=1 t=1 q=1 T=65 rstn=1 t=1 q=0 T=67 rstn=1 t=0 q=0 T=71 rstn=1 t=1 q=0 T=75 rstn=1 t=0 q=1 T=79 rstn=1 t=1 q=1 T=83 rstn=1 t=0 q=1 T=87 rstn=1 t=1 q=1 T=95 rstn=1 t=0 q=0 Simulation complete via $finish(1) at time 115 NS + 0
Design
module single_port_sync_ram
# (parameter ADDR_WIDTH = 4,
parameter DATA_WIDTH = 32,
parameter DEPTH = 16
)
( input clk,
input [ADDR_WIDTH-1:0] addr,
inout [DATA_WIDTH-1:0] data,
input cs,
input we,
input oe
);
reg [DATA_WIDTH-1:0] tmp_data;
reg [DATA_WIDTH-1:0] mem [DEPTH];
always @ (posedge clk) begin
if (cs & we)
mem[addr] <= data;
end
always @ (posedge clk) begin
if (cs & !we)
tmp_data <= mem[addr];
end
assign data = cs & oe & !wr ? tmp_data : 'hz;
endmodule

Testbench
module tb;
parameter ADDR_WIDTH = 4;
parameter DATA_WIDTH = 16;
parameter DEPTH = 16;
reg clk;
reg cs;
reg we;
reg oe;
reg [ADDR_WIDTH-1:0] addr;
wire [DATA_WIDTH-1:0] data;
reg [DATA_WIDTH-1:0] tb_data;
single_port_sync_ram #(.DATA_WIDTH(DATA_WIDTH)) u0
( .clk(clk),
.addr(addr),
.data(data),
.cs(cs),
.we(we),
.oe(oe)
);
always #10 clk = ~clk;
assign data = !oe ? tb_data : 'hz;
initial begin
{clk, cs, we, addr, tb_data, oe} <= 0;
repeat (2) @ (posedge clk);
for (integer i = 0; i < 2**ADDR_WIDTH; i= i+1) begin
repeat (1) @(posedge clk) addr <= i; we <= 1; cs <=1; oe <= 0; tb_data <= $random;
end
for (integer i = 0; i < 2**ADDR_WIDTH; i= i+1) begin
repeat (1) @(posedge clk) addr <= i; we <= 0; cs <= 1; oe <= 1;
end
#20 $finish;
end
endmodule