$24
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.
Note that we may refer to signals as SW9 0, i.e., with the subscripts, but when you write your Verilog, you will need to use SW[0], SW[1], etc.
Resources
You can nd 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
Marking Scheme
This lab is worth 4% of your nal 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
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.
1
Your Verilog code should be well-commented. For your simulations, you should have a script, or number of scripts, that test important aspects of your design. Print out the waveforms from the simulator and paste them into your lab book (e.g. by taking a screenshot). If the simulation is very long, just print out enough to show that key parts of your circuit are working and as evidence that you have done the simulations. It is not necessary to have pages and pages of waveforms. However, occasionally, you will be asked to demonstrate and explain your entire simulation to the TA in the lab, so be prepared for this.
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.
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 le 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 p o r t 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 ] ) , //
c o n n e c t
p o r t SW[ 0 ]
t o
p o r t
x
. y (SW[ 1 ] ) , //
c o n n e c t
p o r t SW[ 1 ]
t o
p o r t
y
. s (SW[ 9 ] ) , //
c o n n e c t
p o r t SW[ 9 ]
t o
p o r t
s
.m(LEDR [ 0 ] ) //
c o n n e c t
p o r t LEDR[ 0 ]
t o p o r t 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
2
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 j 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 le. This le is also provided to you (on Quercus, and in the appendices of this handout).
Inside the .do le, we start o by creating a working directory called work using the vlib command. We then compile the Verilog le using vlog and load it into the simulation with the vsim command. Lastly, to display all the signals on the waveform viewer, we put f/*g after add wave.
#
S e t
t h e
w o r k i n g
d i r , where a l l
c o m p i l e d
V e r i l o g
g o e s .
vlib
work
#
Compile
a l l
V e r i l o g
modules
i n mux . v
t o
w o r k i n g
d i r ;
#
c o u l d a l s o
have
m u l t i p l e
V e r i l o g
f i l e s .
# The
t i m e s c a l e
argument
d e f i n e s
d e f a u l t time
u n i t
#
( used when
no
u n i t
i s
s p e c i f i e d ) ,
w h i l e
t h e
second number
#
d e f i n e s
p r e c i s i o n ( a l l
t i m e s
a r e
rounded
t o t h i s
v a l u e )
vlog t i m e s c a l e
1 ns /1 ns
mux . v
#
Load s i m u l a t i o n
u s i n g
mux as
t h e
t o p
l e v e l
s i m u l a t i o n module .
vsim mux
# Log
a l l
s i g n a l s
and
add
some
s i g n a l s
t o
waveform
window .
log f/∗g
#
add wave f/∗g would add
a l l
i t e m s
i n
t o p
l e v e l s i m u l a t i o n module .
add wave f/∗g
Once everything is initiated, we set the input signals to be a 1 or a 0 with the force command. The force command speci es the state of the inputs in the simulation, which mimics setting the inputs using switches in the lab. The run command instructs the simulator to simulate the behavior of the circuit for a speci ed time duration. During this time, the inputs to the circuit are assumed to have the state speci ed by the last force command. If there are inputs whose values have not been speci ed using the force command, their values will be assumed unknown. Depending on the simulator settings, you may see these values appear displayed using special colour in waveforms, and their values labeled as either z or x, instead of 0 or 1. z and x are special symbols used to indicate unknown values.
3
# S e t
i n p u t v a l u e s u s i n g t h e f o r c e command ,
s i g n a l names need
# t o be i n fg b r a c k e t s .
force
fSW[ 0 ] g
0
#
f o r c e
s w i t c h
0
(SW[ 0 ] )
t o
be
0
force
fSW[ 1 ] g
1
#
f o r c e
s w i t c h
1
(SW[ 1 ] )
t o
be
1
force
fSW[ 9 ] g
0
#
f o c e 3
s w i t c h
9
(SW[ 9 ] )
t o
be
0
# Run
s i m u l a t i o n
f o r a
few ns .
run 10 ns
Perform the following steps:
When you have familiarized yourself with the .do le, 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 les. Next, type do wave.do (or the le name you named your
.do le). Look at the generated waveform , which is the simulation output, and verify that the provided test-cases work as expected. (PRELAB).
Create a new Quartus Prime project for the Verilog code provided and test it on the board during your lab session. Do not forget that you will need the DE1 SoC.qsf le to de ne how the switches and LEDs connect to the pins. Then show your circuit to the TA to be marked. (IN-LAB)
Compare the output results with the simulations you performed.
Did you notice a signi cant time di erence between testing with ModelSim and implementing your design on the board? The di erence becomes greater as the complexity of the circuit increases. Comment on this di erence and its impact on debugging.
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 di cult 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 ; // d e f i n e s a w i r e c a l l e d Connection
The wire created above is called Connection and it can be used to connect the output of a module to the input of another module, the same way you used a physical wire in Lab 1 to connect the output of one gate to the input of another gate. Figure 2 shows a schematic of two modules using the wire Connection. You may also use Connection as input to other logic expressions within the module in which this wire is de ned.
module block1(in1, out1);
module block2(in2, out2);
Connection
SW[0]
in1
out1
in2
out2
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
4
together.
b l o c k 1 B1 (
. i n 1 (SW[ 0 ] ) , // c o n n e c t e x t e r n a l p o r t SW[ 0 ] t o p o r t i n 1 o f b l o c k 1
. out1 ( Connection ) // c o n n e c t w i r e Connection t o p o r t o u t 1 o f b l o c k 1
) ;
b l o c k 2 B2 (
. i n 2 ( Connection ) , // c o n n e c t w i r e Connection t o p o r t i n 2 o f b l o c k 2
. out2 (LEDR [ 5 ] ) // c o n n e c t e x t e r n a l p o r t LEDR[ 5 ] t o p o r t o u t 2 o f b l o c k 2
) ;
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 ; // j o i n s w i r e Connection t o 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
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:
Answer the following question: if the truth table in Table 2 was given in full, how many rows would it have? (PRELAB)
Draw a schematic (not in Quartus) showing how you will connect the mux2to1 modules to build the 4-to-1 multiplexer. Be prepared to explain it to the TA as part of your prelab. The schematic should re ect how you are going to write your Verilog code. (PRELAB)
Create a new Quartus Prime project for your circuit and write the Verilog code. (PRELAB)
Add your Verilog le 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 le to de ne how the switches and LEDs connect to the pins.
Simulate your circuit with ModelSim for di erent values of s, u, v, w and x. Do enough simulations to convince yourself that the circuit is working. You must show these to the TA as part of your prelab. (PRELAB)
Compile the project.
5
Download the compiled circuit into the FPGA chip. Test the functionality of the circuit by toggling the switches and observing the LEDs. Then show your circuit to the TA to be marked. (IN-LAB)
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 nd 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 rst 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
Debugging Strategy: Before diving into the full Part III implementation, you may nd it helpful to start by creating a very simple Verilog module which turns on segment 0 of the 7-segment display, i.e., pin HEX0 0, based on the input from SW 0.
Perform the following steps:
Write the expressions for seven Boolean functions, one for each segment of the 7-segment decoder. You must use Karnaugh maps for optimization. You should be able to explain to the TA how you generated these expressions by showing them the truth-tables you wrote, and Karnaugh maps you used to optimize your circuits. (PRELAB)
Write a Verilog module for the 7-segment decoder taking advantage of the aforementioned expres-sions. (PRELAB)
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
6
provide input signals for B, then A, then 3, then 1, then 4, and nally 5. You must include your simulation waveforms as part of your prelab. (PRELAB)
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 HEX0 0, HEX0 1, : : :, HEX0 6. 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 le.
Compile the project.
Download the compiled circuit into the FPGA chip. Test the functionality of the circuit by toggling the SW3 0 switches and observing the 7-segment display. Then show your circuit to the TA to be marked. (IN-LAB)
7