LabReport

advertisement
ECSE 487
Experiment 1 Lab Report
Michael Dang’ana 110234458
Michael.dangana@mail.mcgill.ca
29-Jan-08
TABLE OF CONTENTS
1.
Methodology/implementation notes ............................................... Error! Bookmark not defined.
2.
Performance testing method and results .................................................................................. 14
References....................................................................................................................................... 16
Appendix A: Source Code ................................................................................................................. 16
1. Lab Description

Design Problem Part 1
The goal is to design an 8-bit 4-function barrel shifter, able to perform arithmetic right
shifts, logical left and right shifts and rotations. Two versions of the barrel shifter are desired
here: behavioural and structural. The behavioural model uses mainly signals and variables
and the process block, while the structural model uses combinational logic components and
storage elements (registers).

Design Problem Part 2
The goal is to design an 8-bit 4-function pipelined barrel shifter, able to perform arithmetic
right shifts, logical left and right shifts and rotations. The version desired here is pipelined.
Like the structural model it uses combinational logic components and storage elements
(registers). It could also be made behaviorally. However, parallelism is employed to allow for
issuance of multiple shift operations simultaneously. This maximizes throughput in the
design.
A structural approach has been taken due to the relative ease of adapting the structural
design of part 1 to a pipelined model. This ease is there because of the similarity between
the structural model explained in the instructions and the pipelined model required in Part
2. Parallelism is achieved by copying a single pipeline and allowing for issuance of inputs in
every clock cycle as opposed to once every 3 clock cycles in the structural model, and once
every 8 cycles in the behavioural model.
2. Behavioural Shift Register
a)
Methodology
Implementing this barrel shift register involved using multiplexers to decide the shift
function required and others to determine the relevant output bits. Each clock cycle
involved the execution of either 1 or 0 shifts, depending on the shift amount specified as
input. Multiple single shifts then add up to any arbitrary shift (0 up to 7) and a counter is
maintained to keep track of the number of shifts executed. This counter is present in VHDL
as signals and not instantiated as a block
3 bit counter (count)
Sinput
Clock
num (shift amount)
S (shift function)
soutput
Figure 1
b)
Source Code
See Appendix A
c)
Simulation Results
See vector file in Appendix B
The circuit was tested for all possible inputs using a visual basic for applications (VBA – part
of MS office) generated vector file. The generating code is in Appendix B. Outputs were
compared in MS excel 2003 to vector generated outputs created in VBA. A simple
comparison was done to determine the values where the circuit output differs from the
expected output. An auto-filter was used to select the error values and the necessary bug
fixes were done. The circuit outputs were generated by the test bench which read values
from the input vector file and run these through the circuit, collected the output and put it
in the output vector file.
Figure 2 below shows the simulation waveform. In it, 8 cycles after each input value is read
the output value is available. For an arithmetic right shift function (ss = 01) and a shift
amount of four (nums = 010), the following input/output pairs are shown: (datas =
11010111, data_out = 01011100) and (datas = 11011000, data_out = 01100000).
Figure 2: behavioural shifter simulation waveform
d)
Test bench and testing software code
See Appendix A for the test bench and Appendix B for the testing software. Also, attached is
the verification excel file containing the testing software functions and macros.
e)
Synthesis
See figure 1 above for the RTL schematic diagram. See Appendix A for the test bench and
Appendix B for the testing software. Also, attached is the verification excel file containing
the testing software functions and macros.
Maximum clock speed and critical path
Maximum clock speed is 91.988 MHz (10.871ns period) and the critical path has a slack of 0.87. This means that the critical path has a latency that is 0.87ns higher than the input clock
period of 10 ns.
As expected, the critical path is that through the counter (which has the most complex
internal logic cells like flip flops on each input and output, etc). Optimization could be made
by implementing this circuit with a simpler block. Instead of using a count process, the shift
amount signal (nums) could be decremented in each clock cycle using a basic adder. The
counter is avoided altogether. This would reduce the number of logic cells used, lowering
latency and circuit area.
Logic Cells
Below is a breakdown of the logic cells used in this circuit:
Total accumulated area :
Number of Dffs or Latches :
23
Number of Function Generators :
Number of MUX CARRYs :
Number of gates :
16
9
16
Number of accumulated instances :
82
Below is the schematic view of the circuit. Compared to the RTL view in figure 2 above, the
lookup tables (LUTs) implement the multiplexers, the D flip flops remaining present, and so
is the counter. Smaller logic cells like inverters and ports are also present, which each add
their own delays and latencies (like setup time, hold time, propagation delay, etc). In
general multiplexers are described by the ‘if’ statements in the VHDL code, D flip flops are
the data and control signals (sinput, S, snum), the counter is the constantly incremented
count variable and the function generators are for the various ‘1’ and ‘0’ bit signals used
inside the code during arithmetic and logical shifts.
The critical path and its optimization are discussed in the ‘Maximum clock speed and critical
path’ section above.
Figure 3: Schematic view of behavioural shift register
LUT = lookup table
FDE_x = D flip flops
S_int = S, shift function
num = shift amount
clk = clock
sinput = 8 bit input
soutput = 8 bit output
f)
Summary of resources and performance (throughput and latency)
For information on logic cell resources kindly see the ‘logic cells’ of section e above. Latency
is also described in the ‘critical path’ above.
Initial edge separation:
10.00
Source clock delay:
1.40
Dest clock delay:
+
-----------
1.40
Edge separation:
Setup constraint:
10.00
-
1.17
----------Data required time:
Data arrival time:
8.83
-
9.70
----------Slack (VIOLATED):
-0.87
These are the delay/latency summary metrics for the behavioural shifter. Delays are in
nanoseconds. Clock width (edge separation) was 10 ns during synthesis. The generated slack
was 0.87 ns mainly due to the critical path latency created by the counter, and also the
setup times at input ports and around the flip flops and multiplexers.
The throughput of the circuit is 1 full execution every 8 clock cycles. This is because every
cycle a single shift is done so a full 8 cycles is needed to execute the largest shift possible (a
shift amount of 111). As we shall soon see, this can be overcome by pipelining.
3. Pure Combinational Shift Register
a)
Methodology
This barrel shift register involved using multiplexers to decide the shift function required
and others to determine the relevant output bits. Each clock cycle involved the execution of
either 1 or 0 shifts, depending on the shift amount specified as input. Multiple single shifts
then add up to any arbitrary shift (0 up to 7) and a counter is maintained to keep track of
the number of shifts executed. This counter is present in VHDL as signals and not
instantiated as a block
3 bit counter (count)
Sinput
Clock
num (shift amount)
S (shift function)
soutput
Figure 1
b)
Source Code
See Appendix A
c)
Simulation Results
See vector file in Appendix B
The circuit was tested for all possible inputs using a visual basic for applications (VBA – part
of MS office) generated vector file. The generating code is in Appendix B. Outputs were
compared in MS excel 2003 to vector generated outputs created in VBA. A simple
comparison was done to determine the values where the circuit output differs from the
expected output. An auto-filter was used to select the error values and the necessary bug
fixes were done. The circuit outputs were generated by the test bench which read values
from the input vector file and run these through the circuit, collected the output and put it
in the output vector file.
Figure 2 below shows the simulation waveform. In it, 8 cycles after each input value is read
the output value is available. For an arithmetic right shift function (ss = 01) and a shift
amount of four (nums = 010), the following input/output pairs are shown: (datas =
11010111, data_out = 01011100) and (datas = 11011000, data_out = 01100000).
Figure 2: behavioural shifter simulation waveform
d)
Test bench and testing software code
See Appendix A for the test bench and Appendix B for the testing software. Also, attached is
the verification excel file containing the testing software functions and macros.
e)
Synthesis
See figure 1 above for the RTL schematic diagram. See Appendix A for the test bench and
Appendix B for the testing software. Also, attached is the verification excel file containing
the testing software functions and macros.
Maximum clock speed and critical path
Maximum clock speed is 91.988 MHz (10.871ns period) and the critical path has a slack of 0.87. This means that the critical path has a latency that is 0.87ns higher than the input clock
period of 10 ns.
As expected, the critical path is that through the counter (which has the most complex
internal logic cells like flip flops on each input and output, etc). Optimization could be made
by implementing this circuit with a simpler block. Instead of using a count process, the shift
amount signal (nums) could be decremented in each clock cycle using a basic adder. The
counter is avoided altogether. This would reduce the number of logic cells used, lowering
latency and circuit area.
Logic Cells
Below is a breakdown of the logic cells used in this circuit:
Total accumulated area :
Number of Dffs or Latches :
23
Number of Function Generators :
Number of MUX CARRYs :
Number of gates :
16
9
16
Number of accumulated instances :
82
Below is the schematic view of the circuit. Compared to the RTL view in figure 2 above, the
lookup tables (LUTs) implement the multiplexers, the D flip flops remaining present, and so
is the counter. Smaller logic cells like inverters and ports are also present, which each add
their own delays and latencies (like setup time, hold time, propagation delay, etc). In
general multiplexers are described by the ‘if’ statements in the VHDL code, D flip flops are
the data and control signals (sinput, S, snum), the counter is the constantly incremented
count variable and the function generators are for the various ‘1’ and ‘0’ bit signals used
inside the code during arithmetic and logical shifts.
The critical path and its optimization are discussed in the ‘Maximum clock speed and critical
path’ section above.
Figure 3: Schematic view of behavioural shift register
LUT = lookup table
FDE_x = D flip flops
S_int = S, shift function
num = shift amount
clk = clock
sinput = 8 bit input
soutput = 8 bit output
f)
Summary of resources and performance (throughput and latency)
For information on logic cell resources kindly see the ‘logic cells’ of section e above. Latency
is also described in the ‘critical path’ above.
Initial edge separation:
10.00
Source clock delay:
1.40
Dest clock delay:
+
-----------
1.40
Edge separation:
Setup constraint:
10.00
-
1.17
----------Data required time:
Data arrival time:
8.83
-
9.70
----------Slack (VIOLATED):
-0.87
These are the delay/latency summary metrics for the behavioural shifter. Delays are in
nanoseconds. Clock width (edge separation) was 10 ns during synthesis. The generated slack
was 0.87 ns mainly due to the critical path latency created by the counter, and also the
setup times at input ports and around the flip flops and multiplexers.
The throughput of the circuit is 1 full execution every 8 clock cycles. This is because every
cycle a single shift is done so a full 8 cycles is needed to execute the largest shift possible (a
shift amount of 111). As we shall soon see, this can be overcome by pipelining.
1.
2. Hardware
o Game, USART, Flash and Timer modules
See Lab Notes to assignment 2.
Modified game module to poll for keypad device interrupts instead of USART interrupts
for user input. See main.c in Appendix A.
o LCD display module
See Lab Notes to assignment 1.
Also available in segmentDisplay.c in Appendix A.
o Keypad module
Enables user input. Keypad is connected according to the schematic on the MSP430
keypad device manual2. Columns are connected to P1.3, P1.4 and P1.5 respectively
while the rows are as specified in the manual. There are no diodes.
The table below has the control register values at initialization. The only values to
change through the operation of the application are the last three: P1IES, P1IFG and
P1IE.
CONTROL
P1SEL
P3SEL
P1OUT
P1DIR
P3DIR
P3OUT
P1IES
P1IFG
P1IE
Value
= 0x00
&=~(BIT0 + BIT1 + BIT2 + BIT3)
= 0x00
&= ~(BIT3 + BIT4 + BIT5)
|= 0x0f
= 0x0f
= 0x00
= 0x00
= (BIT3 + BIT4 + BIT5)
Description
Selects Port 1 for IO
Selects Port 3 for IO
Clears port 1 of charge
Sets port 1 as an input port
Sets port 3 as an output port
Sets pins 3.0 - 3.3 (rows) to high
Enables low-high (edge-select) interrupts
Clears interrupt flags on port 1
Enables interrupts on pins 1.3, 1.4 and 1.5
Table 1
Port 1 interrupts are turned off during the key press and key release events (P1IE =
0x00) and turned on when each event is complete (see last row of table 1). The
interrupt service routine simply asserts the key event flag and turns off interrupts.
Polling of the flag is done by the playgame function (as shown above).
3. User interface
User input is done via the keypad device while output is on the terminal emulator and LCD
display device. Menus are used because user input is simple and requires only single
character responses. At any time while the application is running, player scores can be
toggled on the hex display (2 digit values ranging from 0 to 99) using the ‘*’ and ‘0’ keys of
the keypad (where ‘*’ stands for player X and ‘0’ stands for player O). These values are
retrieved from the flash memory device. At the end of each game, users are given the
option to start a new game, reset the score or quit the game, for which the inputs are now
‘2’, ‘1’ and ‘3’ respectively. These changed from ‘r’, ‘n’ and ‘q’ used in lab 2 because of the
limited key variety on the keypad.
3. Performance testing method and results
For testing on game, USART, flash and timer modules, see lab 2 performance and testing section. The
game module was retested for seamless coupling with the keypad device because in lab 2 the keyboard
was used for input. Re-executed test cases TC1, TC2 and TC4 had the same results as in lab 2 (PASS).
Refer to Lab 2 notes for these. TC3 was re-executed as part of the keypad module test suite. The test
case identifiers used in this lab have no link to those used in lab 2.
Module: keypad
ID: Test case title
TC1: Prolonged key press
Test case title
Purpose
Test if pressing a key for a
long duration will cause
multiple key inputs
Board drawn and awaiting
input
n/a
Purpose
Steps
1. Press and hold a key for a
minute
Steps
Results
PASS; only one key is read
Results
Notes
n/a
Notes
ID: Test case title
Purpose
TC3: Keypad overflow
Try pressing multiple keys at
the same time to see if input
occurs and which key is read
ID: Test case title
Purpose
Prerequisites
Board drawn and awaiting
input
n/a
1. Press multiple keys at the
same time
Prerequisites
PASS; none of the keys is
accepted.
Results
Prerequisites
Test data
Test data
Steps
Results
Prerequisites
Test data
Test data
Steps
TC2: Key pressed before
another is released
Test if key input can occur
while a key is pressed and
held down
Board drawn and awaiting
input
n/a
1. Press and hold a key
2. Press many other keys
one at a time
3. Release held key
PASS; Only one key input
occurs: that of step 1
n/a
TC4: Debounce delays
Run under different
debounce delays to
determine the lowest
acceptable delay
Board drawn and awaiting
input
n/a
1. Input key with bounces
lasting 2 ms (using timer A
to bounce P1.3, P1.4 or
P1.5)
2. Check to see if key is
correctly read
3. Repeat steps 1-2 10 times
with bounces increasing
by 2 (i.e. 2ms, 4ms, etc)
until bounces last 20ms.
4. Adjust the debounce
period and repeat steps 13 until there are no input
errors.
PASS; No key input errors
detected for 20ms debounce
Notes and
Questions
If one key is pressed slightly
ahead of the other, it will be
read
Notes and Questions
Test case did not run well
however because
oscilloscope readings of the
pin values were not
successful when timer A was
running.
TC5: Toggle player scores
during a game using * and 0
keys
Test if hex display works at all
times during a game
Test case title
Board drawn and awaiting
input
n/a
Prerequisites
TC6: Toggle player scores
after a game when waiting
for user input
Test if hex display works at all
times when waiting for a user
response
Game menu displayed and
awaiting user response
n/a
1. Press the * and 0 keys,
alternate between them
PASS; Correct player scores
are displayed on the LCD
n/a
Steps
Module: Segment (LCD hex) display
ID: Test case title
Purpose
Prerequisites
Test data
Steps
Results
Notes
Purpose
Test data
Results
Notes
1. Press the * and 0 keys,
alternate between them
PASS; Correct player scores
are displayed on the LCD
n/a
References
1. Lab 3 instructions (McGill Webct > Microprocessors > Home Page > Experiment Assignments > Lab 3 > LabExperiment3_Fall2007)
2. http://www.cs.mcgill.ca/~mdanga2/courses/ecse426/a3/keypadDoc.pdf > page 2
Appendix A: Source Code
/*************************************************************
*****************
File: main.c
Author: Theodore Herman & Michael Dang'ana
Date: 24 Oct 2007
Turns off watchdog timer and Oscillator faults
Initializes MSP430P140 keypad and USART devices and the game module
Enables interrupts and runs the game
**************************************************************
***************/
#include <msp430x14x.h>
#include <usartio.h>
#include <keypad.h>
#include <game.h>
void main(void)
{
unsigned int i; //Utility counter
/* Stop watchdog */
WDTCTL = WDTPW + WDTHOLD;
/* Turn on the XT2 oscillator and stabilize it*/
BCSCTL1 &= ~XT2OFF;
/* Clock stabilization loop */
do
{
IFG1 &= ~OFIFG; // Clear OSCFault flag
for (i = 0xFF; i > 0; i--); // Time for flag to set
}
while ((IFG1 & OFIFG) != 0); // OSCFault flag still set?
/*
* Choose the MCLK source, SMCLK source, divider for SMCLK,
* Select XT2 for MCLK, select XT2 for SMCLK
*/
BCSCTL2 = SELS + SELM_2; // use the 8MHz clock
// initialize the USART, the board (tic tac toe game), and enable interrupts
initKeypad();
initUsart();
initBoard();
_EINT();
// play the game
playGame();
while(1); /* this is end of program, to keep it from starting over */
}
/*************************************************************
*****************
File: game.h
Author: Theodore Herman & Michael Dang'ana
Date: 05 Oct 2007
Defines the functions and constants for the tic tac toe game. It assumes
that
I/O is done through the USART0 and that the number of X wins and O wins
are stored
in the flash memory
**************************************************************
***************/
#ifndef __game
#define __game
#define GAME_STARTED (0) // a game state denoting a game that has
started but not completed
#define GAME_FINISHED (1) // a game state denoting a completed game,
waiting for user input
#define GAME_EXIT (2) // a game state denoting the user wants to quit
the game
#define BUFFER_EMPTY (0) // denotes that the USART buffer is empty
#define BUFFER_FULL (1) // denotes that the USART buffer is full
#define CHAR_NEW_GAME '2'
// the character the user must press
to start a new game
#define CHAR_RESET_SCORE '1'
// the character the user must press
to reset the score
#define CHAR_QUIT
'3'
// the character the user must press to quit
the game
Input: char xter the location of the next letter that the user wants to
place
Output: Places the X or O on the board if xter is a valid position
*/
void placeLetter(char xter);
/*
#define FLASH_PW_ADDR (0xF000) // the address in flash memory to
store the "password"
#define FLASH_PW_VAL (55) // the "password" value
#define FLASH_X_WINS_ADDR (0xF001) // the address to store the number
of X wins
#define FLASH_O_WINS_ADDR (0xF002) // the address to store the number
of O wins
#define INPUT_DELAY_MS
250
// the delay in milliseconds in
between placement of the character (X or O) before the move is executed
#define CLEAR_BOARD_DELAY_MS 2000
// the delay in milliseconds
after the user inputs the control character before the screen is reset
/*
Input: none
Output: handles high-level game control, calling other game functions to
perform lower-level
functionality
*/
void playGame(void);
/*
Input: none
Output: Draws the current state of the board onto the USART
*/
void drawBoard(void);
/*
Input: none
Output: Initializes the actual board array, game state, and flash
memory (if it has not yet been initialized)
*/
void initBoard(void);
/*
Input: none
Returns: char the winner of the current game (either 'X' or 'O')
or must return '' if the game has not finished
or must return 'T' if the game is a tie
*/
char getWinner(void);
/*
Input: char winner the winner of the game
Output: A string of text indicating who won the game, and the total win
count for X and O.
Also changes the state of the game to finished, and displays a screen for
the user to choose their
action (new game, reset score, quit game)
*/
void declareWinner(char winner);
/*
Input: none
Returns: 1 if the user wishes to exit the game, 0 otherwise
*/
int exitGame(void);
/*
Input: none
Output: takes the character stored in the buffer and passes it to the
appropriate function, depending on the game state
Returns: 0 if the buffer was empty and had nothing to do, 1 if the buffer
was full and the character was passed to a function
*/
int emptyTheBuffer(void);
/*
Input: char input the character entered by the user
Output: Depending on the validity of input, applies a delay, then sets the
game in the appropriate state
*/
void handleEndOfGameSelection(char input);
#endif
/*************************************************************
*****************
File: game.c
Author: Theodore Herman & Michael Dang'ana
Date: 05 Oct 2007
Implementation of the Tic Tac Toe functions
Augmented to use McGumps keypad as input
**************************************************************
***************/
#include <msp430x14x.h>
#include <game.h>
#include <usartio.h>
#include <timer.h>
#include <flashio.h>
#include <keypad.h>
#include <segmentDisplay.h>
/*Board spot values, input buffer and LCD flag to indicate which player
is currently on the hex display*/
char board[3][3], inputBuffer, hexkey;
/*Player variable to show which player made the last move played,
Game state variable to show the state the game is in, and
Buffer state variable to show the state of the buffer*/
int player, gameState, bufferState;
void updateHexDisplay(char control);
/*
Input: none
Output: handles high-level game control, calling other game functions to
perform lower-level
functionality
*/
void playGame(void)
{
char winner, key;
// print instructions
printNewLines(15);
prints("Welcome to Tic Tac Toe v2.0\r\n");
prints("Use the number keypad on the McGumps board to play\r\n");
prints("Number positions match board positions\r\n");
prints("O goes first\r\n");
hexkey = '0';
updateHexDisplay(hexkey);
//initTimerA(); //Testing debounce function
//timerA_delay(2); //Testing debounce function
updateHexDisplay(hexkey);
while(!getNewKeyEvent());
//SetBouncesNum(10); //Testing debounce function
key = readkey();
if (key == '*' || key == '0') {
hexkey = key;
updateHexDisplay(hexkey);
key = '\0';
}
} while (key == '\0');
// if the game is over, pass the character to the end of game function
if (gameState == GAME_FINISHED) handleEndOfGameSelection(key);
else placeLetter(key);
if(exitGame()) // check to see if the user has requested to exit the game
break;
}
// user quit the game, print a goodbye screen
prints("Goodbye!");
}
// play the actual game
while(1)
{
//Wait until user decides to quit, reset or restart
if (gameState != GAME_FINISHED) {
drawBoard(); // draw the board
winner = getWinner(); // check if a winner exists
if (winner != '') declareWinner(winner); // if it does, declare the winner
}
do
{
/*
Input: char xter the location of the next letter that the user wants to
place
Output: Places the X or O on the board if xter is a valid position
*/
void placeLetter(char xter)
{
// determine the position that the user wants to go
int pos = xter - '1';
}
// validate the position
if(xter >= '1' && xter <= '9' && board[pos / 3][pos % 3] == ' ')
{
// toggle the player and place the character on the board
player ^= 0x01;
if (player==0) board[pos / 3][pos % 3] = 'X';
else board[pos / 3][pos % 3] = 'O';
}
if (gameState != GAME_FINISHED) printNewLines(10);
}
// output the board structure
if (count1 != 2) {
for (count2=0; count2<=4; count2++) sendXter('-');
printNewLines(1);
}
}
}
}
void drawBoard(void)
{
int count1, count2; // loop variables
for (count1=0; count1<3; count1++)
{
for (count2=0; count2<3; count2++)
{
// output the character at the given board position
sendXter(board[count1][count2]);
// output a separator if necessary
if (count2<2)
sendXter('|');
else
{
sendXter('\r');
sendXter('\n');
void initBoard(void)
{
int count1, count2;
for (count1=0; count1<3; count1++)
for (count2=0; count2<3; count2++)
board[count1][count2] = ' '; // initialize the board to ' ' characters
player = 0; // the first player is O
// check to see if the flash memory has been initialized
if (flashread((char *)FLASH_PW_ADDR) != FLASH_PW_VAL)
{
// if not, erase the segment, then write FLASH_PW_VAL into
FLASH_PW_ADDR and 0 into the X and O win count
flasherase((char *)FLASH_PW_ADDR);
flashwrite(FLASH_PW_VAL, (char *)FLASH_PW_ADDR);
flashwrite(0, (char *)FLASH_X_WINS_ADDR);
flashwrite(0, (char *)FLASH_O_WINS_ADDR);
}
gameState = GAME_STARTED;
{
}
// assume tie and then check to see if any space is still available
winner = 'T';
for(count = 0; count < 3; count++)
for(count2 = 0; count2 < 3; count2++)
if(board[count][count2] == ' ')
winner = '';
char getWinner(void)
{
int count, count2; // loop counter variables
char winner = ''; // assume no winner
// Check horizontal winner
for (count=0; count<3 && winner==''; count++)
if (board[count][0] != ' ' && board[count][0]==board[count][1] &&
board[count][1]==board[count][2])
winner = board[count][0];
// Check vertical winner
for (count=0; count<3 && winner==''; count++)
if (board[0][count] != ' ' && board[0][count]==board[1][count] &&
board[1][count]==board[2][count])
winner = board[0][count];
// Check diagonal winner
if (board[0][0] != ' ' && board[0][0]==board[1][1] &&
board[1][1]==board[2][2])
winner = board[0][0];
if (board[0][2] != ' ' && board[0][2]==board[1][1] &&
board[1][1]==board[2][0])
winner = board[0][2];
// if no winner yet, check to see if the game is a tie
if(winner == '')
}
return winner;
}
void declareWinner(char winner)
{
char xwins, owins; // the number of X wins and O wins, respectively
gameState = GAME_FINISHED;
// get the number of X wins and O wins from the flash memory
xwins = flashread((char *)FLASH_X_WINS_ADDR);
owins = flashread((char *)FLASH_O_WINS_ADDR);
// increment the winner's score, and store it back in flash memory
flasherase((char *)FLASH_PW_ADDR);
if (winner == 'X') xwins++;
else if(winner == 'O') owins++;
flashwrite(FLASH_PW_VAL, (char *)FLASH_PW_ADDR);
flashwrite(xwins, (char *)FLASH_X_WINS_ADDR);
flashwrite(owins, (char *)FLASH_O_WINS_ADDR);
// display the winner of the game, or a tie message, if it's a tie
if(winner == 'X' || winner == 'O')
{
sendXter(winner);
prints(" wins the game!");
}
else if(winner == 'T')
{
prints("Tie game!");
}
// display the total number of wins for each player
prints("\r\n\r\nNumber of X wins: ");
sendInt(xwins);
prints("\r\nNumber of O wins: ");
sendInt(owins);
// print out an instructional message on the user's available actions
prints("\r\nChoose one of the following:\r\n");
prints("1\t-\tReset the score (and start a new game)\r\n");
prints("2\t-\tNew game\r\n");
prints("3\t-\tQuit\r\n");
}
int emptyTheBuffer(void)
{
if (bufferState == BUFFER_FULL)
{
if (gameState == GAME_STARTED)
{
// if the game has started but not ended, wait INPUT_DELAY_MS
milliseconds
// and then place the letter on the board
softwareDelay(INPUT_DELAY_MS);
placeLetter(inputBuffer);
}
else if (gameState == GAME_FINISHED)
{
// if the game is over, pass the character to the end of game function
handleEndOfGameSelection(inputBuffer);
}
bufferState = BUFFER_EMPTY;
return 1;
}
else return 0;
}
int exitGame(void)
{
if(gameState == GAME_EXIT)
return 1;
else return 0;
}
void handleEndOfGameSelection(char input)
{
switch(input)
{
case CHAR_NEW_GAME:
prints("Starting new game...\r\n");
softwareDelay(CLEAR_BOARD_DELAY_MS);
printNewLines(10);
initBoard();
break;
case CHAR_RESET_SCORE:
prints("Game score reset...\r\n");
flasherase((char *)FLASH_PW_ADDR);
softwareDelay(CLEAR_BOARD_DELAY_MS);
printNewLines(10);
initBoard();
break;
case CHAR_QUIT:
prints("Quitting game...\r\n");
softwareDelay(CLEAR_BOARD_DELAY_MS);
printNewLines(15);
gameState = GAME_EXIT;
break;
}
}
void updateHexDisplay(char control) {
char xwins, owins; // the number of X wins and O wins, respectively
// get the number of X wins and O wins from the flash memory
xwins = flashread((char *)FLASH_X_WINS_ADDR);
owins = flashread((char *)FLASH_O_WINS_ADDR);
//Modify wins to display as decimal numbers on hex display
xwins = xwins + 6 * ((int)xwins / 10);
owins = owins + 6 * ((int)owins / 10);
/* Set P1.0 and P5 as output ports */
P5DIR = 0xFF;
//Display wins on hex display
if (control == '*') display_num(xwins);
if (control == '0') display_num(owins);
}
/*
This function simulates key press bounces to ease testing of the debounce
delay
*/
void simulateKeyBounce(int interval_ms) {
}
/*************************************************************
*****************
File: keypad.h
Authors: Theodore Herman & Michael Dang'ana
Date: 20 Oct 2007
Purpuse: The Keypad module allows for manipulation of the MSP430
Keypad device
. The three functions (initKeypad, readkey and getNewKeyEvent) allow for
initialization and use of the MSP430 keypad device
Function code is available in keypad.c
**************************************************************
***************/
#ifndef __keypad
#define __keypad
#define FALSE
(0) //Boolean 'false' defined as zero
#define TRUE
(1) //Boolean 'true' defined as one
#define DEBOUNCE_DELAY_MS (10) //Debounce delay in milliseconds
/*
Initializes the keypad device
Assumes PORT1 is connecting to the columns, PORT3 is connected to the
rows
*/
void initKeypad(void);
/*
Reads a pressed key based on row and column values
Returns the char value of the key
*/
char readkey(void);
/*
Returns the value of the 'keyevent' variable
Allows for key event polling
*/
int getNewKeyEvent(void);
#endif
/*************************************************************
*****************
File: keypad.c
Authors: Theodore Herman & Michael Dang'ana
Date: 20 Oct 2007
Purpuse: The Keypad module allows for manipulation of the MSP430
Keypad device
. The three functions (initKeypad, readkey and getNewKeyEvent) allow for
initialization and use of the MSP430 keypad device
**************************************************************
***************/
#include <keypad.h>
#include <cross_studio_io.h>
#include <msp430x14x.h>
#include <timer.h>
int keyevent = FALSE; //Indicates that a key event (key press or release) has
occured
int keypress = TRUE; //First keyevent should be a key press
char key = '\0';
//Value of last key pressed
/*
Initializes the keypad device
Assumes PORT1 is connecting to the columns, PORT3 is connected to the
rows
*/
void initKeypad(void) {
// Set P1 as input port and P3 as output port
P1SEL = 0x00; //Select Port 1 for IO
P3SEL &= ~(BIT0 + BIT1 + BIT2 + BIT3); //Select Port 3 for IO
/*P1DIR = 0x0f; //Set port 1 as an output port
P1OUT = 0x00; //Clear port 1 of charge*/
P1DIR &= ~(BIT3 + BIT4 + BIT5); //Set port 1 as an input port
P3DIR |= 0x0f; //Set port 3 as an output port
P3OUT |= 0x0f; //Set pins 3.0 - 3.3 (rows) to high
/*Enable low-high (edge-select) interrupts and interrupt flags on port 1
& Enable interrupts on port 1*/
P1IES = 0x00;
P1IFG = 0x00;
P1IE = (BIT3 + BIT4 + BIT5); // bits 1,2,3 can cause interrupts on port 1
}
/*
Reads a pressed key based on row and column values
Returns the char value of the key
*/
char readkey(void) {
int col, row, i, keymask, identifier;
key = '\0';
keyevent = FALSE; //Turn off key-press flag
softwareDelay(DEBOUNCE_DELAY_MS);//Debounce for
DEBOUNCE_DELAY_MS milliseconds
if (keypress) {
keypress = FALSE; //Next event expected should be a key release
//Determine the column value
col = P1IN;
col &= BIT3 + BIT4 + BIT5; // clear all other bits on P1 since they're not
relevant
//Determine the row value
/*
Check for Port 1 inputs when row = 1
*/
row = -1;
for (i=0; i<4; i++) {
keymask = 1 << i; //Rotate keymask
P3OUT = keymask; //send to row inputs. Only 1 row asserted
if (P1IN & (BIT3 + BIT4 + BIT5)) row = i; //check if Port 1 bit is asserted
to see if
}
// it is the right row
//Row and column values ascertained. Translate to key character
identifier = ((row+1) << 8) + col;
switch (identifier) {
case 800: key = '1'; break;
case 776: key = '2'; break;
case 784: key = '3'; break;
case 1056: key = '4'; break;
case 1032: key = '5'; break;
case 1040: key = '6'; break;
case 288: key = '7'; break;
case 264: key = '8'; break;
case 272: key = '9'; break;
case 544: key = '*'; break;
case 520: key = '0'; break;
case 528: key = '#';
}
/*Enable high-low (edge-select) interrupt for key release and interrupt
flags
on port 1 & Enable interrupts on port 1*/
//debug_printf("%c",key);
P1IES = (BIT3 + BIT4 + BIT5);
P1IFG = (BIT3 + BIT4 + BIT5);
P1IE = (BIT3 + BIT4 + BIT5);
//P1IFG = 0x00;
//P1IE = 0x07;
}
else { //Key release
keypress = TRUE; //Next event expected should be a key press
/*Enable low-high (edge-select) interrupts and interrupt flags on port 1
& Enable interrupts on port 1*/
P1IES = 0x00;
P1IFG = 0x00;
P1IE = (BIT3 + BIT4 + BIT5);
}
P3OUT |= 0x0f; //Drive rows to high
return key;
}
/*
Returns the value of the 'keyevent' variable
Allows for key event polling
*/
int getNewKeyEvent(void)
{
if(keyevent == TRUE)
return TRUE;
else
return FALSE;
}
/*
Returns the value of the 'keyevent' variable
Allows for key event polling
*/
void p1isr(void) __interrupt[PORT1_VECTOR]
{
keyevent = TRUE; //Set key press interrupt flag
//P1IFG = 0x00; //Clear Port 1 interrupt flags
P1IE = 0x00; //Turn off interrupts
}
Download