Lab 3: VHDL
The purpose of this lab is to give you more practice working with VHDL and to introduce you to the concept of a state machine.
For reference, here is a link to the DE1 User Manual.
- Start Quartus. Follow the new project wizard and create a new directory for lab 3. Call your project bright. This is the name of the project and the top level entity. You're free to use any name you like, just make sure it is also the name of your entity and top level file.
Select File->New and create a new VHDL file. Then insert the template
for a Moore state machine (VHDL->Full Designs->State machines).
Change the entity name to bright in both the entity and architecture
lines. Save the file as bright.vhd.
Aside: a state machine is a way of representing a sequential process. You can think of each state as a step in the process. A state machine changes states according to the rules of each state and the values of the inputs used by the state machine. Note that not every state will necessarily care about every input.
In a Moore state machine, the state identifier provides a complete description of what the circuit should output and how it should respond to inputs. How the state machine arrived at its current state is immaterial.
We're going to make a simple state machine that recognizes when you
have pressed three buttons in the proper sequence. Consider the
following description of a state machine.
- In the Idle state no buttons have been pushed and red LED 0 is active. If the first button is pushed, then move to the One state.
- In the One state, the first button has been pushed and red LED 1 is active. If the second button is pressed, then move to the Two state. But if the third button is pressed, move to the Idle state.
- In the Two state, the first and second buttons have been pressed in sequence and red LED 2 is active. If the third button is preseed, then move to the Three state. But if the first button is pressed, move to the Idle state.
- In the Three state, all three buttons have been pressed and green LED 0 is active. If button one or two are pressed, move back to the Idle state.
The following is a visualization of this state machine.
Any action not explicitly shown should leave the state machine in the same state.
- First, change the entity name to bright so it matches the name of the project/file.
Modify the inputs to the entity so there is an input
signal for each button, in addition to the clock and
reset. Make each one a std_logic signal, as shown below.
buttonOne : in std_logic; buttonTwo : in std_logic; buttonThree : in std_logic;
In addition, set up the output signals so there is a three bit redLED output and a one bit greenLED output. Use a std_logic_vector(2 downto 0) for the redLED signal and a std_logic signal for the green LED.
Going to the body of the architecture, notice the structure of the
code. This is a standard Moore state machine structure. In VHDL, a
process statement is like a code block. Inside a process statement you
can use if statements, case statements, and assignments, so it is kind
of like a standard programming block, but don't let that fool you, it
behaves somewhat differently.
Aside: Think of a process like a function. The process statement itself is sensitive to the signals in its parameter list. For a Moore state machine, the important signals are the clock and the reset signals. Any time one of those values changes, the process block will execute.
While executing, however, the process block does not act like a sequential computer. The instructions are not executed in order, in the sense that if you assign a value to A on line 1 and then use A on line 2, A will have the value you assigned it on line 1. Program flow instructions, like if-statements, are executed in the order in which they appear. But assignments do not actually move data; assignments schedule a value to be assigned to a variable. All actual data movement occurs simultaneously at the end of the block. Therefore, it is important that a variable be scheduled an assigned value (appear on the left side of a signal) only once in the process block, given the program flow. Having an assignment to variable A in the two cases of an if-statement, for example, is fine because only one of the cases will execute.
Local constants and signals are defined at the start of the architecture block, before the begin statement. In this case, the enumerated type state_type lists mnemonics for the different states of the state machine. You may want to change the state names to sIdle, sOne, sTwo, and sThree so the state names match the diagram above.
- Inside the process, there is an if statement the tests for a reset signal. Anything that should be done on a reset signal should go there. Edit the reset case so the state gets assigned sIdle. Also, change the test to reset = '0' so that pushing the button on the board causes a reset (the buttons send a '0' when they are pushed.
The elsif case looks for a rising edge of the clock. All state
machine changes take place on the rising edge of the clock, so
everything else goes there.
Inside the rising edge block there is a case statement that switches on the current state. Within each state, there is an implementation of what events cause a state change. One thing that is critical is to note that the state variable will only ever get assigned a new value once inside the process.
Edit the four state cases to use the proper names and make the proper tests, according to the diagram above. Remember that when the user pushes a button its value will be '0'.
- The second process statement modifies the output depending upon the state. Change the state names and assign the proper values to the redLED std_logic_vector output and the greenLED std_logic output. A value of '1' turns on an LED. Each state's case must assign all of the output signal values.
Use ghdl to simulate the circuit. Give yourself a new
terminal and cd to your working lab3 directory.
- Download this test bench file: brighttest.vhd. This file creates the signals that will test the bright.vhd file.
Compile your bright.vhd file and the brighttest.vhd file using the
following series of commands.
ghdl -a bright.vhd brighttest.vhd ghdl -e brighttest ghdl -r brighttest --vcd=brighttest.vcd
Now we can use a program called gtkwave to look at the resulting
simulation. Run the following command to bring up the program.
gtkwave brighttest.vcd &
- Within gtkwave, shift-click to select all of the signals in the lower left panel, then click the Insert button. The waveforms should appear in the main window. You may have to click/select zoom-to-fill in order to see the whole simulation run. It should look like the screen shot below, if your circuit is working correctly.
- Now test the circuit on the DE1 board. Using the pin planner, set up the inputs so buttonOne, buttonTwo, and buttonThree connect to pins R21, T22, and T21. Set the reset to be pin R22. Set the three redLED outputs to pins R20, R19, and U19. Set the greenLED output to pin U22. Set the clock to A12. Recompile your circuit after specifying the pins.
- Use the Programmer to download it to the board. Test out your circuit.
When you have completed the lab assignment, go ahead and get started on the third project.