Add basic support for events and cleanup VCD dumper.

This patch adds support for dumping named events to the VCD
dumper only. The LXT and LXT2 will be added once this has
been tested more. It also reworks the $dumpvars routine
to be more consistent concerning warning messages for duplicate
signal dump requests and fixes some bugs.

For events you will get extra events at T0 and at $dumpon. I
plan to fix this, but that is much more involved.

For duplicate signal warnings. Implicit duplicates loaded
automatically from a scope will not display a warning. Only
an explicit signal request will print a warning if it was
already included. All other will be silently ignored. This
should limit the warning to only what the user cares about.

For example:

  $dumpvars(0, var, scope_that_includes_var);

Will work without a warning message.

  $dumpvars(0, scope_that_includes_var, var);

Will generate a warning since the var was already included
by the scope request.

Other enhancements include the start of including type
information in the output. For now integer is added, the
other type information will require changes to the code
generator and hence will only be done in development.
This commit is contained in:
Cary R 2009-06-25 10:48:05 -07:00 committed by Stephen Williams
parent 236f56949f
commit 7e3a7b87ff
3 changed files with 155 additions and 107 deletions

View File

@ -103,12 +103,14 @@ static char *truncate_bitvec(char *s)
static void show_this_item(struct vcd_info*info) static void show_this_item(struct vcd_info*info)
{ {
s_vpi_value value; s_vpi_value value;
PLI_INT32 type = vpi_get(vpiType, info->item);
if (vpi_get(vpiType, info->item) == vpiRealVar) { if (type == vpiRealVar) {
value.format = vpiRealVal; value.format = vpiRealVal;
vpi_get_value(info->item, &value); vpi_get_value(info->item, &value);
fprintf(dump_file, "r%.16g %s\n", value.value.real, info->ident); fprintf(dump_file, "r%.16g %s\n", value.value.real, info->ident);
} else if (type == vpiNamedEvent) {
fprintf(dump_file, "1%s\n", info->ident);
} else if (vpi_get(vpiSize, info->item) == 1) { } else if (vpi_get(vpiSize, info->item) == 1) {
value.format = vpiBinStrVal; value.format = vpiBinStrVal;
vpi_get_value(info->item, &value); vpi_get_value(info->item, &value);
@ -121,12 +123,16 @@ static void show_this_item(struct vcd_info*info)
} }
} }
/* Dump values for a $dumpoff. */
static void show_this_item_x(struct vcd_info*info) static void show_this_item_x(struct vcd_info*info)
{ {
if (vpi_get(vpiType, info->item) == vpiRealVar) { PLI_INT32 type = vpi_get(vpiType, info->item);
if (type == vpiRealVar) {
/* Some tools dump nothing here...? */ /* Some tools dump nothing here...? */
fprintf(dump_file, "rNaN %s\n", info->ident); fprintf(dump_file, "rNaN %s\n", info->ident);
} else if (type == vpiNamedEvent) {
/* Do nothing for named events. */
} else if (vpi_get(vpiSize, info->item) == 1) { } else if (vpi_get(vpiSize, info->item) == 1) {
fprintf(dump_file, "x%s\n", info->ident); fprintf(dump_file, "x%s\n", info->ident);
} else { } else {
@ -489,22 +495,27 @@ static PLI_INT32 sys_dumplimit_calltf(PLI_BYTE8 *name)
return 0; return 0;
} }
static void scan_item(unsigned depth, vpiHandle item, int skip) static void scan_item(unsigned depth, vpiHandle item, int skip, int expl)
{ {
struct t_cb_data cb; struct t_cb_data cb;
struct vcd_info* info; struct vcd_info* info;
const char* type; const char* type;
const char* name; const char* name;
const char* fullname;
const char* prefix; const char* prefix;
const char* ident; const char* ident;
int nexus_id; int nexus_id;
unsigned size;
PLI_INT32 item_type;
/* list of types to iterate upon */ /* list of types to iterate upon */
int i; int i;
static int types[] = { static int types[] = {
/* Value */ /* Value */
vpiNamedEvent,
vpiNet, vpiNet,
// vpiParameter,
vpiReg, vpiReg,
vpiVariables, vpiVariables,
/* Scope */ /* Scope */
@ -516,50 +527,113 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
-1 -1
}; };
switch (vpi_get(vpiType, item)) { /* Get the displayed type for the various $var and $scope types. */
/* Not all of these are supported now, but they should be in a
case vpiNet: type = "wire"; if(0){ * future development version. */
item_type = vpi_get(vpiType, item);
switch (item_type) {
case vpiNamedEvent: type = "event"; break;
case vpiIntegerVar: type = "integer"; break;
case vpiParameter: type = "parameter"; break;
/* Icarus converts realtime to real. */
case vpiRealVar: type = "real"; break;
case vpiMemoryWord: case vpiMemoryWord:
case vpiReg: type = "reg"; break;
/* Icarus converts a time to a plain register. */
case vpiTimeVar: type = "time"; break;
case vpiNet:
switch (vpi_get(vpiNetType, item)) {
case vpiWand: type = "wand"; break;
case vpiWor: type = "wor"; break;
case vpiTri: type = "tri"; break;
case vpiTri0: type = "tri0"; break;
case vpiTri1: type = "tri1"; break;
case vpiTriReg: type = "trireg"; break;
case vpiTriAnd: type = "triand"; break;
case vpiTriOr: type = "trior"; break;
case vpiSupply1: type = "supply1"; break;
case vpiSupply0: type = "supply0"; break;
default: type = "wire"; break;
}
break;
case vpiNamedBegin: type = "begin"; break;
case vpiNamedFork: type = "fork"; break;
case vpiFunction: type = "function"; break;
case vpiModule: type = "module"; break;
case vpiTask: type = "task"; break;
default:
vpi_printf("VCD warning: $dumpvars: Unsupported argument "
"type (%s)\n", vpi_get_str(vpiType, item));
return;
}
/* Do some special processing/checking on array words. Dumping
* array words is an Icarus extension. */
if (item_type == vpiMemoryWord) {
/* Turn a non-constant array word select into a constant
* word select. */
if (vpi_get(vpiConstantSelect, item) == 0) { if (vpi_get(vpiConstantSelect, item) == 0) {
/* Turn a non-constant array word select into a
* constant word select. */
vpiHandle array = vpi_handle(vpiParent, item); vpiHandle array = vpi_handle(vpiParent, item);
PLI_INT32 index = vpi_get(vpiIndex, item); PLI_INT32 index = vpi_get(vpiIndex, item);
item = vpi_handle_by_index(array, index); item = vpi_handle_by_index(array, index);
} }
case vpiIntegerVar:
case vpiTimeVar:
case vpiReg: type = "reg"; }
/* Skip this signal if it has already been included. */
if (vcd_names_search(&vcd_var, vpi_get_str(vpiFullName, item))) {
vpi_printf("VCD warning: skipping signal %s, it was "
"previously included.\n",
vpi_get_str(vpiFullName, item));
break;
}
/* An array word is implicitly escaped so look for an /* An array word is implicitly escaped so look for an
* escaped identifier that this could conflict with. */ * escaped identifier that this could conflict with. */
/* This does not work as expected since we always find at
* least the array word. We likely need a custom routine. */
if (vpi_get(vpiType, item) == vpiMemoryWord && if (vpi_get(vpiType, item) == vpiMemoryWord &&
vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) { vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) {
vpi_printf("VCD warning: dumping array word %s will " vpi_printf("VCD warning: array word %s will conflict "
"conflict with an escaped identifier.\n", "with an escaped identifier.\n",
vpi_get_str(vpiFullName, item)); vpi_get_str(vpiFullName, item));
} }
}
if (skip || vpi_get(vpiAutomatic, item)) break; fullname = vpi_get_str(vpiFullName, item);
/* Generate the $var or $scope commands. */
switch (item_type) {
case vpiParameter:
vpi_printf("VCD sorry: $dumpvars: can not dump parameters.\n");
break;
case vpiNamedEvent:
case vpiIntegerVar:
// case vpiParameter:
case vpiRealVar:
case vpiMemoryWord:
case vpiReg:
case vpiTimeVar:
case vpiNet:
/* If we are skipping all signal or this is in an automatic
* scope then just return. */
if (skip || vpi_get(vpiAutomatic, item)) return;
/* Skip this signal if it has already been included. */
if (vcd_names_search(&vcd_var, fullname)) {
/* Only warn when the variable is given explicitly. */
if (expl)
vpi_printf("VCD warning: skipping signal %s, it was "
"previously included.\n", fullname);
return;
}
/* Add implicit signals here. */
if (!expl) vcd_names_add(&vcd_var, fullname);
/* Declare the variable in the VCD file. */
name = vpi_get_str(vpiName, item); name = vpi_get_str(vpiName, item);
prefix = is_escaped_id(name) ? "\\" : ""; prefix = is_escaped_id(name) ? "\\" : "";
/* Some signals can have an alias so handle that. */
nexus_id = vpi_get(_vpiNexusId, item); nexus_id = vpi_get(_vpiNexusId, item);
if (nexus_id) { ident = 0;
ident = find_nexus_ident(nexus_id); if (nexus_id) ident = find_nexus_ident(nexus_id);
} else {
ident = 0;
}
if (!ident) { if (!ident) {
ident = strdup(vcdid); ident = strdup(vcdid);
@ -567,6 +641,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
if (nexus_id) set_nexus_ident(nexus_id, ident); if (nexus_id) set_nexus_ident(nexus_id, ident);
/* Add a callback for the signal. */
info = malloc(sizeof(*info)); info = malloc(sizeof(*info));
info->time.type = vpiSimTime; info->time.type = vpiSimTime;
@ -588,107 +663,57 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
info->cb = vpi_register_cb(&cb); info->cb = vpi_register_cb(&cb);
} }
/* Named events do not have a size, but other tools use
* a size of 1 and some viewers do not accept a width of
* zero so we will also use a width of one for events. */
if (item_type == vpiNamedEvent) size = 1;
else size = vpi_get(vpiSize, item);
fprintf(dump_file, "$var %s %u %s %s%s", fprintf(dump_file, "$var %s %u %s %s%s",
type, vpi_get(vpiSize, item), ident, type, size, ident, prefix, name);
prefix, name);
/* FIXME /* Add a range for vectored values. */
if (vpi_get(vpiVector, item)
*/
if (vpi_get(vpiSize, item) > 1 if (vpi_get(vpiSize, item) > 1
|| vpi_get(vpiLeftRange, item) != 0) { || vpi_get(vpiLeftRange, item) != 0) {
fprintf(dump_file, " [%i:%i]", vpi_get(vpiLeftRange, item), fprintf(dump_file, " [%i:%i]", vpi_get(vpiLeftRange, item),
vpi_get(vpiRightRange, item)); vpi_get(vpiRightRange, item));
} }
fprintf(dump_file, " $end\n"); fprintf(dump_file, " $end\n");
break; break;
case vpiRealVar: case vpiModule:
case vpiNamedBegin:
/* Skip this signal if it has already been included. */ case vpiTask:
if (vcd_names_search(&vcd_var, vpi_get_str(vpiFullName, item))) { case vpiFunction:
vpi_printf("VCD warning: skipping signal %s, it was " case vpiNamedFork:
"previously included.\n",
vpi_get_str(vpiFullName, item));
break;
}
if (skip || vpi_get(vpiAutomatic, item)) break;
/* Declare the variable in the VCD file. */
name = vpi_get_str(vpiName, item);
prefix = is_escaped_id(name) ? "\\" : "";
ident = strdup(vcdid);
gen_new_vcd_id();
fprintf(dump_file, "$var real 1 %s %s%s $end\n",
ident, prefix, name);
/* Add a callback for the variable. */
info = malloc(sizeof(*info));
info->time.type = vpiSimTime;
info->item = item;
info->ident = ident;
info->scheduled = 0;
cb.time = &info->time;
cb.user_data = (char*)info;
cb.value = NULL;
cb.obj = item;
cb.reason = cbValueChange;
cb.cb_rtn = variable_cb_1;
info->next = vcd_list;
info->dmp_next = 0;
vcd_list = info;
info->cb = vpi_register_cb(&cb);
break;
case vpiModule: type = "module"; if(0){
case vpiNamedBegin: type = "begin"; }if(0){
case vpiTask: type = "task"; }if(0){
case vpiFunction: type = "function"; }if(0){
case vpiNamedFork: type = "fork"; }
if (depth > 0) { if (depth > 0) {
int nskip; int nskip = (vcd_names_search(&vcd_tab, fullname) != 0);
vpiHandle argv;
const char* fullname = /* We have to always scan the scope because the
vpi_get_str(vpiFullName, item); * depth could be different for this call. */
if (nskip) {
#if 0 vpi_printf("VCD warning: ignoring signals in "
vpi_printf("VCD info: scanning scope %s, %u levels\n", "previously scanned scope %s.\n", fullname);
fullname, depth); } else vcd_names_add(&vcd_tab, fullname);
#endif
nskip = 0 != vcd_names_search(&vcd_tab, fullname);
if (!nskip)
vcd_names_add(&vcd_tab, fullname);
else
vpi_printf("VCD warning: ignoring signals in "
"previously scanned scope %s\n", fullname);
name = vpi_get_str(vpiName, item); name = vpi_get_str(vpiName, item);
fprintf(dump_file, "$scope %s %s $end\n", type, name); fprintf(dump_file, "$scope %s %s $end\n", type, name);
for (i=0; types[i]>0; i++) { for (i=0; types[i]>0; i++) {
vpiHandle hand; vpiHandle hand;
argv = vpi_iterate(types[i], item); vpiHandle argv = vpi_iterate(types[i], item);
while (argv && (hand = vpi_scan(argv))) { while (argv && (hand = vpi_scan(argv))) {
scan_item(depth-1, hand, nskip); scan_item(depth-1, hand, nskip, 0);
} }
} }
/* Sort any signals that we added above. */
if (!nskip) vcd_names_sort(&vcd_var);
fprintf(dump_file, "$upscope $end\n"); fprintf(dump_file, "$upscope $end\n");
} }
break; break;
default:
vpi_printf("VCD warning: $dumpvars: Unsupported parameter "
"type (%s)\n", vpi_get_str(vpiType, item));
} }
} }
@ -770,12 +795,14 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
switch (vpi_get(vpiType, item)) { switch (vpi_get(vpiType, item)) {
case vpiIntegerVar: case vpiIntegerVar:
case vpiMemoryWord: case vpiMemoryWord:
case vpiNamedEvent:
case vpiNet: case vpiNet:
case vpiParameter:
case vpiRealVar: case vpiRealVar:
case vpiReg: case vpiReg:
case vpiTimeVar: case vpiTimeVar:
scname = vpi_get_str(vpiFullName, vpi_handle(vpiScope, item)); scname = vpi_get_str(vpiFullName, vpi_handle(vpiScope, item));
if (vcd_names_search(&vcd_tab, scname)) { if (vcd_names_search(&vcd_var, scname)) {
vpi_printf("VCD warning: skipping signal %s, " vpi_printf("VCD warning: skipping signal %s, "
"it was previously included.\n", "it was previously included.\n",
vpi_get_str(vpiFullName, item)); vpi_get_str(vpiFullName, item));
@ -787,7 +814,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
dep = draw_scope(item, callh); dep = draw_scope(item, callh);
scan_item(depth, item, 0); scan_item(depth, item, 0, 1);
while (dep--) fprintf(dump_file, "$upscope $end\n"); while (dep--) fprintf(dump_file, "$upscope $end\n");

View File

@ -271,12 +271,23 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
case vpiNamedBegin: case vpiNamedBegin:
case vpiNamedFork: case vpiNamedFork:
/* The variable types. */ /* The variable types. */
#if 0
case vpiParameter: /* A constant! */
#endif
case vpiNet: case vpiNet:
case vpiReg: case vpiReg:
case vpiIntegerVar: case vpiIntegerVar:
case vpiTimeVar: case vpiTimeVar:
case vpiRealVar: case vpiRealVar:
case vpiNamedEvent:
break; break;
case vpiParameter: /* A constant! */
vpi_printf("SORRY: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s cannot currently dump a parameter.\n", name);
break;
default: default:
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));

View File

@ -320,6 +320,16 @@ typedef struct t_vpi_delay {
#define vpiDefLineNo 16 #define vpiDefLineNo 16
#define vpiNetType 22 #define vpiNetType 22
# define vpiWire 1 # define vpiWire 1
# define vpiWand 2
# define vpiWor 3
# define vpiTri 4
# define vpiTri0 5
# define vpiTri1 6
# define vpiTriReg 7
# define vpiTriAnd 8
# define vpiTriOr 9
# define vpiSupply1 10
# define vpiSupply0 11
#define vpiArray 28 #define vpiArray 28
#define vpiEdge 36 #define vpiEdge 36
# define vpiNoEdge 0x00 /* No edge */ # define vpiNoEdge 0x00 /* No edge */