icarus verilog bleyer.org/icarus · mohd uzir kamaluddin verilog-2nd ed. [5] assignments within the...
TRANSCRIPT
Mohd Uzir Kamaluddin Verilog-2nd ed. [1]
Verilog Hardware Description Language HDL
Introduction
Verilog HDL is a hardware description language used to design and document electronic systems. Verilog HDL
allows designers to design at various levels of abstraction. It is the most widely used HDL with a user community of
more than 50,000 active designers.
The tool that is used to learn the Verilog language in this brief introduction is the Icarus Verilog. Icarus Verilog (in
short iverilog) is a free Verilog simulation and synthesis tool and can be downloaded from bleyer.org/icarus. It
operates as a compiler, compiling source code written in Verilog (IEEE-1364) into some target format. For batch
simulation, the compiler can generate an intermediate form called vvp assembly. This intermediate form is
executed by the ”vvp” command. For synthesis, the compiler generates netlists in the desired format.
Verilog Basics
Verilog HDL is case sensitive. All verilog keywords are lower case (e.g. module, endmodule, initial, begin, end...)
Logic values in modeling hardware are logic-0, logic-1, high-impedance-z, don’t care-x and unknown-x.
The data types in Verilog HDL is similar to a variable in programming, and belongs to one of the two data types, net
data type and register data type. Nets represent structural connections between components and registers
represent variables used to store data. A net declaration wire [3:0] sig or wire [0:3] sig will result in the variable sig
to be of 4 bits wide. If no size is explicitly specified, the default size is 1 bit, e.g. wire test. The variable test is 1 bit
signal. The wire net is the most commonly used net type.
The different kinds of register data types that are supported for synthesis are reg and integer. Similar to a net
declaration, a reg declaration explicitly specifies the size, that is, the corresponding number of bits of the variable in
the hardware. For example, reg [0:3] sig or reg [3:0] sig will create a 4 bit variable, while reg test will create a 1 bit
variable.
Modules are the building blocks of Verilog designs. Using modules by another modules (instantiating) is called
design hierarchy is a common way of creating a design.
Ports allow communication between a module and its environment and can be associated by order or by name.
Ports can be input, output or inout. Port connection rules:
Inputs: internally must always be of type net, externally the inputs can be connected to variable reg or net type.
Outputs: internally can be of type net or reg, externally the outputs can be connected to a variable net type.
Abstraction Levels
Verilog supports a design at many levels of abstraction. The major three are:−
• Behavioral level (Register Transfer Level) - a description of a circuit in terms of high-level logic and arithmetic
operations and assignments. Working at this level will model in terms of what the circuit will do as opposed to
using the lower-level logic gates which describe how the circuit can be implemented.
• Structural level - a description of a circuit at the abstraction level of logic gates. This type of model could be
seen as a textual representation of a schematic.
• Data Flow level - a description of a circuit which can use logical expressions with continuous assignments.
Bitwise Operators
Bitwise operators perform a bit wise operation on two operands. These operators take each bit in one operand and
perform the operation with the corresponding bit in the other operand. If one operand is shorter than the other, it
will be extended on the left side with zeroes to match the length of the longer operand.
Operation Symbol
Negation (Invert) ~
And (AND) &
Not And (NAND) ~&
Inclusive Or (OR) |
Not Or (NOR) ~|
Mohd Uzir Kamaluddin Verilog-2nd ed. [2]
Exclusive Or (XOR) ^
Exclusive Nor (XNOR) ^~ or ~^
Gate Primitives
The gates have one scalar output and multiple scalar inputs. The first terminal in the list of gate terminals is an
output and the other terminals are inputs.
and N-input AND gate
nand N-input NAND gate
or N-input OR gate
nor N-input NOR gate
xor N-input EX-OR gate
xnor N-input EX-NOR gate
not N-output inverter
Example 1: Implementing a combinational logic circuit:-
Solution 1 Structural Level
module AOI (A, B, C, D, F);
input A, B, C, D;
output F;
wire w1, w2; //internal connections
and (w1, A, B);
and (w2, C, D);
or (F, w1, w2);
endmodule
Solution 2 Data Flow Level
module AOI (A, B, C, D, F);
input A, B, C, D;
output F;
assign F = (A&B) | (C&D); // CDABF
endmodule
Example 2:- Implementing a Full Adder.
Solution 1: Structural Level
module full_adder( A, B, Cin, S, Cout );
input A, B, Cin;
output S, Cout;
wire s1, c1, c2;
xor (s1, A, B);
xor (S, Cin, s1);
and (c1, A, B);
and (c2, s1, Cin);
or (Cout, c1, c2);
endmodule
Solution 2: Data Flow Level
module full_adder( A, B, Cin, S, Cout );
input A, B, Cin;
output S, Cout;
wire s1;
assign s1 = A ^ B;
assign S = s1 ^ cin;
Mohd Uzir Kamaluddin Verilog-2nd ed. [3]
assign Cout = (A & B) | (s1 & Cin);
endmodule
Example 3:- Implementing a Full Adder using Half-Adders and OR gate (Structural Level).
//declare the half adder verilog module.
module half_adder(A, B, S, C);
input A, B;
output S, C;
xor (S, A, B);
and (C, A, B);
endmodule
//declare the full adder verilog module
module full_adder(A, B, Cin, S, C);
input A, B, Cin;
output S, C;
wire S1, C1, C2;
half_adder HA1 ( .A(A), .B(B), .S(S1), .C(C1) );
half_adder HA2 ( .A(S1), .B(Cin), .S(S), .C(C2) );
or (C, C1, C2);
endmodule
Circuit Simulation
Simulation is process of verifying the functional characteristics of models at any level of abstraction. The hardware
models are simulated using the simulators. The objective of simulating a hardware model is to test if the codes
meets the functional requirements of the specification, and all the blocks in the model are functionally correct. To
achieve this, a testbench module needs to be written.
Example 1: To create an AND gate from a NAND gate
//Using structural level
module and_from_nand(X, Y, F);
input X, Y;
output F;
wire W;
nand U1 (W, X, Y);
nand U2 (F, W, W);
endmodule
//***Testbench code******
module test();
reg X, Y; //the inputs are declared as reg
wire F; //the output is declared as wire
and_from_nand uut(.W(W), .Y(Y), .F(F)); //instantiate unit under test
initial begin
$display (“\n The output of the circuit under test:-“);
$monitor (“ X=%b Y=%b F=%b”, X, Y, F); //variables to be displayed
X=0; Y=0; //initialise X and Y to 0
#10 X=1; //now X=1, Y=0 after delay of 10 time units
#10 Y=1; //now X=1, Y=1 after delay of 10 time units
#10 X=0; //now X=0, Y=1 after delay of 10 time units
Mohd Uzir Kamaluddin Verilog-2nd ed. [4]
#10 $finish; //end of simulation after delay of 10 time units
end
endmodule
Output produced:
The output of the circuit under test:-
X=0 Y=0 F=0
X=1 Y=0 F=0
X=1 Y=1 F=1
X=0 Y=1 F=0
Constants
There are three kind of constants in verilog HDL, integer, real and string. Real and string constants are not
supported for synthesis.
An integer constant can be written either in simple decimal or base format. When an integer is written in simple
decimal form, it is interpreted as a signed number. The integer is represented in synthesis as 32 bits in 2’s
complement form. If an integer is written in the base format form, then the integer is treated as an unsigned
number. Some examples of integer declaration:
30 Signed number, 32 bits
-2 Signed number, 32 bits in 2’s complement format
2’b10 Size of 2 bits
6’d-4 6-bit unsigned number (-4 is in 2’s complement using 6 bits)
‘d-10 32-bit unsigned number (-10 is in 2’s complement using 32 bits)
Data Storage
The basic value holders in hardware are wire, flip-flop and latch. The flip-flop is an edge-triggered storage element
while the latch is a level-sensitive storage element. A variable in Verilog HDL can either be of the net data type or
the register data type. For synthesis, a variable of net type maps to a wire in hardware and a variable of the
register type maps either to a wire or a storage element (flip-flop or latch) depending on the context under which
the variable is assigned a value.
In Verilog HDL, a register variable retains its value through the entire simulation run, thus inferring memory.
Assignment: Continuous and Procedural
A continuous assignment statement represents, in hardware, logic that is derived from the expression on the right-
hand side of the assignment statement driving the net that appears on the left-hand side of the assignment. The
target of a continuous assignment is always a net driven by combinational logic.
module Continuous (input StatIn, output StatOut)
assign StatOut = ~StatIn; //continuous assignment (NOT gate)
endmodule
A procedural assignment statement represents, in hardware, logic that is derived from the expression on the right-
hand side of the assignment statement driving the variable that appears on the left-hand side of the assignment.
Procedural assignments can appear only within an always statement. There are two kinds of procedural
assignment statements: blocking and non-blocking.
Blocking Statements: A blocking statement must be executed before the execution of the statements that follow it
in a sequential block.
Non-blocking Statements: Non-blocking statements allows to schedule assignments without blocking the
procedural flow. The non-blocking procedural statement can be used whenever to make several register
Mohd Uzir Kamaluddin Verilog-2nd ed. [5]
assignments within the same time step without regard to order or dependence upon each other. It means that
non-blocking statements resemble the actual hardware more than blocking assignments.
Always block
As the name suggests, an always block executes always, unlike initial blocks which execute only once (at the
beginning of simulation). A second difference 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 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 cannot drive wire data type, but can drive reg and integer data types.
module blocking (clk, a, b, c);
input clk, a;
output b, c; //this two lines can also be written
reg b, c; //as output reg b, c; Output must be reg type when used in always block
wire clk, a; //this is optional as input is already a wire
always @ (posedge clk )
begin
b = a; //blocking statements
c = b; //c will have the value of a – statement run one by one
end
endmodule
module nonblocking (clk, a, b, c);
input clk, a;
output b, c; //this two lines can also be written
reg b, c; //as output reg b,c; Output must be reg type when used in always block
wire clk, a; //this is optional as input is already a wire
always @ (posedge clk )
begin
b <= a; //non-blocking statements
c <= b; //c will have the previous value of b since both statements run simultaneously
end
endmodule
The blocking and non-blocking nature of an assignment does not cause any change to the combinational logic
generated from the assignment statement itself, but affects the use of the resultant value later on.
A good recommendation to follow is to use blocking assignments for modeling combinational logic and to use
non-blocking assignments for modeling sequential logic.
Operators
Logical operators are used in conjunction with relational and equality operators. They provide a means to perform
multiple comparisons within a single expression.
Expressions connected by && and || are evaluated from left to right.
Evaluation stops as soon as the result is known.
The result is a scalar value:
o 0 if the relation is false
o 1 if the relation is true
o x if any of the operands has x (unknown) bits
Mohd Uzir Kamaluddin Verilog-2nd ed. [6]
Logical Negation !
Logical AND &&
Logical OR ||
Relational operators compare two operands and return an indication of whether the compared relationship is true
or false. The result of a comparison is either 0 or 1. It is 0 if the comparison is false and 1 is the comparison is true.
Greater than >
Greater than or equal to >=
Less than <
Less than or equal to <=
Equality and inequality operators are used in exactly the same way as relational operators and return a true or
false indication depending on whether any two operands are equivalent or not.
Case equality (Equal) ==
Case inequality (Not Equal) !=
The conditional if-else statement
The if - else statement controls the execution of other statements. In programming language like c, if - else controls
the flow of program. When more than one statement needs to be executed for an if condition, then we need to use
begin and end as seen in earlier examples.
Syntax : if
if (condition)
statements;
Syntax : if-else
if (condition)
statements;
else
statements;
Syntax : nested if-else-if
if (condition)
statements;
else if (condition)
statements;
................
................
else
statements;
Example: Implementing a 2:1 MUX using if-else
always @ (a or b or sel) //output will change when a or b or sel changes value
begin
y = 0;
if (sel == 0) begin
y = a;
end
else begin
y = b;
end
end
Mohd Uzir Kamaluddin Verilog-2nd ed. [7]
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 flip-flops).
The code below is the same 2:1 MUX but the output y is now a flip-flop output.
always @ (posedge clk)
if (reset == 0) begin
y <= 0;
end
else if (sel == 0) begin
y <= a;
end
else begin
y <= b;
end
The case statement
The case statement compares an expression to a series of cases and executes the statement or statement group
associated with the first matching case. Case statement supports single or multiple statements. Group multiple
statements using begin and end keywords.
Syntax of a case statement.
case ()
< case1 > : < statement >
< case2 > : < statement >
.....
default : < statement >
endcase
Example of 2-1 multiplexer using case statement.
module mux_case(out, cntrl, in1, in2);
input cntrl, in1, in2;
output out;
reg out;
always @ *
case (cntrl)
1'b0 : out = in1;
1'b1 : out = in2;
endcase
endmodule
Example 1:- Implementing a Full Adder (Behavioral Level) with testbench.
module full_adder_behavioral(a, b, cin, sum, cout);
input a, b, cin;
output reg sum, cout; // output are to be declared as reg to be used in an always block
reg T1, T2, T3, S1; // and so as the variables
always @(a, b, cin)
begin
T1 = a & b; //blocking assignments executed in sequence
Mohd Uzir Kamaluddin Verilog-2nd ed. [8]
T2 = b & cin;
T3 = cin & a;
cout = T1 | T2 | T3;
S1 = a ^ b;
sum = S1 ^ cin;
end
endmodule
//**********Testbench******************************************
module fa_tb;
reg a, b, cin;
wire sum, cout;
full_adder_behavioral uut(.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
initial begin
$display("\t\t time,\t A,\t B,\t C,\t Cout, \t Sum");
$monitor("%d, \t %b, \t %b, \t %b, \t %b, \t %b", $time, a, b, cin, cout, sum);
a=0; b=0; cin=0;
#1 a=0; b=1; cin=0;
#1 a=1; b=0; cin=0;
#1 a=1; b=1; cin=0;
#1 a=1; b=0; cin=1;
#1 a=0; b=1; cin=1;
#1 a=1; b=1; cin=0;
#1 a=1; b=1; cin=1;
#1 $finish;
end
endmodule
Sequential Logic Circuits
So far the discussion is only about combinational circuits. This was good as far as the learning of Verilog language
and its constructs are concerned. Practical FPGA circuits, however, almost always contains sequential circuits.
Combinational circuits do not have memory and its present output is a function only of present inputs. A sequential
circuit, on the other hand, has memory and its present output depends not only upon present input but also upon
past input(s).
A better term for past inputs is "state". A sequential circuit consists of finite states and its output depends upon
present input and one of these states.
Implicit in the design of the sequential circuits is a global clock and the circuit operates on the rising or falling edge
of the clock (posedge or negedge).
Flip-Flops
A D flip-flop is the most basic building block of sequential circuit. The basic D flip-flop is a sequential device that
transfers the value of the D input to the Q output on every rising edge (or falling edge) of the clock. From the
abstraction at the top level, a D flip-flop has a Clock and a Data D as input. It has one output designated as Q. For
simplicity, the reset signal is not used.
// D Flip Flop without Reset
module d_ff (Clock, D, Q);
input wire Clock, D;
output reg Q;
always @(posedge Clock) //no need D
Mohd Uzir Kamaluddin Verilog-2nd ed. [9]
Q = D; //there is no Qbar output
endmodule
This D flip flop is a positive edge-triggered FF. An important thing to note is that the input signal D is not present in
the sensitive list. The D signal is sampled only at the rising edge of the clock signal.
//Testbench for D flip flop
`timescale 1ns / 1ps
module stimulus;
reg Clock, D;
wire Q;
// Instantiate the Unit Under Test (UUT)
d_ff d1 (.Clock(Clock), .D(D), .Q(Q));
initial Clock = 0;
always #10 Clock <= ~Clock; //the clock waveform for the D flip flop
initial begin
$dumpfile("test.vcd");
$dumpvars(0, stimulus); //create VCD file for gtkwave
$monitor("Clock=%d, D=%d, Q=%d ", Clock, D, Q); //Display output in tabular form
//The input to the D flip flop
D = 0;
# 8 D = 1;
#10 D = 0;
#10 D = 0;
#10 D = 1;
#10 D = 0;
#10 D = 1;
#10 $finish;
end
endmodule
D-FF: (Behavioural Level)
One of the most useful sequential building blocks is a D flip-flop with an additional asynchronous reset pin. When
the reset is not active, it operates as a basic D flip-flop. When the reset pin is active, the output is held to zero.
Using case statement:-
module dff(d, clock, reset, q, qb);
input d, clock, reset;
output reg q, qb; //output must be reg type when used in always block
always@(posedge clock) //no need reset and d
Mohd Uzir Kamaluddin Verilog-2nd ed. [10]
begin
case({reset,d})
2'b00 : q = 1'b0; //reset=0, d=0, q=0
2'b01 : q = 1'b1; //reset=0, d=1, q=1
default: q = 1'b0; //otherwise q=0 because reset=1
endcase
qb <= ~q; //assign qb
end
endmodule
Using if-else statement:-
module dff (clk, rstn, d, q);
input clk, rst, d;
output reg q;
always @ (posedge clk)
begin
if (! rst)
q <= 0;
else
q <= d;
end
endmodule
T-FF: (Behavioural Level)
If the T input is high, the T flip-flop changes state (“toggles”) whenever the clock input is strobed. If the T input is
low, the flip-flop holds the previous value.
Using case statement:-
module tff(t, clock, reset, q, qb);
input t, clock, reset;
output reg q, qb;
always@(posedge clock) //no need reset and t
begin
case({reset, t})
2'b00 : q = q; //reset=0, t=0, q maintain its previous value (no change)
2'b01 : q = ~q; //reset=0, t=1, q is toggled
default: q = 1'b0; //otherwise q=0 since reset=1
endcase
qb <= ~q; //assign qb
end
endmodule
Using if-else statement:-
module t_flipflop ( t ,clk ,reset , q );
output reg q ;
input t, clk, reset ;
initial q = 0;
always @ (posedge (clk))
begin
if (reset) //flipflop is reset (reset=1), output q=0 no matter what is input t
Mohd Uzir Kamaluddin Verilog-2nd ed. [11]
q <= 0;
else begin
if (t) //flipflop is not reset (reset=0), and input t=1
q <= ~q;
end
end
endmodule
JK-FF: (Behavioural Level)
The JK flip-flop augments the behavior of the SR flip-flop (J=Set, K=Reset) by interpreting the S = R = 1 condition as a
“flip” or toggle command. Specifically, the combination J = 1, K = 0 is a command to set the flip-flop; the
combination J = 0, K = 1 is a command to reset the flip-flop; and the combination J = K = 1 is a command to toggle
the flip-flop.
Using case statement:-
module jkff(j, k, clock, reset, q, qb);
input j, k, clock, reset;
output reg q, qb;
always@(posedge clock) //no need reset, j and k.
// But if reset does not work, may need to include reset here
begin
case({reset, j, k})
3'b100 : q=q; //reset=1, j=0, k=0, q hold its previous value
3'b101 : q=0; //reset=1, j=0, k=1, q=0
3'b110 : q=1; //reset=1, j=1, k=0, q=1
3'b111 : q=~q; //reset=1, j=1, k=1, q toggles
default : q=0; //otherwise q=0 since reset=0,
endcase
qb<=~q; //assign qb
end
endmodule
Using if-else statement:-
module JK_flipflop ( j ,k ,clk ,reset ,q ,qb );
output reg q, qb;
input j, k, clk, reset;
always @ (posedge (clk))
begin
if (reset) begin
q <= 0; //flipflop is reset (reset=1), q=0
qb <= 1;
end
else begin
if (j!=k) begin //flipflop is not reset (reset=0)
q <= j;
qb <= k;
end
else if (j==1 && k==1) begin
q <= ~q;
qb <= ~qb;
Mohd Uzir Kamaluddin Verilog-2nd ed. [12]
end
end
end
endmodule
SR-FF: (Behavioural Level)
The SR flip-flop is similar in operation with the JK flip-flop except that in SR flip-flop the S=R=1 is not allowed, thus
its output when that condition occurs is equated to Don’t Care (x). Can also be equated to High Impedance (z).
Using case statement:-
module SR_flipflop(q, qb, r, s, clk);
output reg q, qb;
input r, s, clk;
initial //Initial Block is used to set the values of q and qb initially because then these values
//will be used as feedback in the always block. Initial Block is executed only once in the code.
begin
q=1'b0;
qb=1'b1; // q is set to 0 and q1 is set to 1.
end
always @(posedge clk)
begin
case({s,r})
2'b00: begin q=q; qb=qb; end
2'b01: begin q=1'b0; qb=1'b1; end
2'b10: begin q=1'b1; qb=1'b0; end
2'b11: begin q=1'bx; q=1'bx; end
endcase
end
endmodule
Using if-else statement:-
module sr_flip_flop ( s ,r ,clk ,reset ,q ,qb );
output reg q, qb ;
input s, r, clk, reset ;
always @ (posedge (clk)) begin
if (reset) begin
q <= 0;
qb <= 1;
end
else begin
if (s!=r) begin
q <= s;
qb <= r;
end
else if (s==1 && r==1) begin
q <= 1'bx;
qb <= 1'bx;
end
end
Mohd Uzir Kamaluddin Verilog-2nd ed. [13]
end
endmodule
Counters
A counter circuit is usually constructed of a number of flip-flops connected in cascade. Counters are a very widely
used component in digital many circuits. There are two types of counter circuit, the asynchronous and
synchronous counter.
The figure below shows the circuit diagram of 3-bit asynchronous counting-down counter using JK flip flops.
Verilog Code for 3-bit Asynchronous DOWN counter using JK-FF (Structural Level):
//******JK Flip Flop******************************************
module jkff(j, k, clock, reset, q, qb);
input j, k, clock, reset;
output reg q, qb;
always@(posedge clock, reset) //Need to include reset here,
//if not simulation does not work
begin
case({reset, j, k})
3'b100 : q=q; //reset=1, j=0, k=0, q hold its previous value
3'b101 : q=0; //reset=1, j=0, k=1, q=0
3'b110 : q=1; //reset=1, j=1, k=0, q=1
3'b111 : q=~q; //reset=1, j=1, k=1, q toggles
default : q=0; //otherwise q=0 since reset=0,
endcase
qb<=~q; //assign qb
end
endmodule
//*********************Down Counter*********************************
module ripple_count(j, k, clock, reset, q0, q1, q2,);
input j, k, clock, reset;
output q0,q1,q2;
jkff FF0(.j(j), .k(k), .clock(clock), .reset(reset), .q(q0));
jkff FF1(.j(j), .k(k), .clock(q0), .reset(reset), .q(q1));
jkff FF2(.j(j), .k(k), .clock(q1), .reset(reset), .q(q2));
endmodule
//****Testbench for the 3-bit asynchronous down counter*********
module ripple4tb;
reg j, k, clock, reset; // Inputs
wire q0, q1, q2; // Outputs
Mohd Uzir Kamaluddin Verilog-2nd ed. [14]
// Instantiate the Unit Under Test (UUT)
ripple_count uut (.j(j), .k(k), .clock(clock), .reset(reset), .q0(q0), .q1(q1), .q2(q2));
//Create clock for the counter.
initial clock = 0; //set clock to 0 initially
always #1 clock = ~clock;
initial begin
$dumpfile("test1.vcd");
$dumpvars(0, ripple4tb); //for the gtkwave waveform viewer
//for the DOS tabular display
$monitor("t=%3d, j=%d, k=%d, reset=%d, q2q1q0=%b%b%b", $time, j, k, reset, q2, q1, q0);
// Initialize Inputs
j=0; k=0; reset=0; //counter output=000
//Apply inputs
#2; reset=1; j=1; k=1; //counter will count down
#15; reset=0; ; //counter reset to 000
#30 reset=1; //counter will count down
#50 $finish;
end
endmodule
Partial tabular output by $monitor()
t= 0, j=0, k=0, reset=0, q2q1q0=000
t= 2, j=1, k=1, reset=1, q2q1q0=001
t= 3, j=1, k=1, reset=1, q2q1q0=000
t= 5, j=1, k=1, reset=1, q2q1q0=111
t= 7, j=1, k=1, reset=1, q2q1q0=110
t= 9, j=1, k=1, reset=1, q2q1q0=101
t= 11, j=1, k=1, reset=1, q2q1q0=100
t= 13, j=1, k=1, reset=1, q2q1q0=011
t= 15, j=1, k=1, reset=1, q2q1q0=010
t= 17, j=1, k=1, reset=0, q2q1q0=000
t= 47, j=1, k=1, reset=1, q2q1q0=001
t= 49, j=1, k=1, reset=1, q2q1q0=000
t= 51, j=1, k=1, reset=1, q2q1q0=111
t= 53, j=1, k=1, reset=1, q2q1q0=110
t= 55, j=1, k=1, reset=1, q2q1q0=101
t= 57, j=1, k=1, reset=1, q2q1q0=100
t= 59, j=1, k=1, reset=1, q2q1q0=011
t= 61, j=1, k=1, reset=1, q2q1q0=010
t= 63, j=1, k=1, reset=1, q2q1q0=001
t= 65, j=1, k=1, reset=1, q2q1q0=000
t= 67, j=1, k=1, reset=1, q2q1q0=111
t= 69, j=1, k=1, reset=1, q2q1q0=110
t= 71, j=1, k=1, reset=1, q2q1q0=101
t= 73, j=1, k=1, reset=1, q2q1q0=100
Mohd Uzir Kamaluddin Verilog-2nd ed. [15]
Graphical output using GTKwave (file test1.vcd)
Circuit diagram of a 4-bit Synchronous up counter using T-Flip Flops
This counter is designed to count up from 0000 to 1111 with output Q3 as MSB.
//***************************T flip flop********************************
module tff(t, clock, reset, q);
input t, clock, reset;
output reg q;
always@(negedge clock, reset)
begin
case({reset,t})
2'b00 :q=q;
2'b01 :q=~q;
default: q=0; //reset=1
endcase
end
endmodule
//******************Synchronous up counter******************************
module upcount(t, clock, reset, q);
input t, clock, reset;
output [3:0]q; //output is 4 bit wide (important)
wire x1, x2;
tff T0(.t(t), .clock(clock), .reset(reset), .q(q[0]));
tff T1(.t(q[0]), .clock(clock), .reset(reset), .q(q[1]));
and (x1, q[0], q[1]);
tff T2(.t(x1), .clock(clock), .reset(reset), .q(q[2]));
and (x2, q[2], x1);
tff T3(.t(x2), .clock(clock), .reset(reset), .q(q[3]));
endmodule
Mohd Uzir Kamaluddin Verilog-2nd ed. [16]
//**************Testbench for the 4-bit synchronous up counter***************
module syn4tb;
reg t, clock, reset; // Inputs
wire [3:0]q; // Outputs
// Instantiate the Unit Under Test (UUT)
upcount uut (.t(t), .clock(clock),.reset(reset), .q(q));
//Create clock for the counter.
initial clock = 0; //set clock to 0 initially
always #1 clock = ~clock;
initial begin
$dumpfile("testsyn.vcd"); //for the gtkwave waveform viewer
$dumpvars(0);
//for the DOS tabular display
$monitor("t=%3d, reset=%b, t=%b, Output = %b%b%b%b", $time, reset, t, q[3], q[2], q[1], q[0]);
//Apply t and reset inputs
t=0; reset=1;
#5 t=0; reset=0;
#10 t=1;
#40 reset=1;
#45 reset=0;
#60 $finish;
end
endmodule
Partial output ($monitor)
t= 0, reset=1, t=0, Output = 0000
t= 5, reset=0, t=0, Output = 0000
t= 15, reset=0, t=1, Output = 0000
t= 16, reset=0, t=1, Output = 0001
t= 18, reset=0, t=1, Output = 0010
t= 20, reset=0, t=1, Output = 0011
t= 22, reset=0, t=1, Output = 0100
t= 24, reset=0, t=1, Output = 0101
t= 26, reset=0, t=1, Output = 0110
t= 28, reset=0, t=1, Output = 0111
t= 30, reset=0, t=1, Output = 1000
t= 32, reset=0, t=1, Output = 1001
t= 34, reset=0, t=1, Output = 1010
t= 36, reset=0, t=1, Output = 1011
t= 38, reset=0, t=1, Output = 1100
t= 40, reset=0, t=1, Output = 1101
t= 42, reset=0, t=1, Output = 1110
t= 44, reset=0, t=1, Output = 1111
t= 46, reset=0, t=1, Output = 0000
t= 48, reset=0, t=1, Output = 0001
t= 50, reset=0, t=1, Output = 0010
t= 52, reset=0, t=1, Output = 0011
Mohd Uzir Kamaluddin Verilog-2nd ed. [17]
t= 54, reset=0, t=1, Output = 0100
t= 55, reset=1, t=1, Output = 0000
t=100, reset=0, t=1, Output = 0001
t=102, reset=0, t=1, Output = 0010
t=104, reset=0, t=1, Output = 0011
t=106, reset=0, t=1, Output = 0100
t=108, reset=0, t=1, Output = 0101
Output obtained using GTKwave(file testsyn.vcd)
Synchronous counter that counts 1,2,3,5,7…..
module JK_FF (j,k,clk,reset,q,qb);
output reg q, qb;
input j, k, clk, reset;
always @ (posedge clk)
begin
if (reset) begin
q <= 0; //flipflop is reset (reset=1)
qb <= 1;
end
else begin
if (j!=k) begin //flipflop is not reset (reset=0)
q <= j;
qb <= k;
end
else if (j==1 && k==1) begin
q <= ~q;
qb <= ~qb;
Mohd Uzir Kamaluddin Verilog-2nd ed. [18]
end
end
end
endmodule
//*****Counter counting 1,2,3,5,7...**********
module counter1(clock, reset, q, qb);
input clock, reset;
output [0:2]q, qb; //3bits wide (must declare output like this)
wire ja, jc;
and a1(ja, q[1], q[2]);
JK_FF jk0(.j(ja), .k(q[1]), .clk(clock), .reset(reset), .q(q[0]), .qb(qb[0]));
JK_FF jk1(.j(1'b1), .k(q[2]), .clk(clock), .reset(reset), .q(q[1]), .qb(qb[1]));
and a2(jc, qb[0], qb[1]);
JK_FF jk2(.j(1'b1), .k(jc), .clk(clock), .reset(reset), .q(q[2]), .qb(qb[2]));
endmodule
//*********Testbench***********************
module testcount;
reg clock, reset;
wire [0:2]q, qb;
counter1 uut(.clock(clock), .reset(reset), .q(q), .qb(qb));
initial clock=0;
always #1 clock=~clock;
initial begin
$monitor("Output=%b%b%b", q[0], q[1], q[2]);
reset=1;
#10 reset=0;
#100 $finish;
end
endmodule
Partial output
Output=xxx
Output=000
Output=011
Output=101
Output=111
Output=001
Output=010
Output=011
Output=101
Output=111
Output=001
Output=010
Output=011
Output=101
Output=111
Output=001
Output=010
Output=011