User Tools

Site Tools


Lab 4: Simple Simon


This lab will culminate in a Simon game that you play using the touch-screen. As you recall, the electronic version of Simon presents a random sequence of lights that you must “play-back” in order to win the game. You can watch a video of my version of the game to see what it looks like.

Because of its complexity, this lab will be completed in four milestones so you can receive credit in stages. You will implement this lab using the state-machine concepts taught in class. Your implementation will consist of four synchronous state machines that communicate using shared variables.

State Machine Overview

  1. button_handler: (1) draws the four small colored squares that serve as buttons, (2) flashes the larger square to show the detection of a touch, (3) reports the number of the square that was touched via a shared variable.
  2. sequence_player: (1) plays the current sequence for the user so they can try to repeat it.
  3. verifier: (1) verifies the sequence touched by the user for correctness. Correctness or failure is communicated via a shared variable.
  4. toplevel_control: (1) coordinates all of the above state machines to implement the required behavior for the Simon game.

You will implement and test each of the first three state machines separately. Once you verify that each of the first three state machines are working correctly, you may proceed to implement the toplevel_control state machine.

In this lab you shall create a game using a synchronous state machine. This will introduce you to using interrupts and a timer.


Write and debug a program implemented with synchronous state machines. You will use the concepts learned in Chapter 4 of the text.


The game you will create is a simple version of Simon, an electronic memory game. Your version of Simon shall use three LEDs (LD0-2) and three buttons (BTNL, BTNC, BTNR). Your game must have at least seven rounds but you may add more if you wish. Each round consists of two parts: first, the player is shown a sequence on the LEDs; second, the player must replicate the sequence on the buttons.

The game begins when you slide SW0 up. As discussed in class, start a software counter running in a state machine as soon as you load the program. When SW0 is slid up, capture the value of the counter and use it as a seed to srand(seed). Calling srand() in this way will set the seed for the random-number generator. You get successive random values by calling rand(). Please see the short code segment that I provide below. Also note that you must #include <stdlib.h> to gain access to rand() and srand().

On the first round of the game, illuminate a random LED for half a second and then turn it off. After the LED has been turned off the player must push the button corresponding with that LED to proceed to the next round. The buttons correspond to the LEDs as follows:

  • LD2 → BTNL
  • LD1 → BTNC
  • LD0 → BTNR

Thus, if LD1 was lit up, the player would press BTNC to advance to the next round.

Each round adds one more thing to the existing sequence, so during the second round a sequence of two shall be shown on the LEDs. The first LED in the second round's sequence should be the same as the first round. The second LED in the sequence should be randomly chosen. Each subsequent round will proceed in a similar fashion; show the same sequence that was shown on the previous round and add one more to it.

When showing a sequence, illuminate each LED for 0.5 seconds and turn off all LEDs for 0.3 seconds before illuminating the next LED.

If the player does not correctly enter the sequence on any round then blink all eight LEDs on and off twice to alert the player. You can decide on the time intervals for these blinks. Then reset the game to the first round.

Your implementation must be a synchronous state machine. Also the book says, “statements inside a state should never include statements that wait.” Your printed code will be checked to make sure you have not committed this iniquity. Rely on a timer and interrupts to wait certain lengths of time as explained in Chapter 4 of the text.


Draw a state diagram of your state machine on paper or the computer. It will help you when you write your code and is one of the things you must turn in.

The hardware you will need to initialize and set up for this lab includes: the timer, the interrupt controller, the buttons, and the LEDs. By now it should be easy for you to setup the GPIOs for the LEDs, and the GPIO for the button is already setup in the skeleton file. The timer and the interrupt controller are setup for you in the skeleton file.

The rand() of the C standard library may be used for random number generation.

You can figure out the frequency of the timer by looking in xparameters.h (it is 100 MHz). You need to know the frequency to figure out what the timer's reset value should be.

Skeleton File

Use the code below as a starting point for the lab. You may copy and paste it. The code sets up a timer, buttons, and interrupt controller for you. Then it enters a loop where the value of the buttons is printed each time there is a timer interrupt.

#include <stdio.h>
#include "platform.h"
#include "xscugic.h"
#include "xtmrctr.h"
#include "xgpio.h"

// Change this value to make timer interrupts more or less frequent
#define TIMER_DURATION 10000000

// Function Prototypes
void TimerISR();
int SetUpInterruptSystem(XScuGic *XScuGicInstancePtr);
int InitInterrupts();

// Global Variables
XScuGic InterruptController;	/* Instance of the Interrupt Controller */
XScuGic_Config *GicConfig;		/* The configuration parameters of the controller */
XTmrCtr Timer;					/* Instance of the Timer */
XGpio Buttons;					/* GPIO instance for the buttons */

volatile unsigned char timerFlag = 0;

// Timer interrupt service routine
void TimerISR()
	timerFlag = 1;
	// Clear interrupt status bit in control register
	XTmrCtr_SetControlStatusReg(XPAR_AXI_TIMER_0_BASEADDR, 0, XTmrCtr_GetControlStatusReg(XPAR_AXI_TIMER_0_BASEADDR, 0));

* This function connects the interrupt handler of the interrupt controller to
* the processor.  This function is seperate to allow it to be customized for
* each application.  Each processor or RTOS may require unique processing to
* connect the interrupt handler.
* @param	XScuGicInstancePtr is the instance of the interrupt controller
*		that needs to be worked on.
* @return	None.
* @note		None.
int SetUpInterruptSystem(XScuGic *XScuGicInstancePtr)

	 * Connect the interrupt controller interrupt handler to the hardware
	 * interrupt handling logic in the ARM processor.
			(Xil_ExceptionHandler) XScuGic_InterruptHandler,

	 * Enable interrupts in the ARM

	return XST_SUCCESS;

int InitInterrupts()
	int Status;

	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	GicConfig = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID);
	if (NULL == GicConfig) {
		return XST_FAILURE;

	Status = XScuGic_CfgInitialize(&InterruptController, GicConfig,
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;

	 * Setup the Interrupt System
	Status = SetUpInterruptSystem(&InterruptController);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;

	 * Connect a device driver handler that will be called when an
	 * interrupt for the device occurs, the device driver handler performs
	 * the specific interrupt processing for the device
	Status = XScuGic_Connect(&InterruptController, XPAR_FABRIC_TMRCTR_0_VEC_ID,
			   (Xil_ExceptionHandler)TimerISR, &Timer);

	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	// Enable the interrupt
	XScuGic_Enable(&InterruptController, XPAR_FABRIC_TMRCTR_0_VEC_ID);

	return XST_SUCCESS;

int main()

    int xStatus;

	//Step-1 :AXI GPIO Initialization
	xStatus = XGpio_Initialize(&Buttons,XPAR_BTNS_5BITS_DEVICE_ID);
	if(XST_SUCCESS != xStatus)
		print("GPIO INIT FAILED\n\r");
	//Step-2 :AXI GPIO Set the Direction
	XGpio_SetDataDirection(&Buttons, 1, 0xFF);
	//Step-3 :AXI Timer Initialization
	xStatus = XTmrCtr_Initialize(&Timer,XPAR_AXI_TIMER_0_DEVICE_ID);
	if(XST_SUCCESS != xStatus)
		print("TIMER INIT FAILED \n\r");
	//Step-5 :Setting timer Reset Value
	//Step-6 :Setting timer Option (Interrupt Mode, Auto Reload, Down Count )
	XTmrCtr_SetOptions(&Timer, XPAR_AXI_TIMER_0_DEVICE_ID,
	//Step-7 :Interrupt controller initialization
	xStatus = InitInterrupts();
	if(XST_SUCCESS != xStatus)
		print("INTERRUPT INIT FAILED \n\r");

    // Start the timer
    XTmrCtr_Start(&Timer, XPAR_AXI_TIMER_0_DEVICE_ID);

    while(1) {
    	u32 buttonValue = XGpio_DiscreteRead(&Buttons, 1);
    	xil_printf("Buttons = %d \n\r", buttonValue);
    	while(!timerFlag) {}
    	timerFlag = 0;

    return 0;

Code for Generating Random Numbers

The code below shows how to use srand() and rand(). Note that you will use a counter that you implement in your software in place of the time value. Note that this code does NOT compile on the Xilinx SDK. It is provided as an example of how to use functions that generate random numbers.

/* srand example */
#include <stdio.h>      /* printf, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */

int main ()
  printf ("First number: %d\n", rand()%100);
  srand (time(NULL));
  printf ("Random number: %d\n", rand()%100);
  srand (1);
  printf ("Again the first number: %d\n", rand()%100);

  return 0;


Demonstrate your Simon game for the TA when it is finished to pass-off. Print out and turn in the code file containing your synchronous state machine. Also turn in a state diagram of your state machine.

In addition, hand in feedback for this lab. Were there confusing or ambiguous parts of the lab specs? What major bugs did you have? This doesn't need to be long, a few highlights are sufficient. Also report how many hours the lab took you.

old_lab_4.txt · Last modified: 2019/04/08 20:11 (external edit)