Module 2
Contents:
⮚ BCD to 7-segment Display Decoder
⮚ BCD Adder
⮚ Traffic Light Controller
⮚ Synchronization and Debouncing
⮚ Shift-and-Add Multiplier
⮚ Array Multiplier
⮚ Keypad scanner
All Images and tables referred from:
Roth, C.H., John, L.K. and Lee, B.K., 2016. Digital systems design using Verilog.
Cengage Learning.
BCD TO 7-SEGMENT DISPLAY DECODER
Seven segment displays are often used to display digits in digital counters, watches, and clocks.
A digital watch displays time by turning on a combination of the segments on a 7-segment display.
Let us design a BCD to 7-segment display decoder. BCD stands for “binary coded decimal.” In
this format, each digit of a decimal number is encoded into 4-bit binary representation.
We will create a behavioral Verilog architectural description of this BCD to 7-segment decoder
by using a single process with a case statement to model this combinational circuit.
module bcd_seven (bcd, seven); input [3:0] bcd; output[7:1] seven;
reg [7:1] seven;
always @(bcd) begin
case (bcd)
4'b0000 : seven = 7'b0111111;
4'b0001 : seven = 7'b0000110;
4'b0010 : seven = 7'b1011011;
4'b0011 : seven = 7'b1001111;
4'b0100 : seven = 7'b1100110;
4'b0101 : seven = 7'b1101101;
4'b0110 : seven = 7'b1111101;
4'b0111 : seven = 7'b0000111;
4'b1000 : seven = 7'b1111111;
4'b1001 : seven = 7'b1101111;
default : seven = 7'b0000000;
endcase
end
endmodule
BCD ADDER
Here, we design a 2-digit BCD adder, which will add two BCD numbers and produce the sum in
BCD format. In BCD representation, each decimal digit is encoded into binary. For instance,
decimal number 97 will be represented as 1001 0111 in the BCD format, where the first 4 bits
represent digit 9 and the next 4 bits represent digit 7. When BCD numbers are added, each sum
digit should be adjusted to skip the six unused codes. For instance, if 6 is added with 8, the sum
is 14 in decimal form. A binary adder would yield 1110, but the lowest digit of the BCD sum should
read 4.
The input BCD numbers are represented by X and Y. The BCD sum of two 2-digit BCD numbers
can exceed two digits and hence three BCD digits are provided for the sum, which is represented
by Z. The compiler directive ‘define’ can be used to denote each digit of each BCD number. For
example, the upper digit of X can be denoted by Xdig1 by using the Verilog statement:
Verilog code for BCD adder:
`define Xdig1 X[7:4]
`define Xdig0 X[3:0]
`define Ydig1 Y[7:4]
`define Ydig0 Y[3:0]
`define Zdig2 Z[11:8]
`define Zdig1 Z[7:4]
`define Zdig0 Z[3:0]
module BCD_Adder (X, Y, Z);
input[7:0] X;
input[7:0] Y;
output[11:0] Z;
wire[4:0] S0;
wire[4:0] S1;
wire C;
assign S0 = `Xdig0 + `Ydig0 ;
assign `Zdig0 = (S0 > 9) ? S0[3:0] + 6 : S0[3:0] ;
assign C = (S0 > 9) ? 1'b1 : 1'b0 ;
assign S1 = `Xdig1 + `Ydig1 + C ;
assign `Zdig1 = (S1 > 9) ? S1[3:0] + 6 : S1[3:0] ;
assign `Zdig2 = (S1 > 9) ? 4'b0001 : 4'b0000 ;
endmodule
TRAFFIC LIGHT CONTROLLER
Methods used to realize SM charts are similar to the methods used to realize state graphs. As
with any sequential circuit, the realization will consist of a combinational subcircuit, together
with flip-flops for storing the state of the circuit. Before deriving next-state and output equations
from an SM chart, a state assignment must be made. The best way of making the assignment
depends on how the SM chart is realized.
The Verilog code for the traffic light controller represents the state machine with two always
statements. Whenever the state—Sa or Sb—changes, the first always statement updates the
outputs and nextstate. When the rising edge of the clock occurs, the second always statement
updates the state register. Since states S0 through S4 have the same outputs and the next states
are in numeric sequence, we use multiple case numbers together instead of five separate case
behaviors
Verilog code for traffic light controller:
module traffic_light (clk, Sa, Sb, Ra, Rb, Ga, Gb, Ya, Yb);
input clk;
input Sa;
input Sb;
inout Ra;
inout Rb;
inout Ga;
inout Gb;
inout Ya;
inout Yb;
reg Ra_tmp;
reg Rb_tmp;
reg Ga_tmp;
reg Gb_tmp;
reg Ya_tmp; reg Yb_tmp;
reg[3:0] state;
reg[3:0] nextstate;
parameter[1:0] R = 0;
parameter[1:0] Y = 1;
parameter[1:0] G = 2;
wire[1:0] lightA;
wire[1:0] lightB;
assign Ra = Ra_tmp;
assign Rb = Rb_tmp;
assign Ga = Ga_tmp;
assign Gb = Gb_tmp;
assign Ya = Ya_tmp;
assign Yb = Yb_tmp;
initial begin
state = 0;
end
always @(state or Sa or Sb) begin
Ra_tmp = 1'b0 ; Rb_tmp = 1'b0 ; Ga_tmp = 1'b0 ; Gb_tmp = 1'b0 ; Ya_tmp = 1'b0 ; Yb_tmp =
1'b0 ; nextstate = 0;
case (state)
0, 1, 2, 3, 4 :
begin
Ga_tmp = 1'b1 ;
Rb_tmp = 1'b1 ; nextstate = state + 1 ;
end
5:
begin
Ga_tmp = 1'b1 ; Rb_tmp = 1'b1 ; if (Sb == 1'b1)
begin
nextstate = 6 ;
end else begin
nextstate = 5 ;
end end
6:
begin
Ya_tmp = 1'b1 ; Rb_tmp = 1'b1 ; nextstate = 7 ;
end
11 :
begin
Ra_tmp = 1'b1 ; Gb_tmp = 1'b1 ;
if (Sa == 1'b1 | Sb == 1'b0)
begin
nextstate = 12 ;
end else begin
nextstate = 11 ;
end end
12 :
begin
Ra_tmp = 1'b1 ; Yb_tmp = 1'b1 ; nextstate = 0 ;
end endcase
end
always @(posedge clk)
begin
state <= nextstate ;
end
assign lightA = (Ra==1'b1) ? R : (Ya==1'b1) ? Y : (Ga==1'b1) ? G : lightA;
assign lightB = (Rb==1'b1) ? R : (Yb==1'b1) ? Y : (Gb==1'b1) ? G : lightB;
endmodule
SYNCHRONIZATION AND DEBOUNCING
The inc, dec, and rst signals to the scoreboard in the previous design are external inputs. An issue
in systems involving external inputs is synchronization. Outputs from a keypad or push button
switches are not synchronous to the system clock signal. Since they will be used as inputs to a
synchronous sequential circuit, they should be synchronized.
Debouncing Mechanical Switches:
Single Pulser:
One assumption in the scoreboard design is that each time the inc and dec signals are provided,
they last only for one clock cycle. Digital systems generally run at speeds higher than actions by
humans, and practically, it is very difficult for humans to produce a signal that lasts only for a
clock pulse.
SHIFT AND ADD MULTIPLIER
Here, we will design a multiplier for unsigned binary numbers. When we form the product A × B,
the first operand (A) is called the multiplicand and the second operand (B) is called the multiplier.
As illustrated here, binary multiplication requires only shifting and adding.
Note that each partial product is either the multiplicand (1101) shifted over by the appropriate
number of places or zero. Instead of forming all the partial products first and then adding, each
new partial product is added in as soon as it is formed, which eliminates the need for adding
more than two binary numbers at a time.
This type of multiplier is sometimes referred to as a serial-parallel multiplier, since the multiplier
bits are processed serially, but the addition takes place in parallel. As indicated by the arrows on
the diagram, 4 bits from the accumulator (ACC) and 4 bits from the multiplicand register are
connected to the adder inputs; the 4 sum bits and the carry output from the adder are connected
back to the accumulator.
Multiple control with counter:
ARRAY MULTIPLIER
An array multiplier is a parallel multiplier that generates the partial products in a parallel fashion.
The various partial products are added as soon as they are available. Consider the process of
multiplication. Two 4-bit unsigned numbers, X3X2X1X0 and Y3Y2Y1Y0, are multiplied to generate a
product that is possibly 8 bits.
4-bit multiplier partial products:
If an adder has three inputs, a full adder (FA) is used, but if an adder has only two inputs, a half-
adder (HA) is used. A half-adder is the same as a full adder with one of the inputs set to 0. This
multiplier requires 16 AND gates, 8 full adders, and 4 half-adders. After the X and Y inputs have
been applied, the carry must propagate along each row of cells, and the sum must propagate
from row to row.
Verilog code for 4x4 array multiplier:
module Array_Mult (X, Y, P);
input[3:0] X;
input[3:0] Y;
output[7:0] P;
wire[3:0] C1;
wire[3:0] C2;
wire[3:0] C3;
wire[3:0] S1;
wire[3:0] S2;
wire[3:0] S3;
wire[3:0] XY0;
wire[3:0] XY1;
wire[3:0] XY2;
wire[3:0] XY3;
assign XY0[0] = X[0] & Y[0] ;
assign XY1[0] = X[0] & Y[1] ;
assign XY0[1] = X[1] & Y[0] ;
assign XY1[1] = X[1] & Y[1] ;
assign XY0[2] = X[2] & Y[0] ;
assign XY1[2] = X[2] & Y[1] ;
assign XY0[3] = X[3] & Y[0] ;
assign XY1[3] = X[3] & Y[1] ;
assign XY2[0] = X[0] & Y[2] ;
assign XY3[0] = X[0] & Y[3] ;
assign XY2[1] = X[1] & Y[2] ;
assign XY3[1] = X[1] & Y[3] ;
assign XY2[2] = X[2] & Y[2] ;
assign XY3[2] = X[2] & Y[3] ;
assign XY2[3] = X[3] & Y[2] ;
assign XY3[3] = X[3] & Y[3] ;
FullAdder FA1 (XY0[2], XY1[1], C1[0], C1[1], S1[1]);
FullAdder FA2 (XY0[3], XY1[2], C1[1], C1[2], S1[2]);
FullAdder FA3 (S1[2], XY2[1], C2[0], C2[1], S2[1]);
FullAdder FA4 (S1[3], XY2[2], C2[1], C2[2], S2[2]);
FullAdder FA5 (C1[3], XY2[3], C2[2], C2[3], S2[3]);
FullAdder FA6 (S2[2], XY3[1], C3[0], C3[1], S3[1]);
FullAdder FA7 (S2[3], XY3[2], C3[1], C3[2], S3[2]);
FullAdder FA8 (C2[3], XY3[3], C3[2], C3[3], S3[3]);
HalfAdder HA1 (XY0[1], XY1[0], C1[0], S1[0]);
HalfAdder HA2 (XY1[3], C1[2], C1[3], S1[3]);
HalfAdder HA3 (S1[1], XY2[0], C2[0], S2[0]);
HalfAdder HA4 (S2[1], XY3[0], C3[0], S3[0]);
assign P[0] = XY0[0] ;
assign P[1] = S1[0] ;
assign P[2] = S2[0] ;
assign P[3] = S3[0] ;
assign P[4] = S3[1] ;
assign P[5] = S3[2] ;
assign P[6] = S3[3] ;
assign P[7] = C3[3] ;
endmodule
module FullAdder (X, Y, Cin, Cout, Sum);
input X;
input Y;
input Cin;
output Cout;
output Sum;
assign Sum = X ^ Y ^ Cin ;
assign Cout = (X & Y) | (X & Cin) | (Y & Cin) ;
endmodule
module HalfAdder (X, Y, Cout, Sum);
input X; input Y; output Cout; output Sum;
assign Sum = X ^ Y ;
assign Cout = X & Y ;
endmodule
KEYPAD SCANNER
The keypad is wired in matrix form with a switch at the intersection of each row and column.
Pressing a key establishes a connection between a row and column. The purpose of the scanner
is to determine which key has been pressed and to output a binary number N = N3N2N1N0, which
corresponds to the key number.
For example, pressing key 5 must output 0101, pressing the * key must output 1010, and pressing
the # key must output 1011. When a valid key has been detected, the scanner should output a
signal V for one clock time. The design must include hardware to protect the circuitry from
malfunction due to keypad bounces.
The keypad contains resistors that are connected to ground. When a switch is pressed, a path is
established from the corresponding column line to the ground. If a voltage can be applied on the
column lines C0, C1, and C2, then the voltage can be obtained on the row line corresponding to
the key that is pressed. One among the rows R0, R1, R2, or R 3 will have an active signal.
Block diagram for keypad scanner:
We will divide the design into several modules
Scanner:
The first part of the design will be a scanner that scans the rows and columns of the keypad.
Keyscan:
The keyscan module generates the column signals to scan the keyboard.
Debounce:
The debounce module generates a signal K when a key has been pressed and a signal Kd after it
has been debounced.
Decoder:
When a valid key is detected, the decoder determines the key number from the row and column
numbers.
Verilog code for scanner:
module scanner (R0, R1, R2, R3, CLK, C0, C1, C2, N0, N1, N2, N3, V);
input R0; input R1; input R2; input R3; input CLK; inout C0; inout C1; inout C2; output N0;
output N1; output N2; output N3; output V;
reg V;
reg C0_tmp, C1_tmp, C2_tmp;
reg QA; wire K; reg Kd;
reg[2:0] state; reg[2:0] nextstate;
assign C0 = C0_tmp;
assign C1 = C1_tmp;
assign C2 = C2_tmp;
assign K = R0 | R1 | R2 | R3 ;
assign N3 = (R2 & ~C0) | (R3 & ~C1) ;
assign N2 = R1 | (R2 & C0) ;
assign N1 = (R0 & ~C0) | (~R2 & C2) | (~R1 & ~R0 & C0) ;
assign N0 = (R1 & C1) | (~R1 & C2) | (~R3 & ~R1 & ~C1) ;
initial begin
state = 0; nextstate = 0;
end
always @(state or R0 or R1 or R2 or R3 or C0 or C1 or C2 or K or Kd or QA) begin
C0_tmp = 1'b0 ; C1_tmp = 1'b0 ; C2_tmp = 1'b0 ; V = 1'b0 ; case (state)
0:
begin
nextstate = 1 ;
end
1:
begin
C0_tmp = 1'b1 ; C1_tmp = 1'b1 ;
C2_tmp = 1'b1 ; if ((Kd & K) == 1'b1) begin
nextstate = 2 ;
end else begin
nextstate = 1 ;
end end
2:
begin
C0_tmp = 1'b1 ; if ((Kd & K) == 1'b1)
begin
V = 1'b1 ;
nextstate = 5 ;
end
else if (K == 1'b0)
begin
nextstate = 3 ;
end else begin
nextstate = 2 ;
end end
3:
begin
C1_tmp = 1'b1 ; if ((Kd & K) == 1'b1) begin
V = 1'b1 ; nextstate = 5 ;
end
else if (K == 1'b0)
begin
nextstate = 4 ;
end else begin
nextstate = 3 ;
end end
4:
begin
C2_tmp <= 1'b1 ; if ((Kd & K) == 1'b1) begin
V <= 1'b1 ; nextstate = 5 ;
end else begin
nextstate = 4 ;
end end
5:
begin
C0_tmp = 1'b1 ; C1_tmp = 1'b1 ; C2_tmp = 1'b1 ; if (Kd == 1'b0)
begin
nextstate = 1 ;
end else
begin
nextstate = 5 ;
end end
endcase end
always @(posedge CLK)
begin
state <= nextstate ; QA <= K ;
Kd <= QA ;
end
endmodule
Problems:
1. Design the correction circuit for a BCD adder that computes Zdigit 0 and C for S0. This
correction circuit adds 0110 to S0 if S0 > 9. This is the same as adding 0AA0 to S0, where
A = 1 if S0 > 9. Draw a block diagram for the correction circuit using one full adder, three
half adders, and a logic circuit to compute A. Design a circuit for A using a minimum
number of gates. Note that the maximum possible value of S0 is 10010.
Soln:
2. Write a Verilog module that describes one bit of a full adder with accumulator. The
module should have two control inputs, Ad and L. If Ad = 1, the Y input (and carry input)
are added to the accumulator. If L = 1, the Y input is loaded into the accumulator.
Soln:
module FA_ACC(L, Ad, CLK, Y, CI, Acc, CO);
input L, Ad, CLK, Y, CI;
inout Acc; output CO; reg tempAcc; wire S;
assign S = Acc ^ Y ^ CI;
assign CO = (Acc & Y) | (Acc & CI) | (Y & CI);
assign Acc = tempAcc;
initial begin
tempAcc <= 1'b0; end always @(posedge CLK) begin if(L == 1'b1) tempAcc <= Y; if(Ad == 1'b1)
tempAcc <= S;
end
endmodule
3. Make the necessary additions to the following state graph so that it is a proper,
completely specified state graph. Demonstrate that your answer is correct. Convert the
graph to a state table using 0’s and 1’s for inputs and outputs.
Soln 1:
Soln 2: