OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 283 to Rev 284
    Reverse comparison

Rev 283 → Rev 284

/eco32/trunk/tools/vcdchk/vcdchk.c
0,0 → 1,1710
/*
* 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;
}
/eco32/trunk/tools/vcdchk/ref.vcd
0,0 → 1,55
$date
June 26, 1998 10:05:41
$end
$version
VERILOG-XL 2.7
$end
 
$timescale
1 ns
$end
 
$scope module top $end
$scope module m1 $end
$var trireg 1 *@ net1 $end
$var trireg 1 *# net2 $end
$var trireg 1 *$ net3 $end
$upscope $end
$scope task t1 $end
$var reg 32 (k accumulator[31:0] $end
$var integer 32 {2 index $end
$upscope $end
$upscope $end
$enddefinitions $end
$comment
Note: $dumpvars was executed at time ’#500’.
All initial values are dumped at this time.
$end
 
#500
$dumpvars x*@ x*# x*$ bx (k bx {2 $end
 
#505
0*@
1*#
1*$
b10zx1110x11100 (k b1111000101z01x {2
#510
0*$
 
#520
1*$
#530
0*$
bz (k
#535
$dumpall 0*@ 1*# 0*$
bz (k b1111000101z01x {2 $end
#540
1*$
#1000
$dumpoff x*@ x*# x*$ bx (k bx {2 $end
#2000
$dumpon z*@ 1*# 0*$ b0 (k bx {2 $end
#2010
1*$
/eco32/trunk/tools/vcdchk/ref-fail.chk
0,0 → 1,3
519 ns
top.t1.accumulator
32'b10zx1010x11xx0
/eco32/trunk/tools/vcdchk/ref-succ.chk
0,0 → 1,3
519 ns
top.t1.accumulator
32'b10zx1110x11xx0
/eco32/trunk/tools/vcdchk/Makefile
0,0 → 1,17
#
# Makefile for VCD check utility
#
 
BUILD = ../../build
 
all: vcdchk
 
install: vcdchk
mkdir -p $(BUILD)/bin
cp vcdchk $(BUILD)/bin
 
vcdchk: vcdchk.c
gcc -m32 -g -Wall -o vcdchk vcdchk.c
 
clean:
rm -f *~ vcdchk
/eco32/trunk/tools/Makefile
4,7 → 4,7
 
BUILD = ../build
 
DIRS = bin2dat bin2exo bin2mcs bit2exo bit2mcs chrgen dspmem
DIRS = bin2dat bin2exo bin2mcs bit2exo bit2mcs chrgen dspmem vcdchk
 
.PHONY: all install clean
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.