If
you can express working of a digital circuit and visualize the flow
of data inside a IC, then learning any HDL or Hardware Description
Language is very easy. This chapter is a overview of how Verilog
code looks like.
This
article will always be under construction.
Let
us start with an AND gate. Here is the truth table:
|
A |
B |
Y |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
1 |
/* A simple AND gate
File: and.v */
module andgate (a, b, y);
input a, b;
output y;
assign y = a & b;
endmodule
|
Now let us try to understand the
code.
/* This is
multi line
comment */
and // this is single line comment,
Comments are same as in C language.
In
verilog, one circuit is represented by set of "modules". We
can consider a module as a black box. With this assumption, if you
draw a block diagram of the circuit with a set of signals connection
each other, that is called top level design. Then go on writing
modules for each black box, then design that black box with in the
same way. This is how we are designing a circuit. You will
understand this concept after studying some examples. A module may be one gate, one flip-flop, one register,
one ALU one controller or one SOC. Go back to the example. Here, module is keyword, andgate is the name
given to the module in this examples and a, b and y are the ports or
connections to the module. Every modules and with the keyword
endmodule.
In
the beginning of a module, we have to declare all ports as input
output or inout. By default, ports will have one pin or one bit.
Using 'assign' statement, we connected inputs and outputs via AND
gate. A will be ANDed with B and will be connected to Y. Here, we
are not going to store the values, and hence we did not declare any
registers. By default, all the ports will be considered as wires. If
we want the output to be latched, we have to declare it using the
keyword 'reg'.
input a, b;
output y;
wire a, b, y;
Next
we will write a testbench to test the gate that we have created.
Testbench is another verilog code that creates a circuit involving
the circuit to be tested. This code will send different inputs to
the code under test and get the output and displays to check the
accuracy.
/* testbench for
AND gate
File: and_tb.v */
module andgate_tb;
wire t_��|7V ��|7V ���|7V ���|7V X��|7V ��|7V @ ��|7V andgate my_gate( .a(t_a), .b(t_b), .y(t_y) );
initial
begin
$monitor(t_a,
t_b, t_y);
t_a = 1'b0;
t_b = 1'b0;
#5
t_a = 1'b0;
t_b = 1'b1;
#5
t_a = 1'b1;
t_b = 1'b0;
#5
t_a = 1'b1;
t_b = 1'b1;
end
endmodule |
Here we
have created another module andgate_tb which will include the module
andgate. We have to give values to input, so we need to store or
latch the input data. So, t_a and t_b are declared as reg and t_y as
wire fto get the outut value from the gate. Now, we create an
instance of andgate. i.e., we are placing the and gate that we have
created previously inside this module. We can use two different
notations to connect the ports.
We can
write andgate
my_gate(t_a, t_b, t_y);. This is called
instanciating by order. Here, all the
ports should be in the order as we declared in the module
definition. If we write as given in the example, we can change the
order. That is,
andgate my_gate( .a(t_a),
.b(t_b), .y(t_y) ); is equal to
andgate my_gate( .b(t_b), .y(t_y), .a(t_a) );.
This is called instanciation by name. Like
this, we can use any number of instances of same module in a design.
'a'
in the andgate will be connected to t_a in the andgate_tb and so on.
If some of the statements in our code is to be executed only in the
beginning of the execution, we can write them using
initial block.
initial
block executes only once and starts at time=0. Your program may have
any number of initial
blocks. initial block begins with
begin and ends
with end.
Inside an initial block, statements will execute sequentially. In
next chapter, we will learn more about flow of execution of a
program.
$monitor is a system task used to display the values in variable
whenever value of one of its arguments changes. After that we will
assign different values to t_a and t_b. Here 1'b0 indicates a low
signal and 1'b1 represents a high signal. Meaning of this notation
is, a 1 bit variable expressed in binary as 1. Similarly we can also
indicates decimal, hex, octal numbers as follows.
Integer |
Meaning |
Stored as |
5'b00101 |
5 bit binary 00101 |
00101 |
8'b0 |
8 bit binary 00000000 |
00000000 |
8'b101 |
8 bit binary 00000101 |
00000101 |
8'd5 |
8 bit decimal 5 |
00000101 |
8'h9f |
8 bit hex 9f |
10011111 |
3'd1 |
3 bit decimal 1 |
001 |
4'bz |
3 bit decimal z |
zzzz |
4'bx1 |
binary |
xxx1 |
5'b11z |
binary |
0011z |
15 |
32 bit decimal 15 |
0....01111(32 bits) |
'o5 |
32 bit octal 5 |
0....00101(32 bits) |
Rules:
-
1:
Active high bit
-
0:
Active low bit
-
z:
high impedance
-
x:
Uncertain/ Don't care
-
If
not mentioned, length is 32 bit and data type is integer by
default.
-
If
value is larger than the length, left most bits will be truncated
-
If
value is smaller,
#5
indicates a delay of 5ns. To observe the changes in the output
waveform, we need to include this delay. If we observe the output,
we can notice that input changes in the intervals of 5ns and we will
get corresponding ANDed output in t_y.
Next:
Verilog Primitives |