Digital Design Lab Manual: Introduction To Verilog
Digital Design Lab Manual: Introduction To Verilog
Introduction to Verilog
This document uses short examples to demonstrate the basic Verilog syntax, time delays, and concurrent execution features. We have tried to condense all the interesting and hard parts of Verilog into 15 pages and skip all of the boring stuff like the what is the difference between real and integer data types. Studying this document will enable you to model circuits using simple structural and behavioral Verilog code and provide a solid framework for learning all the details of the language. If Verilog is a new language for you we recommend getting a copy of "Verilog HDL" by Samir Plantikar. It is a well organized Verilog textbook that is filled with lots of examples. Why Use Verilog Most Verilog and VHDL books begin with several chapters describing the language's history and advantages. But the arguments boil down to these:
HDL simulators are better then gate level simulators for 2 reasons: portable model development, and the ability to design complicated test benches that react to outputs from the model under test. Finding a model for a unique component for your particular gate level simulator can be a frustrating task, with an HDL language you can always write your own model. Also most gate level simulators are limited to simple waveform based test benches which complicates the testing of bus and microprocessor interface circuits. Verilog is a great low level language. Structural models are easy to design and Behavioral RTL code is pretty good. The syntax is regular and easy to remember. It is the fastest HDL language to learn and use. However Verilog lacks user defined data types and lacks the interface-object separation of the VHDL's entityarchitecture model. VHDL is good for designing behavioral models and incorporates some of the modern object oriented techniques. It's syntax is strange and irregular, and the language is difficult to use. Structural models require a lot of code that interferes with the readability of the model. C++as an hardware modeling language is excellent choice for high-level behavioral analysis of a system (like evaluating different data flow architectures in a microprocessor). However C++ lacks the basic hardware concepts like knowledge of strengths, connections, and concurrent execution which complicates model generation for lower level simulations.
Verilog Structure
Verilog differs from regular programming languages (C, Pascal, ...) in 3 main aspects: (1) simulation time concept, (2) multiple threads, and (3) some basic circuit concepts like network connections and primitive gates. If you know how to program in C and you understand basic digital design then learning Verilog will be easy.
Modules
In Verilog, circuit components are designed inside a module. Modules can contain both structural and behavioral statements. Structural statements represent circuit components like logic gates, counters, and microprocessors. Behavioral level statements are programming statements that have no direct mapping to circuit components like loops, ifthen statements, and stimulus vectors which are used to exercise a circuit. A module starts with the keyword module followed by an optional module name and an optional port list. The key word endmodule ends a module.
`timescale 1ns / 1ps //create a NAND gate out of an AND and an Invertor module some_logic_component (c, a, b); // declare port signals output c; input a, b; // declare internal wire wire d; //instantiate structural logic gates and a1(d, a, b); //d is output, a and b are inputs not n1(c, d); //c is output, d is input endmodule
Structural Design with Gate Primitives and the Delay operator Verilog defines some basic logic gates as part of the language. The module some_logic_component instantiates two gate primitives: the not gate and the and gate. The output of the gate is the first parameter, and the inputs are the rest of the parameters. These primitives are scalable so you can get multiple input gates just by adding inputs into the parameter list. For example:
nand a1(out1, in1, in2); //2-input NAND gate nand a2(out1, in1, in2, in3, in4, in5); //5-input NAND gate notif0 #(10,11,27) inv2(c,d,control) //rise=10, fall=11, off=27(not if
Here is a list of logic primitives defined for Verilog: Gate Parameter List Examples and a1(C,A,B);nand na1(out1,in1,in2,in3,in4);nor #(5) n1(D,A,B);//delay = 5 time unitsxor #(3,4,5) x1(E,A,B);//rise,fall,off delaysnor #(3:4:5) n2(F,A,B);//min:typ:max of delays not inv1(c,a);
scalable, requires at nand nor and least 2 inputs(output, or xor xnor input1, input2, , inputx) not buf notif0bufif0 (output, input)
control signal active low(output, input, notif0 inv2(c,a, control); control) control signal active high(output, input, not inv1(c,a, control); control)
notif1bufif1
Structural Design with Assignment Statements If you have a lot of random logic, the gate primitives of the previous section are tedious to use because all the internal wires must be declared and hooked up correctly. Sometimes it is easier to just describe a circuit using a single Boolean equation. In Verilog, Boolean equations which have similar timing properties as the gate primitives are defined using a continuous assignment statement. For example
wire d; and a1(d, a, b);
Behavioral Design with Initial and Always blocks Behavioral code is used to describe circuits at a more abstract level then the structural level statements we have studied. All Behavioral code occurs within either an initial block or in an always block. A module can contain several initial and always blocks. These behavioral blocks contain statements that control simulation time, data flow statements (like if-then and case statements), and blocking and non-blocking statements. An initial block executes once during a simulation. Initial blocks are usually used to initialize variables and to describe stimulus waveforms which exercise which drive the simulation. An always block continuously repeats its execution during a simulation. Always blocks usually contain behavioral code that models the actual circuit operation. During a simulation each always and each initial block begin to execute at time zero. Each block executes concurrently with each structural statement and all the other behavioral blocks. The following example shows a behavioral SRAM model. The initial block sets the memory cells to zero at startup. The always block executes each time there is a change on the write control line, the chip select line, or the address bus. As an exercise, copy and paste this code into a verilog file and write a test bench to exercise the model.
//SRAM Model module sram(CSB,WRB,ABUS,DATABUS); input CSB; // active low chip select input WRB; // active low write control input [11:0] ABUS; // 12-bit address bus inout [7:0] DATABUS; // 8-bit data bus //** internal signals reg [7:0] DATABUS_driver; wire [7:0] DATABUS = DATABUS_driver; reg [7:0] ram[0:4095]; // memory cells integer i; initial //initialize all RAM cells to 0 at startup begin DATABUS_driver = 8'bzzzzzzzz; for (i=0; i < 4095; i = i + 1) ram[i] = 0; end
3.3 Number Syntax Numbers in verilog are in the following format The size is always specified as a decimal number. If no is specified then the default size is at least 32bits and may be larger depending on the machine. Valid base formats are 'b , 'B , 'h , 'H 'd , 'D , 'o , 'O for binary, hexadecimal, decimal, and octal. Numbers consist Dept Of ISE, PESIT 6
3.6 Arrays, Vectors, and Memories Verilog supports three similar data structures called Arrays, Vectors, and Memories. Arrays are used to hold several objects of the same type. Vectors are used to represent multi-bit busses. And Memories are arrays of vectors which are accessed similar to hardware memories. Read the following examples to determine how to reference and use the different data structures.
//*** Arrays for integer, time, reg, and vectors of reg *************** integer i[3:0]; //integer array with a length of 4 time x[20:1]; //time array with length of 19 reg r[7:0]; //scalar reg array with length of 8 c = r[3]; //the 3rd reg value in array r is assigned to c //*** Vectors are multi-bit words of type reg or net (wire)************ reg [7:0] MultiBitWord1; // 8-bit reg vector with MSB=7 LSB=0 wire [0:7] MultiBitWord2; // 8-bit wire vector with MSB=0 LSB=7 reg [3:0] bitslice; reg a; // single bit vector often referred to as a scalar .... //referencing vectors a = MultiBitWord1[3]; //applies the 3rd bit of MultiBitWord1 to a bitslice = MultiBitWord1[3:0]; //applies the 3-0 bits of MultiBitWord1 to bitslice //*** Memories are arrays of vector reg ******************************** reg [7:0] ram[0:4095]; // 4096 memory cells that are 8 bits wide //code excerpt from Chapter 2 SRAM model input [11:0] ABUS; // 12-bit address bus to access all 4096 memory cells inout [7:0] DATABUS; // 8-bit data bus to wite into and out of a memory cell reg [7:0] DATABUS_driver; wire [7:0] DATABUS = DATABUS_driver; //inout must be driven by a wire for (i=0; i < 4095; i = i + 1) // Setting individual memory cells to 0 ram[i] = 0;
Operators Here is a small selection of the Verilog Operators which look similar but have different effects. Logical Operators evaluate to TRUE or FALSE. Bitwise operators act on each bit of the operands to produce a multi-bit result. Unary Reduction operators perform the operation on all bits of the operand to produce a single bit result. Operator Name ! ~ && & & ~& || | | ~| ^ ^ ~^ ^~ ~^ ^~ == === != !== logical negation bitwise negation logical and bitwise and reduction and reduction nand logical or bitwise or reduction or reduction nor bitwise xor reduction xor bitwise xnor reduction xnor logical equality, result may be unknown if x or z in the if (a == b) input logical equality including x and z logical inequality, result may be unknown if x or z in the input logical inequality including x and z abus = bbus&cbus; abit = &bbus; Examples
10
7.
Click Next, then Finish in the New Source Information dialog box to complete the new source file template. 8. Click Next, then Next, then Finish. When you choose the counter.v tab you will see the outline of a Verilog module. Notice that it looks somewhat different than the examples in the textbook. Both methods of listing inputs and outputs are correct! Now fill in the code for the counter as shown below you wont recognize all the commands but for this tutorial just copy what is shown below. module counter(CLOCK, DIRECTION, COUNT_OUT); input CLOCK; input DIRECTION; output [3:0] COUNT_OUT; reg [3:0] count_int = 0; always @(posedge CLOCK) if (DIRECTION) count_int <= count_int + 1; else count_int <= count_int - 1; assign COUNT_OUT = count_int; endmodule
11
When the source files are complete save the file and check the syntax of the design to find errors and typos. 1. Verify that Synthesis/Implementation is selected from the drop-down list in the Sources window. 2. Select the counter design source in the Sources window to display the related processes in the Processes window. 3. Click the + next to the Synthesize-XST process to expand the process group. 4. Double-click the Check Syntax process. Note: You must correct any errors found in your source files. You can check for errors in the Console tab of the Transcript window. If you continue without valid syntax, you will not be able to simulate your design. Create a test bench waveform containing input stimulus you can use to verify the functionality of the counter module. The test bench waveform is a graphical view of a test bench. Create the test bench waveform as follows: 1. Select the counter HDL file in the Sources window. 2. Create a new test bench source by selecting Project New Source. 3. In the New Source Wizard, select Test Bench WaveForm as the source type, and type counter_tbw in the File Name field. 4. Click Next. 5. The Associated Source page shows that you are associating the test bench waveform with the source file counter. Click Next. 6. The Summary page shows that the source will be added to the project, and it displays the source directory, type and name. Click Finish. 7. You need to set the clock frequency, setup time and output delay times in the Initialize Timing dialog box before the test bench waveform editing window opens. The requirements for this design are the following: The counter must operate correctly with an input clock frequency = 25 MHz. The DIRECTION input will be valid 10 ns before the rising edge of CLOCK. The output (COUNT_OUT) must be valid 10 ns after the rising edge of CLOCK. The design requirements correspond with the values below. Fill in the fields in the Initialize Timing dialog box with the following information: Clock High Time: 20 ns. Clock Low Time: 20 ns. Input Setup Time: 10 ns. Output Valid Delay: 10 ns.
12
8. Click Finish to complete the timing initialization. 9. The blue shaded areas that precede the rising edge of the CLOCK correspond to the Input Setup Time in the Initialize Timing dialog box. Toggle the DIRECTION port to define the input stimulus for the counter design as follows: Click on the blue cell at approximately the 300 ns to assert DIRECTION high so that the counter will count up. Click on the blue cell at approximately the 900 ns to assert DIRECTION low so that the counter will count down.
13
waveform. 11. In the Sources window, select the Behavioral Simulation view to see that the test bench waveform file is automatically added to your project. Verify that the counter design functions as you expect by performing behavior simulation as follows: 1. Verify that Behavioral Simulation and counter_tbw are selected in the Sources window. 2. In the Processes tab, click the + to expand the Xilinx ISE Simulator process and double-click the Simulate Behavioral Model process. The ISE Simulator opens and runs the simulation to the end of the test bench. 3. To view your simulation results, select the Simulation tab and zoom in on the transitions. Note: by selecting COUNT_OUT and right-clicking you can change the hex version to decimal. You can expand COUNT_OUT to see the individual counter bits.
14
15
Verilog Code Verilog code for AND GATE module and12(a,b,c); input a; input b; output c; assign c = a & b; endmodule Verilog code for NAND GATE module nand12(a,b,e); input a; input b; output e; assign e = ~(a & b); endmodule Verilog code for XNOR GATE module xnor12(a,b,i); input a; input b; output i; assign i = ~(a ^ b); endmodule Verilog code for NOT GATE module not12(a,g); input a; output g; assign g = ~a;
Verilog code for OR GATE module or12(a,b,d); input a; input b; output d; assign d = a | b; endmodule Verilog code for XOR GATE module xor12(a,b,h); input a; input b; output h; assign h = a ^ b; endmodule Verilog code for NOR GATE module nor12(a,b,f); input a; input b; output f; assign f = ~(a | b); endmodule
16
Circuit Diagram
Equations S (Sum) =A^B C (Carry) =AB Verilog code for Half adder module hadd(a,b,s,c); input a; input b; output s; output c; assign s = a ^ b; assign c = a & b; endmodule B)Full Adder Truth Table
Input A 0 0 0 0 1 1 1 B 0 0 1 1 0 0 1 C 0 1 0 1 0 1 0 Output SUM 0 1 1 0 1 0 0 Cout 0 0 0 1 0 1 1
17
Circuit Diagram
Verilog code for Full adder module fadd(a,b,c,s,cout); input a; input b; input i; output s; output cout; assign s = (a ^ b) ^ c; assign cout = (a & b)|( b & c)|(c & a); endmodule C) Full Adder Using Two Half Adders and one OR gate Circuit Diagram
18
Verilog code for Full adder using half adder module fadd(a,b,ci,s,co); input a; input b; output s; output cout; wire c1,c2,s1 HA 1(s1,c1,a,b); HA 2(s,cout,c1,s1) endmodule module HA(s,c,a,b); input a,b; output s,c; s=a^b; c=ab; endmodule
19
20
module mux4to1(Y, I0,I1,I2,I3, sel); output Y; input I0,I1,I2,I3; input [1:0] sel; reg Y; always @ (sel or I0 or I1 or I2 or I3) case (sel) 2'b00:Y=I0; 2'b01:Y=I1; 2'b10: Y=I2; 2'b11: Y=I3; default: Y=2b00; endcase endmodule B)1:4 Demultiplexer
Function table Data Input D 1 1 1 1 Selection Input S1 S0 0 0 0 1 1 0 1 1 Output Y3 0 0 0 1 Y2 0 0 1 0 Y1 0 1 0 0 Y0 1 0 0 0
21
Verilog code for 1 to 4 demultiplexer module demux(S,D,Y); Input [1:0] S; Input D; Output [3:0] Y; reg Y; always @(S OR D) case({D,S}) 3b100:Y=4b0001; 3b101:Y=4b0010; 3b110:Y=4b0100; 3b111:Y=4b1000; default:Y=4b0000; endcase endmodule
22
23
enable 0 1 1 1 1 1 1 1 1
I7 x 0 0 0 0 0 0 0 1
I6 x 0 0 0 0 0 0 1 0
I5 x 0 0 0 0 0 1 0 0
I4 x 0 0 0 0 1 0 0 0
I2 x 0 0 1 0 0 0 0 0
I1 x 0 1 0 0 0 0 0 0
I0 x 1 0 0 0 0 0 0 0
Y2 0 0 0 0 0 1 1 1 1
Y1 0 0 0 1 1 0 0 1 1
Y0 0 0 1 0 1 0 1 0 1
Y0 = I1 + I3 + I5 + I7 Y1= I2 + I3 + I6 + I7 Y2 = I4 + I5 + I6 +I7 Block Diagram8:3 line encoder(Octal-Binary Conversion) Z7 Z6 Z5 Z4 Z3 Z2 Z1 Dept Of ISE, PESIT Z0 Enable 8 to 3 line decoder A0 A1 A2
24
Verilog Code for Encoder module encodeR(I0,I1,I2,I3,Y0,Y1,Y3); input I0,I1,I2,I3; output Y0,Y1,Y3; wire Y0,Y1,Y3;
25
Verilog Code priority encoder module encodeR(D0,D1,D2,D3,Y0,Y1,V3); input I0,I1,I2,I3; output Y0,Y1,Y3; wire Y0,Y1,V; Y0=D3|D1|~D2 Y1=D2|D3 V=D0|D1|D2|D3 endmodule
26
Circuit Diagram
27
28
Circuit Diagram
Verilog code(Abstract level) module compare(A,B,y); input [3:0] A,B; output [2:0] y; reg y; always @(A or B) if(A==B) y=3b001; else if(A<B) y=3b010; else y=3b100;
29
30
Graphical Notation
Input CP 0
Verilog code for JK flip flop module jkff(jk,pst,clr,clk,qp,qbar); input [1:0] jk; input pst,clr,clk; output qp,qbar; reg qp; wire q; always @ (posedge clk) if (pst) qp= 1; else begin if (clr) qp= 0; else begin case (jk) 2'b00: qp=q;
31
Graphical Notation
Verilog code for D flip flop: module dff(d,clk,q,qbar); input d; input clk; output q,qbar; reg q, qbar; always @ (posedge clk) begin q = d; qbar = ~d; Dept Of ISE, PESIT 32
Graphical Notation
Characteristic Table Input T x 0 1 Characteristic Equation Q(t+1)=TQ(t)+TQ(t) Clock Input CP 0/1 Next State Q(t+1) No Change Q(t) Q(t)
Verilog code for T flip flop: module tffeq(t,rst, clk,qp, qbar); input t,rst, clk; output qp, qbar; wire q; reg qp; always @ (posedge clk) if (rst) qp=0; else qp = q ^ t; assign qbar = ~ qp; endmodule
33
Verilog Code for Ripple Counter module ripple(clkr,st,,t,A,B,C,D); input clk,rst,t; output A,B,C,D; Tff T0(D,clk,rst,t); Tff T1(C,clk,rst,t); Tff T2(B,clk,rst,t); Tff T3(A,clk,rst,t); endmodule module Tff(q,clk,rst,t); input clk,rst,t; output q; reg q; always @(posedge clk) begin if(rst) q<=1b0; else if(t)
34
35
Verilog code for up-down counter module updowncount (R, Clock, clr, E, up_down, Q); parameter n = 4; input [n-1:0] R; input Clock, clr, E, up_down; output [n-1:0] Q; reg [n-1:0] Q; integer direction; always @(posedge Clock) begin if (up_down) direction = 1; else direction = -1; if (clr) Q <= R; else if (E) Q <= Q + direction; end endmodule
36
Count Table
clk Qa 1 2 3 4 1 0 0 0
Qb 0 1 0 0
Qc 0 0 1 0
Qd 0 0 0 1
module ring_count (Resetn, Clock, Q); parameter n = 5; input Resetn, Clock; output [n-1:0] Q;
37
outputs
Vcc 14 QA 13 QB 12 QC 11 QD 10 CLK1 9 8
74LS95
2 A
3 B
4 C
5 D
A1A
Count Table
38
Verilog code
module stc(clk,clr,q,r,s,t); input clk,clr; output q,r,s,t; reg q,r,s,t; always@(negedge clk) begin if(~clr) begin q=1'b0; end else begin q<=~t; r<=q; s<=r; t<=s; end end endmodule
39
Verilog Code for serial adder module serial_adder(a,c,clk,rst,pl,si,sr,qout,p0); input clk,rst,si,sr,pl; output qout; output [3:0] p0; reg [3:0] sra; reg [3:0] srb; input [3:0] a; input [3:0] b; reg p0; wire s,c; FA f1(sra[0].srb[0],qout,s,c); always @ (posedge clk) begin if(rst) begin sra=4b0000; srb=4b0000; qout=0; p0=4b0000; end else if(pl) begin sra=a;
40
41
Function Diagram
42
Notes H = HIGH voltage level h = HIGH voltage level one set-up time prior to the LOW-to-HIGH CP transition L = LOW voltage level I = LOW voltage level one set-up time prior to the LOW-to-HIGH CP transition q,d = lower case letters indicate the state of the referenced input (or output) one set-up time prior to the LOW-to-HIGH CP transition X = dont care = LOW-to-HIGH CP transition
Verilog Code module uni_shift(out,l0,r0,in,li,ri,s,clr,clk); output [3:0] out; output l0,r0; input [3:0] in; intput [1:0] s; input li,ri,clr,clk; reg out; assign l0=out[3]; assign r0=out[0]; always @ (posedge clk) begin if(clr) out<=0; else case(s) 3:out<=in; 2:out<={out[2:0],ri}; 1:out<={li,out[3:1]}; 0:out<=out; endcase end endmodule
43
Block Diagrm
Binary Multiplication
44
The data path for the sequential multiplier is consists of several registers and an adder. The required registers include: B-Register: A 4-bit register which holds the multiplicand (B) P-Register: An 8-bit register which consists of two 4-bit registers PL (P-Low) and PH (P-High). o Initially the multiplier (A) is loaded in PL, while PH is cleared o The final result (product) is stored in P = (PH, PL). E-Register: A 1-bit register, that is used to hold the carryout output of the adder o Initially E is cleared th o It may be considered the 9 Bit of P, i.e. P8. o In the final step, E will hold a 0 value. Cnt: A 2-bit down counter used to control the number of steps to be performed (total of 4 steps). The counter counts from 3 down to 0. The operation is stopped when the count reaches 0. This zero condition (Zero) is detected by a NOR gate Notation: (E, PH) refers to the 5-bit register consisting of E as the MSB and PH. (E, PH, PL) refer to the 9-bit register consisting of E as the MSB, PH. and PL. Computation Steps: 1. Initialize: i=0, PH ? 0, PL ? A, B-Reg ? B, Cnt ? n-1, where n = number of Dept Of ISE, PESIT 45
Verilog code module mult(product,ready,multiplicand,multiplier,start,clock,reset_b); parameter dp_width=5; output [2*dp_width-1:0] product; output ready; input [dp_width-1:0] multiplicand,multiplier; input start, clock,reset_b; parameter bc_size=3; parameter s_Idle=3'b001; parameter s_add=3'b010; parameter s_shift=3'b100; reg [2:0] state,next_state; reg [dp_width-1:0] A,B,Q; reg c; reg [bc_size-1:0] p; reg load_regs,dec_p,add_regs,shift_regs; // miscellaneous combinational logic assign product={A,B}; wire zero=(p==0); //zero=~p; wire ready=(state==s_idle); // control unit
46
47
48