driver.c 7.96 KB
/*
 *  Driver.c, reads tabular input files and places vector values
 *  on wires each clock.
 *
 *  Ignores arguments for formatted dumps.
 *
 *  Input file names specified using range expression such as:
 *   "0,1,3-8"
 *
 *  Input file names must have the form inp%03d.tab.  Input file are
 *  opened in the sequence specified in the range statement.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include "driver.h"
#include "cv.h"

#define POSEDGE         (save_clk && !save_clk_old)
#define NEGEDGE         (!save_clk && save_clk_old)

#define OPTARG          "o:d:f:i:t:s:x:y:h"


/*
 *  Globals
 */
static char *MyOpts[] = { "cv_all" };
static enum  MYOPTS     {  CV_ALL  };
static int DumpFunctions = 0;
static int TestID = 0;

static FILE *Infp = NULL;

extern int Fargc;     /* number of file numbers */
extern char **Fargv;  /* pointer to file numbers from expanded range string */
static int CurFile = 0;  /* index to current file number */

/*
 *  Forward References
 */
void range_expand(char *);

static void print_input_header(FILE *fp);
static void print_input_sigs(FILE *fp, driver_t *dp);

static void print_cv_all(cv_t *cp, driver_t *dp, char *s);
static void print_cv_all_header(FILE *fp);
static void print_cv_all_sigs(FILE *fp, cv_t *cp, driver_t *dp);


/*
 *  formatted_dump(): called by simulation executive after all other modules.
 *  end of arguments list denoted by a zero arg.  Must do this way because
 *  order and number of arguments is not guaranteed, and user may want one
 *  tab file from multiple modules.
 */
void
  formatted_dump( void *np, ... )
{
  static int save_clk = 0;
  va_list ap;
  void *ptr;
  int ptr_no = 0;
  driver_t *drv_p;
  cv_t *cv_p;


  ptr = (void *) va_start(ap, np);
  if(ptr)
  do
  {
    if(!strcmp(((driver_t *)ptr)->label, "DRIVER"))
      drv_p = (driver_t *)ptr;
    else if(!strcmp(((driver_t *)ptr)->label, "CV"))
      cv_p = (cv_t *)ptr;
  } while(ptr = (void *)va_arg(ap, void *));
  va_end(ap);

  /* negedge */
  if(save_clk && !drv_p->gclk_old)
  {
    if(DumpFunctions & (1 << CV_ALL))
      print_cv_all(cv_p, drv_p, NULL);
  }

  /* this is a conspiracy between the drive function and the dump
     function so that we can detect the negative edge of the clock */
  save_clk = drv_p->gclk_old;
}


/*
 *  print_cv_all()
 */
static void
  print_cv_all( cv_t *tp, driver_t *dp, char *s )
{
   char fname[128];
   static FILE *fp = NULL;

  if(!fp)
  {
    sprintf(fname,"OutData/cv_all/test%.3d.tab\0", TestID);
    if((fp = fopen(fname,"w")) == NULL)
    {
      fprintf(stderr,"Unable to open %s for write\n", fname);
      exit(911);
    }
    printf("Writing file: %s\n", fname);
    print_input_header(fp);
    print_cv_all_header(fp);
  } 

  if(s != NULL) /* print comments */
  {
    fprintf(fp,"%s",s);
  }
  else
  {
    print_input_sigs(fp, dp);
    print_cv_all_sigs(fp, tp, dp);
  }
}


/*
 *  open_file
 */
static FILE *
  open_file(char *fn)
{
  FILE *fp;
  char fname[50];
  char line[1024];

  if(!fn)
  {
    fprintf(stderr,"Error, null pointer passed to open_file()\n");
    exit(1);
  }
  else
  {
    sprintf(fname,"InData/inp%s.tab\0", fn);
    fprintf(stderr,"reading %s\n", fname);
    if((fp = fopen(fname,"r")) == NULL)
    {
      fprintf(stderr,"unable to open %s\n", fname);
      exit(1);
    }
  }

  /* skip header */
  while(fgets(line, 1023, fp))
  {
    if(line[0] == '\n')
      break;
  }

  return(fp);
}


/*
 *  driver()
 */

void
  driver(driver_t **pp0, driver_t **pp1)
{
  driver_t *p0, *p1;
  char line[1024], *p;
  int ret, indx, lod_frac;
  int save_clk;
  int save_clk_old;

  /* get initial pointers */
  p0 = *pp0;
  p1 = *pp1;
  save_clk = p0->gclk;
  save_clk_old = p1->gclk_old;

  if(POSEDGE) /* posedge(gclk) */
  {
    /* transfer all next-clock register values to register outputs. */
    *pp0 = p1; /* swap */
    *pp1 = p0;
    p0 = *pp0; /* fix pointers */
    p1 = *pp1;


    /* read line */
    if(!(fgets(line, 1023, Infp)))
    {
      if(CurFile == Fargc)
      {
        fprintf(stderr,"Done processing\n");
        exit(0);
      }
  
      Infp = open_file(Fargv[CurFile++]);
      fgets(line, 1023, Infp);
    }
  
    while(line[0] == '#')
    {
      if(DumpFunctions & (1 << CV_ALL))
        print_cv_all(0, 0, line);

      if(!(fgets(line, 1023, Infp)))
      {
        if(CurFile == Fargc)
        {
          fprintf(stderr,"Done processing\n");
          exit(0);
        }
  
        Infp = open_file(Fargv[CurFile++]);
        fgets(line, 1023, Infp);
      }
    }
  
    /* scan in vector */
    p = line;
    ret = sscanf(p," %i%i%i%i%i%i%i",
      &p0->ew_cv_data_d1,
      &p0->x_major,
      &p0->cycle_type,
      &p0->ew_cv_newspan,
      &p0->left,
      &p0->reset,
      &p0->dv);

    if(ret != 7)
    {
      fprintf(stderr,"Short read\n");
      exit(911);
    }

    /*
     *  This delay is for the csim.  Because of differences in
     *  the way Csim and Verilog react to input data, this signal
     *  shows up a half-clock earlier in the Csim than it does
     *  in the Verilog vectors.  This signal, in the real system,
     *  comes from a mux in the edge-walker.
     */
    p0->ew_cv_data = p1->ew_cv_data_d1;


    p0->dv_d1 = p1->dv;


  } /* posedge */

  p1->gclk_old = p0->gclk_old = save_clk;
}   


/*
 *   driver_init()
 */

void
  driver_init(driver_t *p0, driver_t *p1)
{
  int c, i;
  char *options, *value;

  extern char *optarg;
  extern int optind, opterr, optopt;
  extern int Fargc;
  extern char **Fargv;

  optind = 1;
  opterr = 0;

  p0->gclk = p1->gclk = 0;
  p0->gclk_old = p1->gclk_old = 0;

  while((c = getopt(p1->argc, p1->argv, OPTARG)) != EOF)
  {
     switch(c)
     {
       case 'i':
	  range_expand(optarg);
          break;

       case 't':
	  TestID = atoi(optarg);
          break;

       case 'o':
         options = optarg;
         while(*options != '\0')
         {
           switch(getsubopt(&options, MyOpts, &value))
           {
             case CV_ALL:
               DumpFunctions |= (1 << CV_ALL);
               break;
             default:
               printf("Error, output dump %d not known\n", value);
               break;
           }
         }
         break;

       case 'h': fprintf(stderr,"Usage for driver:\n");
		fprintf(stderr," -i <range expression>\n");
		fprintf(stderr," -s <set_tile file>\n");
		fprintf(stderr," -o <dump_tag>\n");
	        return;
       default:
	  break;
     }
  }

  /* open first file */

  if(Fargc <= 0) {
    fprintf(stderr,"Error, no input files given\n");
    exit(1);
  }
  Infp = open_file(Fargv[CurFile++]);
}



/*
 * 
 *  Formatted Dumps
 *
 */

/*
 *  Prints header info for input signals, same for all dumps
 */
static void
  print_input_header(FILE *fp)
{
  fprintf(fp,"gclk                   @C 1(8) 0(8)\n");
  fprintf(fp,"ew_cv_data[12:0]       @I @E 2\n");
  fprintf(fp,"ew_cv_start_x[11:0]    @I @E 2\n");
  fprintf(fp,"cycle_type             @I @E 2\n");
  fprintf(fp,"ew_cv_newspan          @I @E 2\n");
  fprintf(fp,"left                   @I @E 2\n");
  fprintf(fp,"reset_l                @I @E 2\n");
  fprintf(fp,"dv                     @V\n");
  fprintf(fp,"dv_d1                  @V\n");
}

/*
 *  Prints signal values info for input signals, same for all dumps
 */
static void
  print_input_sigs(FILE *fp, driver_t *dp)
{
  fprintf(fp,"0x%.4x 0x%0.3x %d %d %d %d %d %d ",
    dp->ew_cv_data_d1,
    dp->x_major,
    dp->cycle_type,
    dp->ew_cv_newspan,
    dp->left,
    dp->reset,
    dp->dv,
    dp->dv_d1);
}

/*
 *  Prints header info for cv_all dump
 */
static void
  print_cv_all_header(FILE *fp)
{
  fprintf(fp,"cv_value[3:0]          @O @S 15 @V dv_d1\n");
  fprintf(fp,"mask15                 @O @S 15 @V dv_d1\n");
  fprintf(fp,"x_offset[1:0]          @O @S 15 @V dv_d1\n");
  fprintf(fp,"y_offset[1:0]          @O @S 15 @V dv_d1\n");
  fprintf(fp,"\n"); /* required newline */
} 


/*
 *  Prints header info for cv_all dump
 */
static void
  print_cv_all_sigs(FILE *fp, cv_t *cp, driver_t *dp)
{
  fprintf(fp," 0x%.1x %d 0x%.1x 0x%.1x\n",
    cp->cv_value,
    cp->mask15,
    cp->x_offset,
    cp->y_offset);
}