/*******************************************************************************
 *   (c) Copyright 2014 Microsemi Corporation.  All rights reserved.
 *
 *   File:          main.c
 *   File history:  Initial version
 *   Revision:      1.0                    Date: March 18, 2014
 *
 *   Description: Description of the design.
 *
 *
 *   Author:Corporate Applications Engineering
 *
 *******************************************************************************/

#include "drivers/mss_uart/mss_uart.h"
#include "drivers/mss_gpio/mss_gpio.h"
#include "stdio.h"

extern void delay ( volatile unsigned int n);
mss_uart_instance_t * const gp_my_uart = &g_mss_uart0;

int main()
{
	uint32_t *DDR_Mem;
	uint32_t *DDR_Mem_S;
	uint32_t *DDR_Mem_D;
	uint32_t *fabric_cycles;

	int i,j;
	int error;

	DDR_Mem	       = (uint32_t *)0xA0000000;
	DDR_Mem_S	   = (uint32_t *)0xA1007000;
	DDR_Mem_D	   = (uint32_t *)0xA0007000;

	/* Initialization and configuration of the MMUART_0 with 57,600 baud rate, 8 data bits, 1 stop bit,
	 * no parity, and no flow control */

    MSS_UART_init(gp_my_uart,
                  MSS_UART_115200_BAUD,
                  MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT);

    /* Initialization and Configuration of GPIOs (MSS_GPIO_0 to MSS_GPIO_7 are configured in output
     * mode)*/

	MSS_GPIO_init();
	MSS_GPIO_config( MSS_GPIO_0 , MSS_GPIO_OUTPUT_MODE );
	MSS_GPIO_config( MSS_GPIO_1 , MSS_GPIO_OUTPUT_MODE );
	MSS_GPIO_config( MSS_GPIO_2 , MSS_GPIO_OUTPUT_MODE );
	MSS_GPIO_config( MSS_GPIO_3 , MSS_GPIO_OUTPUT_MODE );
	MSS_GPIO_config( MSS_GPIO_4 , MSS_GPIO_OUTPUT_MODE );
	MSS_GPIO_config( MSS_GPIO_5 , MSS_GPIO_OUTPUT_MODE );
	MSS_GPIO_config( MSS_GPIO_6 , MSS_GPIO_OUTPUT_MODE );
	MSS_GPIO_config( MSS_GPIO_7 , MSS_GPIO_OUTPUT_MODE );

	/* Initialization of DDR3 SDRAM
	 * 16777216x4 locations, starting from address 0xA0000000, are filled with zeros.*/

	for( i = 0; i < 16777216; i++ )
	{
		*DDR_Mem = 0x00000000;
		 DDR_Mem++;
	}

	/* 8x1024x4 locations, starting from address 0xA1000000, are filled with incremental
	 * patterns */

	DDR_Mem	   = (uint32_t *)0xA1000000;

	for( j = 0; j < 8; j++ )
	{
		for( i = 0; i < 1024; i++ )
		{
			*DDR_Mem = i;
			 DDR_Mem++;
		}
	}

	/* AXI master reads 4KB of data from DDR3 SDRAM, starting from address 0xA1000000
	 * (i.e. 0x01000000), and written into LSRAM */
	MSS_GPIO_set_outputs(0x4A); // 4KB Reading from DDR3 SDRAM and writing into LSRAM
	delay(50);
	MSS_GPIO_set_outputs(0x48);

	delay(500);

	/* AXI master reads 4KB of data from LSRAM (512x64) and written into DDR3 SDRAM,
	 * starting from address 0xA0000000 (i.e. 0x00000000) */

	MSS_GPIO_set_outputs(0x49); // 4KB reading from LSRAM and writing into DDR3 SDRAM
	delay(50);
	MSS_GPIO_set_outputs(0x48);

	printf("\r   Source Address : Data        Destination Address : Data\n");
	printf("\r----------------------------------------------------------------------\n");

	for( i = 0; i < 1024; i++)
	{
		if (*DDR_Mem_S == *DDR_Mem_D)
		{
			j = 0;
			printf("\r   %p     : %lu            %p     : %lu  \n", DDR_Mem_S,(unsigned long)*DDR_Mem_S,DDR_Mem_D,(unsigned long)*DDR_Mem_D);
		}
		else
		{
			j = 1;
			error = error + 1;
		}

		DDR_Mem_D++;
		DDR_Mem_S++;
	}

	printf("\n");
	printf("\rIntegrity Test Completed \n");
	printf("\n");

	if ( j == 0 )
	{
		printf("\rStatus : PASSED !\n");
	}
	else
	{
		printf("\rStatus : FAILED !\n");
		printf("\rError Count = %d \n", error);

	}

	printf("\n");

	DDR_Mem	       = (uint32_t *)0xA0000000;

	for( i = 0; i < 16777216; i++ )
	{
		*DDR_Mem = 0x00000000;
		 DDR_Mem++;
	}

	DDR_Mem	   = (uint32_t *)0xA1000000;

	for( j = 0; j < 8; j++ )
	{
		for( i = 0; i < 1024; i++ )
		{
			*DDR_Mem = i;
			 DDR_Mem++;
		}
	}

	printf("\r++++++++++++++++++++\n");
	printf("\rDDR SDRAM Bandwidth \n");
	printf("\r++++++++++++++++++++\n");

	printf("\r \n");
	printf("\r Read Throughput \n");
	printf("\r--------------------\n");
	printf("\r \n");

	fabric_cycles = ((uint32_t *)0x20008104);

	for(i=1;i<9;i++)
	{
		*fabric_cycles = 0x00000000;
		fabric_cycles++;
	}
	delay(10000);

	/* DDR3 SDRAM READ OPERATION
	 * Performing the read operation. Uncomment the any of the following lines
	 * based on the size of the data to be read from DDR3 SDRAM. The default size is 2KB*/

    MSS_GPIO_set_outputs(0x26); // 2KB
    delay(50);					// 2KB
    MSS_GPIO_set_outputs(0x24); // 2KB

	//MSS_GPIO_set_outputs(0x4A); // 4KB
	//delay(50);				  // 4KB
	//MSS_GPIO_set_outputs(0x48); // 4KB

	//MSS_GPIO_set_outputs(0x6E); // 8KB
	//delay(50);				  // 8KB
	//MSS_GPIO_set_outputs(0x6C); // 8KB

	//MSS_GPIO_set_outputs(0x92); // 16KB
	//delay(50);				  // 16KB
	//MSS_GPIO_set_outputs(0x90); // 16KB


	delay(10000);

	fabric_cycles = ((uint32_t *)0x20008104);

	for(i=1;i<9;i++)
	{
		printf("\rAXI Clocks (%d) : %lu \n",i, (unsigned long)*fabric_cycles);
		fabric_cycles++;
	}

	printf("\r \n");
	printf("\r Write Throughput    \n");
	printf("\r--------------------\n");
	printf("\r \n");

	delay(10000);
	fabric_cycles = ((uint32_t *)0x20008104);

	for(i=1;i<9;i++)
	{
		*fabric_cycles = 0x00000000;
		fabric_cycles++;
	}

	delay(10000);

	/* DDR3 SDRAM WRITE OPERATION
	 * Performing the write operation. Uncomment the any of the following lines based on
	 * the size of the data to be written into DDR3 SDRAM. The default size is 2KB */

	MSS_GPIO_set_outputs(0x25); // 2KB
	delay(50);				    // 2KB
	MSS_GPIO_set_outputs(0x24); // 2KB

	//MSS_GPIO_set_outputs(0x49); // 4KB
	//delay(50);				  // 4KB
	//MSS_GPIO_set_outputs(0x48); // 4KB

	//MSS_GPIO_set_outputs(0x6D); // 8KB
	//delay(50); 				  // 8KB
	//MSS_GPIO_set_outputs(0x6C); // 8KB

	//MSS_GPIO_set_outputs(0x91); // 16KB
	//delay(50);					// 16KB
	//MSS_GPIO_set_outputs(0x90); // 16KB

	delay(10000);

	fabric_cycles = ((uint32_t *)0x20008104);

	for(i=1;i<9;i++)
	{
		printf("\rAXI Clocks (%d) : %lu \n",i, (unsigned long)*fabric_cycles);
		fabric_cycles++;
	}

	printf("\r \n");
	printf("\rCompleted !. Re-run for next size \n");

	while(1);
}


void delay ( volatile unsigned int n)
{
    while(n!=0)
    {
        n--;
    }
}

