/*************************************** This program was produced by the CodeWizardAVR V1.0.0.7 Standard Automatic Program Generator © Copyright 1998-2000 Pavel Haiduc Project : EE 476 Spring 2000 Final Project Version : 1.00 Date : 4/26/2000 Author : Jonathan Wicks and Victor Tao Company : Cornell University, Ithaca, USA Chip type : AT90S8515 Clock frequency : 4.000000 MHz ***************************************/ #include <90s8515.h> #include #include //Global variables unsigned char snake[64]; //This variable stores the orientation of each piece of the snake (bit-packed) unsigned char apples[2][20]; //This stores the apples in (x,y) coordinate pairs, max number of apples is 20 unsigned char randState; //This stores the random number seed, used by rand() function //LCD functions void resetLCD(); void clearGraphicsMem(); void clearTextMem(); void setText(unsigned char ch, unsigned char x, unsigned char y); void setPixel(unsigned char x, unsigned char y); void clearPixel(unsigned char x, unsigned char y); unsigned char readPixel(unsigned char x, unsigned char y); void status(unsigned char statusVal); unsigned char readData(); void writeData(unsigned char data); void writeCmd(unsigned char command); //Snes controller functions unsigned char getInput(); //Game play functions void startupScreen(); void gameOverScreen(unsigned char value); void printScore (unsigned char value); //Miscellaneous functions unsigned char rand (); //Start of actual code void main(void) { //Local variables unsigned char isApple[3]; //This variable tells us which apples are still on the screen (bit-packed) unsigned char headx,heady; //Stores the x and y coordinates of the head (in screen coordinates) unsigned char tailx,taily; //Stores the x and y coordinated of the tail (in screen coordinates) unsigned char eating; //Keeps track of how much the snake has eaten (gets decremented after each turn) unsigned char direction; //Stores the data that the controller sends back unsigned char snakeHead, snakeTail; //A pointer to the head and the tail values in the snake[] array unsigned char temp, temp2; //Two temporary variables used throughout the code unsigned char die; //Keeps track of if we are dead, or have won the game unsigned char numOfApples; //Stores how many apples are left on the screen unsigned char score; //Stores the value of the score unsigned char timer; //A timer used to keep track of when we need to decrement the score unsigned char timerLookup[10]; //A lookup table which tells the timer value based on the delay variable unsigned char applex, appley; //Temporary variables to help move the apples around unsigned char delay; //Keeps track of how fast the game play is //This defines the ports for the assembly language code used later #asm .equ PORTA =$1b .equ DDRA =$1a .equ PINA =$19 .equ PORTB =$18 .equ DDRB =$17 .equ PINB =$16 .equ PORTC =$15 .equ DDRC =$14 .equ PINC =$13 .equ PORTD =$12 .equ DDRD =$11 .equ PIND =$10 #endasm while (1) { //SNES CONTROLLER //We Make all of the pins outputs except for Pin0 since it reads the data from the controller //Also put pin7 high for 5v power for controller, pin8 is used for ground //start data clock high (pin 1), all other snes controller pins low. DDRA = 0xFE; PORTA = 0x82; //Port B is used for LCD data //LED'S - used for debugging DDRC = 0xFF; PORTC = 0xF0; //LCD CONTROL LINES, RESET, MD2, and FS1 DDRD = 0xFF; PORTD = 0x0F; //Low long enough to perform a hardware reset delay_ms(1); //Call the software reset function - sets up the display for us, and defines new characters resetLCD(); //Setup inital board (Clears bottom part of screen and writes some text) clearTextMem(); setText('S',0,14); setText('N',1,14); setText('A',2,14); setText('K',3,14); setText('E',4,14); setText(0xA1,0,15); setText(0xA2,1,15); setText(0xA2,2,15); setText(0xA2,3,15); setText(0xA3,4,15); setText('S',6,14); setText('c',7,14); setText('o',8,14); setText('r',9,14); setText('e',10,14); setText(':',11,14); setText('0',12,14); setText('0',13,14); setText('0',14,14); setText('F',6,15); setText('r',7,15); setText('o',8,15); setText('g',9,15); setText('s',10,15); setText(':',11,15); setText('2',13,15); setText('0',14,15); //Initialize our lookup table for timer values, this will make it so that the score will //decrease approx every 2 sec if no frog has been eaten // Timer value = 2000 / ((12 - delay) * 8) = 250 / (12 - delay) timerLookup[0] = 21; timerLookup[1] = 23; timerLookup[2] = 25; timerLookup[3] = 28; timerLookup[4] = 31; timerLookup[5] = 36; timerLookup[6] = 42; timerLookup[7] = 50; timerLookup[8] = 63; timerLookup[9] = 83; //Set the bottom two rows to all 1's in the graphics memory to make inverted text. for (temp = 110 ; temp < 128; temp+=2) for (temp2 = 0; temp2 < 128; temp2+=2) setPixel(temp2,temp); //Clear the rest of the screen and draw border clearGraphicsMem(); //Initialize delay variable delay = 5; //Main loop while(1) { //Show startup screen startupScreen(); //Print out speed value setText(delay+0x30,11,11); //Wait for the user to press start, increment temp in order to get a random seed while(1) { temp++; direction = getInput(); if (direction & 0x20) { if (delay < 9) delay++; else delay = 0; setText(delay+0x30,11,11); while (getInput() & 0x20) {} } if (direction & 0x01) break; } //Check to make sure that the seed isn't 0, if it is then the rand() function doesn't work if (!temp) temp = 0xAA; randState = temp; //clear text in the main game part of the screen for (temp = 3; temp < 12; temp+=2) for (temp2 = 1; temp2 < 15; temp2++) setText(0x20, temp2, temp); //Here we randomize the x coordinate of the apples for (temp = 0; temp < 20; temp++) { temp2 = (rand() & 0x7E) + 0x02; if (temp2 > 125) temp2 -= 122; apples[0][temp] = temp2; } //Here we randomize the y coordinate of the apples for (temp = 0; temp < 20; temp++) { temp2 = (rand() & 0x7E) + 0x02; if (temp2 > 109) temp2 -= 106; apples[1][temp] = temp2; } //Clear the game part of the screen clearGraphicsMem(); //Make sure that the number of apples left is posted setText('2',13,15); setText('0',14,15); //Reinitialize and print the score score = 0x00; printScore(score); //Clear out the snake variable for (temp = 0; temp < 64; temp++) snake[temp] = 0x00; //Initialize the game variables headx = 64; heady = 44; tailx = 64; taily = 82; snakeHead = 19; snakeTail = 0; eating = 0; numOfApples = 0x20; //Initialize apples - say that all apples are still valid for (temp = 0; temp < 3; temp++) isApple[temp] = 0xFF; //Draw apples for (temp = 0; temp < 20; temp++) setPixel(apples[0][temp],apples[1][temp]); //Draw snake on screen for (temp = 0; temp < 40; temp+=2) setPixel(64,heady+temp); //Wait for at least a second to give the user some time before starting delay_ms(1000); //Start game code while (1) { direction = getInput(); if (direction & 0x01) { //Pause while (getInput() & 0x01){} //wait for release while (!(getInput() & 0x01)){} //wait for press while (getInput() & 0x01){} //wait for release continue; } snakeHead++; temp = ((snakeHead << 6) >> 5); temp2 = (snakeHead >> 2); snake[temp2] = (snake[temp2] & (~(0x03 << temp))); //Move up if (direction & 0x02) temp=temp; //Move down else if(direction & 0x04) snake[temp2] |= (0x01 << temp); //Move left else if(direction & 0x08) snake[temp2] |= (0x02 << temp); //Move right else if(direction & 0x10) snake[temp2] |= (0x03 << temp); //Keep the same directon else { //If we are at the boundary condition if (temp == 0) { if (snakeHead == 0) snake[temp2] |= (snake[63] >> 6); else snake[temp2] |= (snake[temp2 - 1] >> 6); } else snake[temp2] |= (((snake[temp2] << (8-temp)) >> 6) << temp); } //Move head temp = ((snake[temp2] << (6 - temp)) >> 6); //Temporary store this variable if (temp == 0x0) heady-=2; //Move the snake up else if (temp == 0x1) heady+=2; //Move the snake down else if (temp == 0x2) headx-=2; //Move the snake to the left else if (temp == 0x3) headx+=2; //Move the snake to the right //check for collisions - loop through table in flash to see if we hit an apple or ourselves if (readPixel(headx,heady)) { die = 1; //Loop through all of the apples for (temp = 0; temp < 20; temp ++) { //See if the apple is still on the screen if (isApple[temp >> 3] & (0x01 << ((temp << 5) >> 5))) { //If the apple is still there and the snake's head is at the apple if ((headx == apples[0][temp]) && (heady == apples[1][temp])) { //Update the number of apples variable if (numOfApples & 0x0F) numOfApples--; else numOfApples = ((((numOfApples >> 4) - 1) << 4) | 0x09); //Print out the number of remaining apples to the screen setText( (numOfApples >> 4) + 0x30,13,15); setText(((numOfApples << 4) >> 4) + 0x30,14,15); //Update and print the score score += 0x0A; printScore (score); //Since we have eaten an apple wait 2 seconds before decrementing the score timer = timerLookup[delay]; //Add to the eating variable so snake will grow eating += 10; //Make that apple invalid isApple[temp >> 3] &= (~(0x01 << ((temp << 5) >> 5))); //If there are more apples then keep playing if (numOfApples) die = 0; //If we are out of apples then go to "You Win" screen else die = 2; } } } //If we lost or won then exit if (die) break; } //if person hits walls then die if ((headx < 2) || (headx > 125) || (heady < 2) || (heady > 109)) break; //Move the head to the new position setPixel(headx,heady); //Delete tail only if the snake isn't eating if(!eating) { //Clear his old tail clearPixel(tailx,taily); //Move the tail pointer snakeTail++; //Figure out what direction the next tail is in. temp = ((snakeTail << 6) >> 5); temp2 = (snakeTail >> 2); temp = ((snake[temp2] << (6 - temp)) >> 6); //Depending on the direction of the next tail move the tailx and taily values if (temp == 0x0) taily-=2; else if (temp == 0x1) taily+=2; else if (temp == 0x2) tailx-=2; else if (temp == 0x3) tailx+=2; } //If snake is eating then decrease the eating value else eating--; //move apples (frogs) randomly for (temp = 0; temp < 20; temp ++) { //Check if the apple is still on the screen if (isApple[temp >> 3] & (0x01 << ((temp << 5) >> 5))) { //Only move the apple 64/255 = 25% of the time if (rand() < 64) { //Get a random value temp2 = rand(); //Make the direction more random - direction = (2nd bit XOR 5th bit) OR (3rd bit XOR 7th bit)*2 temp2 = (((temp2 & 0x02)>>1) ^ ((temp2 & 0x10)>> 4)) | (((temp2 & 0x04)>>1) ^ ((temp2 & 0x40)>> 5)); //Retrieve the current x and y coordinates of the apple applex = apples[0][temp]; appley = apples[1][temp]; //Based on the direction move the x and y coordinates of the apple switch (temp2) { case 0x00: appley+=2; break; case 0x01: appley-=2; break; case 0x02: applex+=2; break; case 0x03: applex-=2; break; } //If the proposed new space is empty then move the apple there if (!(readPixel(applex, appley))) { clearPixel (apples[0][temp], apples[1][temp]); apples[0][temp] = applex; apples[1][temp] = appley; setPixel(applex, appley); } } } } //Print out the score if: // a. Score isn't zero // b. >2sec since last ate apple if (score > 0) { if (timer == 0) { timer = timerLookup[delay]; score --; printScore (score); } else timer --; } //Delay the game loop as a function of the delay variable [(12 - speed) * 8] delay_ms((12-delay) << 3); } gameOverScreen(die); break; } } } //This function draws the opening screen in the middle of the LCD void startupScreen() { setText('S',3,3); setText('N',4,3); setText('A',5,3); setText('K',6,3); setText('E',7,3); setText('4',10,3); setText('7',11,3); setText('6',12,3); setText('b',7,5); setText('y',8,5); setText('V',3,7); setText('i',4,7); setText('c',5,7); setText('t',6,7); setText('o',7,7); setText('r',8,7); setText('T',10,7); setText('a',11,7); setText('o',12,7); setText('J',1,9); setText('o',2,9); setText('n',3,9); setText('a',4,9); setText('t',5,9); setText('h',6,9); setText('a',7,9); setText('n',8,9); setText('W',10,9); setText('i',11,9); setText('c',12,9); setText('k',13,9); setText('s',14,9); setText('S',4,11); setText('p',5,11); setText('e',6,11); setText('e',7,11); setText('d',8,11); setText('=',10,11); setText('0',11,11); } //This first inverts the screen on the game part of the screen and then //prints out either "You Win" or "Game Over" depending on the function arguement void gameOverScreen(unsigned char value) { unsigned char temp, temp2; //Invert the screen for (temp = 0; temp < 16; temp++) for (temp2 = 0; temp2 < 6; temp2++) setText(0xA0,temp,temp2); //Invert the screen for (temp = 6; temp < 9; temp++) { setText(0xA0,0,temp); setText(0xA0,1,temp); setText(0xA0,14,temp); setText(0xA0,15,temp); } //Print out "Game Over" if (value == 1) { setText('G',3,7); setText('A',4,7); setText('M',5,7); setText('E',6,7); setText('O',9,7); setText('V',10,7); setText('E',11,7); setText('R',12,7); } //Print out "You Win" else { setText('Y',4,7); setText('O',5,7); setText('U',6,7); setText('W',9,7); setText('I',10,7); setText('N',11,7); } //Invert the screen for (temp = 0; temp < 16; temp++) for (temp2 = 9; temp2 < 14; temp2++) setText(0xA0,temp,temp2); //Wait for person to press start while (!(getInput() & 0x01)) {} //Uninvert the screen and remove message for (temp = 0; temp < 16; temp++) for (temp2 = 0; temp2 < 14; temp2++) setText(0x20,temp,temp2); } //Generate random numbers using an 8-bit linear feedback shift register unsigned char rand() { unsigned char temp; //XOR the 7th bit and the 6th bit temp = ((randState & 0x40)>>6); temp ^= ((randState & 0x20)>>5); //Shift the register to the left randState <<= 1; //put the result of (7th bit XOR 6th bit) into 1st bit of random number randState |= temp; //return the random number return randState; } //This is a helper function to print out the score, it takes the score as an arguement //and it converts the number to decimal and prints out each digit. void printScore (unsigned char value) { unsigned char result [3]; //Clear out result variable result[2] = 0; result[1] = 0; //Loop over the hundreds digit while (value >= 100) { value -= 100; result[2] ++; } //Loop over the tens digit while (value >= 10) { value -= 10; result[1] ++; } //Store the ones digit result[0] = value; //Output the score setText(result[2] + 0x30, 12, 14); setText(result[1] + 0x30, 13, 14); setText(result[0] + 0x30, 14, 14); } //This function resets the lcd by telling the lcd what mode we are in, where the graphics and text memories //begin, how many columns are on the screen, and what new user defined characters we want void resetLCD() { unsigned char i; //Mode set (CGROM MODE, XOR MODE) status(0x03); writeCmd(0x81); //Set GRAPHICS HOME ADDRESS to 0x0000 status(0x03); //check status writeData(0x00); //write low addr byte of 0x0000 status(0x03); //check status writeData(0x00); //write high addr byte of 0x0000 status(0x03); //check status writeCmd(0x42); //write command //Set GRAPHICS AREA SET - 16 columns status(0x03); //check status writeData(0x10); //write 16 because 8bits * 16 = 128bits status(0x03); //check status writeData(0x00); //write 0x00, always this i guess status(0x03); //check status writeCmd(0x43); //write command //Set TEXT HOME ADDRESS to 0x0818 status(0x03); writeData(0x18); status(0x03); writeData(0x08); status(0x03); writeCmd(0x40); //Set TEXT AREA SET - 16 columns status(0x03); writeData(0x10); status(0x03); writeData(0x00); status(0x03); writeCmd(0x41); //Set OFFSET POINTER (CG AREA) - tell it where CG ram starts status(0x03); writeData(0x02); status(0x03); writeData(0x00); status(0x03); writeCmd(0x22); //Move ADDRESS POINTER to CG-RAM - move to start of CGRAM = 0x1400 status(0x03); writeData(0x00); status(0x03); writeData(0x14); status(0x03); writeCmd(0x24); //Put in data auto write mode so we don't have to increment the address pointer ourselves status(0x03); writeCmd(0xB0); //Write the Character (INVERTED BLANK) into CG-RAM for(i = 0; i < 8; i++) { status(0x08); writeData(0xFF); } //Snake head character - 0xA1 status(0x08); writeData(0x00); status(0x08); writeData(0x07); status(0x08); writeData(0x08); status(0x08); writeData(0x12); status(0x08); writeData(0x20); status(0x08); writeData(0x12); status(0x08); writeData(0x08); status(0x08); writeData(0x07); //Snake regular body character - 0xA2 status(0x08); writeData(0x00); status(0x08); writeData(0x00); status(0x08); writeData(0xFF); status(0x08); writeData(0x00); status(0x08); writeData(0x00); status(0x08); writeData(0x00); status(0x08); writeData(0xFF); status(0x08); writeData(0x00); //Snake tail - 0xA3 status(0x08); writeData(0x00); status(0x08); writeData(0x00); status(0x08); writeData(0xF0); status(0x08); writeData(0x0C); status(0x08); writeData(0x02); status(0x08); writeData(0x0C); status(0x08); writeData(0xF0); status(0x08); writeData(0x00); //Put back in normal auto mode status(0x08); writeCmd(0xB2); //Set DISPLAY MODE (turn on GRAPHICS and TEXT) status(0x03); writeCmd(0x9C); } //Clears out the game play area of the screen for (0,0) to (128,109) //GRAPHICS MEMORY ONLY void clearGraphicsMem() { //Declare local variables unsigned int i; unsigned char temp; //move address pointer to start at 0x0000 status(0x03); writeData(0x18); status(0x03); writeData(0x00); status(0x03); writeCmd(0x24); //Put in data auto write mode so we don't have to move address pointer status(0x03); writeCmd(0xB0); //Write all zeros for(i = 0; i < 1760; i++) { status(0x08); writeData(0x00); } //Put back in normal auto mode status(0x08); writeCmd(0xB2); //Draw 2 pixel border around game play area of screen for (temp = 0; temp < 128; temp+=2) setPixel(temp,0); for (temp = 2; temp < 110; temp+=2) { setPixel(0,temp); setPixel(126,temp); } } //This function clears out all of the text memory on the screen void clearTextMem() { //Declare local variables unsigned int i; //move address pointer to start at 0x0830 status(0x03); writeData(0x30); status(0x03); writeData(0x08); status(0x03); writeCmd(0x24); //Put in data auto write mode so don't have to move address pointer status(0x03); writeCmd(0xB0); //Write all zeros for(i = 0; i < 256; i++) { status(0x08); writeData(0x00); } //Put back in normal auto mode status(0x08); writeCmd(0xB2); } //This function writes the character ch at position x,y //Note: x and y are values between 0 and 15 void setText(unsigned char ch, unsigned char x, unsigned char y) { //move address pointer to spot in text mem unsigned int pointer; unsigned char topPointer, botPointer; //Computer the offset into the text memory pointer = x + ((int)y<<4) + 0x830; topPointer = (pointer >> 8); botPointer = ((pointer << 8) >> 8); //Move address pointer to pixel status(0x03); writeData(botPointer); status(0x03); writeData(topPointer); status(0x03); writeCmd(0x24); //Set character status(0x03); writeData(ch - 0x20); //have to subtract 0x20 since their ascii table is ASCII-0x20 status(0x03); writeCmd(0xC0); } //This sets the pixels at (x,y),(x+1,y),(x,y+1), and (x+1,y+1) to one //Note: X and Y must always be even values void setPixel(unsigned char x, unsigned char y) { unsigned int pointer; unsigned char bitOff, topPointer, botPointer; //Computes the offset to the coordinate (x,y) pointer = (((int)x)>>3) + (((int)y)<<4) + 0x18; // (x/8) + (y*16) to get particular byte //This figures out what bit in the byte we want to change bitOff = 7 - ((x<<5)>>5) + 0xF8; //Gets the upper and lower part of the offset topPointer = (pointer >> 8); botPointer = ((pointer << 8) >> 8); //Move address pointer to pixel status(0x03); writeData(botPointer); status(0x03); writeData(topPointer); status(0x03); writeCmd(0x24); //Set pixel (x,y) and (x+1,y) to one status(0x03); writeCmd(bitOff); status(0x03); writeCmd(bitOff-0x01); //This moves the pointer down exactly one row pointer += 16; topPointer = (pointer >> 8); botPointer = ((pointer << 8) >> 8); //Move address pointer to pixel status(0x03); writeData(botPointer); status(0x03); writeData(topPointer); status(0x03); writeCmd(0x24); //Set pixel (x,y+1) and (x+1,y+1) to one status(0x03); writeCmd(bitOff); status(0x03); writeCmd(bitOff-0x01); } //This sets the pixels at (x,y),(x+1,y),(x,y+1), and (x+1,y+1) to zero //Note: X and Y must always be even values void clearPixel(unsigned char x, unsigned char y) { unsigned int pointer; unsigned char bitOff, topPointer, botPointer; //Computes the offset to the coordinate (x,y) pointer = (((int)x)>>3) + (((int)y)<<4) + 0x18; // (x/8) + (y*16) to get particular byte //This figures out what bit in the byte we want to change bitOff = 7 - ((x<<5)>>5) + 0xF0; //Gets the upper and lower part of the offset topPointer = (pointer >> 8); botPointer = ((pointer << 8) >> 8); //Move address pointer to pixel status(0x03); writeData(botPointer); status(0x03); writeData(topPointer); status(0x03); writeCmd(0x24); //Set pixel (x,y) and (x+1,y) to zero status(0x03); writeCmd(bitOff); status(0x03); writeCmd(bitOff-0x01); //This moves the pointer down exactly one row pointer += 16; topPointer = (pointer >> 8); botPointer = ((pointer << 8) >> 8); //Move address pointer to pixel status(0x03); writeData(botPointer); status(0x03); writeData(topPointer); status(0x03); writeCmd(0x24); //Set pixel (x,y+1) and (x+1,y+1) to zero status(0x03); writeCmd(bitOff); status(0x03); writeCmd(bitOff-0x01); } //This reads the pixel at (x,y) and returns a 1 or a 0 indicating the bit is set or not set unsigned char readPixel(unsigned char x, unsigned char y) { unsigned int pointer; unsigned char bitOff, topPointer, botPointer; unsigned char val; //Computes the offset to the coordinate (x,y) pointer = (((int)x)>>3) + (((int)y)<<4) + 0x18; // (x/8) + (y*16) to get particular byte //This figures out what bit in the byte we want to retrieve bitOff = 7 - ((x<<5)>>5); //Gets the upper and lower part of the offset topPointer = (pointer >> 8); botPointer = ((pointer << 8) >> 8); //Move address pointer to pixel status(0x03); writeData(botPointer); status(0x03); writeData(topPointer); status(0x03); writeCmd(0x24); //Read a particular byte status(0x03); writeCmd(0xC5); status(0x03); val = readData(); //Mask out only bits we want return (val & (0x01 << bitOff)); } //Beginning of assembly language code #pragma warn- //This function checks the status of particular bits in the LCD's status register void status(unsigned char statusVal) { #asm ld r17,y ;get statusVal ;Set portb to be all inputs clr r16 out DDRB, r16 statusWait: ldi r16, 0b00010101 ;/ce taken low, /wr taken high, /rd taken low, /cd taken high out PORTD, r16 ;send to control lines nop ;wait for values in r16, PINB ;read status push r16 ;save status ldi r16, 0b00011101 ;/ce taken high, /wr taken high, /rd taken low, /cd taken high out PORTD, r16 ;send to control lines pop r16 ;retrieve status and r16, r17 ;look only at bits we care about cp r16, r17 ;see if the bits are set brne statusWait ;if not then loop ;Avoids double writing ldi r16, 0b00011010 ;/ce taken high, /wr taken low, /rd taken high, /cd taken low out PORTD, r16 ;send to control lines #endasm } //This reads data from the LCD unsigned char readData() { #asm ;Set portb to be all inputs clr r16 out DDRB, r16 ;/ce low, /wr high, /rd low, /cd low ldi r16, 0b00010100 out PORTD, r16 nop ;may not be needed in r30, PINB ;/ce high, /wr high, /rd low, /cd low ldi r16, 0b00011100 out PORTD, r16 ;Avoids double writing ldi r16, 0b00011010 ;/ce taken high, /wr taken low, /rd taken high, /cd taken low out PORTD, r16 ;send to control lines #endasm } //This writes data to the LCD void writeData(unsigned char data) { #asm ;Get data ld r17, y ;Set portb to be all outputs ser r16 out DDRB, r16 ;Write data to portb out PORTB, r17 ;/ce low, /wr low, /rd high, /cd low ldi r16, 0b00010010 out PORTD, r16 nop ;/ce high, /wr low, /rd high, /cd low ;/ce needed to be pulsed low for greater than 80ns ldi r16, 0b00011010 out PORTD, r16 #endasm } //This writes a command to the LCD void writeCmd(unsigned char command) { #asm ;Get command ld r17, y ;Set portb to be outputs ser r16 out DDRB, r16 ;Write command to D0-D7 out PORTB, r17 ;/ce low, /wr low, /rd high, /cd high ldi r16, 0b00010011 out PORTD, r16 nop ;********************MIGHT NOT BE NEEDED BUT SPEC SAYS PULSE /ce low FOR > 80ns ;/ce high, /wr low, /rd high, /cd high ldi r16, 0b00011011 out PORTD, r16 #endasm } //This function retrieves the input from the SNES controller unsigned char getInput() { #asm .equ SNESdataClk = PA1 .equ SNESdataLatch = PA2 .equ SNESseriaData = PA0 .equ SNESdataClkBit = 1 .equ SNESdataLatchBit = 2 .equ SNESserialDataBit = 0 .equ SNES12 = 11 .equ SNES6 = 5 .equ SNEScycles = 16 ;Begining of reading controller (timed section) nop ldi r17, SNES12 sbi PORTA, SNESdataLatchBit initLatch: nop dec r17 brne initLatch nop nop nop cbi PORTA, SNESdataLatchBit ;its been 12us to here ldi r18, SNEScycles ldi r17, SNES6 wait6: nop dec r17 brne wait6 nop cbi PORTA, SNESdataClkBit ;its been 6us to here in r16, PINA push r16 ldi r17, SNES6 dec r17 wait6again: nop dec r17 brne wait6again nop nop sbi PORTA, SNESdataClkBit ;its been 6us to here ldi r17, SNES6 dec r17 dec r18 nop brne wait6 ;done doing timing stuff clr r19 ;clear out the result register pop r0 ;n/a pop r0 ;n/a pop r0 ;n/a pop r0 ;n/a pop r0 ;R pop r0 ;L pop r0 ;X pop r19 ;A andi r19,0x01 pop r0 ;Right ror r0 rol r19 pop r0 ;Left ror r0 rol r19 pop r0 ;Down ror r0 rol r19 pop r0 ;Up ror r0 rol r19 pop r0 ;Start ror r0 rol r19 pop r0 ;Select pop r0 ;Y pop r0 ;B com r19 ;Complement bits so that 1 means pressed mov r30,r19 ;Return result #endasm } #pragma warn+