/***********************************************************
 * Title : Window Access Test                              *
 *         DRAM Burst on/off Test                          *
 *         Page Comparator Test                            *
 *                                                         *
 * Author : F. Ng                                          *
 * Last revised :                                          *
 ***********************************************************/

#include <stdio.h>
#define	TCPADR	0xFF200000
#define	UARTADR	0xFF300008
#define	RAM_START1	0x00000000
#define	RAM_START2	0x02000000
#define	RAM_START3	0x04000000
#define	RAM_START4	0x06000000
#define	PASS		0
#define	FAIL		1

typedef unsigned char byte;
typedef unsigned short int word;
typedef unsigned int dword;
int	chk_window(), chk_page(), chk_burst();

/* DP8570 Timer Clock Peripheral (TCP) */
struct DP8570
{
  byte	msr;    /* Main status register, REG=0 */
  union
     {
        byte   t0cr;     /* Timer 0 control regsiter, reg sel=0 */
        byte   rtmr;     /* Real time mode register, reg sel=0 */
     } reg1;		     /* REG=1 */
  union
     {
        byte   t1cr;    /* Timer 1 control register, reg sel=0 */
        byte   omr;     /* Output mode register, reg sel=1 */
     } reg2;		    /* REG=2 */
  union
     {
        byte   pfr;     /* Periodic flag register, reg sel=0 */
        byte   icr0;    /* Interrupt control register 0, reg sel=1 */
     } reg3;		    /* REG=3 */
  union
     {
        byte   irr;     /* Interrupt routing registe, reg sel=0 */
        byte   icr1;    /* Interrupt control register 1, reg sel=1 */
     } reg4;		    /* REG=4 */
  byte	  sc;   	    /* 1/100 second counter         REG=5 */
  byte      scc;        /* Seconds clock counter        REG=6 */
  byte      mincc;      /* Minutes clock counter        REG=7 */
  byte      hcc;        /* Hours clock counter          REG=8 */
  byte      domcc;      /* Day of month clock counter   REG=9 */
  byte      moncc;      /* Months clock counter         REG=A */
  byte      ycc;        /* Years clock counter          REG=B */
  byte      ujcc;       /* Units julian clock counter   REG=C */
  byte      hjcc;       /* 100's julian clock counter   REG=D */
  byte      dowck;      /* Day of week clock counter    REG=E */
  byte      t0lsb;      /* Timer 0 LSB                  REG=F */
  byte      t0msb;      /* Timer 0 MSB                  REG=10 */
  byte      t1lsb;      /* Timer 1 LSB                  REG=11 */
  byte      t1msb;      /* Timer 1 MSB                  REG=12 */
  byte      scram;      /* Seconds compare RAM          REG=13 */
  byte      mincram;    /* Minutes compare RAM          REG=14 */
  byte      hcram;      /* Hours compare RAM            REG=15 */
  byte      domcram;    /* Day of month compare RAM     REG=16 */
  byte      moncram;    /* Months compare RAM           REG=17 */
  byte      dowcram;    /* Day of week compare RAM      REG=18 */
  byte      stsram;     /* Seconds time save RAM        REG=19 */
  byte      mintsram;   /* minutes time save RAM        REG=1A */
  byte      htsram;     /* Hours time save RAM          REG=1B */
  byte      domtsram;   /* Dayy of month time save RAM  REG=1C */
  byte      montsram;   /* Months time save RAM         REG=1D *
  byte      ram;        /* RAM                          REG=1E */
  byte      rtr;        /* RAM/test register            REG=1F */
};



/* NS16C552 DUART Definitions */
struct NS16C552
   {
      union
         {
            byte   rbr;     /* receiver buffer register - read only */
            byte   thr;     /* transmitter holding register - write only */
            byte   dll;     /* divisor latch (LS) */
         }  a0;
      union
         {
            byte   ier;     /* interrupt enable register */
            byte   dlm;     /* divisor latch (MS) */
         }  a1;
      union
         {
            byte   iir;     /* interrupt identity register - read only */
            byte   fcr;     /* FIFO control register - write only */
		  byte   afr;	   /* Alternate Function */
         }  a2;
      byte         lcr;     /* line control register */
      byte         mcr;     /* modem control register */
      byte         lsr;     /* line status register */
      byte         msr;     /* modem status register */
      byte         scr;     /* scratch register */
   };


/* Window Access Test - this routine verify access to all four DRAM
   windows.  Read/write patterns on windows will be performed and
   only the second 64K block starting from the beginning of window
   will be tested to reduce the time spent and avoid overwrite of
   the stack and system variables..etc.  The test will continue to
   proceed until all 4 windows are tested even failure occur */
chk_window()
{
	dword	*add_ptr;			/* DRAM address pointer */
	byte		f_flag=0;			/* test fail flag */
	register	int	i;			/* temp increment counter */
	char		*wmsg0 = "\015\n13.a...Testing Window access \015\n ";
	char		*wmsg1 = "  check window 1   ";
	char		*wmsg2 = "  check window 2   ";
	char		*wmsg3 = "  check window 3   ";
	char		*wmsg4 = "  check window 4   ";
	char		*wmsg5 = "passed\015\n";
	char		*wmsg6 = "failed\015\n";

	prtstr(wmsg0);
	prtstr(wmsg1);
	add_ptr = (dword *)(RAM_START1 + 0x10000);	/* check access to W1 */
	for (i=0; i < 0x10000/4; i++) {	
		*add_ptr = i;			/* write incremental pattern and verify */
		if (*add_ptr++ != i) {	/* retrieve pattern and verify, set error */
			f_flag = f_flag | 0x01;	/* bit if incorrect, bit 0 */
			break;
		}
	}
	if ((f_flag & 0x01) == 0)
		prtstr(wmsg5);
	else
		prtstr(wmsg6);

	prtstr(wmsg2);
	add_ptr = (dword *)(RAM_START2 + 0x10000);	/* check access to W2 */
	for (i=0; i < 0x10000/4; i++) {	
		*add_ptr = i;			
		if (*add_ptr++ != i) {
			f_flag = f_flag | 0x02;			/* bit 1 */
			break;
		}
	}
	if ((f_flag & 0x02) == 0)
		prtstr(wmsg5);
	else
		prtstr(wmsg6);

	prtstr(wmsg3);
	add_ptr = (dword *)(RAM_START3 + 0x10000);	/* check access to W3 */
	for (i=0; i < 0x10000/4; i++) {
		*add_ptr = i;
		if (*add_ptr++ != i) {
			f_flag = f_flag | 0x04;			/* bit 2 */
			break;
		}
	}
	if ((f_flag & 0x04) == 0)
		prtstr(wmsg5);
	else
		prtstr(wmsg6);

	prtstr(wmsg4);
	add_ptr = (dword *)(RAM_START4 + 0x10000);	/* check access to W4 */
	for (i=0; i < 0x10000/4; i++) {
		*add_ptr = i;
		if (*add_ptr++ != i) {
			f_flag = f_flag | 0x08;			/* bit 3 */
			break;
		}
	}
	if ((f_flag & 0x08) == 0)
		prtstr(wmsg5);
	else
		prtstr(wmsg6);
	
	if (f_flag == 0)				/* return test status to caller */
		return(PASS);
	else
		return(FAIL);
}


/* DRAM Burst on/off Test - this routine verify the operation of DRAM
   burst mode operation for all four windows. The TCP timer1 is used
   to measure the time spent. Only window 1 and window 2 are compared */
chk_burst()
{
	int	count1, count2, count3, count4;
	char	*bmsg0 = "\015\n13.b...Testing Burst on/off  ";
	char	*bmsg1 = "passed\015\n ";
	char	*bmsg2 = "failed\015\n ";
	char 	*bmsg3 = "  window 4 time < window 3 time -- failed \015\n";
	char 	*bmsg4 = "  window 1 time < window 2 time -- failed \015\n";
	char 	*bmsg5 = "  window 2 time < window 4 time -- failed \015\n";

	prtstr(bmsg0);
	start_T1();			/* check W1, burst on, cacheable */
	fill_blk(0x00000000);
	count1 = stop_T1();

	start_T1();			/* check W2, burst off, cacheable */
	fill_blk(0x02000000);
	count2 = stop_T1();

	start_T1();			/* check W3, burst on, non-cacheable */
	fill_blk(0x04000000);
	count3 = stop_T1();

	start_T1();			/* check W4, burst off, non-cacheable */
	fill_blk(0x06000000);
	count4 = stop_T1();
	if (count4 + 10 >= count3) {
	   prtstr (bmsg3);
	   return (FAIL);
	}
	if (count2 + 10 >= count4)
	{
	   prtstr (bmsg5);
	   return (FAIL);
	}
	if (count1 + 10 >= count2)
	{
	   prtstr (bmsg4);
	   return (FAIL);
	}
	prtstr(bmsg1);		/* passed */
	return (PASS);
}

/* Page comparator test - this routine verify the page comparator circuitry.
   The TCP timer 1 is used to measure the time difference between in-page
   and off-page access. Only window is verified */

chk_page()
{
	int	count1, count2;
	char	*pmsg0 = "\015\n13.c...Testing Page comparator  ";
	char	*pmsg1 = "passed\015\n ";
	char	*pmsg2 = "failed\015\n ";

	prtstr(pmsg0);
	start_T1();
	in_page(0x0);
	count1 = stop_T1();
	start_T1();
	off_page(0x0);
	count2 = stop_T1();
	if (count2-count1 < 10) {	/* check if in-page 3 times faster than off-page*/
		prtstr(pmsg2);		/* yes, => failed */ 
		return(FAIL);
	}
	else {
		prtstr(pmsg1);		/* passed */
		return(PASS);
	}
}

start_T1()
{
	 volatile struct DP8570   * volatile tcp_p= (struct DP8570 *) TCPADR;

	init_tcp();			/* initialize tcp, 1ms clock */
	tcp_p->msr = 0x0;		/* page 0       reg 0        */
	tcp_p->reg2.t1cr = 0x20;	/* stop timer                */
	tcp_p->t1lsb = 0xff;		/* initialize timer counter to generate */
	tcp_p->t1msb = 0xff;		/* a 65.536 sec timing loop */
	tcp_p->reg2.t1cr = 0x21;		/* start timer 1 */
}


stop_T1()
{
	register byte	lsb, msb;
	volatile struct DP8570   * volatile tcp_p=( struct DP8570 *) TCPADR;
	tcp_p->msr = 0x0;			/* page 0       reg 0 */

	tcp_p->reg2.t1cr = 0x61;		/* timer read */
	msb = tcp_p->t1msb;			/* read timer 1 MSB */
	lsb = tcp_p->t1lsb;			/* read timer 1 LSB */
	tcp_p->reg2.t1cr = 0x20;		/* stop timer 1 */
	return(0xffff - ((msb<<8) + lsb));	/* calculate time   */
}
/* fill block -  fill 64K block of memory starting at input address  */

fill_blk(x)
int x;
{
   	asm (" 	sprd	cfg, tos");
   	asm ("	lprd	cfg,$0xaf0");
	asm("	save	[r1, r2, r3]");
	asm("	movd	8(fp), r1");
	asm("	movd	8(fp), r2");
	asm("	addd	$0x100000,r1");
	asm("	addd	$0x200000,r2");
	asm("	movd	$0x100000, r0");
	asm("	movsb		");
	asm("	restore	[r1,r2,r3]");
   	asm (" 	lprd	cfg, tos");
}



/* This routine perform in-page access on the window 
    transfer block of memory within page */
in_page(x)
int x;
{
   	asm (" 	sprd	cfg, tos");
   	asm ("	lprd	cfg,$0xaf0");
	asm("	save	[r1,r2,r3]");	/* save registers */
	asm("	movd	8(fp), r1");		/* create even byte pointer */
	asm("	addd	$0x10000,r1");		/* add 64K offset to avoid overlap */
	asm("	movd	r1, r2");
	asm("	addd	$1, r2");		/* create odd byte pointer */
	asm("	movd	$0x100000, r0");	/* initialize counter, 64K */
	asm("	movsb		");
	asm("	restore	[r1, r2, r3]");
   	asm (" 	lprd	cfg, tos");
}
/* This routine perform off-page access on the window 
    transfer block of memory out of page */
off_page(x)
int x;
{
   	asm (" 	sprd	cfg, tos");
   	asm ("	lprd	cfg,$0xaf0");
	asm("	save	[r1,r2,r3]");	/* save registers */
	asm("	movd	8(fp), r1");		/* create even byte pointer */
	asm("	addd	$0x10000,r1");		/* add 64K offset to avoid overlap */
	asm("	movd	r1, r2");
	asm("	addd	$0x10001, r2");		/* create odd byte pointer */
	asm("	movd	$0x100000, r0");		/* initialize counter, 64K */
	asm("	movsb		");
	asm("	restore	[r1, r2, r3]");
   	asm (" 	lprd	cfg, tos");
}

/* This function initialize the TCP */
init_tcp()
{
	  volatile struct DP8570   * volatile tcp_p= (  struct DP8570 *) TCPADR;
	/* page select = 0, reg select = 0 */
	tcp_p->msr=0x00;
	tcp_p->reg1.t0cr=0x20;	/* stop timer, single pulse, 1ms clock */
				/* !timer read, suspend mode 0-2 */ 
	tcp_p->reg2.t1cr=0x20;  /* stop timer, single pulse, 1ms clock */
				/* !timer read, suspend mode 0-2 */
	tcp_p->reg3.pfr=0x00;   /* not single supply, test mode disable */
	tcp_p->reg4.irr=0x80;	/* time save enable, all interrupt to INT */

		/* page select = 0, reg select = 1 */
	tcp_p->msr=0x40;
	tcp_p->reg1.rtmr=0x45; 	/* leap last year, 24hrs, stop clock */
				/* 4.194304 MHZ */
	tcp_p->reg2.omr=0x00; 	/* T1 - open drain, active low */
				/* INT - open drain, active low */
				/* MFO - open drain, active low */
	tcp_p->reg3.icr0=0x00;	/* disable periodic interrupts, timer0&1*/
	tcp_p->reg4.icr1=0x00;	/* no compare, alarm and power fail */
}

prtstr(strptr)
char	*strptr;
{
	 volatile struct NS16C552 * volatile duart = (struct NS16C552 *) UARTADR;
	while (*strptr != NULL){
		while ((duart->lsr & 0x20) == 0);
		duart->a0.thr = *strptr++;
	}
}

/* 
int abs (i)
int i;
{
   if (i < 0) return ((-1) * i);
   return (i);
}
*/
