/*
 *  * Copyright (c) 2004 Xilinx, Inc.  All rights reserved.
 *
 * Xilinx, Inc.
 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A 
 * COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
 * ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR 
 * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION 
 * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE 
 * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION
 * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO 
 * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO 
 * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE 
 * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY 
 * AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
 * This file is a sample test application
 *
 * This application is intended to test and/or illustrate some 
 * functionality of your system.  The contents of this file may
 * vary depending on the IP in your system and may use existing
 * IP driver functions.  These drivers will be generated in your
 * XPS project when you run the "Generate Libraries" menu item
 * in XPS.
 */


// Located in: microblaze_0/include/xparameters.h
#include "xparameters.h"

#include "xutil.h"
#include "xgpio_l.h"

/* Begin user-supplied interrupt test routine */

/* This example demonstrates how to use an interrupt controller
 * that responds to interrupts from two peripherals (UART and OPB_timer)
 * in a MicroBlaze based system.
 * This interrupt test routine has been added to the test application (TestApp)
 * generated by the Base System Builder.
 */

#include <xtmrctr_l.h> /* timer/counter peripheral control functions */
#include <xuartlite_l.h> /* uartlite peripheral control functions */
#include <xintc_l.h> /* interrupt controller peripheral control functions */

#define LED_MSB 0x00000080 /* mask for position of left-most LED */

/* Global variables */
unsigned int led_data = 0; /* initial LED pattern when interrupt test begins */
unsigned int timer_count = 16777216; /* initial timer period in OPB cycles ~= 0.3 sec */
volatile unsigned int exit_command = 0; /* flag from UART ISR to exit InterruptTest routine */

/* UART interrupt service routine */
void uart_int_handler(void *baseaddr_p) {
   char c;
   /* While UART receive FIFO has data */
   while (!XUartLite_mIsReceiveEmpty(XPAR_RS232_BASEADDR)) {
      /* Read a character */
      c = XUartLite_RecvByte(XPAR_RS232_BASEADDR);
      switch (c) {
         case 'f': /* FASTER command */
            if (timer_count > 1) {
               timer_count >>= 1;
               print("-- Reducing timer period by half --\r\n");}
            break;
         case 's': /* SLOWER command */
            if (timer_count < 1073741824) {
               timer_count <<= 1;
               print("-- Doubling timer period --\r\n");}
            break;
         case 'x': /* EXIT command */
            exit_command = 1;
      }
      /* Update timer period with new value of timer_count */
      XTmrCtr_mSetLoadReg(XPAR_OPB_TIMER_1_BASEADDR, 0, timer_count);
   }
}

/* Timer interrupt service routine */
/* Note: This ISR was registered statically in the Software Platform Settings dialog */
void timer_int_handler(void * baseaddr_p) {
   unsigned int csr;
   /* Read timer 0 CSR to see if it requested the interrupt */
   csr = XTmrCtr_mGetControlStatusReg(XPAR_OPB_TIMER_1_BASEADDR, 0);
   if (csr & XTC_CSR_INT_OCCURED_MASK) {
      /* Increment led_count in a johnson-counter pattern */
      if (led_data & LED_MSB)
         led_data = led_data << 1;
      else
         led_data = (led_data << 1) + 1;
      /* Update LED output pattern */
      XGpio_mSetDataReg(XPAR_LEDS_8BIT_BASEADDR, 1, led_data);
   }
   /* Clear the timer interrupt */
   XTmrCtr_mSetControlStatusReg(XPAR_OPB_TIMER_1_BASEADDR, 0, csr);
}

/* Interrupt test routine */
void InterruptTest(void) {
   print("-- Entering InterruptTest() --\r\n");
   /* Enable MicroBlaze interrupts */
   microblaze_enable_interrupts();
   /* Register the UART interrupt handler in the vector table */
   XIntc_RegisterHandler(XPAR_OPB_INTC_0_BASEADDR,XPAR_OPB_INTC_0_RS232_INTERRUPT_INTR,
      (XInterruptHandler)uart_int_handler,(void *)XPAR_RS232_BASEADDR);
   /* Start the interrupt controller */
   XIntc_mMasterEnable(XPAR_OPB_INTC_0_BASEADDR);
   /* Set the gpio for LEDs as output */
   XGpio_mSetDataDirection(XPAR_LEDS_8BIT_BASEADDR, 1, 0x00000000);
   /* Set the number of cycles the timer counts before interrupting */
   XTmrCtr_mSetLoadReg(XPAR_OPB_TIMER_1_BASEADDR, 0, timer_count);
   /* Reset the timers, and clear interrupts */
   XTmrCtr_mSetControlStatusReg(XPAR_OPB_TIMER_1_BASEADDR, 0,
      XTC_CSR_INT_OCCURED_MASK | XTC_CSR_LOAD_MASK );
   /* Enable timer and UART interrupt requests in the interrupt controller */
   XIntc_mEnableIntr(XPAR_OPB_INTC_0_BASEADDR,
      XPAR_OPB_TIMER_1_INTERRUPT_MASK | XPAR_RS232_INTERRUPT_MASK);
   /* Start the timers */
   XTmrCtr_mSetControlStatusReg(XPAR_OPB_TIMER_1_BASEADDR, 0,
      XTC_CSR_ENABLE_TMR_MASK | XTC_CSR_ENABLE_INT_MASK |
      XTC_CSR_AUTO_RELOAD_MASK | XTC_CSR_DOWN_COUNT_MASK);
   /* Enable UART interrupts */
   XUartLite_mEnableIntr(XPAR_RS232_BASEADDR);

   /* Wait for interrupts to occur until exit_command received from UART ISR */
   while (!exit_command)
   ;

   /* Disable MicroBlaze interrupts */
   microblaze_disable_interrupts();
   print("-- Exiting InterruptTest() --\r\n");
}


/* End user-supplied interrupt test routine */

/*
 * Routine to write a pattern out to a GPIO
 * which is configured as an output
 *   PARAMETER C_ALL_INPUTS = 0
 */ 
void WriteToGPOutput(Xuint32 BaseAddress, int gpio_width) {
   int i=0, j=0, k=0;
   int numTimes = 5;
 
   XGpio_mSetDataDirection(BaseAddress, 1, 0x00000000);   /* Set as outputs */
   while (numTimes > 0) {
      j = 1;
      for(i=0; i<(gpio_width-1); i++) {
         XGpio_mSetDataReg(BaseAddress, 1, j);
         j = j << 1;
         for (k=0; k<1000000; k++) {
            ; //wait
         }
      }
      j = 1;
      j = ~j;
      for(i=0; i<(gpio_width-1); i++) {
         XGpio_mSetDataReg(BaseAddress, 1, j);
         j = j << 1;
         for (k=0; k<1000000; k++) {
            ; //wait
         }
      }
      numTimes--;
   }
}


/*
 * Routine to read data from a GPIO
 * which is configured as an input
 *   PARAMETER C_ALL_INPUTS = 1
 */
Xuint32 ReadFromGPInput(Xuint32 BaseAddress) {
   Xuint32 data = XGpio_mGetDataReg(BaseAddress, 1);
   return data;
}


//====================================================

int main (void) {


   print("-- Entering main() --\r\n");

   /* 
    * MemoryTest routine will not be run for the memory at 
    * dlmb_cntlr.C_BASEADDR
    * because it is being used to hold a part of this application program
    */


   /* 
    * MemoryTest routine will not be run for the memory at 
    * ilmb_cntlr.C_BASEADDR
    * because it is being used to hold a part of this application program
    */


   WriteToGPOutput(XPAR_LEDS_8BIT_BASEADDR, 8);

   {
      Xuint32 data = ReadFromGPInput(XPAR_PUSH_BUTTONS_3BIT_BASEADDR);
      //xil_printf("Data read from Push_Buttons_3Bit: 0x%x\r\n", data);
   }

   /* Testing EMC Memory (SRAM_256Kx32)*/
   {
      XStatus status;

      print("Starting MemoryTest for SRAM_256Kx32:\r\n");
      print("  Running 32-bit test...");
      status = XUtil_MemoryTest32((Xuint32*)XPAR_SRAM_256KX32_MEM0_BASEADDR, 1024, 0xAAAA5555, XUT_ALLMEMTESTS);
      if (status == XST_SUCCESS) {
         print("PASSED!\r\n");
      }
      else {
         print("FAILED!\r\n");
      }
      print("  Running 16-bit test...");
      status = XUtil_MemoryTest16((Xuint16*)XPAR_SRAM_256KX32_MEM0_BASEADDR, 2048, 0xAA55, XUT_ALLMEMTESTS);
      if (status == XST_SUCCESS) {
         print("PASSED!\r\n");
      }
      else {
         print("FAILED!\r\n");
      }
      print("  Running 8-bit test...");
      status = XUtil_MemoryTest8((Xuint8*)XPAR_SRAM_256KX32_MEM0_BASEADDR, 4096, 0xA5, XUT_ALLMEMTESTS);
      if (status == XST_SUCCESS) {
         print("PASSED!\r\n");
      }
      else {
         print("FAILED!\r\n");
      }
   }

   /* Testing BRAM Memory (opb_bram_if_cntlr_1)*/
   {
      XStatus status;

      print("Starting MemoryTest for opb_bram_if_cntlr_1:\r\n");
      print("  Running 32-bit test...");
      status = XUtil_MemoryTest32((Xuint32*)XPAR_OPB_BRAM_IF_CNTLR_1_BASEADDR, 1024, 0xAAAA5555, XUT_ALLMEMTESTS);
      if (status == XST_SUCCESS) {
         print("PASSED!\r\n");
      }
      else {
         print("FAILED!\r\n");
      }
      print("  Running 16-bit test...");
      status = XUtil_MemoryTest16((Xuint16*)XPAR_OPB_BRAM_IF_CNTLR_1_BASEADDR, 2048, 0xAA55, XUT_ALLMEMTESTS);
      if (status == XST_SUCCESS) {
         print("PASSED!\r\n");
      }
      else {
         print("FAILED!\r\n");
      }
      print("  Running 8-bit test...");
      status = XUtil_MemoryTest8((Xuint8*)XPAR_OPB_BRAM_IF_CNTLR_1_BASEADDR, 4096, 0xA5, XUT_ALLMEMTESTS);
      if (status == XST_SUCCESS) {
         print("PASSED!\r\n");
      }
      else {
         print("FAILED!\r\n");
      }
   }

   /* Run user-supplied interrupt test routine */
   InterruptTest();

   print("-- Exiting main() --\r\n");
   return 0;
}

