icarus verilog bleyer.org/icarus · mohd uzir kamaluddin verilog-2nd ed. [5] assignments within the...

18
Mohd Uzir Kamaluddin Verilog-2 nd 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 vvpcommand. 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) ~|

Upload: others

Post on 18-Apr-2020

4 views

Category:

Documents


0 download

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