Qucs-core  0.0.19
check_vcd.cpp
Go to the documentation of this file.
00001 /*
00002  * check_vcd.cpp - iterate a vcd file
00003  *
00004  * Copyright (C) 2005, 2006, 2008, 2010 Stefan Jahn <stefan@lkcc.org>
00005  * Copyright (C) 2005 Raimund Jacob <raimi@lkcc.org>
00006  *
00007  * This is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2, or (at your option)
00010  * any later version.
00011  *
00012  * This software is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this package; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021  *
00022  * $Id$
00023  *
00024  */
00025 
00026 #if HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <cmath>
00034 #include <assert.h>
00035 #include <float.h>
00036 #include <ctype.h>
00037 
00038 #include "check_vcd.h"
00039 
00040 // Enable for debugging purposes.
00041 #define VCD_DEBUG 0
00042 
00043 // Some more definitions.
00044 #define VCD_SKIP_ARRAYS 1
00045 #define VCD_INCLUDE_RANGE 0
00046 #define VCD_TIMEVAR "dtime"
00047 
00048 // Global variables.
00049 struct vcd_file * vcd = NULL;
00050 int vcd_errors = 0;
00051 int vcd_freehdl = 1;
00052 int vcd_correct = 0;
00053 struct vcd_set * vcd_sets = NULL;
00054 struct dataset_variable * dataset_root = NULL;
00055 
00056 /* The function looks through all variable definitions in all scopes
00057    to find the given reference code. */
00058 static struct vcd_vardef *
00059 vcd_find_code (struct vcd_scope * root, char * code) {
00060   struct vcd_scope * scope;
00061   for (scope = root; scope; scope = scope->next) {
00062     struct vcd_vardef * var;
00063     for (var = scope->vardefs; var; var = var->next) {
00064       if (!strcmp (var->code, code))
00065         return var;
00066     }
00067     // search in sub-scopes
00068     if ((var = vcd_find_code (scope->scopes, code)) != NULL)
00069       return var;
00070   }
00071   return NULL;
00072 }
00073 
00074 // Free's the given VCD change.
00075 static void vcd_free_change (struct vcd_change * vc) {
00076   free (vc->code);
00077   free (vc->value);
00078   free (vc);
00079 }
00080 
00081 // Free's the given VCD changeset.
00082 static void vcd_free_changeset (struct vcd_changeset * cs) {
00083   struct vcd_change * vc, * vnext;
00084   for (vc = cs->changes; vc; vc = vnext) {
00085     vnext = vc->next;
00086     vcd_free_change (vc);
00087   }
00088   free (cs);
00089 }
00090 
00091 #if VCD_FAST
00092 
00093 /* Returns changes sets in the list's order itself. */
00094 static struct vcd_changeset *
00095 vcd_find_firstset_fast (struct vcd_changeset * root) {
00096   static struct vcd_changeset * last = root;
00097   struct vcd_changeset * result = NULL;
00098   result = last;
00099   if (last) last = last->next;
00100   return result;
00101 }
00102 
00103 /* Reverses the given change set and returns the pointer to the new
00104    root change set. */
00105 static struct vcd_changeset *
00106 vcd_reverse_changesets (struct vcd_changeset * root) {
00107   struct vcd_changeset * cs = NULL;
00108   while (root != NULL) {
00109     struct vcd_changeset * next = root->next;
00110     root->next = cs;
00111     cs = root;
00112     root = next;
00113   }
00114   return cs;
00115 }
00116 
00117 #else
00118 
00119 /* Returns the change set with the smallest time stamp which is yet
00120    unprocessed.  It is based upon the fact that the list is in reverse
00121    order. */
00122 static struct vcd_changeset *
00123 vcd_find_firstset (struct vcd_changeset * root) {
00124   struct vcd_changeset * cs, * result = NULL;
00125   double Min = root ? root->t : 0;
00126   for (cs = root; cs; cs = cs->next) {
00127     if (!cs->done && cs->t <= Min) {
00128       Min = cs->t;
00129       result = cs;
00130     }
00131   }
00132   return result;
00133 }
00134 
00135 #endif
00136 
00137 /* Looks for the a variable name in the given list of variables. */
00138 static struct vcd_variable *
00139 vcd_find_variable (struct vcd_variable * root, struct vcd_vardef * var) {
00140   for (struct vcd_variable * vv = root; vv; vv = vv->next) {
00141     if (!strcmp (vv->code, var->code))
00142       return vv;
00143   }
00144   return NULL;
00145 }
00146 
00147 /* The function sorts the given VCD changesets.  For this it creates a
00148    new list of VCD sets.  Changesets with the same timestamp are
00149    merged appropriately. */
00150 static void vcd_sort_changesets (struct vcd_changeset * root) {
00151   struct vcd_changeset * cs;
00152   struct vcd_set * vs, * current = NULL;
00153   struct vcd_change * vc;
00154   struct vcd_variable * vv;
00155 
00156 #if VCD_FAST
00157   // for fast lookup, need to reverse list
00158   root = vcd_reverse_changesets (root);
00159 #endif
00160 
00161   // as long as there are still changesets unprocessed
00162 #if VCD_FAST
00163   while ((cs = vcd_find_firstset_fast (root)) != NULL) {
00164 #else
00165   while ((cs = vcd_find_firstset (root)) != NULL) {
00166 #endif
00167     // create set if necessary
00168     if (current == NULL || current->t != cs->t) {
00169       vs = (struct vcd_set *) calloc (1, sizeof (struct vcd_set));
00170       vs->t = cs->t;
00171       // chain the list of sets
00172       if (!current)
00173         vcd_sets = vs;
00174       else
00175         current->next = vs;
00176       current = vs;
00177     }
00178 
00179     // go through list of value changes
00180     for (vc = cs->changes; vc; vc = vc->next) {
00181       vv = vcd_find_variable (current->variables, vc->var);
00182       if (vv != NULL) {
00183         // duplicate value change
00184         vv->value = vc->value;
00185         vv->isreal = vc->isreal;
00186         if (current->t > 0) { // due to a $dumpvars before
00187           fprintf (stderr, "vcd notice, duplicate value change at t = %g of "
00188                    "variable `%s'\n", current->t, vc->var->ident);
00189         }
00190       }
00191       else {
00192         // add variable to set
00193         vv = (struct vcd_variable *) calloc (1, sizeof (struct vcd_variable));
00194         vv->ident = vc->var->ident;
00195         vv->type = vc->var->type;
00196         vv->value = vc->value;
00197         vv->isreal = vc->isreal;
00198         vv->code = vc->code;
00199         vv->next = current->variables;
00200         current->variables = vv;
00201       }
00202     }
00203 #ifndef VCD_FAST
00204     // changeset processed
00205     cs->done = 1;
00206 #else
00207     //vcd_free_changeset (cs);
00208 #endif
00209   }
00210 }
00211 
00212 /* Predends the scope identifiers in front of a variable identfier. */
00213 static char *
00214 vcd_prepend_scopes (struct vcd_vardef * var, char * ident) {
00215   struct vcd_scope * scope = var->scope;
00216   while (scope && scope != vcd->scopes) {
00217     if (vcd->scopes) {
00218       if (scope == vcd->scopes->scopes && vcd->scopes->vardefs == NULL) {
00219         /* skip top-scope description if there are no variables */
00220         scope = scope->parent;
00221         continue;
00222       }
00223     }
00224     char * txt = (char *) malloc (strlen (ident) + strlen (scope->ident) + 2);
00225     sprintf (txt, "%s.%s", scope->ident, ident);
00226     free (ident);
00227     ident = txt;
00228     scope = scope->parent;
00229   }
00230   return ident;
00231 }
00232 
00233 /* This function initially creates a dataset variable based on the
00234    given VCD variable. */
00235 static struct dataset_variable *
00236 vcd_create_variable (struct vcd_vardef * var) {
00237   struct dataset_variable * ds;
00238   int len = strlen (var->ident) + 1;
00239 
00240   ds = (struct dataset_variable *)
00241     calloc (1, sizeof (struct dataset_variable));
00242   ds->output = 1;
00243 
00244 #if VCD_INCLUDE_RANGE
00245   if (var->range) len += 32;
00246 #endif
00247   char * id1, * id2 = (char *) malloc (len);
00248 
00249   // using VCD produced by FreeHDL
00250   if (vcd_freehdl) {
00251     // skip these
00252     if (strstr (var->ident, "implicit_wait_for"))
00253       ds->output = 0;
00254     // correct nodes
00255     if (vcd_correct) {
00256       if (strstr (var->ident, "net") == var->ident) {
00257         id1 = strdup (&var->ident[3]);
00258       } else {
00259         id1 = strdup (var->ident);
00260       }
00261     }
00262     // keep nodes
00263     else {
00264       id1 = strdup (var->ident);
00265     }
00266   }
00267   // other than FreeHDL
00268   else {
00269     id1 = strdup (var->ident);
00270   }
00271 
00272 #if VCD_INCLUDE_RANGE
00273   if (!var->range) {
00274     // no range
00275     sprintf (id2, "%s", id1);
00276   } else if (var->range->l == -1) {
00277     // one bit
00278     sprintf (id2, "%s[%d]", id1, var->range->h);
00279   } else if (var->range->h == -1) {
00280     // arrays
00281     sprintf (id2, "%s[%d]", id1, var->range->l);
00282   } else {
00283     // bit range
00284     sprintf (id2, "%s[%d:%d]", id1, var->range->l, var->range->h);
00285   }
00286 #else
00287   sprintf (id2, "%s", id1);
00288 #endif
00289 
00290 #if VCD_SKIP_ARRAYS
00291   if (var->range && var->range->h == -1 && var->range->l != -1) {
00292     ds->output = 0;
00293   }
00294 #endif
00295 
00296   ds->ident = strdup (id2);
00297   if (vcd_freehdl) {
00298     ds->ident = vcd_prepend_scopes (var, ds->ident);
00299   }
00300 
00301   free (id1);
00302   free (id2);
00303   return ds;
00304 }
00305 
00306 /* Based on the value in the given VCD variable and the size (in bits)
00307    the function returns a nicely formatted value for the dataset. */
00308 static char * vcd_create_value (struct vcd_variable * vv, int size) {
00309   int i, len = strlen (vv->value);
00310   char * value;
00311 
00312   if (vv->type == VAR_REAL) {
00313     // a real
00314     char txt[64];
00315     double val = strtod (vv->value, NULL);
00316     sprintf (txt, "%+.11e", val);
00317     value = strdup (txt);
00318   } else if (vv->type == VAR_INTEGER) {
00319     // an integer
00320     char txt[64];
00321     long val = 0, bit, i = strlen (vv->value) - 1;
00322     for (bit = 1; i >= 0; i--, bit <<= 1) {
00323       if (vv->value[i] == '1')
00324         val |= bit;
00325       else if (vv->value[i] == '0')
00326         val &= ~bit;
00327     }
00328     sprintf (txt, "%+ld", val);
00329     value = strdup (txt);
00330     vv->isreal = 1;
00331   } else if (size == len) {
00332     // already good
00333     value = strdup (vv->value);
00334   } else {
00335     // fill left extending values for vectors
00336     value = (char *) calloc (1, size + 1);
00337     char fill;
00338     fill = (vv->value[0] == '1') ? '0' : vv->value[0];
00339     for (i = 0; i < size - len; i++) value[i] = fill;
00340     strcpy (&value[i], vv->value);
00341   }
00342   return value;
00343 }
00344 
00345 /* The function creates a full dataset variable for the given VCD
00346    variable. */
00347 static struct dataset_variable *
00348 vcd_create_dataset (struct vcd_vardef * var) {
00349   struct dataset_variable * ds;
00350   struct dataset_value * dv, * current = NULL;
00351   struct vcd_set * vs;
00352   struct vcd_variable * vv;
00353   char * currentval = NULL;
00354   int found;
00355 
00356   ds = vcd_create_variable (var);
00357 
00358   // go through all VCD sets
00359   for (vs = vcd_sets; vs; vs = vs->next) {
00360     found = 0;
00361     // through all variables in the set
00362     for (vv = vs->variables; vv; vv = vv->next) {
00363       if (!strcmp (vv->code, var->code)) {
00364         // found the variable in the set
00365         dv = (struct dataset_value *)
00366           calloc (1, sizeof (struct dataset_value));
00367         dv->value = vcd_create_value (vv, var->size);
00368         // get value attribute
00369         ds->isreal = vv->isreal;
00370         // chain the list of values
00371         if (!current)
00372           ds->values = dv;
00373         else
00374           current->next = dv;
00375         current = dv;
00376         // save current value of the variable
00377         currentval = dv->value;
00378         found++;
00379         break;
00380       }
00381     }
00382     if (!found) {
00383       // variable did not occur in the current VCD set
00384       if (!currentval) {
00385         // no initial value given
00386         fprintf (stderr, "vcd error, variable `%s' has no initial value\n",
00387                  ds->ident);
00388         vcd_errors++;
00389       } else {
00390         // else: apply previous value
00391         dv = (struct dataset_value *)
00392           calloc (1, sizeof (struct dataset_value));
00393         dv->value = strdup (currentval);
00394         // chain the list
00395         if (!current)
00396           ds->values = dv;
00397         else
00398           current->next = dv;
00399         current = dv;
00400       }
00401     }
00402   }
00403   return ds;
00404 }
00405 
00406 /* The function creates the independent (timestamps) variable.  It
00407    passes through all VCD changesets and collects the simulation
00408    times. */
00409 static struct dataset_variable * vcd_create_indep (const char * name) {
00410   struct dataset_variable * ds;
00411   struct dataset_value * dv, * current = NULL;
00412   struct vcd_set * vs;
00413 
00414   // create dataset
00415   ds = (struct dataset_variable *)
00416     calloc (1, sizeof (struct dataset_variable));
00417   ds->ident = strdup (name);
00418   ds->output = 1;
00419 
00420   // go through all VCD sets
00421   for (vs = vcd_sets; vs; vs = vs->next) {
00422     dv = (struct dataset_value *) calloc (1, sizeof (struct dataset_value));
00423     ds->size++;
00424     // apply timestamp transformation
00425     char txt[64];
00426     sprintf (txt, "%+.11e", vs->t * vcd->t * vcd->scale);
00427     dv->value = strdup (txt);
00428     // chain the list
00429     if (!current)
00430       ds->values = dv;
00431     else
00432       current->next = dv;
00433     current = dv;
00434   }
00435   return ds;
00436 }
00437 
00438 /* The function creates a list of dataset for each VCD variable. */
00439 static void vcd_prepare_variable_datasets (struct vcd_scope * root) {
00440   struct vcd_scope * scope;
00441   struct dataset_variable * data;
00442   // through each scope
00443   for (scope = root; scope; scope = scope->next) {
00444     struct vcd_vardef * var;
00445     // through each variable in this scope
00446     for (var = scope->vardefs; var; var = var->next) {
00447       data = vcd_create_dataset (var);
00448       data->type = DATA_DEPENDENT;
00449       data->dependencies = strdup (VCD_TIMEVAR);
00450       data->next = dataset_root;
00451       dataset_root = data;
00452     }
00453     vcd_prepare_variable_datasets (scope->scopes);
00454   }
00455 }
00456 
00457 /* The function creates a list of dataset for each VCD variable and
00458    for the independent (timestamps) variable as well. */
00459 static void vcd_prepare_datasets (void) {
00460   struct dataset_variable * data;
00461   // the dependent variables
00462   vcd_prepare_variable_datasets (vcd->scopes);
00463   // the independent variable
00464   data = vcd_create_indep (VCD_TIMEVAR);
00465   data->type = DATA_INDEPENDENT;
00466   data->next = dataset_root;
00467   dataset_root = data;
00468 }
00469 
00470 #if VCD_DEBUG
00471 // Debugging: Prints the VCD sets.
00472 static void vcd_print_sets (void) {
00473   struct vcd_changeset * vs;
00474   struct vcd_change * vv;
00475   for (vs = vcd->changesets; vs; vs = vs->next) {
00476     fprintf (stderr, "--- t => %g\n", vs->t);
00477     for (vv = vs->changes; vv; vv = vv->next) {
00478       fprintf (stderr, "%s\t => %s\n", vv->value, vv->var->ident);
00479     }
00480   }
00481 }
00482 
00483 // Debugging: Prints the generate data sets.
00484 static void vcd_dataset_print (void) {
00485   struct dataset_variable * ds;
00486   struct dataset_value * dv;
00487   for (ds = dataset_root; ds; ds = ds->next) {
00488     fprintf (stderr, "\n%s%s => %s\n",
00489              ds->type == DATA_INDEPENDENT ? "in" : "",
00490              ds->type == DATA_UNKNOWN ? "xxx" : "dep", ds->ident);
00491     for (dv = ds->values; dv; dv = dv->next) {
00492       fprintf (stderr, "  %s\n", dv->value);
00493     }
00494   }
00495 }
00496 #endif /* VCD_DEBUG */
00497 
00498 /* This function is the overall VCD data checker.  It returns zero on
00499    success, non-zero otherwise. */
00500 int vcd_checker (void) {
00501 
00502   // de-reference each value change identfier code
00503   struct vcd_changeset * changeset;
00504   for (changeset = vcd->changesets; changeset; changeset = changeset->next) {
00505     struct vcd_change * change;
00506     for (change = changeset->changes; change; change = change->next) {
00507       change->var = vcd_find_code (vcd->scopes, change->code);
00508       if (change->var == NULL) {
00509         fprintf (stderr, "vcd error, no such variable reference `%s' "
00510                  "found\n", change->code);
00511         vcd_errors++;
00512       }
00513     }
00514   }
00515 
00516   if (vcd_errors) return -1;
00517 
00518   // sort the VCD changesets
00519   vcd_sort_changesets (vcd->changesets);
00520 
00521   // create the outgoing datasets
00522   vcd_prepare_datasets ();
00523 
00524 #if VCD_DEBUG
00525   vcd_print_sets ();
00526   vcd_dataset_print ();
00527 #endif /* VCD_DEBUG */
00528 
00529   return vcd_errors ? -1 : 0;
00530 }
00531 
00532 // Free's the given scope root.
00533 static void vcd_free_scope (struct vcd_scope * root) {
00534   struct vcd_scope * vs, * snext;
00535   for (vs = root; vs; vs = snext) {
00536     snext = vs->next;
00537     free (vs->ident);
00538     struct vcd_vardef * vv, * vnext;
00539     for (vv = vs->vardefs; vv; vv = vnext) {
00540       vnext = vv->next;
00541       free (vv->code);
00542       free (vv->ident);
00543       free (vv->range);
00544       free (vv);
00545     }
00546     vcd_free_scope (vs->scopes);
00547     free (vs);
00548   }
00549 }
00550 
00551 // Free's the given VCD file.
00552 static void vcd_free_file (struct vcd_file * vcd) {
00553   vcd_free_scope (vcd->scopes);
00554   struct vcd_changeset * cs, * cnext;
00555   for (cs = vcd->changesets; cs; cs = cnext) {
00556     cnext = cs->next;
00557     vcd_free_changeset (cs);
00558   }
00559   free (vcd);
00560 }
00561 
00562 // Free's the given set of VCD changes.
00563 static void vcd_free_set (struct vcd_set * root) {
00564   struct vcd_set * vs, * snext;
00565   for (vs = root; vs; vs = snext) {
00566     snext = vs->next;
00567     struct vcd_variable * vv, * vnext;
00568     for (vv = vs->variables; vv; vv = vnext) {
00569       vnext = vv->next;
00570       free (vv);
00571     }
00572     free (vs);
00573   }
00574 }
00575 
00576 // Free's the given dataset list.
00577 static void vcd_free_dataset (struct dataset_variable * root) {
00578   struct dataset_variable * ds, * snext;
00579   for (ds = root; ds; ds = snext) {
00580     snext = ds->next;
00581     free (ds->ident);
00582     free (ds->dependencies);
00583     struct dataset_value * dv, * dnext;
00584     for (dv = ds->values; dv; dv = dnext) {
00585       dnext = dv->next;
00586       free (dv->value);
00587       free (dv);
00588     }
00589     free (ds);
00590   }
00591 }
00592 
00593 // Destroys data used by the VCD checker.
00594 void vcd_destroy (void) {
00595   vcd_errors = 0;
00596   vcd_free_file (vcd);
00597   vcd = NULL;
00598   vcd_free_set (vcd_sets);
00599   vcd_sets = NULL;
00600   vcd_free_dataset (dataset_root);
00601   dataset_root = NULL;
00602 }
00603 
00604 // Initializes the VCD checker.
00605 void vcd_init (void) {
00606   vcd = (struct vcd_file *) calloc (1, sizeof (struct vcd_file));
00607 }