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

#include <stdio.h>
#include <ctype.h>
#define LDEBUG 0
#define maxsigs 72
#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
#define maxcode 40000


/* 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; long codelen=0l;
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; long j=0l;
 set_hardware();
 if (argc<2)
  error("USAGE: ctest <designname> [-no_group|-ng] [-l] [-id]");

 fin=efopen(cf(argv[1],".vec"),"r");
 init();

 if (arg_num(argc,argv,"-stdout")) fo=stdout;
   else fo= efopen(cf(argv[1],".cv"),"w");

 if (arg_num(argc,argv,"-skew"))
  { do_skew=TRUE; fs=fopen(cf(argv[1],".skw"),"w");}
 if (arg_num(argc,argv,"-no_group")||arg_num(argc,argv,"-ng"))
      group=FALSE;
 if (arg_num(argc,argv,"-id")) {printf("Version FEB/5/89\n"); exit(0);}

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

expect_sym("DEFPINS");

while (strneq(s,"END") && !feof(fin))
{
 g_s();
 if (strneq(s,"PIN") && strneq(s,"END"))
   error("PIN or END expected in defpins");
  else
  {
   if (strequ(s,"PIN"))
   {i=get_int();
    if (i>maxsigs || i<=0) error("invalid pin range");
    sigs[sindex].pin=i;
    g_s();
    if (strequ(s,"VSS") || strequ(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,"# 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='-';}
for(i=0;i<=maxsigs/8;i++) pindata[i].ov=0;


foris
  switch (SG.vt)
   {
     case 'O': setd(SG.pin,'O'); break;
     case 'B': SG.dir='O'; setd(SG.pin,'O'); break;
   }

ssync(); /* get power on */

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

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


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

 /* copy old vals */
 foris { SG.ov = SG.v; SG.odir = SG.dir;}
 if(codelen>maxcode-50) error("cv codelength too long");
 putc(newvec,fo); codelen++;
 get_vline();
 if(!feof(fin))
 {assert_vec(snone,0);
  strobe_vec();
 }
} /* END of vector while */
putc(end,fo); codelen++;
fclose(fo);

if(arg_num(argc,argv,"-l"))
 {fin=efopen(cf(argv[1],".cv"),"r");
  printf("\n\n CODE LISTING\n ============\n\n");
  while(!feof(fin)) code[j++]=getc(fin);
  listcode(code);
  printf("\n END OF CODE LISTING\n\n");
 }

printf("-I- length of compiled code is %d bytes\n",codelen);
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")  && 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 */
}

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

assert_vec(skew,pn)
stype skew; int pn;
{ int i=0;

  if(skew==early)
  { while(SG.pin!=pn&&i<sindex) i++; printf("eraly\n");
    if(SG.dir!=SG.odir)           setd(SG.pin,SG.dir);
    if(SG.vt=='I'&&SG.v!=SG.ov)   setp(SG.pin,SG.v);
    if(SG.dir=='I'&&SG.v!=SG.ov)  setp(SG.pin,SG.v);
   ssync();
  }

  foris /* assert vals */
   if(skew==snone||skew!=snone&&SG.pin!=pn)  /* filter the skew sig */
   {
    if(SG.dir!=SG.odir)           setd(SG.pin,SG.dir);
    if(SG.vt=='I'&&SG.v!=SG.ov)   setp(SG.pin,SG.v);
    if(SG.dir=='I'&&SG.v!=SG.ov)  setp(SG.pin,SG.v);
   }

  ssync();

  if(skew==late )
  { while(SG.pin!=pn&&i<sindex) i++; printf("late\n");
    if(SG.dir!=SG.odir)           setd(SG.pin,SG.dir);
    if(SG.vt=='I'&&SG.v!=SG.ov)   setp(SG.pin,SG.v);
    if(SG.dir=='I'&&SG.v!=SG.ov)  setp(SG.pin,SG.v);
    ssync();
  }
}

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

strobe_vec()
{ int i, tsterr=FALSE;
  extern char read_pin();
  for(i=0;i<=maxsigs/8;i++) pindata[i].status='F';
  foris
  {/* set mask value */
   if((SG.dir!=SG.odir||SG.v!=SG.ov)&&SG.vt!='I' )
    if(SG.v=='X'||SG.dir=='I')
    { pindata[(SG.pin-1)/8].m &= ~(1<<(SG.pin-1)%8);
      if(LDEBUG) printf("mask on pin %d = %d\n",SG.pin,0);}
      else {pindata[(SG.pin-1)/8].m |= 1<<(SG.pin-1)%8;
            if(LDEBUG) printf("mask on pin %d = %d\n",SG.pin,1);}
  }

  foris  /* update expected value */
   {if(SG.vt!='I'&&SG.dir!='I')
    {if(SG.v=='1') pindata[(SG.pin-1)/8].ov |= 1<<(SG.pin-1)%8;
     if(SG.v=='0') pindata[(SG.pin-1)/8].ov &= ~(1<<(SG.pin-1)%8);}
   }

  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) 
  {
   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;   /* 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);
                   if(rv&cs[i+1] != cs[i+1]&cs[i+2])
                    fpf(stderr,"fail at vector %d\n",v);
                   cs[i+2]=rv; i+=3; 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 */
}


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 exp %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 */
}

/*
compress_code(cs)   
byte *cs;  
{long i=0l,v=0l; int j,num_sets; byte lastmask,maskbeforelast;
 while(cs[i])
 { if (cs[i++]==set_group) 
   { 
*/

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


outp(a,d)
int a; byte d;
{
 if(LDEBUG) printf("outp %x %x\n",a,d);
 putc(set_group,fo);
 putc(a-tbase,fo);
 putc(d,fo);
 codelen+=3;
}

inp(a)
int a;
{int i=0;

 while(i<maxsigs/8 && a != pindata[i].oaddr+tbase) i++;
 if(a!=pindata[i].oaddr+tbase) error("inp");
 if(pindata[i].m!=0)
 {
  putc(get_group,fo);
  putc(a-tbase,fo);
  putc(pindata[i].m,fo);
  putc(pindata[i].ov,fo);
  if(LDEBUG) printf("inp %x %x %d\n",a,pindata[i].m,i);
 }
 codelen +=4;
 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--;
 if(pindata[p/8].status=='F') /* check if its already read */
  {pindata[p/8].ov=inp(tbase+pindata[p/8].oaddr);
   pindata[p/8].status='R';}
 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);
 }
}