My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
check_vcd.cpp
Go to the documentation of this file.
1 /*
2  * check_vcd.cpp - iterate a vcd file
3  *
4  * Copyright (C) 2005, 2006, 2008, 2010 Stefan Jahn <stefan@lkcc.org>
5  * Copyright (C) 2005 Raimund Jacob <raimi@lkcc.org>
6  *
7  * This is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this package; see the file COPYING. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * $Id: check_vcd.cpp 1825 2011-03-11 20:42:14Z ela $
23  *
24  */
25 
26 #if HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 #include <assert.h>
35 #include <float.h>
36 #include <ctype.h>
37 
38 #include "check_vcd.h"
39 
40 // Enable for debugging purposes.
41 #define VCD_DEBUG 0
42 
43 // Some more definitions.
44 #define VCD_SKIP_ARRAYS 1
45 #define VCD_INCLUDE_RANGE 0
46 #define VCD_TIMEVAR "dtime"
47 
48 // Global variables.
49 struct vcd_file * vcd = NULL;
50 int vcd_errors = 0;
51 int vcd_freehdl = 1;
52 int vcd_correct = 0;
53 struct vcd_set * vcd_sets = NULL;
55 
56 /* The function looks through all variable definitions in all scopes
57  to find the given reference code. */
58 static struct vcd_vardef *
59 vcd_find_code (struct vcd_scope * root, char * code) {
60  struct vcd_scope * scope;
61  for (scope = root; scope; scope = scope->next) {
62  struct vcd_vardef * var;
63  for (var = scope->vardefs; var; var = var->next) {
64  if (!strcmp (var->code, code))
65  return var;
66  }
67  // search in sub-scopes
68  if ((var = vcd_find_code (scope->scopes, code)) != NULL)
69  return var;
70  }
71  return NULL;
72 }
73 
74 // Free's the given VCD change.
75 static void vcd_free_change (struct vcd_change * vc) {
76  free (vc->code);
77  free (vc->value);
78  free (vc);
79 }
80 
81 // Free's the given VCD changeset.
82 static void vcd_free_changeset (struct vcd_changeset * cs) {
83  struct vcd_change * vc, * vnext;
84  for (vc = cs->changes; vc; vc = vnext) {
85  vnext = vc->next;
86  vcd_free_change (vc);
87  }
88  free (cs);
89 }
90 
91 #if VCD_FAST
92 
93 /* Returns changes sets in the list's order itself. */
94 static struct vcd_changeset *
95 vcd_find_firstset_fast (struct vcd_changeset * root) {
96  static struct vcd_changeset * last = root;
97  struct vcd_changeset * result = NULL;
98  result = last;
99  if (last) last = last->next;
100  return result;
101 }
102 
103 /* Reverses the given change set and returns the pointer to the new
104  root change set. */
105 static struct vcd_changeset *
106 vcd_reverse_changesets (struct vcd_changeset * root) {
107  struct vcd_changeset * cs = NULL;
108  while (root != NULL) {
109  struct vcd_changeset * next = root->next;
110  root->next = cs;
111  cs = root;
112  root = next;
113  }
114  return cs;
115 }
116 
117 #else
118 
119 /* Returns the change set with the smallest time stamp which is yet
120  unprocessed. It is based upon the fact that the list is in reverse
121  order. */
122 static struct vcd_changeset *
123 vcd_find_firstset (struct vcd_changeset * root) {
124  struct vcd_changeset * cs, * result = NULL;
125  double Min = root ? root->t : 0;
126  for (cs = root; cs; cs = cs->next) {
127  if (!cs->done && cs->t <= Min) {
128  Min = cs->t;
129  result = cs;
130  }
131  }
132  return result;
133 }
134 
135 #endif
136 
137 /* Looks for the a variable name in the given list of variables. */
138 static struct vcd_variable *
139 vcd_find_variable (struct vcd_variable * root, struct vcd_vardef * var) {
140  for (struct vcd_variable * vv = root; vv; vv = vv->next) {
141  if (!strcmp (vv->code, var->code))
142  return vv;
143  }
144  return NULL;
145 }
146 
147 /* The function sorts the given VCD changesets. For this it creates a
148  new list of VCD sets. Changesets with the same timestamp are
149  merged appropriately. */
150 static void vcd_sort_changesets (struct vcd_changeset * root) {
151  struct vcd_changeset * cs;
152  struct vcd_set * vs, * current = NULL;
153  struct vcd_change * vc;
154  struct vcd_variable * vv;
155 
156 #if VCD_FAST
157  // for fast lookup, need to reverse list
158  root = vcd_reverse_changesets (root);
159 #endif
160 
161  // as long as there are still changesets unprocessed
162 #if VCD_FAST
163  while ((cs = vcd_find_firstset_fast (root)) != NULL) {
164 #else
165  while ((cs = vcd_find_firstset (root)) != NULL) {
166 #endif
167  // create set if necessary
168  if (current == NULL || current->t != cs->t) {
169  vs = (struct vcd_set *) calloc (1, sizeof (struct vcd_set));
170  vs->t = cs->t;
171  // chain the list of sets
172  if (!current)
173  vcd_sets = vs;
174  else
175  current->next = vs;
176  current = vs;
177  }
178 
179  // go through list of value changes
180  for (vc = cs->changes; vc; vc = vc->next) {
181  vv = vcd_find_variable (current->variables, vc->var);
182  if (vv != NULL) {
183  // duplicate value change
184  vv->value = vc->value;
185  vv->isreal = vc->isreal;
186  if (current->t > 0) { // due to a $dumpvars before
187  fprintf (stderr, "vcd notice, duplicate value change at t = %g of "
188  "variable `%s'\n", current->t, vc->var->ident);
189  }
190  }
191  else {
192  // add variable to set
193  vv = (struct vcd_variable *) calloc (1, sizeof (struct vcd_variable));
194  vv->ident = vc->var->ident;
195  vv->type = vc->var->type;
196  vv->value = vc->value;
197  vv->isreal = vc->isreal;
198  vv->code = vc->code;
199  vv->next = current->variables;
200  current->variables = vv;
201  }
202  }
203 #ifndef VCD_FAST
204  // changeset processed
205  cs->done = 1;
206 #else
207  //vcd_free_changeset (cs);
208 #endif
209  }
210 }
211 
212 /* Predends the scope identifiers in front of a variable identfier. */
213 static char *
214 vcd_prepend_scopes (struct vcd_vardef * var, char * ident) {
215  struct vcd_scope * scope = var->scope;
216  while (scope && scope != vcd->scopes) {
217  if (vcd->scopes) {
218  if (scope == vcd->scopes->scopes && vcd->scopes->vardefs == NULL) {
219  /* skip top-scope description if there are no variables */
220  scope = scope->parent;
221  continue;
222  }
223  }
224  char * txt = (char *) malloc (strlen (ident) + strlen (scope->ident) + 2);
225  sprintf (txt, "%s.%s", scope->ident, ident);
226  free (ident);
227  ident = txt;
228  scope = scope->parent;
229  }
230  return ident;
231 }
232 
233 /* This function initially creates a dataset variable based on the
234  given VCD variable. */
235 static struct dataset_variable *
236 vcd_create_variable (struct vcd_vardef * var) {
237  struct dataset_variable * ds;
238  int len = strlen (var->ident) + 1;
239 
240  ds = (struct dataset_variable *)
241  calloc (1, sizeof (struct dataset_variable));
242  ds->output = 1;
243 
244 #if VCD_INCLUDE_RANGE
245  if (var->range) len += 32;
246 #endif
247  char * id1, * id2 = (char *) malloc (len);
248 
249  // using VCD produced by FreeHDL
250  if (vcd_freehdl) {
251  // skip these
252  if (strstr (var->ident, "implicit_wait_for"))
253  ds->output = 0;
254  // correct nodes
255  if (vcd_correct) {
256  if (strstr (var->ident, "net") == var->ident) {
257  id1 = strdup (&var->ident[3]);
258  } else {
259  id1 = strdup (var->ident);
260  }
261  }
262  // keep nodes
263  else {
264  id1 = strdup (var->ident);
265  }
266  }
267  // other than FreeHDL
268  else {
269  id1 = strdup (var->ident);
270  }
271 
272 #if VCD_INCLUDE_RANGE
273  if (!var->range) {
274  // no range
275  sprintf (id2, "%s", id1);
276  } else if (var->range->l == -1) {
277  // one bit
278  sprintf (id2, "%s[%d]", id1, var->range->h);
279  } else if (var->range->h == -1) {
280  // arrays
281  sprintf (id2, "%s[%d]", id1, var->range->l);
282  } else {
283  // bit range
284  sprintf (id2, "%s[%d:%d]", id1, var->range->l, var->range->h);
285  }
286 #else
287  sprintf (id2, "%s", id1);
288 #endif
289 
290 #if VCD_SKIP_ARRAYS
291  if (var->range && var->range->h == -1 && var->range->l != -1) {
292  ds->output = 0;
293  }
294 #endif
295 
296  ds->ident = strdup (id2);
297  if (vcd_freehdl) {
298  ds->ident = vcd_prepend_scopes (var, ds->ident);
299  }
300 
301  free (id1);
302  free (id2);
303  return ds;
304 }
305 
306 /* Based on the value in the given VCD variable and the size (in bits)
307  the function returns a nicely formatted value for the dataset. */
308 static char * vcd_create_value (struct vcd_variable * vv, int size) {
309  int i, len = strlen (vv->value);
310  char * value;
311 
312  if (vv->type == VAR_REAL) {
313  // a real
314  char txt[64];
315  double val = strtod (vv->value, NULL);
316  sprintf (txt, "%+.11e", val);
317  value = strdup (txt);
318  } else if (vv->type == VAR_INTEGER) {
319  // an integer
320  char txt[64];
321  long val = 0, bit, i = strlen (vv->value) - 1;
322  for (bit = 1; i >= 0; i--, bit <<= 1) {
323  if (vv->value[i] == '1')
324  val |= bit;
325  else if (vv->value[i] == '0')
326  val &= ~bit;
327  }
328  sprintf (txt, "%+ld", val);
329  value = strdup (txt);
330  vv->isreal = 1;
331  } else if (size == len) {
332  // already good
333  value = strdup (vv->value);
334  } else {
335  // fill left extending values for vectors
336  value = (char *) calloc (1, size + 1);
337  char fill;
338  fill = (vv->value[0] == '1') ? '0' : vv->value[0];
339  for (i = 0; i < size - len; i++) value[i] = fill;
340  strcpy (&value[i], vv->value);
341  }
342  return value;
343 }
344 
345 /* The function creates a full dataset variable for the given VCD
346  variable. */
347 static struct dataset_variable *
348 vcd_create_dataset (struct vcd_vardef * var) {
349  struct dataset_variable * ds;
350  struct dataset_value * dv, * current = NULL;
351  struct vcd_set * vs;
352  struct vcd_variable * vv;
353  char * currentval = NULL;
354  int found;
355 
356  ds = vcd_create_variable (var);
357 
358  // go through all VCD sets
359  for (vs = vcd_sets; vs; vs = vs->next) {
360  found = 0;
361  // through all variables in the set
362  for (vv = vs->variables; vv; vv = vv->next) {
363  if (!strcmp (vv->code, var->code)) {
364  // found the variable in the set
365  dv = (struct dataset_value *)
366  calloc (1, sizeof (struct dataset_value));
367  dv->value = vcd_create_value (vv, var->size);
368  // get value attribute
369  ds->isreal = vv->isreal;
370  // chain the list of values
371  if (!current)
372  ds->values = dv;
373  else
374  current->next = dv;
375  current = dv;
376  // save current value of the variable
377  currentval = dv->value;
378  found++;
379  break;
380  }
381  }
382  if (!found) {
383  // variable did not occur in the current VCD set
384  if (!currentval) {
385  // no initial value given
386  fprintf (stderr, "vcd error, variable `%s' has no initial value\n",
387  ds->ident);
388  vcd_errors++;
389  } else {
390  // else: apply previous value
391  dv = (struct dataset_value *)
392  calloc (1, sizeof (struct dataset_value));
393  dv->value = strdup (currentval);
394  // chain the list
395  if (!current)
396  ds->values = dv;
397  else
398  current->next = dv;
399  current = dv;
400  }
401  }
402  }
403  return ds;
404 }
405 
406 /* The function creates the independent (timestamps) variable. It
407  passes through all VCD changesets and collects the simulation
408  times. */
409 static struct dataset_variable * vcd_create_indep (const char * name) {
410  struct dataset_variable * ds;
411  struct dataset_value * dv, * current = NULL;
412  struct vcd_set * vs;
413 
414  // create dataset
415  ds = (struct dataset_variable *)
416  calloc (1, sizeof (struct dataset_variable));
417  ds->ident = strdup (name);
418  ds->output = 1;
419 
420  // go through all VCD sets
421  for (vs = vcd_sets; vs; vs = vs->next) {
422  dv = (struct dataset_value *) calloc (1, sizeof (struct dataset_value));
423  ds->size++;
424  // apply timestamp transformation
425  char txt[64];
426  sprintf (txt, "%+.11e", vs->t * vcd->t * vcd->scale);
427  dv->value = strdup (txt);
428  // chain the list
429  if (!current)
430  ds->values = dv;
431  else
432  current->next = dv;
433  current = dv;
434  }
435  return ds;
436 }
437 
438 /* The function creates a list of dataset for each VCD variable. */
439 static void vcd_prepare_variable_datasets (struct vcd_scope * root) {
440  struct vcd_scope * scope;
441  struct dataset_variable * data;
442  // through each scope
443  for (scope = root; scope; scope = scope->next) {
444  struct vcd_vardef * var;
445  // through each variable in this scope
446  for (var = scope->vardefs; var; var = var->next) {
447  data = vcd_create_dataset (var);
448  data->type = DATA_DEPENDENT;
449  data->dependencies = strdup (VCD_TIMEVAR);
450  data->next = dataset_root;
451  dataset_root = data;
452  }
453  vcd_prepare_variable_datasets (scope->scopes);
454  }
455 }
456 
457 /* The function creates a list of dataset for each VCD variable and
458  for the independent (timestamps) variable as well. */
459 static void vcd_prepare_datasets (void) {
460  struct dataset_variable * data;
461  // the dependent variables
462  vcd_prepare_variable_datasets (vcd->scopes);
463  // the independent variable
464  data = vcd_create_indep (VCD_TIMEVAR);
465  data->type = DATA_INDEPENDENT;
466  data->next = dataset_root;
467  dataset_root = data;
468 }
469 
470 #if VCD_DEBUG
471 // Debugging: Prints the VCD sets.
472 static void vcd_print_sets (void) {
473  struct vcd_changeset * vs;
474  struct vcd_change * vv;
475  for (vs = vcd->changesets; vs; vs = vs->next) {
476  fprintf (stderr, "--- t => %g\n", vs->t);
477  for (vv = vs->changes; vv; vv = vv->next) {
478  fprintf (stderr, "%s\t => %s\n", vv->value, vv->var->ident);
479  }
480  }
481 }
482 
483 // Debugging: Prints the generate data sets.
484 static void vcd_dataset_print (void) {
485  struct dataset_variable * ds;
486  struct dataset_value * dv;
487  for (ds = dataset_root; ds; ds = ds->next) {
488  fprintf (stderr, "\n%s%s => %s\n",
489  ds->type == DATA_INDEPENDENT ? "in" : "",
490  ds->type == DATA_UNKNOWN ? "xxx" : "dep", ds->ident);
491  for (dv = ds->values; dv; dv = dv->next) {
492  fprintf (stderr, " %s\n", dv->value);
493  }
494  }
495 }
496 #endif /* VCD_DEBUG */
497 
498 /* This function is the overall VCD data checker. It returns zero on
499  success, non-zero otherwise. */
500 int vcd_checker (void) {
501 
502  // de-reference each value change identfier code
503  struct vcd_changeset * changeset;
504  for (changeset = vcd->changesets; changeset; changeset = changeset->next) {
505  struct vcd_change * change;
506  for (change = changeset->changes; change; change = change->next) {
507  change->var = vcd_find_code (vcd->scopes, change->code);
508  if (change->var == NULL) {
509  fprintf (stderr, "vcd error, no such variable reference `%s' "
510  "found\n", change->code);
511  vcd_errors++;
512  }
513  }
514  }
515 
516  if (vcd_errors) return -1;
517 
518  // sort the VCD changesets
519  vcd_sort_changesets (vcd->changesets);
520 
521  // create the outgoing datasets
522  vcd_prepare_datasets ();
523 
524 #if VCD_DEBUG
525  vcd_print_sets ();
526  vcd_dataset_print ();
527 #endif /* VCD_DEBUG */
528 
529  return vcd_errors ? -1 : 0;
530 }
531 
532 // Free's the given scope root.
533 static void vcd_free_scope (struct vcd_scope * root) {
534  struct vcd_scope * vs, * snext;
535  for (vs = root; vs; vs = snext) {
536  snext = vs->next;
537  free (vs->ident);
538  struct vcd_vardef * vv, * vnext;
539  for (vv = vs->vardefs; vv; vv = vnext) {
540  vnext = vv->next;
541  free (vv->code);
542  free (vv->ident);
543  if (vv->range) free (vv->range);
544  free (vv);
545  }
546  vcd_free_scope (vs->scopes);
547  free (vs);
548  }
549 }
550 
551 // Free's the given VCD file.
552 static void vcd_free_file (struct vcd_file * vcd) {
553  vcd_free_scope (vcd->scopes);
554  struct vcd_changeset * cs, * cnext;
555  for (cs = vcd->changesets; cs; cs = cnext) {
556  cnext = cs->next;
557  vcd_free_changeset (cs);
558  }
559  free (vcd);
560 }
561 
562 // Free's the given set of VCD changes.
563 static void vcd_free_set (struct vcd_set * root) {
564  struct vcd_set * vs, * snext;
565  for (vs = root; vs; vs = snext) {
566  snext = vs->next;
567  struct vcd_variable * vv, * vnext;
568  for (vv = vs->variables; vv; vv = vnext) {
569  vnext = vv->next;
570  free (vv);
571  }
572  free (vs);
573  }
574 }
575 
576 // Free's the given dataset list.
577 static void vcd_free_dataset (struct dataset_variable * root) {
578  struct dataset_variable * ds, * snext;
579  for (ds = root; ds; ds = snext) {
580  snext = ds->next;
581  free (ds->ident);
582  if (ds->dependencies) free (ds->dependencies);
583  struct dataset_value * dv, * dnext;
584  for (dv = ds->values; dv; dv = dnext) {
585  dnext = dv->next;
586  free (dv->value);
587  free (dv);
588  }
589  free (ds);
590  }
591 }
592 
593 // Destroys data used by the VCD checker.
594 void vcd_destroy (void) {
595  vcd_errors = 0;
596  vcd_free_file (vcd);
597  vcd = NULL;
598  vcd_free_set (vcd_sets);
599  vcd_sets = NULL;
600  vcd_free_dataset (dataset_root);
601  dataset_root = NULL;
602 }
603 
604 // Initializes the VCD checker.
605 void vcd_init (void) {
606  vcd = (struct vcd_file *) calloc (1, sizeof (struct vcd_file));
607 }