URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
[/] [eco32/] [trunk/] [tools/] [vcdchk/] [vcdchk.c] - Rev 302
Go to most recent revision | Compare with Previous | Blame | View Log
/* * vcdchk.c -- check the value of a signal in a VCD file */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #define MAX_LINE 200 #define MAX_NAME 1000 /**************************************************************/ typedef int Bool; #define FALSE 0 #define TRUE 1 /**************************************************************/ Bool debugVCD = FALSE; Bool debugCHK = FALSE; Bool debugCheck = FALSE; /**************************************************************/ void error(char *fmt, ...) { va_list ap; va_start(ap, fmt); printf("Error: "); vprintf(fmt, ap); printf("\n"); va_end(ap); exit(1); } void *allocate(int size) { void *res; res = malloc(size); if (res == NULL) { error("no memory"); } return res; } void release(void *p) { if (p == NULL) { error("NULL pointer in release()"); } free(p); } /**************************************************************/ #define KW_COMMENT 0 #define KW_DATE 1 #define KW_DUMPALL 2 #define KW_DUMPOFF 3 #define KW_DUMPON 4 #define KW_DUMPVARS 5 #define KW_END 6 #define KW_ENDDEFS 7 #define KW_SCOPE 8 #define KW_TIMESCALE 9 #define KW_UPSCOPE 10 #define KW_VAR 11 #define KW_VERSION 12 typedef struct { char *name; int number; } Keyword; static Keyword keywords[] = { { "comment", KW_COMMENT }, { "date", KW_DATE }, { "dumpall", KW_DUMPALL }, { "dumpoff", KW_DUMPOFF }, { "dumpon", KW_DUMPON }, { "dumpvars", KW_DUMPVARS }, { "end", KW_END }, { "enddefinitions", KW_ENDDEFS }, { "scope", KW_SCOPE }, { "timescale", KW_TIMESCALE }, { "upscope", KW_UPSCOPE }, { "var", KW_VAR }, { "version", KW_VERSION }, }; Keyword *lookupKeyword(char *name) { int lo, hi, tst; int res; lo = 0; hi = sizeof(keywords) / sizeof(keywords[0]) - 1; while (lo <= hi) { tst = (lo + hi) / 2; res = strcmp(keywords[tst].name, name); if (res == 0) { return &keywords[tst]; } if (res < 0) { lo = tst + 1; } else { hi = tst - 1; } } return NULL; } /**************************************************************/ #define VT_EVENT 0 #define VT_INTEGER 1 #define VT_PARAMETER 2 #define VT_REAL 3 #define VT_REG 4 #define VT_SUPPLY0 5 #define VT_SUPPLY1 6 #define VT_TIME 7 #define VT_TRI 8 #define VT_TRI0 9 #define VT_TRI1 10 #define VT_TRIAND 11 #define VT_TRIOR 12 #define VT_TRIREG 13 #define VT_WAND 14 #define VT_WIRE 15 #define VT_WOR 16 typedef struct { char *name; int number; } VarType; static VarType varTypes[] = { { "event", VT_EVENT }, { "integer", VT_INTEGER }, { "parameter", VT_PARAMETER }, { "real", VT_REAL }, { "reg", VT_REG }, { "supply0", VT_SUPPLY0 }, { "supply1", VT_SUPPLY1 }, { "time", VT_TIME }, { "tri", VT_TRI }, { "tri0", VT_TRI0 }, { "tri1", VT_TRI1 }, { "triand", VT_TRIAND }, { "trior", VT_TRIOR }, { "trireg", VT_TRIREG }, { "wand", VT_WAND }, { "wire", VT_WIRE }, { "wor", VT_WOR }, }; VarType *lookupVarType(char *name) { int lo, hi, tst; int res; lo = 0; hi = sizeof(varTypes) / sizeof(varTypes[0]) - 1; while (lo <= hi) { tst = (lo + hi) / 2; res = strcmp(varTypes[tst].name, name); if (res == 0) { return &varTypes[tst]; } if (res < 0) { lo = tst + 1; } else { hi = tst - 1; } } return NULL; } /**************************************************************/ typedef struct change { int code; /* id code of variable */ char *vectorValue; /* vector value stored as string */ /* NULL if value is scalar value */ char scalarValue; /* one of '0', '1', 'x', or 'z' */ /* '\0' if value is vector value */ struct change *next; /* next value change in this step */ } Change; Change *newChange(int code, char *vectorValue, char scalarValue) { Change *change; change = allocate(sizeof(Change)); change->code = code; if (vectorValue != NULL) { change->vectorValue = allocate(strlen(vectorValue) + 1); strcpy(change->vectorValue, vectorValue); change->scalarValue = '\0'; } else { change->vectorValue = NULL; change->scalarValue = scalarValue; } change->next = NULL; return change; } typedef struct step { int time; /* simulation time for this step */ struct step *prev; /* previous time step */ struct step *next; /* next time step */ Change *changes; /* variables that changed in this step */ } Step; Step *newStep(int time, Step *prev) { Step *step; step = allocate(sizeof(Step)); step->time = time; step->prev = prev; step->next = NULL; step->changes = NULL; return step; } typedef struct var { int type; /* one of VT_xxx */ int size; /* number of bits */ int code; /* id code of variable */ char *name; /* local name of variable */ int msi; /* most significant index */ int lsi; /* least significant index */ struct var *next; /* linked list of vars in scope */ } Var; Var *newVar(int type, int size, int code, char *name, int msi, int lsi) { Var *var; var = allocate(sizeof(Var)); var->type = type; var->size = size; var->code = code; var->name = allocate(strlen(name) + 1); strcpy(var->name, name); var->msi = msi; var->lsi = lsi; var->next = NULL; return var; } #define SCOPE_MODULE 0 #define SCOPE_TASK 1 #define SCOPE_FUNCTION 2 #define SCOPE_BEGIN 3 #define SCOPE_FORK 4 typedef struct scope { int number; /* every scope has a unique number */ int type; /* one of SCOPE_xxx */ char *name; /* the name of the scope */ struct scope *parent; struct scope *siblings; struct scope *children; struct scope *lastchild; Var *variables; Var *lastvar; } Scope; Scope *newScope(int type, char *name, Scope *parent) { static int scopeNumber = 0; Scope *scope; scope = allocate(sizeof(Scope)); scope->number = scopeNumber++; scope->type = type; scope->name = allocate(strlen(name) + 1); strcpy(scope->name, name); scope->parent = parent; scope->siblings = NULL; scope->children = NULL; scope->lastchild = NULL; scope->variables = NULL; scope->lastvar = NULL; return scope; } #define VCD_TS_S 0 #define VCD_TS_MS 1 #define VCD_TS_US 2 #define VCD_TS_NS 3 #define VCD_TS_PS 4 #define VCD_TS_FS 5 typedef struct { char *date; /* generation date */ char *version; /* simulator version */ int timescaleMult; /* 1, 10, 100 */ int timescaleUnit; /* one of VCD_TS_xx */ Scope *root; /* root scope */ Step *steps; /* time steps */ } VCD; /**************************************************************/ #define INITIAL_HASH_SIZE 100 typedef struct entry { char *name; /* key */ Var *var; /* value */ unsigned hashValue; /* hash value of name */ struct entry *next; /* bucket chaining */ } Entry; static int hashSize = 0; static Entry **buckets; static int numEntries; static unsigned hash(char *s) { unsigned h, g; h = 0; while (*s != '\0') { h = (h << 4) + *s++; g = h & 0xF0000000; if (g != 0) { h ^= g >> 24; h ^= g; } } return h; } static Bool isPrime(int i) { int t; if (i < 2) { return FALSE; } if (i == 2) { return TRUE; } if (i % 2 == 0) { return FALSE; } t = 3; while (t * t <= i) { if (i % t == 0) { return FALSE; } t += 2; } return TRUE; } static void initTable(void) { int i; hashSize = INITIAL_HASH_SIZE; while (!isPrime(hashSize)) { hashSize++; } buckets = (Entry **) allocate(hashSize * sizeof(Entry *)); for (i = 0; i < hashSize; i++) { buckets[i] = NULL; } numEntries = 0; } static void growTable(void) { int newHashSize; Entry **newBuckets; int i, n; Entry *p, *q; /* compute new hash size */ newHashSize = 2 * hashSize + 1; while (!isPrime(newHashSize)) { newHashSize += 2; } /* init new hash table */ newBuckets = (Entry **) allocate(newHashSize * sizeof(Entry *)); for (i = 0; i < newHashSize; i++) { newBuckets[i] = NULL; } /* rehash old entries */ for (i = 0; i < hashSize; i++) { p = buckets[i]; while (p != NULL) { q = p; p = p->next; n = q->hashValue % newHashSize; q->next = newBuckets[n]; newBuckets[n] = q; } } /* swap tables */ release(buckets); buckets = newBuckets; hashSize = newHashSize; } Var *lookupVar(char *name) { unsigned hashValue; int n; Entry *p; /* check for no table at all */ if (hashSize == 0) { /* not found */ return NULL; } /* compute hash value and bucket number */ hashValue = hash(name); n = hashValue % hashSize; /* search in bucket list */ p = buckets[n]; while (p != NULL) { if (p->hashValue == hashValue) { if (strcmp(p->name, name) == 0) { /* found: return variable */ return p->var; } } p = p->next; } /* not found */ return NULL; } void enterVar(char *name, Var *var) { char nameBuffer[500]; unsigned hashValue; int n; Entry *p; /* concat module name and variable name */ strcpy(nameBuffer, name); strcat(nameBuffer, var->name); /* initialize hash table if necessary */ if (hashSize == 0) { initTable(); } /* grow hash table if necessary */ if (numEntries == hashSize) { growTable(); } /* compute hash value and bucket number */ hashValue = hash(nameBuffer); n = hashValue % hashSize; /* add new variable to bucket list */ p = (Entry *) allocate(sizeof(Entry)); p->name = (char *) allocate(strlen(nameBuffer) + 1); strcpy(p->name, nameBuffer); p->var = var; p->hashValue = hashValue; p->next = buckets[n]; buckets[n] = p; numEntries++; } /**************************************************************/ static FILE *vcdFile; static int vcdLine; Bool skipBlanks(void) { int c; do { c = fgetc(vcdFile); if (c == EOF) { break; } if (c == '\n') { vcdLine++; } } while (c == ' ' || c == '\t' || c == '\n'); if (c != EOF) { ungetc(c, vcdFile); } return c == EOF; } Keyword *getKeyword(void) { int c; char buf[MAX_LINE]; char *p; c = fgetc(vcdFile); if (c == EOF) { return NULL; } if (c != '$') { ungetc(c, vcdFile); return NULL; } c = fgetc(vcdFile); if (c == EOF) { return NULL; } p = buf; while (isalpha(c)) { *p++ = c; c = fgetc(vcdFile); } ungetc(c, vcdFile); *p = '\0'; return lookupKeyword(buf); } void skipPastEnd(void) { int c; Keyword *kwp; while (1) { do { c = fgetc(vcdFile); if (c == EOF) { error("unexpected end of VCD file"); } if (c == '\n') { vcdLine++; } } while (c != '$'); ungetc(c, vcdFile); kwp = getKeyword(); if (kwp != NULL && kwp->number == KW_END) { return; } } } int collectTillDollar(char *buffer) { char *p; int c; p = buffer; do { c = fgetc(vcdFile); if (c == EOF) { error("unexpected end of VCD file"); } if (c == '\n') { vcdLine++; } *p++ = c; } while (c != '$'); ungetc(c, vcdFile); p -= 2; while (*p == ' ' || *p == '\t' || *p == '\n') { p--; } *++p = '\0'; return p - buffer; } int getString(char *buffer) { char *p; int c; p = buffer; while (1) { c = fgetc(vcdFile); if (c == EOF) { error("unexpected end of VCD file"); } if (c == ' ' || c == '\t' || c == '\n') { break; } *p++ = c; } ungetc(c, vcdFile); *p = '\0'; return p - buffer; } Bool getIdent(char *buffer) { char *p; int c; c = fgetc(vcdFile); if (c == EOF) { return FALSE; } if (!isalpha(c) && c != '_') { ungetc(c, vcdFile); return FALSE; } p = buffer; while (isalnum(c) || c == '_' || c == '$') { *p++ = c; c = fgetc(vcdFile); } if (c != EOF) { ungetc(c, vcdFile); } *p = '\0'; return TRUE; } int getVarCode(void) { int varCode; int weight; int c; int i; varCode = 0; weight = 1; for (i = 0; i <= 4; i++) { c = fgetc(vcdFile); if (c < '!' || c > '~') { break; } if (i == 4) { error("line %d: too many base-94 digits", vcdLine); } varCode += weight * (c - '!'); weight *= 94; } if (i == 0) { error("line %d: variable code expected", vcdLine); } if (c != EOF) { ungetc(c, vcdFile); } return varCode; } int getInteger(void) { int val; int c; val = 0; skipBlanks(); c = fgetc(vcdFile); if (!isdigit(c)) { error("line %d: number expected", vcdLine); } while (1) { if (!isdigit(c)) { break; } val = val * 10 + (c - '0'); c = fgetc(vcdFile); } if (c != EOF) { ungetc(c, vcdFile); } return val; } void getIndexRange(int *msip, int *lsip) { int c; *msip = -1; *lsip = -1; skipBlanks(); c = fgetc(vcdFile); if (c == EOF) { return; } if (c != '[') { ungetc(c, vcdFile); return; } *msip = getInteger(); skipBlanks(); c = fgetc(vcdFile); if (c != ':' && c != ']') { error("line %d: ':' or ']' expected", vcdLine); } if (c == ':') { skipBlanks(); *lsip = getInteger(); skipBlanks(); c = fgetc(vcdFile); } if (c != ']') { error("line %d: ']' expected", vcdLine); } } int getTime(void) { int c; c = fgetc(vcdFile); if (c != '#') { ungetc(c, vcdFile); return -1; } return getInteger(); } Change *getChange(void) { int c; int varCode; Change *change; char buffer[MAX_LINE]; char *p; c = fgetc(vcdFile); if (c != '0' && c != '1' && c != 'x' && c != 'X' && c != 'z' && c != 'Z' && c != 'b' && c != 'B') { if (c == 'r' || c == 'R') { error("line %d: real numbers are not supported, sorry", vcdLine); } if (c != EOF) { ungetc(c, vcdFile); } return NULL; } if (c == 'b' || c == 'B') { /* vector */ p = buffer; do { c = fgetc(vcdFile); switch (c) { case '0': case '1': case 'x': case 'z': *p++ = c; break; case 'X': case 'Z': *p++ = tolower(c); break; default: break; } } while (c == '0' || c == '1' || c == 'x' || c == 'X' || c == 'z' || c == 'Z'); if (c != EOF) { ungetc(c, vcdFile); } *p = '\0'; skipBlanks(); varCode = getVarCode(); change = newChange(varCode, buffer, '\0'); } else { /* scalar */ if (c == 'X') { c = 'x'; } else if (c == 'Z') { c = 'z'; } varCode = getVarCode(); change = newChange(varCode, NULL, c); } return change; } VCD *parseVCD(FILE *input) { VCD *vcd; int section; Keyword *kwp; char buffer[MAX_LINE]; int length; char *endptr; Scope *currentScope; Scope *scope; int scopeType; char currentPrefix[MAX_NAME]; VarType *vtp; int varType; int varSize; int varCode; int msi; int lsi; Var *var; Step *currentStep; Step *step; int time; Change *currentChange; Change *change; /* allocate a VCD structure */ vcd = allocate(sizeof(VCD)); vcd->date = NULL; vcd->version = NULL; vcd->timescaleMult = -1; vcd->timescaleUnit = -1; vcd->root = NULL; vcd->steps = NULL; /* start parsing */ vcdFile = input; vcdLine = 1; section = 1; /* read header and node information */ currentScope = NULL; currentPrefix[0] = '\0'; while (section == 1) { skipBlanks(); kwp = getKeyword(); if (kwp == NULL) { error("line %d: keyword expected", vcdLine); } switch (kwp->number) { case KW_COMMENT: /* ignore comment */ skipPastEnd(); break; case KW_DATE: /* record date as string */ skipBlanks(); length = collectTillDollar(buffer); vcd->date = allocate(length + 1); strcpy(vcd->date, buffer); skipPastEnd(); break; case KW_VERSION: /* record version as string */ skipBlanks(); length = collectTillDollar(buffer); vcd->version = allocate(length + 1); strcpy(vcd->version, buffer); skipPastEnd(); break; case KW_TIMESCALE: /* record timescale as multiplier and unit */ skipBlanks(); length = collectTillDollar(buffer); /* get multiplier */ vcd->timescaleMult = strtol(buffer, &endptr, 10); if (vcd->timescaleMult != 1 && vcd->timescaleMult != 10 && vcd->timescaleMult != 100) { error("line %d: illegal timescale multiplier (%d)", vcdLine, vcd->timescaleMult); } /* multiplier and unit may be separated by whitespace */ while (*endptr == ' ' || *endptr == '\t') { endptr++; } /* get unit */ if (endptr[0] == 's' && endptr[1] == '\0') { vcd->timescaleUnit = VCD_TS_S; } else if (endptr[0] == 'm' && endptr[1] == 's' && endptr[2] == '\0') { vcd->timescaleUnit = VCD_TS_MS; } else if (endptr[0] == 'u' && endptr[1] == 's' && endptr[2] == '\0') { vcd->timescaleUnit = VCD_TS_US; } else if (endptr[0] == 'n' && endptr[1] == 's' && endptr[2] == '\0') { vcd->timescaleUnit = VCD_TS_NS; } else if (endptr[0] == 'p' && endptr[1] == 's' && endptr[2] == '\0') { vcd->timescaleUnit = VCD_TS_PS; } else if (endptr[0] == 'f' && endptr[1] == 's' && endptr[2] == '\0') { vcd->timescaleUnit = VCD_TS_FS; } else { error("line %d: illegal timescale unit (%s)", vcdLine, endptr); } skipPastEnd(); break; case KW_SCOPE: /* open a new scope */ skipBlanks(); /* get type */ getString(buffer); if (strcmp(buffer, "module") == 0) { scopeType = SCOPE_MODULE; } else if (strcmp(buffer, "task") == 0) { scopeType = SCOPE_TASK; } else if (strcmp(buffer, "function") == 0) { scopeType = SCOPE_FUNCTION; } else if (strcmp(buffer, "begin") == 0) { scopeType = SCOPE_BEGIN; } else if (strcmp(buffer, "fork") == 0) { scopeType = SCOPE_FORK; } else { error("line %d: unknown scope type '%s'", vcdLine, buffer); } skipBlanks(); /* get name */ if (!getIdent(buffer)) { error("line %d: identifier expected", vcdLine); } /* allocate and link a new scope */ scope = newScope(scopeType, buffer, currentScope); if (currentScope == NULL) { /* new scope is a top-level scope */ if (vcd->root == NULL) { /* first top-level scope */ vcd->root = scope; } else { /* another top-level scope */ /* append, use currentScope as auxiliary variable */ currentScope = vcd->root; while (currentScope->siblings != NULL) { currentScope = currentScope->siblings; } currentScope->siblings = scope; } } else { /* new scope is not a top-level scope */ if (currentScope->children == NULL) { currentScope->children = scope; } else { currentScope->lastchild->siblings = scope; } currentScope->lastchild = scope; } currentScope = scope; /* augment current prefix */ strcat(currentPrefix, currentScope->name); strcat(currentPrefix, "."); skipPastEnd(); break; case KW_UPSCOPE: /* close the current scope */ if (currentScope == NULL) { error("line %d: no $scope for this $upscope", vcdLine); } currentScope = currentScope->parent; /* prune current prefix */ length = strlen(currentPrefix) - 2; while (length >= 0 && currentPrefix[length] != '.') { length--; } length++; currentPrefix[length] = '\0'; skipPastEnd(); break; case KW_VAR: /* record a new variable */ skipBlanks(); /* get type */ getString(buffer); vtp = lookupVarType(buffer); if (vtp == NULL) { error("line %d: unknown variable type '%s'", vcdLine, buffer); } varType = vtp->number; skipBlanks(); /* get size */ getString(buffer); varSize = strtol(buffer, &endptr, 10); if (*endptr != '\0' || varSize <= 0) { error("line %d: cannot read variable size", vcdLine); } skipBlanks(); /* get code */ varCode = getVarCode(); skipBlanks(); /* get name */ if (!getIdent(buffer)) { error("line %d: identifier expected", vcdLine); } skipBlanks(); /* get optional index range */ getIndexRange(&msi, &lsi); /* allocate and link a new variable */ var = newVar(varType, varSize, varCode, buffer, msi, lsi); if (currentScope->variables == NULL) { currentScope->variables = var; } else { currentScope->lastvar->next = var; } currentScope->lastvar = var; /* additionally, enter variable in var table */ enterVar(currentPrefix, var); skipPastEnd(); break; case KW_ENDDEFS: /* end the first section of the VCD file */ section = 2; skipPastEnd(); break; default: error("line %d: unexpected keyword '$%s'", vcdLine, kwp->name); break; } } /* read value changes */ currentStep = NULL; currentChange = NULL; while (1) { if (skipBlanks()) { break; } kwp = getKeyword(); if (kwp != NULL) { switch (kwp->number) { case KW_COMMENT: /* ignore comment */ skipPastEnd(); break; case KW_DUMPVARS: case KW_DUMPALL: case KW_DUMPOFF: case KW_DUMPON: /* record value changes */ while (1) { skipBlanks(); change = getChange(); if (change == NULL) { break; } if (currentChange == NULL) { if (currentStep == NULL) { error("line %d: value change without simulation time", vcdLine); } currentStep->changes = change; } else { currentChange->next = change; } currentChange = change; } skipPastEnd(); break; default: error("line %d: unexpected keyword '%s'", vcdLine, kwp->name); break; } continue; } time = getTime(); if (time >= 0) { if (currentStep != NULL && currentStep->time >= time) { error("line %d: time step has illegal simulation time", vcdLine); } step = newStep(time, currentStep); if (currentStep == NULL) { vcd->steps = step; } else { currentStep->next = step; } currentStep = step; currentChange = NULL; continue; } change = getChange(); if (change != NULL) { if (currentChange == NULL) { if (currentStep == NULL) { error("line %d: value change without simulation time", vcdLine); } currentStep->changes = change; } else { currentChange->next = change; } currentChange = change; continue; } error("line %d: keyword, time, or value change expected", vcdLine); } /* done */ return vcd; } char *varType[] = { "event", "integer", "parameter", "real", "reg", "supply0", "supply1", "time", "tri", "tri0", "tri1", "triand", "trior", "trireg", "wand", "wire", "wor", }; char *scopeType[] = { "module", "task", "function", "begin", "fork", }; void showVarPrefix(Scope *scope) { if (scope == NULL) { return; } showVarPrefix(scope->parent); printf("%s.", scope->name); } void showScope(Scope *scope) { Var *var; printf(" scope #%d\n", scope->number); printf(" type : %s\n", scopeType[scope->type]); printf(" name : %s\n", scope->name); printf(" parent : "); if (scope->parent == NULL) { printf("-- none --"); } else { printf("scope #%d", scope->parent->number); } printf("\n"); printf(" siblings : "); if (scope->siblings == NULL) { printf("-- none --"); } else { printf("scope #%d", scope->siblings->number); } printf("\n"); printf(" children : "); if (scope->children == NULL) { printf("-- none --"); } else { printf("scope #%d", scope->children->number); } printf("\n"); printf(" lastchild : "); if (scope->lastchild == NULL) { printf("-- none --"); } else { printf("scope #%d", scope->lastchild->number); } printf("\n"); printf(" var prefix : "); showVarPrefix(scope); printf("\n"); printf(" variables : "); if (scope->variables == NULL) { printf("-- none --\n"); } else { printf("\n"); var = scope->variables; while (var != NULL) { printf(" "); printf("%s", var->name); if (var->msi != -1) { printf(" [%d", var->msi); if (var->lsi != -1) { printf(":%d", var->lsi); } printf("]"); } printf("\n"); printf(" "); printf("type = %-9s ", varType[var->type]); printf("size = %4d ", var->size); printf("code = %6d\n", var->code); var = var->next; } } if (scope->siblings != NULL) { showScope(scope->siblings); } if (scope->children != NULL) { showScope(scope->children); } } void showSteps(Step *steps) { Change *changes; while (steps != NULL) { printf(" #%d\n", steps->time); changes = steps->changes; while (changes != NULL) { printf(" code %8d : value ", changes->code); if (changes->vectorValue != NULL) { printf("'%s'", changes->vectorValue); } else { printf("'%c'", changes->scalarValue); } printf("\n"); changes = changes->next; } steps = steps->next; } } char *tsUnit[6] = { "s", "ms", "us", "ns", "ps", "fs" }; void showVCD(VCD *vcd) { printf("Value Change Dump Data\n"); printf("date : "); if (vcd->date == NULL) { printf("-- none --"); } else { printf("%s", vcd->date); } printf("\n"); printf("version : "); if (vcd->version == NULL) { printf("-- none --"); } else { printf("%s", vcd->version); } printf("\n"); printf("timescale : "); if (vcd->timescaleMult < 0 || vcd->timescaleUnit < 0) { printf("-- none --"); } else { printf("%d %s", vcd->timescaleMult, tsUnit[vcd->timescaleUnit]); } printf("\n"); printf("root scope : "); if (vcd->root == NULL) { printf("-- none --"); printf("\n"); } else { printf("%d", vcd->root->number); printf("\n"); showScope(vcd->root); } printf("value changes : "); if (vcd->steps == NULL) { printf("-- none --"); printf("\n"); } else { printf("\n"); showSteps(vcd->steps); } } /**************************************************************/ typedef struct chk { int timeMult; /* this many timeUnits */ int timeUnit; /* one of VCD_TS_xxx */ char *name; /* name of variable to check */ int width; /* width of variable to check */ char *value; /* value to check variable against */ struct chk *next; /* list elements are connected by 'and' */ } CHK; void shift(char *buffer, int width, int amount, char *val) { int j, i; for (j = 0; j < amount; j++) { for (i = 0; i < width - 1; i++) { buffer[i] = buffer[i + 1]; } buffer[i] = val[j]; } } char *bitval1[2] = { "0", "1" }; char *bitval4[16] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; int skipSpace(int c, FILE *chkFile) { while (1) { while (c == ' ' || c == '\t' || c == '\n') { c = fgetc(chkFile); } if (c != '/') { return c; } c = fgetc(chkFile); if (c == EOF) { error("chk spec: unexpected end of input"); } if (c != '/') { ungetc(c, chkFile); return '/'; } do { c = fgetc(chkFile); if (c == EOF) { return EOF; } } while (c != '\n'); } } CHK *parseSingleChk(FILE *chkFile) { CHK *chk; int c, d; char name[MAX_LINE]; char *p; int base; int i; chk = allocate(sizeof(CHK)); c = fgetc(chkFile); c = skipSpace(c, chkFile); chk->timeMult = 0; if (!isdigit(c)) { error("chk spec: time multiplier does not start with a digit"); } while (isdigit(c)) { chk->timeMult = chk->timeMult * 10 + (c - '0'); c = fgetc(chkFile); } c = skipSpace(c, chkFile); if (c == 's') { chk->timeUnit = VCD_TS_S; } else { d = fgetc(chkFile); if (c == 'm' && d == 's') { chk->timeUnit = VCD_TS_MS; } else if (c == 'u' && d == 's') { chk->timeUnit = VCD_TS_US; } else if (c == 'n' && d == 's') { chk->timeUnit = VCD_TS_NS; } else if (c == 'p' && d == 's') { chk->timeUnit = VCD_TS_PS; } else if (c == 'f' && d == 's') { chk->timeUnit = VCD_TS_FS; } else { error("chk spec: illegal time unit"); } } c = fgetc(chkFile); c = skipSpace(c, chkFile); p = name; if (!isalpha(c) && c != '_') { error("chk spec: name does not start with a letter"); } while (isalnum(c) || c == '_' || c == '$' || c == '.') { *p++ = c; c = fgetc(chkFile); } *p = '\0'; chk->name = allocate(p - name + 1); strcpy(chk->name, name); c = skipSpace(c, chkFile); chk->width = 0; if (!isdigit(c)) { error("chk spec: bit width does not start with a digit"); } while (isdigit(c)) { chk->width = chk->width * 10 + (c - '0'); c = fgetc(chkFile); } if (chk->width <= 0) { error("chk spec: illegal bit width"); } chk->value = allocate(chk->width + 1); if (c != '\'') { error("chk spec: apostrophe missing after bit width"); } c = fgetc(chkFile); if (c == 'b') { base = 2; } else if (c == 'h') { base = 16; } else { error("chk spec: illegal number base"); } c = fgetc(chkFile); if (c == 'x' || c == 'X') { for (i = 0; i < chk->width; i++) { chk->value[i] = 'x'; } } else if (c == 'z' || c == 'Z') { for (i = 0; i < chk->width; i++) { chk->value[i] = 'z'; } } else { for (i = 0; i < chk->width; i++) { chk->value[i] = '0'; } } chk->value[chk->width] = '\0'; if (base == 2) { if (c != 'x' && c != 'X' && c != 'z' && c != 'Z' && c != '0' && c != '1') { error("chk spec: base-2 number does not start with binary digit"); } while (1) { if (c == 'x' || c == 'X') { shift(chk->value, chk->width, 1, "x"); } else if (c == 'z' || c == 'Z') { shift(chk->value, chk->width, 1, "z"); } else if (c == '0' || c == '1') { shift(chk->value, chk->width, 1, bitval1[c - '0']); } else { break; } c = fgetc(chkFile); } } else if (base == 16) { if (c != 'x' && c != 'X' && c != 'z' && c != 'Z' && !isxdigit(c)) { error("chk spec: base-16 number does not start with hex digit"); } while (1) { if (c == 'x' || c == 'X') { shift(chk->value, chk->width, 4, "xxxx"); } else if (c == 'z' || c == 'Z') { shift(chk->value, chk->width, 4, "zzzz"); } else if (c >= '0' && c <= '9') { shift(chk->value, chk->width, 4, bitval4[c - '0']); } else if (c >= 'A' && c <= 'F') { shift(chk->value, chk->width, 4, bitval4[c - 'A' + 10]); } else if (c >= 'a' && c <= 'f') { shift(chk->value, chk->width, 4, bitval4[c - 'a' + 10]); } else { break; } c = fgetc(chkFile); } } c = skipSpace(c, chkFile); if (c != EOF) { ungetc(c, chkFile); } chk->next = NULL; return chk; } CHK *parseCHK(FILE *chkFile) { CHK *chk; CHK *cur; int c; chk = parseSingleChk(chkFile); cur = chk; c = fgetc(chkFile); while (c != EOF) { ungetc(c, chkFile); cur->next = parseSingleChk(chkFile); cur = cur->next; c = fgetc(chkFile); } return chk; } void showSingleCHK(CHK *chk) { printf("time mult = %d\n", chk->timeMult); printf("time unit = %s\n", tsUnit[chk->timeUnit]); printf("var name = %s\n", chk->name); printf("var width = %d\n", chk->width); printf("var value = %s\n", chk->value); } void showCHK(CHK *chk) { do { showSingleCHK(chk); chk = chk->next; if (chk != NULL) { printf("&&\n"); } } while (chk != NULL); } /**************************************************************/ #define bitEqual(v, c) ((v) == (c) || (c) == 'x') Bool compare(Change *change, char *check, int width) { char *value; int i, n; if (change->vectorValue != NULL) { /* compare two vectors */ value = allocate(width + 1); n = strlen(change->vectorValue); if (change->vectorValue[0] == 'x') { for (i = 0; i < width - n; i++) { value[i] = 'x'; } } else if (change->vectorValue[0] == 'z') { for (i = 0; i < width - n; i++) { value[i] = 'z'; } } else { for (i = 0; i < width - n; i++) { value[i] = '0'; } } for (i = 0; i < n; i++) { value[width - n + i] = change->vectorValue[i]; } value[width] = '\0'; if (debugCheck) { printf("v = '%s'\nc = '%s'\n", value, check); } for (i = 0; i < width; i++) { if (!bitEqual(value[i], check[i])) { return FALSE; } } return TRUE; } else { /* compare two scalars */ if (debugCheck) { printf("v = '%c'\nc = '%c'\n", change->scalarValue, check[0]); } return bitEqual(change->scalarValue, check[0]); } } Bool check(VCD *vcd, CHK *chk) { Var *var; int time; Step *step; Step *next; Change *change; /* locate variable */ var = lookupVar(chk->name); if (var == NULL) { error("check: variable '%s' not found", chk->name); } /* check sizes */ if (var->size != chk->width) { error("check: variable size in vcd and chk different"); } /* check time units */ if (vcd->timescaleUnit != chk->timeUnit) { error("check: time units in vcd and chk different"); } /* locate time step just before specified time */ time = chk->timeMult; step = vcd->steps; if (step == NULL) { error("check: no simulation time steps at all"); } if (time < step->time) { error("check: check time < first simulation time step"); } next = step->next; while (next != NULL && time >= next->time) { step = next; next = step->next; } /* find oldest time step in which the variable changed */ while (step != NULL) { change = step->changes; while (change != NULL) { if (change->code == var->code) { /* value change found */ return compare(change, chk->value, chk->width); } change = change->next; } step = step->prev; } error("check: variable '%s' was never dumped", chk->name); return FALSE; } /**************************************************************/ void usage(char *myself) { printf("Usage: %s <VCD file> <CHK file>\n", myself); exit(1); } int main(int argc, char *argv[]) { char *vcdName; FILE *vcdFile; VCD *vcd; char *chkName; FILE *chkFile; CHK *chk; if (argc != 3) { usage(argv[0]); } vcdName = argv[1]; vcdFile = fopen(vcdName, "r"); if (vcdFile == NULL) { error("cannot open VCD file '%s'", vcdName); } vcd = parseVCD(vcdFile); fclose(vcdFile); if (debugVCD) { showVCD(vcd); } chkName = argv[2]; chkFile = fopen(chkName, "r"); if (chkFile == NULL) { error("cannot open CHK file '%s'", chkName); } chk = parseCHK(chkFile); if (debugCHK) { showCHK(chk); } fclose(chkFile); while (chk != NULL) { if (!check(vcd, chk)) { printf("failure, check:\n"); showSingleCHK(chk); return 1; } chk = chk->next; } printf("success\n"); return 0; }
Go to most recent revision | Compare with Previous | Blame | View Log