/* Inputs and outputs are chip NOT tester relative           */

#include <stdio.h>
#include <ctype.h>
#define LDEBUG 0
#define maxsigs 72
#define maxcode 40000
#define SG sigs[i]
#define fpf fprintf
#define foris for(i=0;i<sindex;i++)
#define g_s() get_sym(s,&t)
#define tbase 0x300


/* Parser constants etc */
char cmt_start_ch      = '{',
     cmt_end_ch        = '}',
     line_cmt_ch       = '#',
     x_id_start_chs[]  = {'$','_','\0'},
     x_id_chs[]        = {'$','_','\0'},
     x_space_chs[]     = {';',':','@','=','\0'},
     op_chs[]          = {'+','*','/','\0'};
char *keys[] = { "END", "INPUT", "OUTPUT", "PIN", "BIDIR", "DEFPINS" };
#include "procs5.c"

/* program vars */
int   sindex=0, vecnum=0, group=TRUE, out=FALSE;
typedef enum {snone=0,early,late} stype;
typedef enum {end=0,set_group,get_group,set_dir,clock,newvec} comm;
stype skew=snone;
struct sig { char v,ov,rv,dir,odir,vt, name[N_L]; int pin; } sigs[maxsigs];
struct pinadd {int iaddr,oaddr; byte iv,ov,m,status;} pindata[maxsigs/8];
char code[maxcode];

FILE *fo,*fs;

main(argc,argv)
int argc; char *argv[];
{int i,do_skew=FALSE; char *cd;
 set_hardware();
 if (argc<2)
  error("USAGE: ftest <designname> [-o[ut]] [-id[ent]] [-s[tdout]]\n");
 if (arg_num(argc,argv,"-id")) {printf("Version JAN/5/89\n"); exit(0);}

 fin=efopen(cf(argv[1],".cv"),"r");
 cd=code;
 while(!feof(fin)) *cd++ = getc(fin);
 fclose(fin);
 if (arg_num(argc,argv,"-o*ut")) out=TRUE;
 fastrun(code); /* run the test and get results */

/*------------------------------------------------------------------*/
if (arg_num(argc,argv,"-l*ist")) listcode(code);
if (!out) exit(0);
/* else parse the .vec file and read back the results */

if (arg_num(argc,argv,"-s*tdout")) fo=stdout;
   else fo=efopen(cf(argv[1],".ov"),"w");
fin=efopen(cf(argv[1],".vec"),"r");
init();

expect_sym("DEFPINS");

while (SNE(s,"END") && !feof(fin))
{
 g_s();
 if (SNE(s,"PIN") && SNE(s,"END"))
   error("PIN or END expected in defpins");
  else
  {
   if (SEQ(s,"PIN"))
   {i=get_int();
    if (i>maxsigs || i<=0) error("invalid pin range");
    sigs[sindex].pin=i;
    g_s();
    if (SEQ(s,"VSS") || SEQ(s,"VDD"))
    { /* if (strequ(s,"VDD")) {setd(i,'I'); setp(i,'1');}
       else {setd(i,'I'); setp(i,'0');} */
    }
    else
    {
     if (t!=ident) error("Signal name expected");
     if (sig_exists(s)) error("Duplicate signal found in sigdefs");
     strcpy(sigs[sindex].name,s);
     g_s();
     if (s[0] != 'I' && s[0] != 'O' && s[0] != 'B')
      error("INPUT, OUTPUT, or BIDIR expected");
     sigs[sindex].vt = s[0];
     sindex++;                 }}
                                 }
                                   } /* while */

/*------- Output the header        ----------------------------------*/

fpf(fo,"# Fast Test Output\n\nDEFPINS\n");
foris fpf(fo," PIN %d %s %c;\n",SG.pin,SG.name,SG.vt);
fpf(fo,"END;\n\n");
pr_header();

/*------- Init the pins            ----------------------------------*/

/* init values */
foris { SG.v='-'; SG.dir='-'; SG.odir='-';}

/*
 foris 
   printf("%s %c %c %c %d\n",SG.name,SG.vt,SG.v,SG.dir,SG.pin);
*/

/*-------- Read and deal with vectors ------------------------------*/

veccode(code);

while (!feof(fin))  /* deal with vector */
{
 vecnum++;

 /* copy old vals */
 foris { SG.ov = SG.v; SG.odir = SG.dir;}

 get_vline();
 if(!feof(fin))
 {veccode(code);
  compare_vec();
 }
} /* END of vector while */

fpf(stdout,"-I-  %d vectors \n",--vecnum  );

} /* main */

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

cv(c)
char c;
{ switch (c) {
  case 'L': return('0');
  case 'H': return('1');
  default : return(c);
 }
}


vt(c)
char c;
{ c=uc(c);
  if (c == 'L' || c == 'H') return('I'); else
   {if (c == '0' || c == '1' || c == 'X') return('O');
    else return('U'); }}

iv(c)
char c;
{ if(c=='0') return 'L'; if(c=='1') return 'H'; return c; }


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

get_value()
{ /* fpf(fo,"gv\n"); */
 do {
     xgetch();
     if (ch=='#') { while (ch != '\n') xgetch(); }
     if (ch=='{') { while (ch != '}')  xgetch(); }
     if (ch >= 'a' && ch <= 'z') ch = toupper(ch);
               } while (cinstring(ch,"HL10X") == FALSE && ch != EOF);
 return(ch);
}

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

get_vline()
{ int i; char c;
  foris
  { c = get_value();
    if (SG.vt == 'O' && (c == 'H' || c == 'L'))
                            error("Expected output value");
    if (SG.vt == 'I' && (c == '0' || c == '1' || c == 'X'))
                            error("Expected input value");
    if (SG.vt == 'B') SG.dir = vt(c);
    SG.v = cv(c);
  } /* for */
}

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

compare_vec()
{ int i, tsterr=FALSE;
  extern char read_pin();
  for(i=0;i<=maxsigs/8;i++) pindata[i].status='F';

  foris /* read back vals to SG.rv */
   if(SG.vt=='O'||SG.dir=='O')
    {
     SG.rv=read_pin(SG.pin);
     if(SG.rv!=SG.v&&SG.v!='X') tsterr = TRUE;
    }


  foris
    if(SG.vt=='I'||SG.dir=='I') fpf(fo,"%c",iv(SG.v));
    else
    {if(SG.v=='X') fpf(fo,"X"); else fpf(fo,"%c",SG.rv);}

  fpf(fo," {%d}\n",vecnum);

  if(tsterr) /* insert a line to annotate errors */
  {
   foris
    if(SG.v != SG.rv && (SG.vt=='O'||SG.dir=='O') && SG.v!='X')
     fpf(fo,"#"); else fpf(fo," ");
   fpf(fo,"\n");
   fpf(stderr,"Fail at vector %d\n",vecnum);
  }
}

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

pr_header()
{ int i=0,j=0,l=0;
  fpf(fo,"{\n");
  foris if(strlen(SG.name)>l) l=strlen(SG.name);
  l--;
  for(;j<=l;j++)
   { foris if(strlen(SG.name)>j)
       fpf(fo,"%c",SG.name[j]); else fpf(fo,"%c",' ');
     fpf(fo,"\n");
   }
  fpf(fo,"}\n");
}


set_hardware()
{             /* maps pin numbers to expander device addresses */
 int i=0,j;   /* HARDWARE DEPENDANT ROUTINE */
 /* set outputs from tester */
 outp(tbase+3,0x80);
 outp(tbase+7,0x80);
 outp(tbase+0xb,0x80);
 /* set inputs to tester */
 outp(0x310+0x3,0x9b);
 outp(0x310+0x7,0x9b);
 outp(0x310+0xb,0x9b);
 /* set outputs from tester */
 for(i=0 ; i<=2;i++) outp(tbase+i,0xff);
 for(i=4 ; i<=6;i++) outp(tbase+i,0xff);
 for(i=8 ;i<=10;i++) outp(tbase+i,0xff);

 /* set up pindata vals, mask and addresses */
 while(i<=maxsigs/8)
  {pindata[i].iv=0xff; pindata[i].m=0; pindata[i++].ov=0;}
 for(i=0 ;i<= 2;i++) pindata[i].iaddr=i;
 for(i=3 ;i<= 5;i++) pindata[i].iaddr=i+1;
 for(i=6 ;i<=8 ;i++) pindata[i].iaddr=i+2;

 for(i=0 ;i<= 2;i++) pindata[i].oaddr=i+0x10;
 for(i=3 ;i<= 5;i++) pindata[i].oaddr=i+0x11;
 for(i=6 ;i<= 8;i++) pindata[i].oaddr=i+0x12;

}



fastrun(cs)   /* compacted code interpreter */
byte *cs;     /* HARDWARE DEPENDENT         */
{long i=0l,v=0l; int j; byte rv;
 while(cs[i]) /* !end */
 {switch((char) cs[i])
  {
   case set_group: /* set_group|offset|value */
                   outp(cs[i+1]+tbase,cs[i+2]); i+=3; break;
   case get_group: /* get_group|offset|mask|expected_val */
                    rv=inp(cs[++i]+tbase); i++;
                    if(!out&&((char)rv&cs[i]) != ((char)cs[i]&cs[i+1]))
                     fpf(stderr,"fail at vector %d\n",v);
                    cs[++i]=rv; i++;  break;
                   /* clock|count|offset|val1|val2 */
   case clock    : for(j=cs[++i];j>0;j--)
                     {outp(cs[i+1]+tbase,cs[i+2]);
                      outp(cs[i+1]+tbase,cs[i+3]);}
                   i+=4; break;
   case newvec   : v++; i++; break;
   default: error("in compacted code interpreter");
  }
 } /* while */
}


veccode(cs)   /* reads back pindata for this vector from code[] */
char *cs;
{long v=0l; static long i=0l; int x;

 while(cs[i] && cs[i]!=(char)newvec) /* !end */
 {switch((char) cs[i])
  {
   case set_group: i+=3; break;
   case get_group:
       x=0; i++;   /* locate the pindata byte */
       while(x<maxsigs/8 && cs[i] != pindata[x].oaddr) x++;
       if(cs[i]!=pindata[x].oaddr) error("offset");
       if (LDEBUG) printf("reading %x for pindata %d\n",cs[i],x);
       i+=2;
       pindata[x].ov=cs[i++]; break;
   case clock    : i+=5; break;
   default: printf("found command %x\n",cs[i]);
            error("in compacted code interpreter");
  }
 } /* while */
 if(cs[i]==(char)newvec) i++;
}


sig_exists(sg)
char *sg;
{int i;
 for(i = 0;i!=sindex && SNE(sg,sigs[i].name);i++) ;
 if (SEQ(sg,SG.name)) return TRUE;
  else return FALSE;
}

/*
outp(a,d)
int a; byte d;
{if (LDEBUG) printf("outp %x %x\n",a,d);}

inp(a)
int a;
{int i=0; 
 if(LDEBUG)
 {while(i<maxsigs/8 && a != pindata[i].oaddr+tbase) i++;
  if(a!=pindata[i].oaddr+tbase) error("inp");
  printf("inp addr %x mask %x pindata %d\n",a,pindata[i].m,i);} return(0);}
*/

setp(p,v)
int p; char v;
{p--;
 if(v=='1') pindata[p/8].iv=pindata[p/8].iv |1<<p%8;
    else pindata[p/8].iv=pindata[p/8].iv & ~(1<<p%8);
 if(!group) outp(tbase+pindata[p/8].iaddr,pindata[p/8].iv);
  else pindata[p/8].status='T';
 if(LDEBUG) printf("set pin %d to  %c\n",p+1,v);
}

setd(p,d)
int p; char d;
{
 /* printf("set dir %d to  %c\n",p,d); */
 if(d=='O') setp(p,'1');
 if(d=='I') setp(p,'0');
}

char read_pin(p)
int p;
{
 p--;
 /* printf("pin %d pindata[%d].ov= %x returned %d\n",p+1,p/8,pindata[p/8].ov,
         ((pindata[p/8].ov & 1<<p%8) ?1:0)); */
 if(pindata[p/8].ov & 1<<p%8) return '1';
 return '0';
}

ssync()    /* output grouped signals for speed */
{int i;  /* printf("ssync\n"); */
 if(group)
 { for(i=0;i<maxsigs/8;i++)
    if(pindata[i].status=='T') outp(tbase+pindata[i].iaddr,pindata[i].iv);
 }
}



listcode(cs)   /* compacted code interpreter */
char *cs;
{long i=0l,v=0l;

 while(cs[i]) /* !end */
 {switch((char) cs[i])
  {
   case set_group: printf(" set offset %x to %x \n",cs[i+1],cs[i+2]);
                   i+=3; break;
   case get_group: printf(" get offset %x mask %x found %x\n",
                           cs[i+1],cs[i+2],cs[i+3]); i+=4; break;
   case clock    : printf("clock %x %x %x %x\n",cs[i+1],cs[i+2],
                          cs[i+3],cs[i+4]); i++; break;
   case newvec   : printf(" newvec\n"); v++; i++; break;
   default: printf("found command %x\n",cs[i]);
            error("in compacted code interpreter");
  }
 } /* while */
}

^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z^Z