/*The example code involves the following conditions.
	CCLK = 1000 MHz, DCLK = 800 MHz, SYSCLK = 500  MHz, SCLK0 = 125 MHz
	- EPPI0(SCB3): 24-bit transmit, internal clock and frame sync mode at EPPICLK = 56.25 MHz.
					    Required throughput = 56.25 MHz * 3 = 168.75 MB/s.
	- MDMA0 channel 8,  required throughput = 500 MHz * 4 <= 2000 MB/s.
	- MDMA1 channel 18, required throughput = 500 MHz * 4 <= 2000 MB/s.
	- MDMA2 channel 39, required throughput = 500 MHz * 4 <= 2000 MB/s.
	- MDMA3 channel 43, required throughput = 500 MHz * 8 <= 4000 MB/s.
	- MDMA4 channel 45, required throughput = 500 MHz * 4 <= 2000 MB/s.
	- MDMA5 channel 47, required throughput = 500 MHz * 4 <= 2000 MB/s.
	- Throughout requirements depend upon the corresponding DMAx_BWLCNT register values. If not programmed, the MDMA channels request for the bandwidth with full throttle.

The code can be run under different conditions by commenting/un-commenting the corresponding conditions/optimization techniques in the "Multiple_DMAs.h" file.
 */
#include <sys/platform.h>
#include "adi_initialize.h"
#include "sru.h"
#include <services/int/adi_int.h>

#include "Bandwidth_optimisation_Core1.h"


char __argv_string[] = "";

volatile clock_t clock_start_mdma0=0;
volatile clock_t clock_stop_mdma0=0;
volatile clock_t cycles_mdma0=0;
volatile clock_t cycles_mdma0_pre;
float throughput_mdma0=0;

volatile clock_t clock_start_mdma1=0;
volatile clock_t clock_stop_mdma1=0;
volatile clock_t cycles_mdma1=0;
volatile clock_t cycles_mdma1_pre;
float throughput_mdma1=0;

volatile clock_t clock_start_mdma2=0;
volatile clock_t clock_stop_mdma2=0;
volatile clock_t cycles_mdma2=0;
volatile clock_t cycles_mdma2_pre;
float throughput_mdma2=0;

volatile clock_t clock_start_mdma3=0;
volatile clock_t clock_stop_mdma3=0;
volatile clock_t cycles_mdma3=0;
volatile clock_t cycles_mdma3_pre;
float throughput_mdma3=0;

volatile clock_t clock_start_mdma4=0;
volatile clock_t clock_stop_mdma4=0;
volatile clock_t cycles_mdma4=0;
volatile clock_t cycles_mdma4_pre;
float throughput_mdma4=0;

volatile clock_t clock_start_mdma5=0;
volatile clock_t clock_stop_mdma5=0;
volatile clock_t cycles_mdma5=0;
volatile clock_t cycles_mdma5_pre;
float throughput_mdma5=0;

volatile clock_t clock_start_ppi0;
volatile clock_t clock_stop_ppi0=0;
volatile clock_t cycles_ppi0;
volatile clock_t cycles_ppi0_pre;
float throughput_ppi0=0;

float throughput_total=0;

#pragma align 32
unsigned char ucIntDest0Buff[MAX_SIZE];

#pragma align 32
unsigned char ucIntDest1Buff[MAX_SIZE];

#pragma align 32
unsigned char ucIntDest2Buff[MAX_SIZE];

#pragma align 32
unsigned char ucIntDest3Buff[MAX_SIZE];

#pragma align 32
unsigned char ucIntDest4Buff[MAX_SIZE];

#pragma align 32
unsigned char ucIntDest5Buff[MAX_SIZE];

void mdma0_Interrupt_Handler(uint32_t iid, void* handlerArg);
void mdma1_Interrupt_Handler(uint32_t iid, void* handlerArg);
void mdma2_Interrupt_Handler(uint32_t iid, void* handlerArg);
void mdma3_Interrupt_Handler(uint32_t iid, void* handlerArg);
void mdma4_Interrupt_Handler(uint32_t iid, void* handlerArg);
void mdma5_Interrupt_Handler(uint32_t iid, void* handlerArg);


volatile int DMA_Count_mdma0=0;
volatile int DMA_Count_mdma1=0;
volatile int DMA_Count_mdma2=0;
volatile int DMA_Count_mdma3=0;
volatile int DMA_Count_mdma4=0;
volatile int DMA_Count_mdma5=0;

//volatile int Error_Count_PPI0=0;

int main(int argc, char *argv[])
{
	unsigned int uiBytes=0;

	adi_initComponents();
	adi_pwr_cfg0_init();
	/* Work unit size = 4 pages = 8K words */
	uiBytes=2048*4;

	    *pREG_SPU0_SECUREP140=0x3;
		*pREG_SPU0_SECUREP141=0x3;
		*pREG_SPU0_SECUREP142=0x3;
		*pREG_SPU0_SECUREP143=0x3;
		*pREG_SPU0_SECUREP128=0x3;
		*pREG_SPU0_SECUREP129=0x3;
		*pREG_SPU0_SECUREP144=0x3;
		*pREG_SPU0_SECUREP145=0x3;
		*pREG_SPU0_SECUREP146=0x3;
		*pREG_SPU0_SECUREP147=0x3;
		*pREG_SPU0_SECUREP152=0x3;
	    *pREG_SPU0_SECUREP130=0x3;



	/* Enables MDMA0 */
#ifdef ENABLE_MDMA0_DMA_2000MBPS
	adi_int_InstallHandler(INTR_SYS_MDMA0_DST, mdma0_Interrupt_Handler, NULL, true);
	MDMA_CONFIG(8, SOURCE_DMA_CFG_MDMA0 , MDMA0_DMA_DMC_START_ADDRESS, SOURCE_MSIZE_MDMA0, uiBytes/SOURCE_MSIZE_MDMA0,9,DEST_DMA_CFG_MDMA0, (uint32_t)ucIntDest0Buff, DEST_MSIZE_MDMA0, uiBytes/DEST_MSIZE_MDMA0);

#ifdef LIMIT_MDMA0_BW
	*pREG_DMA8_BWLCNT=SOURCE_MSIZE_MDMA0*SYSCLK_SPEED/LIMIT_MDMA0_BW;
#endif

#endif

	/* Enables MDMA1 */
#ifdef ENABLE_MDMA1_DMA_2000MBPS
	adi_int_InstallHandler(INTR_SYS_MDMA1_DST, mdma1_Interrupt_Handler, NULL, true);
	MDMA_CONFIG(18, SOURCE_DMA_CFG_MDMA1 , MDMA1_DMA_DMC_START_ADDRESS, SOURCE_MSIZE_MDMA1, uiBytes/SOURCE_MSIZE_MDMA1,19,DEST_DMA_CFG_MDMA1, (uint32_t)ucIntDest1Buff, DEST_MSIZE_MDMA1, uiBytes/DEST_MSIZE_MDMA1);

#ifdef LIMIT_MDMA1_BW
	*pREG_DMA18_BWLCNT=SOURCE_MSIZE_MDMA1*SYSCLK_SPEED/LIMIT_MDMA1_BW;
#endif

#endif

	/* Enables MDMA2 */
#ifdef ENABLE_MDMA2_DMA_2000MBPS
	adi_int_InstallHandler(INTR_SYS_MDMA2_DST, mdma2_Interrupt_Handler, NULL, true);
	MDMA_CONFIG(39, SOURCE_DMA_CFG_MDMA2 , MDMA2_DMA_DMC_START_ADDRESS, SOURCE_MSIZE_MDMA2, uiBytes/SOURCE_MSIZE_MDMA2,40,DEST_DMA_CFG_MDMA2, (uint32_t)ucIntDest2Buff, DEST_MSIZE_MDMA2, uiBytes/DEST_MSIZE_MDMA2);

#ifdef LIMIT_MDMA2_BW
	*pREG_DMA39_BWLCNT=SOURCE_MSIZE_MDMA2*SYSCLK_SPEED/LIMIT_MDMA2_BW;
#endif

#endif

	/* Enables MDMA3 */
#ifdef ENABLE_MDMA3_DMA_4000MBPS
	adi_int_InstallHandler(INTR_SYS_MDMA3_DST, mdma3_Interrupt_Handler, NULL, true);
	MDMA_CONFIG(43, SOURCE_DMA_CFG_MDMA3 , MDMA3_DMA_DMC_START_ADDRESS, SOURCE_MSIZE_MDMA3, uiBytes/SOURCE_MSIZE_MDMA3,44,DEST_DMA_CFG_MDMA3, (uint32_t)ucIntDest3Buff, DEST_MSIZE_MDMA3, uiBytes/DEST_MSIZE_MDMA3);

#ifdef LIMIT_MDMA3_BW
	*pREG_DMA43_BWLCNT=SOURCE_MSIZE_MDMA3*SYSCLK_SPEED/LIMIT_MDMA3_BW;
#endif

#endif

	/* Enables MDMA4 */
#ifdef ENABLE_MDMA4_DMA_2000MBPS
	adi_int_InstallHandler(INTR_SYS_MDMA4_DST, mdma4_Interrupt_Handler, NULL, true);
	MDMA_CONFIG(45, SOURCE_DMA_CFG_MDMA4 , MDMA4_DMA_DMC_START_ADDRESS, SOURCE_MSIZE_MDMA4, uiBytes/SOURCE_MSIZE_MDMA4,46,DEST_DMA_CFG_MDMA4, (uint32_t)ucIntDest4Buff, DEST_MSIZE_MDMA4, uiBytes/DEST_MSIZE_MDMA4);

#ifdef LIMIT_MDMA4_BW
	*pREG_DMA45_BWLCNT=SOURCE_MSIZE_MDMA4*SYSCLK_SPEED/LIMIT_MDMA4_BW;
#endif

#endif

	/* Enables MDMA5 */
#ifdef ENABLE_MDMA5_DMA_2000MBPS
	adi_int_InstallHandler(INTR_SYS_MDMA5_DST, mdma5_Interrupt_Handler, NULL, true);
	MDMA_CONFIG(47, SOURCE_DMA_CFG_MDMA5 , MDMA5_DMA_DMC_START_ADDRESS, SOURCE_MSIZE_MDMA5, uiBytes/SOURCE_MSIZE_MDMA5,48,DEST_DMA_CFG_MDMA5, (uint32_t)ucIntDest5Buff, DEST_MSIZE_MDMA5, uiBytes/DEST_MSIZE_MDMA5);

#ifdef LIMIT_MDMA5_BW
	*pREG_DMA47_BWLCNT=SOURCE_MSIZE_MDMA5*SYSCLK_SPEED/LIMIT_MDMA5_BW;
#endif

#endif

#define WAIT_COUNT 500

	/* Wait for all the DMAs to complete at least 500 times */
	while(DMA_Count_mdma0<WAIT_COUNT||DMA_Count_mdma1<WAIT_COUNT||DMA_Count_mdma2<WAIT_COUNT||DMA_Count_mdma3<WAIT_COUNT||DMA_Count_mdma4<WAIT_COUNT||DMA_Count_mdma5<WAIT_COUNT);


	DISABLE_MDMAs(8,9);
	DISABLE_MDMAs(18,19);
	DISABLE_MDMAs(39,40);
	DISABLE_MDMAs(43,44);
	DISABLE_MDMAs(45,46);
	DISABLE_MDMAs(47,48);

	/* Print the throughput numbers */


#ifdef ENABLE_MDMA0_DMA_2000MBPS
	throughput_mdma0=(float)uiBytes*CCLK_SPEED/cycles_mdma0;
	printf("Throughput mdma0 = %f MB/s\n\n", throughput_mdma0);
#endif

#ifdef ENABLE_MDMA1_DMA_2000MBPS
	throughput_mdma1=(float)uiBytes*CCLK_SPEED/cycles_mdma1;
	printf("Throughput mdma1 = %f MB/s\n\n", throughput_mdma1);
#endif

#ifdef ENABLE_MDMA2_DMA_2000MBPS
	throughput_mdma2=(float)uiBytes*CCLK_SPEED/cycles_mdma2;
	printf("Throughput mdma2 = %f MB/s\n\n", throughput_mdma2);
#endif

#ifdef ENABLE_MDMA3_DMA_4000MBPS
	throughput_mdma3=(float)uiBytes*CCLK_SPEED/cycles_mdma3;
	printf("Throughput mdma3 = %f MB/s\n\n", throughput_mdma3);
#endif

#ifdef ENABLE_MDMA4_DMA_2000MBPS
	throughput_mdma4=(float)uiBytes*CCLK_SPEED/cycles_mdma4;
	printf("Throughput mdma4 = %f MB/s\n\n", throughput_mdma4);
#endif

#ifdef ENABLE_MDMA5_DMA_2000MBPS
	throughput_mdma5=(float)uiBytes*CCLK_SPEED/cycles_mdma5;
	printf("Throughput mdma5 = %f MB/s\n\n", throughput_mdma5);
#endif

	throughput_total = throughput_mdma0 + throughput_mdma1+ throughput_mdma2 + throughput_mdma3 + throughput_mdma4 + throughput_mdma5;

	printf("Throughput total = %f MB/s\n\n", throughput_total);

	while(1)
	{
		asm("nop;"); /* wait forever */
	}

}



void mdma0_Interrupt_Handler(uint32_t iid, void* handlerArg)
{
	clock_start_mdma0=clock_stop_mdma0;
	clock_stop_mdma0 = clock();
	cycles_mdma0_pre=cycles_mdma0;
	cycles_mdma0=clock_stop_mdma0-clock_start_mdma0;
	if(DMA_Count_mdma0>1)
	{
		cycles_mdma0=(DMA_Count_mdma0*cycles_mdma0_pre+cycles_mdma0)/(DMA_Count_mdma0+1);
	}

	*pREG_DMA9_STAT |= ENUM_DMA_STAT_IRQDONE;			 //Clear the W1C interrupt status bit

	DMA_Count_mdma0++;
}

void mdma1_Interrupt_Handler(uint32_t iid, void* handlerArg)
{
	clock_start_mdma1=clock_stop_mdma1;
	clock_stop_mdma1 = clock();
	cycles_mdma1_pre=cycles_mdma1;
	cycles_mdma1=clock_stop_mdma1-clock_start_mdma1;
	if(DMA_Count_mdma1>1)
	{
		cycles_mdma1=(DMA_Count_mdma1*cycles_mdma1_pre+cycles_mdma1)/(DMA_Count_mdma1+1);
	}

	*pREG_DMA19_STAT |= ENUM_DMA_STAT_IRQDONE;			 //Clear the W1C interrupt status bit

	DMA_Count_mdma1++;
}

void mdma2_Interrupt_Handler(uint32_t iid, void* handlerArg)
{
	clock_start_mdma2=clock_stop_mdma2;
	clock_stop_mdma2 = clock();
	cycles_mdma2_pre=cycles_mdma2;
	cycles_mdma2=clock_stop_mdma2-clock_start_mdma2;
	if(DMA_Count_mdma2>1)
	{
		cycles_mdma2=(DMA_Count_mdma2*cycles_mdma2_pre+cycles_mdma2)/(DMA_Count_mdma2+1);
	}

	*pREG_DMA40_STAT |= ENUM_DMA_STAT_IRQDONE;			 //Clear the W1C interrupt status bit

	DMA_Count_mdma2++;
}

void mdma3_Interrupt_Handler(uint32_t iid, void* handlerArg)
{
	clock_start_mdma3=clock_stop_mdma3;
	clock_stop_mdma3= clock();
	cycles_mdma3_pre=cycles_mdma3;
	cycles_mdma3=clock_stop_mdma3-clock_start_mdma3;
	if(DMA_Count_mdma3>1)
	{
		cycles_mdma3=(DMA_Count_mdma3*cycles_mdma3_pre+cycles_mdma3)/(DMA_Count_mdma3+1);
	}

	*pREG_DMA44_STAT |= ENUM_DMA_STAT_IRQDONE;			 //Clear the W1C interrupt status bit

	DMA_Count_mdma3++;
}

void mdma4_Interrupt_Handler(uint32_t iid, void* handlerArg)
{
	clock_start_mdma4=clock_stop_mdma4;
	clock_stop_mdma4 = clock();
	cycles_mdma4_pre=cycles_mdma4;
	cycles_mdma4=clock_stop_mdma4-clock_start_mdma4;
	if(DMA_Count_mdma4>1)
	{
		cycles_mdma4=(DMA_Count_mdma4*cycles_mdma4_pre+cycles_mdma4)/(DMA_Count_mdma4+1);
	}

	*pREG_DMA46_STAT |= ENUM_DMA_STAT_IRQDONE;			 //Clear the W1C interrupt status bit

	DMA_Count_mdma4++;
}

void mdma5_Interrupt_Handler(uint32_t iid, void* handlerArg)
{
	clock_start_mdma5=clock_stop_mdma5;
	clock_stop_mdma5 = clock();
	cycles_mdma5_pre=cycles_mdma5;
	cycles_mdma5=clock_stop_mdma5-clock_start_mdma5;
	if(DMA_Count_mdma5>1)
	{
		cycles_mdma5=(DMA_Count_mdma5*cycles_mdma5_pre+cycles_mdma5)/(DMA_Count_mdma5+1);
	}

	*pREG_DMA48_STAT |= ENUM_DMA_STAT_IRQDONE;			 //Clear the W1C interrupt status bit

	DMA_Count_mdma5++;
}


