Description
Multiplexers, Design Hierarchy, and HEX Displays
1 Learning Objectives
The purpose of this exercise is to apply Verilog in expressing simple circuits, and to learn the importance of simulations and hierarchies when writing Verilog. This exercise is also meant to illustrate the importance of Karnaugh maps in designing circuits, and introduce important devices such as the multiplexer and seven-segment decoder.
This lab also introduces components of the DE1-SoC board and FPGA design in general. We will use switches SW9−0 on the DE1-SoC board as inputs to the circuit, and Light Emitting Diodes (LEDs) and 7-segment displays as output devices.
2 Resources
You can find many resources about the DE1-SoC board here http://cd-de1-soc.terasic.com/. The User Manual for the DE1-SoC board can be downloaded from here: http://www-ug.eecg.toronto.
edu/desl/manuals/DE1-SoC_User_manual.pdf
3 Marking Scheme
This lab is worth 4% of your final grade, but you will be graded out of 8 marks for this lab, as follows:
• Prelab + Simulations: 3 marks
• Part I (in-lab): 1 mark
• Part II (in-lab): 2 marks
• Part III (in-lab): 2 marks
4 Preparation Before the Lab
For this lab, and all future labs, you will be asked to prepare schematics (which can be drawn by hand on paper, and not necessarily in Quartus), Verilog code and ModelSim simulations for your prelab. The schematics should show the structure of your Verilog code, much like the schematics in Lab 1 showed how your circuit should be built. Figure 2 is an example of how to draw the schematic of a Verilog code.
Your Verilog code will consist of a number of modules and the schematic should show how those modules are wired together, as well as the input and output ports of your circuit, i.e., connections to switches, LEDs, 7-segment hex displays, etc. Think of modules as logic functions consisting of multiple gates, such as the logic functions you wired together in Lab 1. All port names of the modules, wires and I/O ports should be clearly labeled in your schematics.
As an example, if your circuit implements a logic function with three or four inputs, it is reasonable to show waveforms demonstrating the functionality of all possible combinations of input values. However, if your circuit implements a logic function with ten inputs, it would be unreasonable to simulate all 210 possible input values.
5 Part I
Verilog File (.v)
The DE1-SoC board provides 10 toggle switches, called SW9−0, that can be used as inputs to a circuit, and 10 red lights, called LEDR9−0, that can be used to display output values.
A Verilog file for a 2-to-1 multiplexer, named mux.v, has already been provided to you (on Quercus, and in the appendices of this handout). The top module mux has 3 inputs. SW[0] is the input 0 signal, SW[1] is the input 1 signal, and SW[9] is the select signal. The output is displayed on LEDR[0].
module mux(LEDR, SW); // module name and port l i s t
The top module, mux, is a very trivial example of a design hierarchy, as it instantiates a single mux2to1 module. In the more general case, any module can instantiate a number of interconnected modules, just like when you wired up a number of chips in Lab 1. However, in any circuit you build, there must be only one top-level module. The .port(connection) notation matches the port name from the mux2to1 module to a connection (e.g., port or internal wire) inside the mux top-level module. Note that multiple modules of the same type can be used to build larger circuits. Each use of a module is called an instance. Every instance has to have a unique name. In our example below we used only one instance of the mux2to1 module, which we named u0.
mux2to1 u0(
. x(SW[0]) , // connect port SW[0] to port x
. y(SW[1]) , // connect port SW[1] to port y
. s (SW[9]) , // connect port SW[9] to port s
.m(LEDR[0]) // connect port LEDR[0] to port m
);
Figure 1 shows the symbol for a 2-to-1 multiplexer. As mentioned in Lab 1, a multiplexer is a device that uses a select signal to select which one of multiple inputs should appear on the output of the device. In Figure 1, input s will control which of the inputs x and y will appear on the output m. If s is 0, x will appear on the output, while if s is 1, y will appear on the output.
Figure 1: Symbol for a 2-to-1 multiplexer
The Boolean expression for a 2-to-1 multiplexer is m = xs’+ ys, and one way you can express this in Verilog is the following:
assign m = x & ˜s | y & s ;
Table 1 shows a mapping of all the bitwise Verilog operators to Boolean symbols.
|bitwise OR &bitwise AND
~bitwise negation
^bitwise XOR
Table 1: Verilog Operators
Simulation File (.do)
After writing a Verilog code, and to verify the code functionnality properly, we can perform a simulation using a script written in a .do file. This file is also provided to you (on Quercus, and in the appendices of this handout).
Inside the .do file, we start off by creating a working directory called work using the vlib command. We then compile the Verilog file using vlog and load it into the simulation with the vsim command. Lastly, to display all the signals on the waveform viewer, we put {/*} after add wave.
# Set the working dir , where a l l compiled Verilog goes . vlib work
# Compile a l l Verilog modules in mux. v to working dir ; # could also have multiple Verilog f i l e s .
# The timescale argument defines default time unit
# ( used when no unit is specified ) , while the second number # defines precision ( a l l times are rounded to this value ) vlog −timescale 1ns/1ns mux. v
# Load simulation using mux as vsim mux the top l e v e l simulation module .
# Log a l l signals and add some log {/∗} signals to waveform window .
# add wave {/∗} would add a l l items in top l e v e l simulation module .
add wave {/∗}
# Set input values using the force command, # to be in {} brackets . signal names need
force {SW[0]} 0 # force switch 0 (SW[0]) to be 0
force {SW[1]} 1 # force switch 1 (SW[1]) to be 1
force {SW[9]} 0 # foce3 switch 9 (SW[9]) to # Run simulation for a few ns . be 0
run 10ns
Perform the following steps:
1. When you have familiarized yourself with the .do file, open ModelSim, and in the ModelSim’s Transcript window (near the bottom) use the cd command to change to the directory where you placed the wave.do and mux.v files. Next, type do wave.do (or the file name you named your .do file). Look at the generated waveform , which is the simulation output, and verify that the provided test-cases work as expected. (PRELAB).
3. Compare the output results with the simulations you performed.
4. Did you notice a significant time difference between testing with ModelSim and implementing your design on the board? The difference becomes greater as the complexity of the circuit increases. Comment on this difference and its impact on debugging.
6 Part II
Start with the code given in Part I and modify the design to make it a 4-to-1 multiplexer. You must use multiple instantiations of the mux2to1 module given to you in Part I. This is known as hierarchical design and is a good practice especially for larger designs where the Verilog code you write can become more difficult to debug. Smaller submodules are generally easier to test thoroughly and debug.
To complete this section, you will need to use the wire declaration to create wires that can be used to connect the multiple blocks together.
wire Connection ; // defines a wire called Connection
module block1(in1, out1); module block2(in2, out2);
in1 out1 Connection in2 out2
SW[0]LEDR[5]
Figure 2: Using the wire Connection to make a connection between two modules
The following Verilog code fragment corresponds to Figure 2. It creates instances of modules block1 and block2, named B1 and B2, respectively. The wire Connection is used to wire the module instances together.
block1 B1(
. in1 (SW[0]) , // connect external port SW[0] to port in1 of block1
. out1 ( Connection )
);
block2 B2 ( // connect wire Connection to port out1 of block1
. in2 ( Connection ) , // connect wire Connection to port in2 of block2
. out2 (LEDR[5])
); // connect external port LEDR[5] to port out2 of block2
Another way to make a connection is to use the assign statement. For example, if we wanted to connect the wire called Connection to LEDR0, we do the following:
assign LEDR[0] = Connection ; // joins wire Connection to LEDR[0]
Now construct a module for the 4-to-1 multiplexer shown in Figure 3 with the truth table shown in Table 2 using the wire construct and multiple instances of the mux2to1 module. Note that the truth table in Table 2 is given in a short-hand form. A real truth table would consist of rows enumerating all possible combinations of values of inputs u, v, w, x, in addition to s0 and s1, and show the value (0 or 1) of the output m for each row of the truth table. Since this would result in a truth table with a large number of rows, it is written in short-hand form instead.
s1s0 m
00 u
01 v
10 w
11 x
Figure 3: Symbol for a 4-to-1 multiplexer Table 2: Truth table for a 4-to-1 multiplexer
Perform the following steps:
1. Answer the following question: if the truth table in Table 2 was given in full, how many rows would it have? (PRELAB)
3. Create a new Quartus Prime project for your circuit and write the Verilog code. (PRELAB)
4. Add your Verilog file for the circuit to your project. Use switches SW 9−8 on the DE1-SoC board as the 2-bit s input, and switches SW 3−0 as the data inputs (labeled as u, v, w, x in Figure 3). Connect the output to LEDR0. Do not forget that you will need the DE1 SoC.qsf file to define how the switches and LEDs connect to the pins.
6. Compile the project.
7 Part III
In this part of the lab, you will design a decoder for the 7-segment HEX display as shown in Figure 4. The output of the HEX display is determined by the value at the input of the decoder as shown in Table 3. We call this a HEX display because it can display all hexadecimal digits.
The 7-segment display uses a common anode. What does common anode mean in terms of lighting up a segment? You should be able to find the answer online. Section 3.6.2 in the DE1-SoC User manual also tells you what is needed to turn on a segment.
HINT: In order to solve this part you need to first identify which segment needs to be illuminated for every input and then write a Boolean function for each one of the seven segments of the HEX display so they are turned on when needed. You must use Karnaugh maps to optimize those Boolean expressions before you write the corresponding Verilog code.
c3c2c1c0 Character
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 A
1011 b
1100 C
1101 d
1110 E
1111 F
Figure 4: HEX decoder Table 3: Desired behaviour of HEX decoder
Perform the following steps:
2. Write a Verilog module for the 7-segment decoder taking advantage of the aforementioned expressions. (PRELAB)
3. In order to be sure that your circuit is correct, you need to simulate your 7-segment decoder module with ModelSim, ensuring the output waveforms are correct. For this purpose of this lab, use your lab room as the test phrase (e.g. BA3145, BA3145). Now you should provide this sequence of letters and numbers as the input to your module, and check the output. So for BA3145, you will provide input signals for B, then A, then 3, then 1, then 4, and finally 5. You must include your simulation waveforms as part of your prelab. (PRELAB)
4. Create a new Quartus Prime project for your circuit. You should instantiate the 7-segment decoder module in your top-level module. Connect the c3c2c1c0 inputs to switches SW 3−0, and connect the outputs of the decoder to the HEX0 display on the DE1-SoC board. The segments in this display are called HEX00, HEX01, …, HEX06. You should declare a 7-bit port for the segments in your Verilog code, as follows:
output [6 :0 ] HEX0;
This way, the names of these outputs match the corresponding names in the DE1-SoC User Manual and the pin assignment DE1 SoC.qsf file.
5. Compile the project.
Appendices: Source Codes
A mux.v
//SW[2:0] data inputs
//SW[9] select signal //LEDR[0] output display
module mux(LEDR, SW); input [9 :0 ] SW; output [9 :0 ] LEDR;
mux2to1 u0(
. x(SW[0]) ,
. y(SW[1]) , . s (SW[9]) ,
.m(LEDR[0])
); endmodule module mux2to1(x , y , s , m);
input x ; // selected when s is 0
input y ; // selected when s is 1
input s ; // select signal
output m; // output
assign m = s & y | ˜s & x ;
// OR
// assign m = s ? y : x ;
endmodule
B wave.do
# Set the working dir , where a l l compiled Verilog goes . vlib work
# Compile a l l Verilog modules in mux. v to working dir ; # could also have multiple Verilog f i l e s .
# The timescale argument defines default time unit
# ( used when no unit is specified ) , while the second number # defines precision ( a l l times are rounded to this value ) vlog −timescale 1ns/1ns mux. v
# Load simulation using mux as vsim mux the top l e v e l simulation module .
# Log a l l signals and add some log {/∗} signals to waveform window .
# add wave {/∗} would add a l l add wave {/∗}
# First test case items in top l e v e l simulation module .
# Set input values using the force command, signal names need to be in {} brackets .
force {SW[0]} 0 force {SW[1]} 0
1
force {SW[9]} 0
# Run simulation for a few ns . run 10ns
# Second test case : change input values and run for another 10ns .
# SW[0] should control LED[0]
force {SW[0]} 0
force {SW[1]} 1
force {SW[9]}
run 10ns # . . . 0
# SW[0] should control LED[0]
force {SW[0]} 1
force {SW[1]} 0
force {SW[9]} run 10ns 0
# SW[0] should control LED[0]
force {SW[0]} 1
force {SW[1]} 1
force {SW[9]} run 10ns 0
# SW[1] should control LED[0]
force {SW[0]} 0
force {SW[1]} 0
force {SW[9]} run 10ns 1
# SW[1] should control LED[0]
force {SW[0]} 0
force {SW[1]} 1
force {SW[9]} run 10ns 1
# SW[1] should control LED[0]
force {SW[0]} 1
force {SW[1]} 0
force {SW[9]} run 10ns 1
# SW[1] should control LED[0]
force {SW[0]} 1
force {SW[1]} 1
force {SW[9]} run 10ns 1
2
Reviews
There are no reviews yet.