Introduction: CPE 133 Beat the Countdown
In this tutorial, we will be building a game that generates a pattern that the player attempts to guess before time runs out. The game utilizes several pieces of hardware to create an experience for the player where they must attempt to keep their cool when every mistake they make cuts their remaining time in half. The device also contains a method for pseudo randomly generating the number that the user is going to guess. During gameplay, a clock and speaker enhance the experience by reminding the player just how fast time is flying by. If the player guess the pattern correctly before time runs out, the game shows the user the word “success” letting them know they finished the game before time ran out. Although, if the user is unable to find the pattern in time the device reminds them with the word fail that they are hopeless. After this reminder, the user can press any button to return themselves to the welcome screen of the game. The game also features a hard reset button for the shameless losers who can’t face their inevitable defeat. This example is the simplest version of the game, but the game can be augmented in several different ways depending on the builders wishes. The speaker can be set to program sounds for all different phases of the game, or the game can be set to record best time for the winners. It can also be set to work with a 24 bit input if the user wishes for a more challenging experience.
Step 1: Device Structure
The main functionality of the device is controlled
within the state driver. This contains all 4 stages of the games. The intro state, the difficulty selection state, and the end state. The State Controller is a FSM which outputs the current value of state as a 4 bit binary bus. The functionality of the device can be broken down into several segments.
The button segments are always active, and they allow the user to select game difficulty, enter the difficulty selection mode, and reset the device when necessary. The button segments take in an input and outputs to other modules.
The difficulty Driver is a state machine with three states: easy, medium, and hard. This module has two functions. The first is a driver for the seven segment display to display the words for the actual difficulty. The second function is to output a 16 bit bus to the game module.
The final modules are all related specifically to the seven segment display. The end, init, and game drivers all map to specifically to the seven segment display. The outputs are sent through the SSEG select module, and depending on the state being sent from the state machine the module sends four of the buses to the SSEGDriver.
In the next step, we will be walking through the construction of each particular module.
Step 2: Button Modules
The button module is probably the most finicky module in the whole device. The designer has to take into account debounce to create a button that goes high only when they push it. We found that 100 mS appears to be enough to verify that the user has actually pushed the button down. The button module is the only part of the program where the module can run independent of the state controller.
The module needs the following inputs and outputs:
raw_input(This is mapped to the actual buttons on the device)
clk(this is the 100 MHz clock that is always running on the device)
When the input raw_input goes high, it acts like a chip enable and a counter begins counting(up to 100 mS). If the counter overflows and the input raw input is still high, the value debounced output goes high. When raw input drops back to low, both the counter and the value of debounced output drop back down to low.
Step 3: State_Controller
The state controller acts as the brain for the whole device. Its I/O are as follows: The state machine takes several inputs used to change the internal game state. These include the game over, center_button, and reset inputs. It also includes the clock which is how it acts to switch between the states. There is only a single output. The state output is a 4 bit bus that the other modules use to define their behavior. The basic cycle can be seen in one of the images above. When the resets are included the module changes significantly, but for the purposes of understanding the basic gameflow, the image works pretty well.
Step 4: Difficulty Driver
The difficulty driver module is a state machine that outputs the current difficulty when in a particular state. It also outputs the buses used to identify the text that will be sent to the seven segment display. The left button and right button modules are used to switch between states. If either of the two buttons is high then the machine follows the logic in the diagram above. If for some reason the module enters an unknown state it defaults back to the easy state. because of the extremely short time for the debounce on the button modules, if the player pushes both buttons, the state will simply follow the order in which the buttons were pushed.
The difficulty driver outputs 4 six bit buses that represent letters in the word for the current difficulty. The possible words are Easy, Fair, and Hard. The module internally uses a display_word module to scroll through a larger number of letters. When the display_word module changes one of the four buses out, the difficulty driver output changes as well.
The outputs for the 16 bit difficulty bus are dependent on the state the module is currently in. If in the easy state, the output is a bit mask that will specify the pattern for only the 4 least significant digits in the bus. If in the medium state, the output is a medium bit mask which specifies the pattern for the 8 least significant digits. If the state is hard, the bit mask uses all of the bits in the bus.
Step 5: Initial State Driver
This submodule is dedicated to displaying "HELLO" on the seven segment display when the state controller is in the 'init' state. The only input to this module is a clock signal. The clock signal enables the driver to effectively scroll its text every 500 ms across the seven segment display. The four outputs represent a character currently being sent to display on the seven segment.
Step 6: The Game Driver
This is the module which controls the countdown timer, pattern generation, and pattern matching of the game. When the state controller is in the 'game' state, the game driver is turned on. This game driver will then read the difficulty input and use it to generate a pattern for the user to solve.
Once the pattern is generated, the clock signal is used to drive an internal countdown timer which is displayed on the seven segment. The countdown timer starts at 240 s in hard mode, 60 s in fair mode, and 30 s in easy mode.
The user input corresponds to the actual positions of the 16 switches on the Basys-3 board. Whenever a switch position has changed, the game driver will test to see if the new input matches the pattern. If the pattern matches, then the win output is pulled high and the state controller changes to the 'end' state. If the pattern does not match, then the degree to which it does not match is evaluated. If 2 or more switches are out of position, the countdown timer will increase in speed by a factor of two. If this timer reaches zero, the lose signal is pulled high and the state controller switches to the 'end' state.
Step 7: The End Driver
This module is tasked with displaying "SUCCESS" or "FAILURE" on the seven segment display. It does this based on the current state in addition to the win and lose signals.
When the current state matches the 'end' state, the driver will evaluate the win and lose signals to determine which message to display. If the win signal is high the message will be "SUCCESS". If the lose signal is high the message will be "FAILURE". When both signals are high, which does not happen, the message will default to "SUCCESS". We are not completely heartless.
Step 8: The SSEG Select Driver
This module is in charge of displaying the proper message on the seven segment display. It uses the seven segment outputs from each of the other drivers combined with the current state from the state controller.
The 16 seven segment inputs are subdivided into groups of four. Each group corresponds to either the difficulty driver, game driver, init driver, or the end driver. The 4 seven segment outputs are driven according to the value on the state input bus. For example, when the state matches 'difficulty' the difficulty seven segment inputs are routed to the module's outputs.
Step 9: The SSEG Driver
This module is directly connected to the Basys-3 board's seven segment display. It is tasked with generating the correct timings in addition to anode and cathode configurations to display messages.
The module has a clock input as well as 4 seven segment character inputs. The clock input is divided internally to 200 Hz for a non-flickering display. Since the display is common cathode, every 1/200 seconds the anode configuration is switched. For example, if the current anode configuration is "1110" (left digit is on), after 1/200 s the configuration changes to "1101" (2nd from the left is on). This process runs continuously from: "1110"=>"1101"=>"1011"=>"0111"
The 4 seven segment character inputs are routed through a large case statement which maps the the character into the correct cathode configuration. Each cathode configuration is 8 bits wide since there is a decimal point on the Basys-3 board's display.
Step 10: The Word_Key Module
The word key module handles all of the possible word combinations that the device outputs to the seven segment display. However, it does not handle the countdown timer. The word key module takes in a 3 bit binary input which acts as a key for the different words the device uses. The device then outputs the 6 bit buses that represent the letters in the word. In this device, the maximum word size the device handles is 8 letters. If the word does not contain 8 letters, the remaining bits act as spaces.
Step 11: The Pattern Generator
The pattern generator module generates the pattern that the player will be attempting to guess. The generator takes in a clock input as well as a reset. It outputs the 15 bit pattern the user will play against. The module has a counter that counts up on every clock pulse. It counts to the value when every bit in the 16 bit counter bus is high then it resets back to zero and starts counting again. When the falling edge of the reset button occurs the module outputs the current value of the counter to the 16 bit bus. This allows for pseudo random number generation due to the high speed of the clock.
Step 12: The Display Word Module
The Display_Key module is the module that scrolls through the 8 letters sent to it. It contains the Key_Map module described previously. The inputs it takes in are the clock input and the 3 bit bus used for the key module. The module then outputs 4 of the 8 outputs from the key map. The 4 outputs change every 500 ms. This is done by including an internal counter with a maximum value of 7. Every 500 ms the counter increments. Depending on the value of the the counter the 4 output bits change. This allows for the scrolling text.
Step 13: The Trap Module
The Trap module is tasked with evaluating the user input and setting a 'trap'. In this scenario, the trap will divide the current time remaining by 2. A trap is set off anytime the player has 2 or more switches in the high position that do not match the generated pattern.
Inside the module, the user input is OR'd with the pattern and then XOR'd with the pattern. This yields a 16 bit bus that contains 1's anywhere that do not match with the current pattern. These 1's are then summed together to define a magnitude of error. If this magnitude of error is greater than or equal to 2 the trap is executed.
The output is a clock signal which routes directly to the countdown timer. So by increasing the outputs frequency by a factor of two, the timer the counts down twice as fast.
Step 14: Comparing User Inputs to the Pattern
This module compares the bitmask outputted from the difficulty select with the generated 16 bit pattern to decide which bits to use for the actual gameplay. The resulting 16 bit number is then compared against the 16 bit input from the player which has also been compared to the bitmask. If the inputs match, the result goes high, otherwise the result stays low.
Step 15: Countdown to BCD for Display
This module is tasked with converting the time remaining on the countdown into a binary converted decimal. What this does is allow the countdown value to be displayed appropriately on a seven segment display.
The current time remaining is sampled and processed through an algorithm known as the shift-add-3 or double dabble algorithm. This algorithm has been setup to convert an 12 bit input into BCD form.
The module then outputs the ones, tens, hundreds, and thousands place of the remaining time.
Step 16: Timer Module
The timer module handles the countdown clock for the game. It takes the output from the difficulty select and depending on the value, it initializes a counter of 30 seconds, 60 seconds, or 240 seconds. The device has two outputs a remaining time bus that outputs the time left in the counter, and an out of time output that will be used to trigger the controller state to go into the end game state. Depending on how soft the user wishes to be on the player, they can add extra time to the game states. This can be done simply by changing the size of the internal counter signals to a larger number.
Step 17: The Buzzer Module
This module controls the speaker for the game. The speaker is an external module, and the game can function fine without it, but the speaker adds both tension and excitement to the game. The constant beeping of the speaker reminds the player that with every beep they are one second closer to failure. There are three inputs: clock, reset, and countdown. When the reset input is high it resets the internal counter. When the reset input is low and the countdown input is high the buzz output goes high. This signal goes to the speaker which generates the sound.
Step 18: Device Constraints File
This file is the constraints file for the device. It routes the signals in the Device Wrapper to the physical pins on the board. This includes the switches, buttons, pmod connectors, and seven segment display. The clock is also set in the constraints file to a 100 MHz clock.