#include <io.h>
#include <system.h>
#include <stdio.h>
#include <alt_types.h>
#include <math.h>
#include "alt_up_character_lcd.h"
#include "keyboard.h"

//Macros to interface to the AES block
#define AES_WRITE_KEY(offset,data)  IOWR_32DIRECT(AES128_BASE,(offset*4),data)
#define AES_READ_KEY(offset)        IORD_32DIRECT(AES128_BASE,(offset*4))
#define AES_WRITE_DATA(addr,data)   IOWR_32DIRECT(AES128_BASE,16+(addr*4),data)
#define AES_READ_DATA(addr)         IORD_32DIRECT(AES128_BASE,16+(addr*4))

//Macros to write into VGA
#define VGA_GO()                    IOWR_16DIRECT(VGASRAM_BASE,524288*2,1)      //Tell VGA that it is safe to read data from SRAM
#define VGA_NO()                    IOWR_16DIRECT(VGASRAM_BASE,524288*2,0)      //Tell VGA to not read data
#define VGA_BUSY()                  IORD_16DIRECT(VGASRAM_BASE,524288*4)        //Are we inside the rectangle?

//Macros to get data from SPI
#define SPI_CHOOSE_CARD_ADDR(addr)  IOWR_32DIRECT(SPI_BASE, 2*4, addr)
#define SPI_START()                 IOWR_32DIRECT(SPI_BASE, 1*4, 1)
#define SPI_END()                   IOWR_32DIRECT(SPI_BASE, 1*4, 0)
#define SPI_READY()                 IORD_32DIRECT(SPI_BASE, 16*4)
#define SPI_CHOOSE_BUFF_ADDR(addr)  IOWR_32DIRECT(SPI_BASE, 64*4, addr)
#define SPI_GET_BUFF_DATA()         IORD_32DIRECT(SPI_BASE, 128*4)

//Macros to write into SRAM
#define SRAM_WRITE(addr, data)      IOWR_16DIRECT(VGASRAM_BASE,(addr*2),data)
#define SRAM_READ(addr)             IORD_16DIRECT(VGASRAM_BASE,(addr*2))

#define NUM_FRAME                   3270 //short = 84 //long = 3274

int main()
{      
    printf("\nWelcome to the AES 128-bit decryption project!");  
    unsigned int data = 0;
    unsigned long int i = 0, addr=0;
    int j =0,count=0,k=0, m=0, limit=0;
    unsigned long int frame = 0, frameStartAddr=0, frameSize=0x13040;    //0x13038
    unsigned long int frameEndAddr=0, startBlock, endBlock;    
    unsigned long int keydata[4]=//{0x00000000,0x00000000,0x00000000,0x00000000};
                               {0x2b28ab09,0x7eaef7cf, 0x15d2154f, 0x16a6883c}; //This is the passphrase!
  
    printf("\n\nPlease enter the decryption key (32 hex digits).\n");
  
    /* 
    //Passphrase keyboard entry; If this section is 
    key = getKey();
    for(i=0;i<32;i++) 
        keydata[i>>3] = (keydata[i>>3]<<4)|(key[i]&0xF);
    */
    
    // Write the passphrase to the AES module
    for(i=0;i<4;i++)
        AES_WRITE_KEY(i,keydata[i]);
        
    printf("\nStarting Decryption...");
  
//    for(frame = 0; frame <= NUM_FRAME; frame=frame+1)
    for(frame = NUM_FRAME; frame >= 0; frame--)
    { 
        VGA_GO();
        addr = 0;     //Reset the SRAM address
        frameStartAddr = frame*frameSize;
        frameEndAddr = frame*frameSize + frameSize;
      
        // Calculate the address to the nearest 512-byte multiple        
        startBlock = abs(frameStartAddr/512)*512;
        endBlock = abs(frameEndAddr/512 )*512;
      
        for(i = startBlock; i <= endBlock; i = i+512)
        {           
            // Calculate the buffer spill
            m = (i==startBlock)?(frame%8):0;                     

            // If there is no spill, then the data is no presently in the buffer, and
            // a new SD card read is issued
            if (m == 0)
            {
                SPI_CHOOSE_CARD_ADDR(i);
                SPI_START();
                SPI_END();
            }
            
            // Poll the SPI ready bit until it is done. This signals the buffer has been
            // filled
            while(!SPI_READY());
            
            // Calculate the ending address of the buffer. We want to avoid writing 
            // images belonging to the next frame into the SRAM
            limit = (i==endBlock)?(64*((frame+1)%8)):512;           
            
            // Since the spill will be multiple of 64-bytes, multiple it from the previous
            // calculation    
            k = m*64;        
            
            // Loop through the contents of the SPI buffer and feed it to the AES descrypto,
            // and then write it to the SRAM
            for (;k<limit; k=k+4)
            {                
                // Read data from SPI buffer
                SPI_CHOOSE_BUFF_ADDR(k);
                data = SPI_GET_BUFF_DATA();
                // Feed data to AES decrypto
                AES_WRITE_DATA(count++,data);
                                
                if(k%16 == 0)
                  while(!VGA_BUSY());

                // When we have 4 32-bits, or 128-bits, start the decryption process and
                // feed the result into SRAM                                                  
                if(count==4) 
                {           
                    for (j=0;j<4;j++)
                    {
                        // Start decryption
                        data = AES_READ_DATA(j);
                        // Ask VGA to not retrieve data from the SRAM
                        VGA_NO();
                        // Write 2x16 bits of data into the SRAM
                        SRAM_WRITE(addr++,(data&0xFFFF0000)>>16);
                        SRAM_WRITE(addr++,(data&0x0000FFFF));
                        // Give the VGA thumbs up to read from the SRAM
                        VGA_GO();
                    }  
                    count=0;
                }
            }
      }
      // Restart playback when the last frame is reached
      if(frame >= NUM_FRAME)     
        frame = 0;
  }
  printf("\nEncryption Completed.");
  return 0;       
}    
