
/* This example code can be used to measure iDMA throughput for different parameters.
 * Test combinations can be varied in "testparam.dat" file.
 */

/*=============  INCLUDES  =============*/
#include "IDMA_throughput_test_Core1.h"
#include "../system/adi_initialize.h"

/*=============  LOCAL DEFINES   =============*/
/* When the processor's L1 and/or L2 cache is enabled the receive data buffers must */
/* be aligned on cache line boundaries. If they are not then any data access by the core may        */
/* pull a buffer into the cache while the DMA is operating on the data buffer. Both the core and    */
/* the DMA are masters on the bus. The core will be performing cache operations. The DMA engine will*/
/* not be. So it is important for the application to both align data that will be operated on by the*/
/* DMA and to separate this data from other application data.                                       */
#define DSTALIGN ADI_CACHE_ALIGN_MIN_4
#define SRCALIGN __attribute__((aligned(32)))

/*=============  DATA  =============*/

/* Flag to register Memory DMA copy completion */
static volatile bool bMemCopyInProgress;

/* Internal buffer */
ALIGNDCACHE static uint32_t IntDataBufL1[MAX_MEMCOPY_BUF_SIZE]__attribute__ ((section(".L1.data")));

ALIGNDCACHE static uint32_t IntDataBufL2[MAX_MEMCOPY_BUF_SIZE]__attribute__ ((section(".L2.data")));

ALIGNDCACHE static uint32_t IntDataBufL3[MAX_MEMCOPY_BUF_SIZE]__attribute__ ((section(".L3.data")));

/* External buffer */
ALIGNDCACHE static uint32_t ExtDataBufL1[ADI_CACHE_ROUND_UP_SIZE(MAX_MEMCOPY_BUF_SIZE, uint8_t)]__attribute__ ((section(".L1.data")));

ALIGNDCACHE static uint32_t ExtDataBufL2[ADI_CACHE_ROUND_UP_SIZE(MAX_MEMCOPY_BUF_SIZE, uint8_t)]__attribute__ ((section(".L2.data")));

ALIGNDCACHE static uint32_t ExtDataBufL3[ADI_CACHE_ROUND_UP_SIZE(MAX_MEMCOPY_BUF_SIZE, uint8_t)]__attribute__ ((section(".L3.data")));

volatile clock_t clock_start __attribute__ ((section(".L3.data")));
volatile clock_t clock_stop __attribute__ ((section(".L3.data")));;
//volatile clock_t cycles;
volatile clock_t cycles_offset __attribute__ ((section(".L3.data")));;
int cycles2 __attribute__ ((section(".L3.data")));;

/* Callback parameter */
int cbparam=10;//__attribute__ ((section(".L3.data")));


/* To store internal buffer start address */
uint32_t* pInt;

/* To store external buffer start address */
uint32_t* pExt;

clock_t cycle_start __attribute__ ((section(".L3.data")));;
clock_t cycle_stop __attribute__ ((section(".L3.data")));;
int cycles __attribute__ ((section(".L3.data")));;
float throughput __attribute__ ((section(".L3.data")));;

/* Holds list of all the test parameters combinations for which the test should run */
TEST_PARAM TestParamArray[MAX_TEST_COMBINATIONS]__attribute__ ((section(".L1.data")))=
{
	#include "testparam.dat"
};

/* To keep track of the total number of failures */
int fail_count=0;

/* To keep track of the failed test combinations */
uint32_t TestFaillog[MAX_TEST_COMBINATIONS];//__attribute__ ((section(".L3.data")));;

/* Holds the test suite information*/
TEST_INFO TestInfo =
{
	TestParamArray, 0
};

/*=============  LOCAL FUNCTION DECLARATIONS  =============*/

/* Prepares data buffers for Memory DMA copy */
static void PrepareDataBuffers (uint32_t* psrc, uint32_t* pdst, uint32_t count);//__attribute__ ((section(".L3.data")));;

/* Verifies memory DMA copy by comparing destination data with source */
static TEST_RES VerifyDataCopy (uint32_t* psrc, uint32_t* pdst, uint32_t count);//__attribute__ ((section(".L3.data")));;

/* Callback for MDMA service */
static void idmaCallback(void *pArg);//__attribute__ ((section(".L3.data")));;

void CacheRegionInvalidate(uint8_t* pdst, uint32_t size);//__attribute__ ((section(".L3.data")));;

/*iDMA Descriptor Buffer for Task*/
IDMA_BUFFER_DEFINE(task1, 1, IDMA_1D_DESC);

/*=============  EXTERNAL FUNCTION DECLARATIONS  =============*/

/*=============  MAIN FUNCTION DEFINITION  =============*/
int main(int argc, char *argv[])//__attribute__ ((section(".L3.code")))
{
    /* Time-out counter to make sure the example exits */
    volatile uint32_t   TimeOutCount = MEMCOPY_TIME_OUT_VAL;

    /* DMA Return code */
    TEST_RES     eResult = SUCCESS;

    /* To keep track of the test iteration */
    int test_iteration=0;

    /* Initialize managed drivers and/or services */
    adi_initComponents();

    clock_start = clock();
    clock_stop = clock();
    cycles_offset = clock_stop-clock_start;

    int i=0;

    /* Iterate over multiple test combinations */
    if (eResult == SUCCESS)
    {
		while(TestParamArray[test_iteration].TestIndex!=-1)
		{
			if(TestParamArray[test_iteration].TestIndex!=0)
			{
				DBG_MSG("\nTesting combination %d\n", TestParamArray[test_iteration].TestIndex);
				DBG_MSG("Internal memory type = 0x%x\n", TestParamArray[test_iteration].eIntMem);
				DBG_MSG("External memory type = 0x%x\n", TestParamArray[test_iteration].eExtMem);
				DBG_MSG("Buffer count = %d\n", TestParamArray[test_iteration].BuffCount);
				DBG_MSG("Burst size  = %d\n", TestParamArray[test_iteration].Blocksize);

				switch(TestParamArray[test_iteration].eIntMem)
				{
					case L1MEM: pInt = IntDataBufL1; break;
					case L2MEM: pInt = IntDataBufL2; break;
					case L3MEM: pInt = IntDataBufL3; break;
					default:	pInt = (uint32_t*)TestParamArray[test_iteration].eIntMem;
				}

				switch(TestParamArray[test_iteration].eExtMem)
				{
					case L1MEM: pExt = ExtDataBufL1; break;
					case L2MEM: pExt = ExtDataBufL2; break;
					case L3MEM: pExt = ExtDataBufL3; break;
					default:	pExt = (uint32_t*)TestParamArray[test_iteration].eExtMem;
				}

//changed from 2 to 16
				idma_init(0, TestParamArray[test_iteration].Blocksize, 16, TICK_CYCLES_8, 100000, NULL);
				idma_init_task(task1, IDMA_1D_DESC, 1, idmaCallback, task1);

				/* Prepare data buffers */
//				PrepareDataBuffers (&pInt[i*TestParamArray[test_iteration].BuffCount], &pExt[i*TestParamArray[test_iteration].BuffCount], TestParamArray[test_iteration].BuffCount);
				PrepareDataBuffers (pInt, pExt, TestParamArray[test_iteration].BuffCount);

				/* Initialize flag */
				bMemCopyInProgress = true;

				DBG_MSG("DMA copy started\n");

				idma_add_desc(task1, (void *)pExt, (void *)pInt, TestParamArray[test_iteration].BuffCount*4, DESC_NOTIFY_W_INT);
				idma_schedule_task(task1);

				cycle_start = clock();


				/* Reinitialize the TimeOutCount value */
				TimeOutCount = MEMCOPY_TIME_OUT_VAL;

				/* Wait until DMA copy is complete or the time-out counter expires */
				while ((bMemCopyInProgress) && (TimeOutCount))
				{
					/* Decrement time-out counter */
					TimeOutCount--;
				}


				/* If no timeout */
				if(TimeOutCount)
				{
//					eResult = VerifyDataCopy (&pInt[i*TestParamArray[test_iteration].BuffCount], &pExt[i*TestParamArray[test_iteration].BuffCount], TestParamArray[test_iteration].BuffCount);
					eResult = VerifyDataCopy (pInt, pExt, TestParamArray[test_iteration].BuffCount);

					/* IF (Failure) */
					if (eResult != SUCCESS)
					{
						DBG_MSG("Data verification failed\n");

						break;
					}
				}
				else
				{
					 DBG_MSG("Time out\n");
					 eResult = FAILURE;
				}

				/* Stop iDMA */
				idma_stop();

				/* IF (Success) */
				if (eResult == SUCCESS)
				{
					DBG_MSG ("Test combination %d passed\n\n",TestParamArray[test_iteration].TestIndex);

					cycles2 = cycle_stop - cycle_start;
					cycles= cycles2-cycles_offset;

					throughput = TestParamArray[test_iteration].BuffCount*4*CLK_SPEED/cycles;

					DBG_MSG("Cycles = %d, Throughput = %f MB/s\n\n",cycles, throughput);
				}
				/* ELSE (Failure) */
				else
				{
					DBG_MSG ("Test combination %d failed\n\n",TestParamArray[test_iteration].TestIndex);
					TestInfo.FailedTestInfo[TestInfo.FailCount].TestIndex = TestParamArray[test_iteration].TestIndex;
					TestInfo.FailedTestInfo[TestInfo.FailCount++].ErrorCode = eResult;
				}
			}
			test_iteration++;
		}
	}
	
	/* IF (Success) */
	if ((eResult == SUCCESS)&&(TestInfo.FailCount == 0))
	{
		printf ("All done\n");
	}
	/* ELSE (Failure) */
	else
	{
		printf ("Failed for %d test combinations\n",TestInfo.FailCount);
	}

  return 0;
}

static void idmaCallback(void *pArg)
{
	cycle_stop = clock();
	 bMemCopyInProgress = false;
}

static void PrepareDataBuffers (uint32_t* psrc, uint32_t* pdst, uint32_t count)
{
    /* Loop variable */
    uint32_t    i;

    /* Generate Source data, Clear destination buffer */
    for (i = 0u; i < count; i++)
    {
    	psrc[i]  = (uint8_t)rand();
    	pdst[i]  = 0;
    }

	/* Flush the source buffer */
	flush_data_buffer((void *)psrc,
					(void *)((char *)psrc + count*4),
					ADI_FLUSH_DATA_NOINV);

	/* Flush and invalidate destination buffer */
	flush_data_buffer((void *)pdst,
					(void *)((char *)pdst + count*4),
					ADI_FLUSH_DATA_INV);
}

void CacheRegionInvalidate(uint8_t* pdst, uint32_t size)
{
	/* For cache coherence */
	xthal_dcache_region_invalidate(pdst, size);
}

static TEST_RES VerifyDataCopy (uint32_t* psrc, uint32_t* pdst, uint32_t count)
{
	CacheRegionInvalidate((uint8_t*)pdst, count*4);

	/* Loop variable */
    uint32_t        i;

    /* Compare the destination data with source */
    for (i = 0u; i < count; i++)
    {
        /* IF (Destination data not same as source) */
        if (psrc[i] != pdst[i])
        {
            /* Return error */
            return (FAILURE);
        }
    }

    /* Return success */
    return (SUCCESS);
}

/*****/

/*
** EOF
*/
