Qucs-core
0.0.19
|
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 }