CS 232: Lab 3

Title image Fall 2026

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.

If you are using the board, here is a link to the DE0 User Manual.


Tasks

  1. Setup
    • Start Quartus.
    • Follow the new project wizard to create a new directory for project 3 and a subdirectory within that called bright. Call your Quartus project bright. This is the name of the project and the top level entity.
  2. Create a VHDL file with a Moore state machine template
    • Select File->New and create a new VHDL file.
    • 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 and 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.

    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.

  3. 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. The user needs to press Button1, then Button2, then Button3. Once Button3 is pressed, the leftmost green LED (Green LED 9) turns on. You can think of the this light coming on as the reward for good behavior. To keep track of the order in which the buttons are pressed, we use a state machine, which we describe here.

    1. In the Idle state no buttons have been pushed. Green LED 0 is active, green LED 1, green LED 2, and green LED 9 are not active. If the first button is pushed, then move to the One state.
    2. In the One state, the first button has been pushed and green 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.
    3. In the Two state, the first and second buttons have been pressed in sequence. Green LED 2 is active and the others are inactive. If the third button is pressed, then move to the Three state. But if the first button is pressed, move to the Idle state.
    4. In the Three state, all three buttons have been pressed. Green LED 9 is active and the other three green 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.

  4. Set the entity name

    Change the entity name to bright so it matches the name of the project/file.

  5. 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 four bit greenLED output (use a std_logic_vector(3 downto 0)).

  6. 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.

  7. 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'. You will be resetting the circuit using Switch 0. Up (on, '1') will indicate "Let the circuit run" and down (off, '0') will indicate "Reset back to the idle state".

  8. 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'.

  9. 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 greenLED std_logic_vector output. A value of '1' turns on an LED. Each state's case must assign all four of the output signal values. Use bit 0 for green LED 0, bit 1 for green LED 1, bit 2 for green LED 2, and bit 3 for green LED 9.

  10. Simulate the circuit

    Use ghdl to simulate the circuit. Give yourself a new terminal and cd to your working project3/bright directory.

    1. Download this test bench file: brighttest.vhd. This file creates the signals that will test the bright.vhd file.
    2. 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

    3. Use gtkwave to look at the resulting simulation. Run the following command to bring up the program.

      gtkwave brighttest.vcd &

    4. 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 and you will have to click/select zoom-to-fill in order to see the whole simulation run. You should also click on the gled signal to expand it to show each individual bit. It should look like the screen shot below, if your circuit is working correctly. gtkwave screen shot
  11. Demonstrate the circuite
    • Using the pin planner, set up the inputs as below.

      SignalPinWidget
      resetPIN_J6Switch 0
      buttonOnePIN_H2Button 0
      buttonTwoPIN_G3Button 1
      buttonThreePIN_F1Button 2
      greenLED[0]PIN_J1Green LED 0
      greenLED[1]PIN_J2Green LED 1
      greenLED[2]PIN_J3Green LED 2
      greenLED[3]PIN_B1Green LED 9
      clockPIN_G2150 MHz Clock
    • 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.