/* ************************************************************************* */
/* ===================================================================== 
** vmemem.c
**
** Test program to access a VME memory module from a MVME2604 running
** Linux 2.2.9 using Gabriel Pauberts VME universe driver module.
**
** 17may02 das initial
**
**  ======================================================================== */
/*									     */

#include <linux/vme.h>
#include <stdio.h>
#include <sys/time.h>

#include <asm/mman.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fcntl.h>


#define vmeaddr_t unsigned long

#define VME_MEM_SIZE 0x9F0000   /* using MM6326 in A24 D16 mode */
#define VME_BASE_ADDR 0x100000

#if 0
/* ClearPoint 16Mb memory module */
#define VME_MEM_SIZE 0x100000   
#define VME_BASE_ADDR 0x87800000
#endif

#define GET_TIMEBASE  \
 ({unsigned int tmp; __asm__ volatile ("mftb %0": "=r" (tmp):); tmp;})

#define MEASURE_LOAD(n) \
  ({ unsigned t0; int v; t0= GET_TIMEBASE; \
     asm volatile("lwz%U1%X1 %0,%1": "=r" (v): "g" (n)); \
     total += GET_TIMEBASE - t0; v; \
})

int main(int argc, char **argv)
{
  struct timeval _tstart, _tend;
  double deltat,t1,t2;
  FILE *fp;

  int vme_dev_file;
  vmeaddr_t vme_ptr;

  off_t	vme_base = VME_BASE_ADDR;
  int	status;

  off_t	offset;
  int	page_size;


  VME_attr memdesc = {base:  0xd00000, /* re-assigned */
		      limit: 0xdfffff, /* re-assigned */
		      flags: VME_AM_A24(16) | VME_USE_MAP | VME_USE_RMW
		      };
  unsigned error;
  int i, j;
  unsigned duration;

/* -----------------------------------------------------------------------   */



#ifdef DEBUG
  printf("vmemem: vme_base = 0x%0x\n",vme_base);
#endif


  /* make sure VME device file is closed before we open */
  if(vme_dev_file != 0 )
	close(vme_dev_file);


  if ((vme_dev_file = open("/dev/vme", O_RDWR) ) == -1) {
    printf("Error opening %s. Did you insmod universe?\n","/dev/vme");
    perror("open");
    return(-1);
    }


  page_size = getpagesize();
  offset = vme_base & ~(page_size-1);
#ifdef DEBUG
  printf("vme_base = 0x%0x, ANDed with 0x%0x\n",vme_base, ~(page_size-1));
#endif



  /* set base and limit to the values we really wanted */
  /* why can't memdesc.base be vme_base, and offset 0? */
  memdesc.base = /*vme_base*/ 0x00000000;  
  memdesc.limit = vme_base + (VME_MEM_SIZE-1); 
#ifdef DEBUG
  printf("memdesc.base = 0x%0x, memdesc.limit = 0x%0x\n",
               memdesc.base,memdesc.limit);
#endif

  error = ioctl(vme_dev_file, VME_SET_ATTR, &memdesc);
  if (error) perror("failed VME_SET_ATTR");
  error = ioctl(vme_dev_file, VME_GET_ATTR, &memdesc);
#ifdef DEBUG
  printf("memdesc: flags %x, vme_addr %x, length %x\n", 
          memdesc.flags, memdesc.base, memdesc.limit-memdesc.base+1);
#endif



  vme_ptr = (vmeaddr_t) mmap ( (caddr_t)0, VME_MEM_SIZE,
                                PROT_READ|PROT_WRITE,
				MAP_SHARED, vme_dev_file, 
                                (off_t)offset);
  if ( vme_ptr == (vmeaddr_t)-1 ) {
    printf("Error Mapping to file %s, offset=%x, length=%x\n",
		"/dev/vme", offset, VME_MEM_SIZE);
    perror("mmap");
    return(-1);
  }

#ifdef DEBUG
    printf("vme_ptr = 0x%0x\n",vme_ptr);
#endif



    duration = GET_TIMEBASE;

    for (j=0; j<1000; j++)
      {
	gettimeofday(&_tstart, NULL);
	t1=(double)_tstart.tv_sec + (double)_tstart.tv_usec/(1000*1000);
		
	/* memory write loop */
	
	for (i=0; i<VME_MEM_SIZE; i+=4) {
	  *(unsigned int *)vme_ptr = 0xA5A5;
	}
	
	  gettimeofday(&_tend, NULL);
	  t2=(double)_tend.tv_sec + (double)_tend.tv_usec/(1000*1000);
	  /*      fprintf(fp,"timetest: %f,%f,%f\n",t1,t2,t2-t1);*/
	  fp =fopen("vmetest1", "a");
	  fprintf(fp,"%f\n",(t2-t1));
	  fclose(fp);
      }
    duration = GET_TIMEBASE - duration;



    printf("1MB transferred through direct accesses in %d ticks.\n", 
	       duration);
    printf("MVME2604 is a 400MHz cpu, the timebase is cpu clock/4\n");



    return (0);
}

