CS232 Lab 3: State Machine
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.
Starting with this project, you may work with a partner.
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.
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 a 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 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 should 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 to 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. 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 causes a reset.
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.
Let's simulate it to test it. You can simulate with ModelSim, or you can use Gnu's VHDL compiler ghdl and then visualize with gtkwave. The nice thing about ghdl is that it takes less effort to generate the input pattern (and you can probably get it working on your own computer!). Here are instructions for both options:
- Option: Use ghdl.
- 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.
- 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.
- Option: Use ModelSim
Make the EDA netlist and simulate the circuit. Give the clock a 50ps
period over 1000ps. Then make constant signals for the three buttons
and the reset signal, then use the Edit mode of the waveform window to
adjust the signals as appropriate.
To get to the edit mode in the waveform window, look for the icon set below.
Click the fourth button from the left. With this tool active, you can click and drag on a waveform to select it. Then you can right-click on the selected area and pick Wave Editor from the popup menu. Then you have the option to Invert, Mirror, or set a specific Value for the waveform.
- Make the EDA netlist and simulate the circuit. Give the clock a 50ps period over 1000ps. Then make constant signals for the three buttons and the reset signal, then use the Edit mode of the waveform window to adjust the signals as appropriate.
- Option: Use ghdl.
- 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.
- Compile your design and then 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 project.