/*
memory test with DSP core
Author: Brighton
Created on 2010-10-27
*/

#include <stdio.h>

#define MAX_FILL_FAIL_COUNT 		(10)
#define MAX_ADDRESS_FAIL_COUNT 		(10)
#define MAX_BITWALKING_FAIL_COUNT 	(2)

#define BIT_PATTERN_FILLING_TEST 	1
#define ADDRESS_TEST 				1
#define BIT_WALKING_TEST 			1

#define PRINT_DETAILS 			1
#if PRINT_DETAILS
#define 	PRINT	 		printf
#else
#define 	PRINT			// 		
#endif

unsigned long long ulDataPatternTable[] = { 
0x0000000000000000, 
0xffffffffffffffff, 
0xaaaaaaaaaaaaaaaa, 
0x5555555555555555 };

/*
This function fills the patterns into memory and reads back and verification
*/
unsigned int MEM_FillTest(unsigned int uiStartAddress,
                        unsigned int uiCount,
                        unsigned long long ulBitPattern,
                        unsigned int uiStep)
{
    unsigned int i, uiFailCount=0;
    volatile unsigned long long *ulpAddressPointer;
    volatile unsigned long long ulReadBack;

    /* Write the pattern */
	ulpAddressPointer = (unsigned long long *)uiStartAddress;
	for(i=0; i<uiCount; i++)
	{
        *ulpAddressPointer = ulBitPattern;	  /* fill with pattern */
        ulpAddressPointer += (uiStep);
    }

	ulpAddressPointer = (unsigned long long *)uiStartAddress;
	for(i=0; i<uiCount; i++)
	{
        ulReadBack = *ulpAddressPointer;
        if ( ulReadBack!= ulBitPattern)      /* verify pattern */
        {
			PRINT("Memory Test fails at 0x%8x, Write 0x%16llx, Readback 0x%16llx\n", ulpAddressPointer, ulBitPattern, ulReadBack);
            uiFailCount++;
			if(uiFailCount>=MAX_FILL_FAIL_COUNT)
				return uiFailCount;
        }
        ulpAddressPointer += (uiStep);
    }
	return uiFailCount;
}

/*
this function write the address to corresponding memory unit and readback for verification
*/
unsigned int MEM_AddrTest(unsigned int uiStartAddress, 
						unsigned int uiCount,
                        int iStep)
{
    unsigned int i, uiFailCount=0;
    volatile unsigned long long *ulpAddressPointer;
    volatile unsigned long long ulReadBack;

	ulpAddressPointer = (unsigned long long *)uiStartAddress;
	for(i=0; i<uiCount; i++)
	{
		/* fill with address value */
        *ulpAddressPointer = _itoll(((unsigned int)ulpAddressPointer)+4, 
        	(unsigned int)ulpAddressPointer);	  
        ulpAddressPointer += (iStep);
    }

	ulpAddressPointer = (unsigned long long *)uiStartAddress;
	for(i=0; i<uiCount; i++)
	{
        ulReadBack = *ulpAddressPointer;
        if ( ulReadBack != _itoll(((unsigned int)ulpAddressPointer)+4, 
        	(unsigned int)ulpAddressPointer)) /* verify data */
        {
			PRINT("Memory Test fails at 0x%8x, Write 0x%16llx, Readback 0x%16llx\n", ulpAddressPointer, _itoll(((unsigned int)ulpAddressPointer)+4, (unsigned int)ulpAddressPointer), ulReadBack);
            uiFailCount++;
			if(uiFailCount>=MAX_ADDRESS_FAIL_COUNT)
				return uiFailCount;
        }
        ulpAddressPointer += (iStep);
    }
    return uiFailCount;              /* show no error */
}

unsigned int Bus_Bit_Walking(unsigned int uiAddress)
{
    unsigned int i, uiFailCount;
    volatile unsigned long long *ulpAddressPointer;
    volatile unsigned long long ulReadBack;
    unsigned long long ulBitMask;
    
	ulpAddressPointer = (unsigned long long *)uiAddress;

    ulBitMask = 1;
	uiFailCount=0;
    for (i = 0; i < 64; i++)
    {
        // Test one in bit position i
        *ulpAddressPointer = ulBitMask;
		ulReadBack= *ulpAddressPointer;
        if (ulReadBack != ulBitMask)
		{
			PRINT("Bit walking Test fails at 0x%8x, Write 0x%16llx, Readback 0x%16llx\n", (unsigned int)ulpAddressPointer, (ulBitMask), ulReadBack);
            uiFailCount++;
		}	            
        // Test zero in bit position i
        *ulpAddressPointer = ~ulBitMask;
		ulReadBack= *ulpAddressPointer;
        if (ulReadBack != (~ulBitMask))
		{
			PRINT("Bit walking Test fails at 0x%8x, Write 0x%8x, Readback 0x%8x\n", (unsigned int)ulpAddressPointer, (~ulBitMask), ulReadBack);
            uiFailCount++;
		}
        ulBitMask = ulBitMask << 1;
    }

    return uiFailCount;
}

unsigned int MEM_Bit_Walking(unsigned int uiStartAddress,
						unsigned int uiCount,
                        unsigned int uiStep)
{
    unsigned int uiFailCount=0;
    unsigned int j;
    unsigned long long ulBitMask=1;
    for (j = 0; j < 64; j++)
    {
	  	PRINT("Memory Bit Walking at 0x%8x with pattern 0x%16llx\n",uiStartAddress, ulBitMask);
        if(MEM_FillTest(uiStartAddress, uiCount, ulBitMask, uiStep))
        	uiFailCount++;
	  	PRINT("Memory Bit Walking at 0x%8x with pattern 0x%16llx\n",uiStartAddress, ~ulBitMask);
        if(MEM_FillTest(uiStartAddress, uiCount, ~ulBitMask, uiStep))
        	uiFailCount++;

		if(uiFailCount>= MAX_BITWALKING_FAIL_COUNT)
			return uiFailCount;

        ulBitMask <<= 1;
    }
	return uiFailCount;
}

int DSP_core_MEM_Test(unsigned int uiStartAddress, unsigned int uiStopAddress, unsigned int uiStep)
{
    unsigned int uiCount, uiFailCount=0, uiTotalFailCount=0;
    int j;

    uiCount = ((uiStopAddress - uiStartAddress)/8)/uiStep;

#if BIT_PATTERN_FILLING_TEST
    // Fill with values from pattern table
    for (j = 0; j < 4; j++)
    {
        uiFailCount = MEM_FillTest(uiStartAddress, uiCount, ulDataPatternTable[j], uiStep);
	    if (uiFailCount)
	    {
	    	PRINT("!!!Failed Memory Fill Test at %d Units with pattern 0x%16llx\n",uiFailCount, ulDataPatternTable[j]);
	        uiTotalFailCount+=uiFailCount;
	    }
		else
		   	PRINT("Passed Memory Fill Test from 0x%8x to 0x%8x with pattern 0x%16llx\n",uiStartAddress,uiStopAddress, ulDataPatternTable[j]);
    }
    
#endif
#if ADDRESS_TEST    
    // Test the address range from low to high
    uiFailCount = MEM_AddrTest(uiStartAddress, uiCount, uiStep);
    if (uiFailCount)
    {
    	PRINT("!!!Failed Memory Address Test at %d units\n",uiFailCount);
        uiTotalFailCount+=uiFailCount;
    }
	else
	   	PRINT("Passed Memory Address Test from 0x%8x to 0x%8x\n",uiStartAddress,uiStopAddress);

    // Test the address range from high to low
    uiFailCount = MEM_AddrTest(uiStopAddress-uiStep*8, uiCount, -uiStep);
    if (uiFailCount)
    {
    	PRINT("!!!Failed Memory Address Test at %d units\n",uiFailCount);
        uiTotalFailCount+=uiFailCount;
    }
	else
	   	PRINT("Passed Memory Address Test from 0x%8x to 0x%8x\n", uiStopAddress, uiStartAddress);
#endif
#if BIT_WALKING_TEST
    // Do walking ones and zeroes test
    uiFailCount = Bus_Bit_Walking(uiStartAddress);
    if (uiFailCount)
    {
	   	PRINT("!!!Failed Bus Bit Walking at %d units\n",uiFailCount);
        uiTotalFailCount+=uiFailCount;
    }    
	else
	  	PRINT("Passed Bus Bit Walking at 0x%8x\n",uiStartAddress);
    uiFailCount = MEM_Bit_Walking(uiStartAddress,uiCount, uiStep);
    if (uiFailCount)
    {
	   	PRINT("!!!Failed Memory Bit Walking at %d units\n",uiFailCount);
        uiTotalFailCount+=uiFailCount;
    }    
	else
	  	PRINT("Passed Memory Bit Walking from 0x%8x to 0x%8x\n",uiStartAddress,uiStopAddress);
#endif
  	return uiTotalFailCount;
}
