/*/////////////////////////////////////////////////////////////////////////////
//                                                                           //
//        Copyright 2001 Equator Technologies, Inc. Unpublished              //
//                                                                           //
// Equator Technologies, Inc.                                                //
// Proprietary & Confidential                                                //
//                                                                           //
// This source code and the algorithms implemented therein constitute        //
// confidential information and may comprise trade secrets of Equator        //
// or its associates, and any use thereof is subject to the terms and        //
// conditions of the Non-Disclosure Agreement pursuant to which this         //
// source code was originally received.                                      //
//                                                                           //
/////////////////////////////////////////////////////////////////////////////*/

/*******************************************************************************/
/***************************  New ETI France version ***************************/
/***************************  S. Jackson - October 26th 01 *********************/
/*******************************************************************************/

#include <eti/mm.h>
#define MEGABYTE (1024*1024)

#define PRINTF printf
#define NULL 0

#define MAX_MEM 128 // the maximum memory to be allocated in MBytes
#define HEAP_SAFE 2	// size in MBytes to be kept for heap, stack

#define pack_16_64_var(a, b, c, d) hmpv_combine_64(((a)<<16) |((b) & 0xFFFF),((c)<<16) |((d) & 0xFFFF))


//#define loquacious 1 // sets PRINTF options (verbosity)

int allocate_memory(char **);
int sdram_address_testing(char *, int);
int sdram_patternA(char *, int);
int sdram_patternB(char *, int);
int sdram_refresh(char *, int);
int sdram_exhaustive(char *, int);
int sdram_random(char *, int);
int sdram_walking_one(char *, int);
int sdram_walking_zero(char *, int);
int sdram_address_cached(char *, int);
int sdram_pattern_cached(char *, int);
void exit_with_error(char *);

int keep_going;

int 
main(int argc, char *argv[]) {

        char *ptr_memory;
        int sizeof_memory, count;

	if ( argc > 1 && strcmp(argv[1], "-k") == 0 )
	   	keep_going = 1;

		if(!(sizeof_memory = allocate_memory(&ptr_memory))){
		   printf("\n\nError allocating memory!\n\n");
		   exit(1);		
		}


		while(1){
			
			PRINTF("\n--*-- Begin SDRAM cached test --*--\n");

			#define num_tests 15
       		// it's too fast using the cache, so iterate num_tests times
       		for (count = 0; count < num_tests; count ++){
       		   if(!sdram_address_cached(ptr_memory, sizeof_memory)){
       		      exit_with_error(ptr_memory);
       		   }
    
       		   if(!sdram_pattern_cached(ptr_memory, sizeof_memory)){
       		      exit_with_error(ptr_memory);
       		   }
			   PRINTF("Test %d of %d.\n", count+1, num_tests);
        	}

			PRINTF("\n--*-- Begin SDRAM non-cached test --*--\n");

       		if(!sdram_address_testing(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
       		}
       
       		if(!sdram_patternA(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
       		}
       
       		if(!sdram_patternB(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
       		}
       
       		if(!sdram_refresh(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
       		}

       		if(!sdram_random(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
       		}

       		if(!sdram_walking_one(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
       		}

       		if(!sdram_walking_zero(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
       		}

       		if(!sdram_exhaustive(ptr_memory, sizeof_memory)){
       		   exit_with_error(ptr_memory);
			}
       
       
			PRINTF("\nDone - no errors.\n");
        
		}

        PRINTF("\n--*-- SDRAM/DCACHE test PASSED --*--\n");
		free(ptr_memory);
}


void exit_with_error(char *ptr_memory){
	printf("\nError verifying memory!\n\n");

	if ( !keep_going )
	{
		free(ptr_memory);
		exit(1);		
	}
}

int allocate_memory(char **ptr_memory){
    int index=0;
 
    for (index = MAX_MEM; index >=0; index--){
       *ptr_memory = (char *) memalign (32, MEGABYTE*index);
       if(*ptr_memory != NULL){
     	 free (*ptr_memory);
		 index -= HEAP_SAFE;                   // keep some memory for heap/stack
         *ptr_memory = (char *) memalign (32, MEGABYTE*(index));
		 break;
       }
  	   printf("Tried to allocate %dMBytes and failed.\n", index);
    }
    if(*ptr_memory != NULL){
       printf("\nMemory space to be tested is %dMByte.\n", index);
       printf("Memory range [%p, %p)\n", *ptr_memory, *ptr_memory + MEGABYTE*(index));
       return(index); 
    }

   return(NULL); 
}    

// this tests the address lines of the memory chips by linearly increasing the addresses with
// every INT data entry being unique

int sdram_address_testing(char *ptr_memory, int sizeof_memory){
   int counter;
   int *int_ptr = (int *)ptr_memory;

   printf("\nDoing address test.\n");
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 1); counter ++){ //access in INTS
      int_ptr[counter] = counter;

#ifdef loquacious
      if ( !(counter % 0x700000)){
         printf("Write.\n");
      }   
#endif

   }

   printf("\nVerifying:\n");

   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 1); counter++){
      if( int_ptr[counter] != counter){
   	     printf("Failed at address = 0x%x\n", &int_ptr[counter]);
   	     printf("Expected = 0x%x  actual = 0x%x", counter, int_ptr[counter]);
	     return(0);
      }

#ifdef loquacious
       
	  if (!(counter % 0x700000)){
	     printf("Ok.\n");
      }   
#endif

   }   
   printf("\nPass address test.\n");
   return(1);
}

int sdram_patternA(char *ptr_memory, int sizeof_memory){
   int counter;
   int *int_ptr = (int *)ptr_memory;

   // Exercising with maximum activity on data bus
   printf("\nDoing SDRAM pattern A test.\n");
  
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter+=2){
      int_ptr[counter]   = 0xaaaaaaaa;
      int_ptr[counter+1] = 0x55555555;

#ifdef loquacious
      if ( !(counter % 0x700000)){
         printf("Write.\n");
      }   
#endif
   }

   printf("\nVerifying:\n");

   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter+=2){
      if( int_ptr[counter] != 0xaaaaaaaa){
   	     printf("Failed at address = 0x%x\n", &int_ptr[counter]);
   	     printf("Expected = 0xAAAAAAAA  actual = 0x%x", int_ptr[counter]);
	     return(0);
      }
        
      if( int_ptr[counter+1] != 0x55555555){
   	     printf("Failed at address = 0x%x\n", &int_ptr[counter]);
   	     printf("Expected = 0x55555555  actual = 0x%x", int_ptr[counter]);
	     return(0);
      }
        
#ifdef loquacious
	  if (!(counter % 0x700000)){
	     printf("Ok.\n");
      }   
#endif

   }   
   printf("\nPass pattern A test.\n");
   return(1);
}

int sdram_patternB(char *ptr_memory, int sizeof_memory){
   int counter;
   int *int_ptr = (int *)ptr_memory;

   // Exercising with maximum activity on data bus
   printf("\nDoing SDRAM pattern B test.\n");
  
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter+=2){
      int_ptr[counter] = 0x55555555;
      int_ptr[counter+1]   = 0xaaaaaaaa;

#ifdef loquacious
      if ( !(counter % 0x700000)){
         printf("Write.\n");
      }   
#endif

   }

   printf("\nVerifying:\n");

   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter+=2){
      if( int_ptr[counter] != 0x55555555){
   	     printf("Failed at address = 0x%x\n", &int_ptr[counter]);
   	     printf("Expected = 0x55555555  actual = 0x%x", int_ptr[counter]);
	     return(0);
      }
        
      if( int_ptr[counter+1] != 0xaaaaaaaa){
   	     printf("Failed at address = 0x%x\n", &int_ptr[counter]);
   	     printf("Expected = 0xAAAAAAAA  actual = 0x%x", int_ptr[counter]);
	     return(0);
      }
        
#ifdef loquacious
	  if (!(counter % 0x700000)){
	     printf("Ok.\n");
      }   
#endif

   }   
   printf("\nPass pattern B test.\n");
   return(1);
}

int sdram_refresh(char *ptr_memory, int sizeof_memory){
   int counter, temp;
   n64 *n64_ptr = (n64 *)ptr_memory;
   volatile int dummy;

   // SDRAM Refresh test: write-wait-verify. This tests volatility of SDRAM chips: the SDRAM auto refresh 
   printf("\nDoing SDRAM refresh test.\n");
  
#pragma unroll_amount 8
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 3) - 2); counter++)
   { // count in 64bits - n64
      temp = counter % 256;
      n64_ptr[counter] = pack_16_64_var(temp, temp, temp, temp);

#ifdef loquacious
	  if (!(counter % 0x700000)){
	     printf("Write.\n");
      }   
#endif

   }

#if 0    
   printf("\nWaiting ca. 20 seconds:\n");
   sleep(20);
#endif
    
   printf("\nVerifying:\n");

#pragma unroll_amount 8
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 3) - 2); counter++){
      temp = counter % 256;

      if(n64_ptr[counter] != pack_16_64_var(temp, temp, temp, temp)){
   	     printf("Failed at address = 0x%x\n", &n64_ptr[counter]);
	     printf("Expected = 0x%llx  actual = 0x%llx", pack_16_64_var(temp, temp, temp, temp), n64_ptr[counter]);
	     return(0);
      }

#ifdef loquacious
	  if (!(counter % 0x700000)){
	     printf("Ok.\n");
      }   
#endif

   }   
   printf("\nPass refresh test.\n");
   return(1);
}

int sdram_random(char *ptr_memory, int sizeof_memory){
   unsigned int counter, LFSR, temp;
   int *int_ptr = (int *)ptr_memory;


   int dummy = 0;

   // Exercising memory with random address access using a linear-feedback-shift-register 
   // (LFSR) to generate the addresses

   printf("\nDoing SDRAM random test.\n");
  
   LFSR = 1;
   for (counter = 0; counter < (( 0x1 << 23)); counter++){

	  temp = 0;                // do EXOR and LFSR
	  if ((LFSR >> 24) ^ (LFSR & 0x1)){
	     temp = 0x1 << 24;
	  }
      LFSR = (LFSR >> 1) | temp;

	  temp = LFSR;
      if (temp < (((MEGABYTE*sizeof_memory) >> 2) - 2)){
         int_ptr[temp] = counter;
		 dummy++;
      }

#ifdef loquacious
      if ( !(counter % 0x200000)){
         printf("Write.\n");
         //printf("Address: 0x%x\n", LFSR);
      }   
#endif

   }


   printf("Wrote %d words of 32 bits.\n", dummy);
   printf("\nVerifying:\n");

   dummy = 0;
   LFSR = 1;

   for (counter = 0; counter < (( 0x1 << 23)); counter++){

      
	  temp = 0;                // do EXOR and LFSR
	  if ((LFSR >> 24) ^ (LFSR & 0x1)){
	     temp = 0x1 << 24;
	  }
      LFSR = (LFSR >> 1) | temp;

	  temp = LFSR;

      if (temp < (((MEGABYTE*sizeof_memory) >> 2) - 2)){
         if( int_ptr[temp] != counter){
   	        printf("Failed at address = 0x%x\n", temp);
   	        printf("Expected = 0x%x  actual = 0x%x", counter, int_ptr[temp]);
	        return(0);
         }
		 dummy++;
      }

#ifdef loquacious
	  if (!(counter % 0x200000)){
	     printf("Ok.\n");
      }   
#endif

   }   
   printf("Verified %d words.\n", dummy);
   printf("\nPass random test.\n");

   return(1);
}

int sdram_walking_one(char *ptr_memory, int sizeof_memory){
   unsigned int counter, data, up_down;
   unsigned int *int_ptr = (unsigned int *)ptr_memory;
   #define up 1
   #define down 0

   // Exercising with 1-bit activity on data bus
   printf("\nDoing SDRAM walking-ones test.\n");

   data = 0x1;
   up_down = up;
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter++){
      int_ptr[counter]   = data;
  	  if (up_down == up){  // move 1 left
         data = data << 1; 
	     if (data == 0x80000000){
	  	    up_down = down;
	     }
	  }	else {	  // move 1 right
         data = data >> 1; 
	     if (data == 0x1){
	  	    up_down = up;
	     }
	  }

#ifdef loquacious
      if ( !(counter % 0x700000)){
         printf("Write.\n");
      }   
#endif

   }

   printf("\nVerifying:\n");

   data = 0x1;
   up_down = up;
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter++){
      if( int_ptr[counter] != data){
         printf("Failed at address = 0x%x\n", &int_ptr[counter]);
         printf("Expected = 0x%x  actual = 0x%x", data, int_ptr[counter]);
         return(0);
      }
	  if (up_down == up){  // move 1 left
         data = data << 1; 
	     if (data == 0x80000000){
	  	    up_down = down;
	     }
	  }	else {	  // move 1 right
         data = data >> 1; 
	     if (data == 0x1){
	  	    up_down = up;
	     }
	  }

#ifdef loquacious
	  if (!(counter % 0x700000)){
	     printf("Ok.\n");
      }   
#endif

   }   
   printf("\nPass walking-one test.\n");
   return(1);
}

int sdram_walking_zero(char *ptr_memory, int sizeof_memory){
   unsigned int counter, data, up_down;
   unsigned int *int_ptr = (unsigned int *)ptr_memory;
   #define up 1
   #define down 0

   // Exercising with 1-bit activity on data bus
   printf("\nDoing SDRAM walking-zero test.\n");

   data = 0x1;
   up_down = up;
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter++){
      int_ptr[counter]   = 0xFFFFFFFF ^ data;
	  if (up_down == up){  // move 1 left
         data = data << 1; 
	     if (data == 0x80000000){
	  	    up_down = down;
	     }
	  }	else {	  // move 1 right
         data = data >> 1; 
	     if (data == 0x1){
	  	    up_down = up;
	     }
	  }

#ifdef loquacious
      if ( !(counter % 0x700000)){
         printf("Write.\n");
      }   
#endif

   }

   printf("\nVerifying:\n");

   data = 0x1;
   up_down = up;
   for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 2) - 2); counter++){

      if( int_ptr[counter] != (0xFFFFFFFF ^ data)){
         printf("Failed at address = 0x%x\n", &int_ptr[counter]);
         printf("Expected = 0x%x  actual = 0x%x", (0xFFFFFFFF ^ data), int_ptr[counter]);
         return(0);
      }
	  if (up_down == up){  // move 1 left
         data = data << 1; 
	     if (data == 0x80000000){
	  	    up_down = down;
	     }
	  }	else {	  // move 1 right
         data = data >> 1; 
	     if (data == 0x1){
	  	    up_down = up;
	     }
	  }

               
#ifdef loquacious
	  if (!(counter % 0x700000)){
	     printf("Ok.\n");
      }   
#endif

   }   
   printf("\nPass walking-zero test.\n");
   return(1);
}

// this tests the address lines of the cache by linearly increasing the addresses with
// every INT data entry being unique. Stresses cache, while other tests stress SDRAM.

int sdram_address_cached(char *ptr_memory, int sizeof_memory){
   int counter, block;
   int *int_ptr = (int *)ptr_memory;

   printf("\nDoing cached tests.\n");
   for (block = 0; block < (((MEGABYTE*sizeof_memory) >> 2) - 8192); block += 8192){  
      for (counter = 0; counter < 8192; counter ++){ //access in INTS
         int_ptr[counter + block] = counter + block;
      }

      for (counter = 0; counter < 8192; counter ++){ //access in INTS
         if( int_ptr[counter + block] != counter + block){
   	        printf("Failed at address = 0x%x\n", &int_ptr[counter + block]);
   	        printf("Expected = 0x%x  actual = 0x%x\n", 
                       counter + block, 
                       int_ptr[counter + block]);
   	        printf("\nCache error!\n");
	        return(0);
         }
      }
   }

   return(1);
}

int sdram_pattern_cached(char *ptr_memory, int sizeof_memory){
   int counter, block;
   int *int_ptr = (int *)ptr_memory;

   for (block = 0; block < (((MEGABYTE*sizeof_memory) >> 2) - 8192); block += 8192){  
      for (counter = 0; counter < 8192; counter +=2){ //access in INTS
         int_ptr[counter+block]   = 0xaaaaaaaa;
         int_ptr[counter+block+1] = 0x55555555;
      }

      for (counter = 0; counter < 8192; counter +=2){ //access in INTS
         if( int_ptr[counter + block] != 0xaaaaaaaa){
   	        printf("Failed at address = 0x%x\n", &int_ptr[counter+block]);
   	        printf("Expected = 0xAAAAAAAA  actual = 0x%x", int_ptr[counter+block]);
	        return(0);
         }
         if( int_ptr[counter + block + 1] != 0x55555555){
   	        printf("Failed at address = 0x%x\n", &int_ptr[counter+block]);
   	        printf("Expected = 0x55555555  actual = 0x%x", int_ptr[counter+block]);
	        return(0);
         }
      }
   }

   printf("Passed cached pattern tests.\n");
   return(1);
}

int sdram_exhaustive(char *ptr_memory, int sizeof_memory){
   int counter, temp;
   n64 *n64_ptr = (n64 *)ptr_memory;
   int iteration, max_iteration = 256;

   // Exhaustive testing: do all possible combinations of bits(!) in Memory. This should take A LONG TIME!

   // this does 256 entire RAM (up to 120MBytes) checks. Memory is written with 4 bytes having the same
   // (increasing) value: 0,0,0,0; 1,1,1,1; 2,2,2,2; ..... The count is then increased by one on the 
   // next iteration. This puts Every possible number into every Memory byte. */
 
   printf("\nDoing SDRAM exhaustive test. This will take a long time.\n");

   for(iteration = 0; iteration < max_iteration; iteration ++){ 
      printf("Write.\n");
#pragma unroll_amount 8
      for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 3) - 2); counter++){ // counting in 64bits (n64)
         temp = (((int)n64_ptr) + iteration) % 256;
	     n64_ptr[counter] = pack_16_64_var((temp<<8) | temp, (temp<<8) | temp, (temp<<8) | temp, (temp<<8) | temp);

#ifdef loquacious
	     if (!(counter % 0x700000)){
	        printf("Write.\n");
         }   
#endif

      }
      printf("\nVerifying iteration %d of 256:\n", iteration+1);
    
      // every n64 in RAM should have a different content
#pragma unroll_amount 8
      for (counter = 0; counter < (((MEGABYTE*sizeof_memory) >> 3) - 2); counter++){ // counting in 64bits (n64)
         temp = (((int)n64_ptr) + iteration) % 256;
   	     if(n64_ptr[counter] != pack_16_64_var((temp<<8) | temp, (temp<<8) | temp, (temp<<8) | temp, (temp<<8) | temp)){
   	        printf("Failed at address = 0x%x\n", n64_ptr);
   	        printf("Expected = 0x%llx  actual = 0x%llx", pack_16_64_var((temp<<8) | temp, (temp<<8) | temp, (temp<<8) | temp, (temp<<8) | temp),
   	                                                 n64_ptr[counter]);
	        return(0);
         }

#ifdef loquacious
         if (!(counter % 0x700000)){
	        printf("Ok.\n");
         }   
#endif

      }
	  printf("Ok.\n");

   }
   printf("\nPass exhaustive test.\n");
   return(1);
}
