Describe Combinational Logic Behaviorally

Project 5: Multiplexer, Decoder, Encoder, and Shifter

Introduction

In this project you will design a multiplexer, a decoder, an encoder, and a shifter using Verilog HDL. Instead of building the circuit using logic operators, you will learn to describe a circuit behaviorally according to the functionality you wish the circuit to perform.

Before you begin, you should:
  • Have the Xilinx® ISE WebPACK™ installed.
  • Have your FPGA board set up.
  • Be able to write combinational logic using logic operators in Verilog and implement them on an FPGA.
After you're done, you should:
  • Be able to implement combinational logic behaviorally using Verilog HDL.
  • Understand the functionality for basic combinational logic cells.

Inventory:

Qty Description
1 Digilent® Nexys™4, Nexys™3, Nexys™2, or Basys™2 FPGA Board
1 Xilinx ISE Design Suite: WebPACK (14.6 Recommended)
1 Digilent Adept

Multiplexer

Data selectors, more commonly called multiplexers (or just “muxes”), function by connecting one of their input signals to their output signals as directed by their “select” or control input signals. Figure 1 shows the truth table, logic graph, and block diagram of a 4-to-1 mux, where I0, I1, I2, I3 are four data inputs, Y is the output, S1 and S1 are select signals.

Figure 1. Truth table, logic graph, and block diagram of a 4-to-1 multiplexer.

Since most data elements in computer systems are bytes, or words consisting of 8, 16, 32 or more bits, muxes used in computer circuits must switch 8, 16, 32, or more signals all at once. Muxes that can switch many signals simultaneously are called “bus muxes”. A block diagram and schematic for a bus mux that can select one of four 8-bit data elements is shown in Fig. 2.

Figure 2. Block diagram and schematic for a 4-to-1 8-bit multiplexer.

Step 1: Design a Multiplexer

This project starts with designing a 4-1 2-bit bus multiplexer. Eight on-board slide switches will be used to provide the data inputs, two push buttons will be used as select signals, and LEDs 0 and 1 will be used to show the output of the multiplexer. Instead of implementing the multiplexer using logic operators, we are going to describe the circuit behaviorally using an always block and an if statement, or a case statement.

We are presenting three ways to code the multiplexer behaviorally here. However, you only need one in your code. You are encouraged to try out all three of the different ways so as to understand and experience the difference in Verilog syntax.

  1. Create a project in Xilinx ISE targeting the FPGA board you are using, as you have done in previous labs.
  2. Create a Verilog module called mux_4_1 with inputs I0, I1, I2, I3, Sel and output Y as follows:
    						module mux_4_1 (
    							input [1:0] I0,
    							input [1:0] I1,
    							input [1:0] I2,
    							input [1:0] I3,
    							input [1:0] Sel,
    							output [1:0] Y
    						);
    					
  3. The first way to code a mux behaviorally is to use the “?:” selection operator.
    						assign Y = (Sel == 2'd0) ? I0 : (
    										(Sel == 2'd1) ? I1 : (
    											(Sel == 2'd2) ? I2 : I3
    										)
    									);
    					
  4. The second way to code a mux is by using an always block together with an “if” statement. However, as Y is assigned in an always block, Y needs to be declared as type reg.
    						reg [1:0] Y;
    
    						always @ (Sel, I0, I1, I2, I3)
    						begin
    							if (Sel == 2'd0)
    								Y = I0;
    							else if (Sel == 2'd1)
    								Y = I1;
    							else if (Sel == 2'd2)
    								Y = I2;
    							else
    								Y = I3;
    						end
    					
  5. The third way to code a mux is by using an always block together with a “case” statement.
    						reg [1:0] Y;
    						
    						always @ (Sel, I0, I1, I2, I3)
    						begin
    							case (Sel)
    								2'd0:
    									Y = I0;
    								2'd1:
    									Y = I1;
    								2'd2:
    									Y = I2;
    								2'd3:
    									Y = I3;
    								default:
    									Y = 2'd0;
    							endcase
    						end
    					
  6. Create a UCF File and map.
    • I0[0] to SW0, I0[1] to SW1
    • I1[0] to SW2, I1[1] to SW3
    • I2[0] to SW4, I2[1] to SW5
    • I3[1] to SW6, I3[2] to SW7
    • Sel[0] to BTN0, Sel[1] to BTN1
    • Y[0] to LED0, Y[1] to LED1

Binary Decoder

Decoder circuits receive inputs in the form of an N-bit binary number and generate one or more outputs according to some requirement. A binary decoder has $N$ inputs and $2^N$ outputs. If the N inputs are taken as an N-bit binary number, then only the output that corresponds to the input binary number is asserted. For example, in the 3:8 binary decoder shown in Fig. 3 below, if a binary 5 (or “101”) is presented on the input of the decoder, then only the 5th output of the decoder (Y5) will be asserted and all of the other outputs will be de-asserted.

Figure 3. Truth Table and Block Diagram of a 3:8 Binary Decoder.

Step 2: Design a Binary Decoder

In this section we are going to design a 3:8 binary decoder. Switches 0 to 2 are used as the inputs for 3:8 decoder and 8 on-board LEDs are used to indicate the output of the decoder.

  1. Create a project in Xilinx ISE targeting the FPGA board you are using, as in the previous projects.
  2. Create a Verilog module called decoder_3_8 with inputs I and output Y as follows:
    											module decoder_3_8 ( 
    												input [2:0] I,
    												output [7:0] Y
    											);
    										
  3. The most efficient way to describe the behavior of a decoder is to use a case statement in an always block.
    						reg [7:0] Y;
    						
    						always @ (I)
    						begin
    							case (I)
    								3'd0:
    									Y = 8'd1;
    								3'd1:
    									Y = 8'd2;
    								3'd2:
    									Y = 8'd4;
    								3'd3:
    									Y = 8'd8;
    								3'd4:
    									Y = 8'd16;
    								3'd5:
    									Y = 8'd32;
    								3'd6:
    									Y = 8'd64;
    								3'd7:
    									Y = 8'd128;
    								default:
    									Y = 8'd0;
    							endcase
    						end
    					
  4. Create a UCF File and map
    • I[2:0] to SW2, SW1, SW0
    • Y[7:0] to LED 7-0

Priority Encoder

An encoder essentially performs the reverse of a decoder function in a combinational logic. It receives N inputs (where N is typically power of two, i.e., 4, 8, 16, etc.), and asserts an output binary code of M bits (usually $M=log_{2}N$). The M-bit binary code indicates which input was asserted. Since more than one input line to the encoder might be asserted at any given time, the priority encoder asserts an output code corresponding to the highest numbered input that is asserted. The truth table and block diagram of a priority encoder is displayed in Fig. 4 below.

Figure 4. Truth Table and Block Diagram of a Priority Encoder with GS and Enable.

Step 3: Design a Priority Encoder

In this section, we are going to design a 4-input priority encoder. Four on-board switches will be used as data inputs. Another slide switch will act as “Enable” signal. Two LEDs will show the encoded value of inputs, and another two LEDs act as the “GS” and the “Eout” Signal.

  1. Create a project in Xilinx ISE targeting the FPGA board you are using, as in previous projects.
  2. Create a Verilog module called encoder with inputs I, Ein, and outputs Eout, GS, and Y as follows:
    						module decoder_3_8 ( 
    							input [3:0] I,
    							input Ein,
    							output [1:0] Y,
    							output GS,
    							output Eout
    						);
    					
  3. The most efficient way to describe the behavior of a priority encoder is to use if statement in an always block. As we have three outputs here, we will code the behavioral description for those three outputs in three always blocks.
    						reg [1:0] Y;
    						reg GS;
    						reg Eout;
    
    						always @ (I, Ein)
    						begin
    							if(Ein == 1)
    								Y = (I[3] == 1) ? 2'd3 : (
    										(I[2] == 1) ? 2'd2 : (
    											(I[1] == 1) ? 2'd1 : 2'd0
    										)
    									);
    							else
    								Y = 2'd0;
    						end
    
    						always @ (I, Ein)
    						begin
    							if (Ein == 1 && I == 0)
    								Eout = 1'b1;
    							else
    								Eout = 1'b0;
    						end
    
    						always @ (I, Ein)
    						begin
    							if (Ein == 1 && I != 0)
    								GS = 1'b1;
    							else
    								GS = 1'b0;
    						end
    					
  4. Create a UCF File and map.
    • I[3:0] to SW3, SW2, SW1, SW0
    • Ein to SW7
    • Y[1:0] to LED 1-0
    • Eout to LED 7
    • GS to LED 6

Shifter

A shifter is a circuit that produces an N-bit output based on an N-bit data input and some control bits, where the N output bits are place-shifted copies of the input bits, and the way the bits will be shifted is determined by the control bits. As an example, the truth table for a 4-bit shifter is shown below in Fig. 5. There are three control bits (D, R, En) in the example. They enable different functions:

  • A Fill signal (F) determines whether bits vacated by shift operations receive a '1' or a '0'.
  • A Rotate signal (R = '1' for rotate) determines whether shifted-out bits are discarded or recaptured in vacated bits.
  • A Direction signal (D = '1' for right) determines which direction the shift will take.
  • An Enable signal (En = '1' for shift by 1 bit, '0' for shift by 0 bit, i.e., bypass) determines whether a shift operation needs to be done.
Figure 5. Truth Table and Block Diagram of a 4-bit Shifter.

Step 4: Design a Shifter

In this section, we are going to design a 4-input Shifter. Four on-board switches will be used as data inputs. Three other slide switches will act as control signals F, R, and D. A push button will be used as the Enable signal. Four LEDs will show the output of the shifter.

  1. Create a project in Xilinx ISE targeting the FPGA board you are using, as in previous projects.
  2. Create a Verilog module called “shifter” with inputs I, En, D, R, F and outputs Y as follows:
    						module decoder_3_8 ( 
    							input [3:0] I,
    							input D,
    							input R,
    							input F,
    							input En,
    							output [3:0] Y
    						);
    					
  3. Similar to previous steps, we are going to use if statement again to implement the shifter.
    						reg [3:0] Y;
    
    						always @ (I, Ein)
    						begin
    							if (En == 0)
    								Y = I;
    							else
    								if (R == 0)
    									Y = (D == 0) ? {I[2:0], F} : {F, I[3:1]};
    								else
    									Y = (D == 0) ? {I[2:0], I[3]} : {I[0], I[3:1]};
    						end
    					
    In the previous codes, {A,B} is used to concatenate two groups of signals into a bus. For example, Y = {I[2:0], F} means Y[3:1] = I[2:0] and Y[0] = F.
  4. Create a UCF File and map.
    • I[3:0] to SW3, SW2, SW1, SW0
    • R to SW7, D to SW6, F to SW5
    • En to Btn0
    • Y[3:0] to LED 3-0

Test Your Knowledge!

Now that you've completed this project, try these modifications:

  1. Create a test fixture for each of the circuits discussed in this section (multiplexer, decoder, priority encoder, and shifter). Keep in mind to test all possible input patterns.

Challenge Problem

  • If you are confident in your ability to design a multiplexer, a decoder, an encoder, and a shifter using Verilog HDL, go ahead and try out the design challenge problem below for some extra practice!

  • Other product and company names mentioned herein are trademarks or trade names of their respective companies. © 2014 Digilent Inc. All rights reserved.