0% found this document useful (0 votes)
2 views

Base_of_Verilog

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Base_of_Verilog

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

Base of Verilog

August 2023
List of Figures
1 Diagram 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 Sequence of execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3 Diagram 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4 Diagram 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5 Operators in Verilog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

1
Contents
1 Introduction 3
1.1 What is it About? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Levels of Abstraction 4
2.1 Behavioral Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Register-Transfer Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Gate Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

3 Wire and Reg Data Types 5


3.1 Wire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.2 Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

4 Blocking and Nonblocking in Verilog 7


4.1 Blocking Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.2 Nonblocking Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

5 Basics of Verilog 10
5.1 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.2 Control Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.3 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.4 Variable Assigments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

6 Blocks 14
6.1 Initial Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.2 Always Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.3 Assign Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

7 Test Benches 15

8 Program and Testbench using this Content. 17


8.1 Main Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
8.2 Testbench . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

9 References 19

2
1 Introduction
1.1 What is it About?
This document is just a revision (for the author) of the most basics Verilog subjects.
This explanations comes from the author experiences and the resources in the references.
Some parts of this text are from ASIC World.

3
2 Levels of Abstraction
Verilog allow us to design a device in three dierent levels of implementations:

1. Behavioral Level.

2. Register-Transfer Level.

3. Gate Level.

2.1 Behavioral Level


This level describes a system by concurrent algorithms (Behavioral). Each algorithm
itself is sequential, that means it consists of a set of instructions that are executed one
after the other. Functions, Tasks and Always blocks are the main elements. There is no
regard to the structural realization of the design.

2.2 Register-Transfer Level


Designs using the Register-Transfer Level specify the characteristics of a circuit by
operations and the transfer of data between the registers. An explicit clock is used. RTL
design contains exact timing bounds: operations are scheduled to occur at certain times.
Modern RTL code denition is ”Any code that is synthesizable is called RTL code”.

2.3 Gate Level


Within the logic level the characteristics of a system are described by logical links
and their timing properties. All signals are discrete signals. They can only have denite
logical values (‘0’, ‘1’, ‘X’, ‘Z‘). The usable operations are predened logic primitives
(AND, OR, NOT etc gates). Using gate level modeling might not be a good idea for any
level of logic design. Gate level code is generated by tools like synthesis tools and this
netlist is used for gate level simulation and for backend.

4
3 Wire and Reg Data Types
As a HDL language Verilog doesn’t have data types, but wire and reg are more like
drivers. A driver is a data type which can drive a load. Basically, in a physical circuit, a
driver would be anything that electrons can move through/into.
1. Driver that can store a value (example: ip-op).

2. Driver that can not store value, but connects two points (example: wire).

3.1 Wire
Wire connects two points, and thus does not have any driving strength. In the gure
below, in wire is a wire which connects the AND gate input to the driving source, clk wire
connects the clock to the ip-op input, d wire connects the AND gate output to the ip-
op D input.

Figure 1: Diagram 1

There is something else about wire which sometimes confuses. wire data types can be
used for connecting the output port to the actual driver. Below is the code which when
synthesized gives a AND gate as output, as we know a AND gate can drive a load.
1 module wire_example (a , b , y ) ;
2 input a , b ;
3 output y ;
4
5 wire a , b , y ;
6
7 assign y = a & b ;
8 endmodule

What this implies is that wire is used for designing combinational logic, as we all know
that this kind of logic can not store a value. As you can see from the example above,
a wire can be assigned a value by an assign statement. Default data type is wire: this
means that if you declare a variable without specifying reg or wire, it will be a 1-bit wide
wire.

3.2 Registers
Now, coming to reg data type, reg can store value and drive strength. Something that
we need to know about reg is that it can be used for modeling both combinational and
sequential logic. Reg data type can be driven from initial and always block.
Reg data type as Combinational element:

5
1 module reg _combo _examp le (a , b , y ) ;
2 input a , b ;
3 output y ;
4
5 reg y ;
6 wire a , b ;
7
8 always @ ( a or b )
9 begin
10 y = a & b;
11 end
12
13 endmodule

This gives the same output as that of the assign statement, with the only dierence that
y is declared as reg. There are distinct advantages to have reg modeled as combinational
element; reg type is useful when a ”case” statement is required. To model a sequential
element using reg, we need to have edge sensitive variables in the sensitivity list of the
always block.
Reg data type as Sequential element:
1 module reg_seq_example ( clk , reset , d , q ) ;
2 input clk , reset , d ;
3 output q ;
4
5 reg q ;
6 wire clk , reset , d ;
7
8 always @ ( posedge clk or posedge reset )
9 if ( reset ) begin
10 q <= 1 ' b0 ;
11 end else begin
12 q <= d ;
13 end
14
15 endmodule

There is a dierence in the way we assign to reg when modeling combinational logic: in
this logic we use blocking assignments while modeling sequential logic we use nonblocking
ones.

6
4 Blocking and Nonblocking in Verilog
4.1 Blocking Statements
A blocking statement must be executed before the execution of the statements that
follow it in a sequential block. In the example below the rst time statement to get
executed is a = b followed by out d = 0.

Figure 2: Sequence of execution

4.2 Nonblocking Statements


Nonblocking statements allow you to schedule assignments without blocking the procedural
ow. You can use the nonblocking procedural statement whenever you want to make
several register assignments within the same time step without regard to order or dependence
upon each other. It means that nonblocking statements resemble actual hardware more
than blocking assignments.
1 module block_nonblock () ;
2 reg a , b , c , d , e , f ;
3
4 // Blocking assignments
5 initial begin
6 a = #10 1 ' b1 ; // The simulator assigns 1 to a at time 10
7 b = #20 1 ' b0 ; // The simulator assigns 0 to b at time 30
8 c = #40 1 ' b1 ; // The simulator assigns 1 to c at time 70
9 end
10
11 // Nonblocking assignments
12 initial begin
13 d <= #10 1 ' b1 ; // The simulator assigns 1 to d at time 10
14 e <= #20 1 ' b0 ; // The simulator assigns 0 to e at time 20
15 f <= #40 1 ' b1 ; // The simulator assigns 1 to f at time 40
16 end
17
18 endmodule

7
Example - Blocking:
1 module blocking ( clk , a , c ) ;
2 input clk ;
3 input a ;
4 output c ;
5
6 wire clk ;
7 wire a ;
8 reg c ;
9 reg b ;
10
11 always @ ( posedge clk )
12 begin
13 b = a;
14 c = b;
15 end
16
17 endmodule

Synthesis Output:

Figure 3: Diagram 2

8
Example - Nonblocking:
1 module nonblocking ( clk , a , c ) ;
2 input clk ;
3 input a ;
4 output c ;
5
6 wire clk ;
7 wire a ;
8 reg c ;
9 reg b ;
10
11 always @ ( posedge clk )
12 begin
13 b <= a ;
14 c <= b ;
15 end
16
17 endmodule

Synthesis Output:

Figure 4: Diagram 3

9
5 Basics of Verilog
Some operators and control statements.

5.1 Operators

Figure 5: Operators in Verilog

5.2 Control Statements


If, else, repeat, while, for, case - it’s Verilog that looks exactly like C (and probably
whatever other language you’re used to program in)! Even though the functionality

10
appears to be the same as in C, Verilog is an HDL, so the descriptions should translate to
hardware. This means you’ve got to be careful when using control statements (otherwise
your designs might not be implementable in hardware).

If-else: If-else statements check a condition to decide whether or not to execute a portion
of code. If a condition is satised, the code is executed. Else, it runs this other portion
of code.
1 // begin and end act like curly braces in C / C ++.
2 if ( enable == 1 ' b1 ) begin
3 data = 10; // Decimal assigned
4 address = 16 ' hDEAD ; // Hexadecimal
5 wr_enable = 1 ' b1 ; // Binary
6 end else begin
7 data = 32 ' b0 ;
8 wr_enable = 1 ' b0 ;
9 address = address + 1;
10 end

One could use any operator in the condition checking, as in the case of C language. If
needed we can have nested if else statements; statements without else are also ok, but
they have their own problem, when modeling combinational logic, in case they result in
a Latch (this is not always true).

Case: Case statements are used where we have one variable which needs to be checked
for multiple values. like an address decoder, where the input is an address and it needs
to be checked for all the values that it can take. Instead of using multiple nested if-else
statements, one for each value we’re looking for, we use a single case statement: this is
similar to switch statements in languages like C++.
Case statements begin with the reserved word case and end with the reserved word
endcase (Verilog does not use brackets to delimit blocks of code). The cases, followed
with a colon and the statements you wish executed, are listed within these two delimiters.
It’s also a good idea to have a default case. Just like with a nite state machine (FSM), if
the Verilog machine enters into a non-covered statement, the machine hangs. Defaulting
the statement with a return to idle keeps us safe.
1 case ( address )
2 0 : $display ( " It is 11:40 PM " ) ;
3 1 : $display ( " I am feeling sleepy " ) ;
4 2 : $display ( " Let me skip this tutorial " ) ;
5 default : $display ( " Need to complete " ) ;
6 endcase

Looks like the address value was 3 and so I am still writing this tutorial.
Note: One thing that is common to if-else and case statement is that, if you don’t
cover all the cases (don’t have ’else’ in If-else or ’default’ in Case), and you are trying to
write a combinational statement, the synthesis tool will infer Latch.

While: A while statement executes the code within it repeatedly if the condition it is
assigned to check returns true. While loops are not normally used for models in real life,
but they are used in test benches. As with other statement blocks, they are delimited by
begin and end.

11
1 while ( free_time ) begin
2 $display ( " Continue with webpage development " ) ;
3 end

As long as free time variable is set, code within the begin and end will be executed.
i.e print ”Continue with web development”. Let’s looks at a stranger example, which uses
most of Verilog constructs. Well, you heard it right. Verilog has fewer reserved words
than VHDL, and in this few, we use even lesser for actual coding. So good of Verilog...
so right.
1 module counter ( clk , rst , enable , count ) ;
2 input clk , rst , enable ;
3 output [3:0] count ;
4 reg [3:0] count ;
5
6 always @ ( posedge clk or posedge rst )
7 if ( rst ) begin
8 count <= 0;
9 end else begin : COUNT
10 while ( enable ) begin
11 count <= count + 1;
12 disable COUNT ;
13 end
14 end
15
16 endmodule

The example above uses most of the constructs of Verilog. You’ll notice a new block
called always - this illustrates one of the key features of Verilog. Most software languages,
as we mentioned before, execute sequentially - that is, statement by statement. Verilog
programs, on the other hand, often have many statements executing in parallel. All blocks
marked always will run - simultaneously - when one or more of the conditions listed within
it is fullled.
In the example above, the always block will run when either rst or clk reaches a positive
edge - that is, when their value has risen from 0 to 1. You can have two or more always
blocks in a program going at the same time (not shown here, but commonly used).
We can disable a block of code, by using the reserve word disable. In the above
example, after each counter increment, the COUNT block of code (not shown here) is
disabled.

For Loop: For loops in Verilog are almost exactly like for loops in C or C++. The
only dierence is that the ++ and – operators are not supported in Verilog. Instead of
writing i++ as you would in C, you need to write out its full operational equivalent, i =
i + 1.
1 for ( i = 0; i < 16; i = i + 1) begin
2 $display ( " Current value of i is % d " , i ) ;
3 end

This code will print the numbers from 0 to 15 in order. Be careful when using for loops for
register transfer logic (RTL) and make sure your code is actually sanely implementable
in hardware... and that your loop is not innite.

12
Repeat: Repeat is similar to the for loop we just covered. Instead of explicitly
specifying a variable and incrementing it when we declare the for loop, we tell the program
how many times to run through the code, and no variables are incremented (unless we
want them to be, like in this example).
1 repeat (16) begin
2 $display ( " Current value of i is % d " , i ) ;
3 i = i + 1;
4 end

The output is exactly the same as in the previous for-loop program example. It is relatively
rare to use a repeat (or for-loop) in actual hardware implementation.

5.3 Summary
1. While, if-else, case(switch) statements are the same as in C language.

2. If-else and case statements require all the cases to be covered for combinational
logic.

3. For-loop is the same as in C, but no ++ and – operators.

4. Repeat is the same as the for-loop but without the incrementing variable.

5.4 Variable Assigments


In digital there are two types of elements, combinational and sequential. Of course
we know this. But the question is ”How do we model this in Verilog ?”. Well Verilog
provides two ways to model the combinational logic and only one way to model sequential
logic.

1. Combinational elements can be modeled using assign and always statements.

2. Sequential elements can be modeled using only always statement.

3. There is a third block, which is used in test benches only: it is called Initial
statement.

13
6 Blocks
6.1 Initial Blocks
An initial block, as the name suggests, is executed only once when simulation starts.
This is useful in writing test benches. If we have multiple initial blocks, then all of them
are executed at the beginning of simulation.
1 initial begin
2 clk = 0;
3 reset = 0;
4 req_0 = 0;
5 req_1 = 0;
6 end

In the above example, at the beginning of simulation, (i.e. when time = 0), all the
variables inside the begin and end block are driven zero.

6.2 Always Blocks


As the name suggests, an always block executes always, unlike initial blocks which
execute only once (at the beginning of simulation). A second dierence is that an always
block should have a sensitive list or a delay associated with it.
The sensitive list is the one which tells the always block when to execute the block of
code, as shown in the gure below. The @ symbol after reserved word ’ always’, indicates
that the block will be triggered ”at” the condition in parenthesis after symbol @.
One important note about always block: it can not drive wire data type, but can drive
reg and integer data types.
1 always @ ( a or b or sel )
2 begin
3 y = 0;
4 if ( sel == 0) begin
5 y = a;
6 end else begin
7 y = b;
8 end
9 end

The above example is a 2:1 mux, with input a and b; sel is the select input and y is the
mux output. In any combinational logic, output changes whenever input changes. This
theory when applied to always blocks means that the code inside always blocks needs to
be executed whenever the input variables (or output controlling variables) change. These
variables are the ones included in the sensitive list, namely a, b and sel.
There are two types of sensitive list: level sensitive (for combinational circuits) and
edge sensitive (for ip-ops). The code below is the same 2:1 Mux but the output y is
now a ip-op output.

14
1 always @ ( posedge clk )
2 if ( reset == 0) begin
3 y <= 0;
4 end else if ( sel == 0) begin
5 y <= a ;
6 end else begin
7 y <= b ;
8 end

We normally have to reset ip-ops, thus every time the clock makes the transition from
0 to 1 (posedge), we check if reset is asserted (synchronous reset), then we go on with
normal logic. If we look closely we see that in the case of combinational logic we had
”=” for assignment, and for the sequential block we had the ”¡=” operator. Well, ”=” is
blocking assignment and ”¡=” is nonblocking assignment. ”=” executes code sequentially
inside a begin / end, whereas nonblocking ”¡=” executes in parallel.
We can have an always block without sensitive list, in this case we need to have a
delay as shown in the code below.
1 always begin
2 #5 clk = ~ clk ;
3 end

#5 in front of the statement delays its execution by 5 time units.

6.3 Assign Statement


An assign statement is used for modeling only combinational logic and it is executed
continuously. So the assign statement is called ’continuous assignment statement’ as there
is no sensitive list.
1 assign out = ( enable ) ? data : 1 ' bz ;

The above example is a tri-state buer. When enable is 1, data is driven to out, else out
is pulled to high-impedance. We can have nested conditional operators to construct mux,
decoders and encoders.
1 assign out = data ;

This example is a simple buer.

7 Test Benches
Ok, we have code written according to the design document, now what?
Well we need to test it to see if it works according to specs. Most of the time, it’s
the same we use to do in digital labs in college days: drive the inputs, match the outputs
with expected values. Let’s look at the arbiter testbench.
1 module arbiter (
2 clock ,
3 reset ,
4 req_0 ,
5 req_1 ,
6 gnt_0 ,
7 gnt_1

15
8 );
9
10 input clock , reset , req_0 , req_1 ;
11 output gnt_0 , gnt_1 ;
12
13 reg gnt_0 , gnt_1 ;
14
15 always @ ( posedge clock or posedge reset )
16 if ( reset ) begin
17 gnt_0 <= 0;
18 gnt_1 <= 0;
19 end else if ( req_0 ) begin
20 gnt_0 <= 1;
21 gnt_1 <= 0;
22 end else if ( req_1 ) begin
23 gnt_0 <= 0;
24 gnt_1 <= 1;
25 end
26
27 endmodule
28
29 // Testbench Code Goes here
30
31 module arbiter_tb ;
32
33 reg clock , reset , req0 , req1 ;
34 wire gnt0 , gnt1 ;
35
36 initial begin
37 $monitor ( " req0 =% b , req1 =% b , gnt0 =% b , gnt1 =% b " , req0 , req1 , gnt0 ,
gnt1 ) ;
38 clock = 0;
39 reset = 0;
40 req0 = 0;
41 req1 = 0;
42 #5 reset = 1;
43 #15 reset = 0;
44 #10 req0 = 1;
45 #10 req0 = 0;
46 #10 req1 = 1;
47 #10 req1 = 0;
48 #10 { req0 , req1 } = 2 ' b11 ;
49 #10 { req0 , req1 } = 2 ' b00 ;
50 #10 $finish ;
51 end
52
53 always begin
54 #5 clock = ! clock ;
55 end
56
57 arbiter U0 (
58 . clock ( clock ) ,
59 . reset ( reset ) ,

16
60 . req_0 ( req0 ) ,
61 . req_1 ( req1 ) ,
62 . gnt_0 ( gnt0 ) ,
63 . gnt_1 ( gnt1 )
64 ) ;
65
66 endmodule

It looks like we have declared all the arbiter inputs as reg and outputs as wire; well, that’s
true. We are doing this as test bench needs to drive inputs and needs to monitor outputs.
After we have declared all needed variables, we initialize all the inputs to known state:
we do that in the initial block. After initialization, we assert/de-assert reset, req0, req1
in the sequence we want to test the arbiter. Clock is generated with an always block.
After we are done with the testing, we need to stop the simulator. Well, we use $nish
to terminate simulation. $monitor is used to monitor the changes in the signal list and
print them in the format we want.

8 Program and Testbench using this Content.


Follow a simple counter that was made using this revision.

8.1 Main Program


1 module counter ( clk , out , rst ) ;
2 input clk , rst ;
3 output reg [3:0] out ;
4
5 always @ ( posedge clk or negedge rst )
6 if ( rst == 1 ' d0 )
7 out <= 1 ' d0 ;
8 else
9 out <= out + 1 ' d1 ;
10 endmodule

17
8.2 Testbench
1 `timescale 10 ns /1 ps
2 module counter_tb ;
3
4 reg clk_tb , rst_tb ;
5 wire [3:0] out_tb ;
6
7 initial
8 begin
9 clk_tb = 1 ' d0 ;
10 rst_tb = 1 ' d0 ;
11 #5 rst_tb = 1 ' d1 ;
12 #100 rst_tb = 1 ' d0 ;
13 #110 rst_tb = 1 ' d1 ;
14 end
15
16 always
17 begin
18 #5 clk_tb = ~ clk_tb ;
19 end
20
21 counter dut (. clk ( clk_tb ) , . rst ( rst_tb ) , . out ( out_tb ) ) ;
22 endmodule

18
9 References
1. Site: ASIC World, URL:https://www.asic-world.com/verilog/index.html

19

You might also like