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 pinouts section of 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.
- Create a VHDL file with a Moore state machine template
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.
+ (more detail)
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.
- Design a State Machine to Recognize a Pattern
We're going to make a simple state machine that recognizes when you have pressed three buttons in the proper sequence. Depending on the state, one of four LEDs should be on. Consider the following description of a state machine.
- In the Idle state no buttons have been pushed. Red LED 0 is active, red LED 1, red LED 2, and green LED 0 are not 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; the other three are inactive. 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. Red LED 2 is active and the others are inactive. 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. Green LED 0 is active and the three red LEDs are inactive. 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.
- Set the entity name
Change the entity name to bright so it matches the name of the project/file.
- Set up the inputs
Modify the inputs in the port statement of the entity section so there is an input signal for each button, in addition to the clock and reset. Make each input or output a std_logic signal, as shown below.
buttonOne : in std_logic; buttonTwo : in std_logic; buttonThree : in std_logic;
In addition, add 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.
- Examine the state machine body code
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.
+ (more detail)
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 quite 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.
- Define the reset behavior
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.
- Define the state machine behavior
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'.
- Define the output signal behavior
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 four of the output signal values.
- Simulate the circuit
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
Use 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.
- Test the circuit on the board
Test the circuit on the DE1 board. Using the pin planner, set up the inputs as below.
Signal Pin reset PIN_R22 buttonOne PIN_R21 buttonTwo PIN_T22 buttonThree PIN_T21 redLED PIN_R20 redLED PIN_R19 redLED PIN_U19 greenLED PIN_U22 clock PIN_A12
Recompile your circuit after specifying the pins. 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 third project.