Add parameters to vcd dumps

Writing parameters into VCD files makes the values available to waveform
tools. This can be done easily enough by writing out a $dumpadd section
at the beginning of the file that sets the parameter values. We don't need
to track the values over change, because by definition they do not change.

This changes the typical vcd output as well, so a few of the regression tests
need to be adjusted to account for this.

Also, while tracking this down, found and fixed the vvp/README.txt documention
for the .param/x records.
This commit is contained in:
Stephen Williams 2022-05-15 18:47:18 -07:00
parent e67a796a77
commit a1485906ca
9 changed files with 132 additions and 16 deletions

View File

@ -1,5 +1,5 @@
$date
Tue Apr 21 18:40:22 2009
Sun May 15 18:09:10 2022
$end
$version
Icarus Verilog
@ -17,6 +17,9 @@ $scope module top $end
$var reg 8 # \array[2] [7:0] $end
$upscope $end
$enddefinitions $end
$comment Show the parameter values. $end
$dumpall
$end
#0
$dumpvars
bx #

View File

@ -0,0 +1,25 @@
$date
Sun May 15 09:20:23 2022
$end
$version
Icarus Verilog
$end
$timescale
1s
$end
$scope module main $end
$var wire 4 ! bat [3:0] $end
$var parameter 4 " bar $end
$var parameter 4 # foo $end
$upscope $end
$enddefinitions $end
$comment Show the parameter values. $end
$dumpall
b101 #
b111 "
$end
#0
$dumpvars
b1100 !
$end
#1

View File

@ -1,5 +1,5 @@
$date
Wed Jun 4 10:37:42 2008
Sun May 15 18:09:25 2022
$end
$version
Icarus Verilog
@ -11,6 +11,9 @@ $scope module top $end
$var reg 8 ! \arr[4] [7:0] $end
$upscope $end
$enddefinitions $end
$comment Show the parameter values. $end
$dumpall
$end
#0
$dumpvars
b0 !

View File

@ -1,5 +1,5 @@
$date
Tue Sep 15 16:56:35 2009
Sun May 15 18:19:07 2022
$end
$version
Icarus Verilog
@ -16,6 +16,9 @@ $scope module top $end
$var reg 4 " \array[1] [3:0] $end
$upscope $end
$enddefinitions $end
$comment Show the parameter values. $end
$dumpall
$end
#0
$dumpvars
bx "

View File

@ -1,5 +1,5 @@
$date
Fri Oct 16 08:46:35 2009
Sun May 15 15:15:18 2022
$end
$version
Icarus Verilog
@ -53,6 +53,9 @@ $upscope $end
$upscope $end
$upscope $end
$enddefinitions $end
$comment Show the parameter values. $end
$dumpall
$end
#0
$dumpvars
x/

View File

@ -0,0 +1,17 @@
//
// This tests that the parameter and localparam show up in the vcd dump.
//
module main;
parameter [3:0] foo = 4'd5;
localparam [3:0] bar = 7;
wire [3:0] bat = foo + bar;
initial begin
$dumpfile("work/br_gh156.vcd");
$dumpvars(0, main);
#1 $finish;
end
endmodule // main

View File

@ -309,6 +309,7 @@ br_gh127e normal ivltests gold=br_gh127e.gold
br_gh127f normal ivltests gold=br_gh127f.gold
br_gh142 CE ivltests
br_gh152 CE ivltests
br_gh156 normal ivltests diff=work/br_gh156.vcd:gold/br_gh156.vcd.gold:2
br_gh157 CE ivltests gold=br_gh157.gold
br_gh162 normal ivltests
br_gh163 CE ivltests

View File

@ -37,6 +37,16 @@ static int dump_no_date = 0;
static struct t_vpi_time zero_delay = { vpiSimTime, 0, 0, 0.0 };
/*
* The vcd_list is the list of all the objects that are tracked for
* dumping. The vcd_checkpoint goes through the list to dump the current
* values for everything. When the item has a value change, it is added to the
* vcd_dmp_list for dumping in the current time step.
*
* The vcd_const_list is a list of all of the parameters that are being
* dumped. This list is scanned less often, since parameters do not change
* values.
*/
struct vcd_info {
vpiHandle item;
vpiHandle cb;
@ -47,7 +57,7 @@ struct vcd_info {
int scheduled;
};
static struct vcd_info *vcd_const_list = NULL;
static struct vcd_info *vcd_list = NULL;
static struct vcd_info *vcd_dmp_list = NULL;
static PLI_UINT64 vcd_cur_time = 0;
@ -158,6 +168,18 @@ __inline__ static int dump_header_pending(void)
return dumpvars_status != 2;
}
/*
* This function writes out all the traced parameters. They never change, so
* this is the only way they get written.
*/
static void vcd_const_checkpoint(void)
{
struct vcd_info *cur;
for (cur = vcd_const_list ; cur ; cur = cur->next)
show_this_item(cur);
}
/*
* This function writes out all the traced variables, whether they
* changed or not.
@ -232,6 +254,11 @@ static PLI_INT32 variable_cb_1(p_cb_data cause)
return 0;
}
/*
* This is called at the end of the timestep where the $dumpvars task is
* called. This allows for values to settle for the timestep, so that the
* checkpoint gets the current values.
*/
static PLI_INT32 dumpvars_cb(p_cb_data cause)
{
if (dumpvars_status != 1) return 0;
@ -244,7 +271,13 @@ static PLI_INT32 dumpvars_cb(p_cb_data cause)
fprintf(dump_file, "$enddefinitions $end\n");
if (!dump_is_off) {
fprintf(dump_file, "$comment Show the parameter values. $end\n");
fprintf(dump_file, "$dumpall\n");
vcd_const_checkpoint();
fprintf(dump_file, "$end\n");
fprintf(dump_file, "#%" PLI_UINT64_FMT "\n", dumpvars_time);
fprintf(dump_file, "$dumpvars\n");
vcd_checkpoint();
fprintf(dump_file, "$end\n");
@ -275,6 +308,12 @@ static PLI_INT32 finish_cb(p_cb_data cause)
free(cur);
}
vcd_list = 0;
for (cur = vcd_const_list ; cur ; cur = next) {
next = cur->next;
free((char *)cur->ident);
free(cur);
}
vcd_const_list = 0;
vcd_names_delete(&vcd_tab);
vcd_names_delete(&vcd_var);
nexus_ident_delete();
@ -601,10 +640,6 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
/* 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 vpiBitVar:
@ -618,7 +653,6 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
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;
@ -684,6 +718,35 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
fprintf(dump_file, " $end\n");
break;
case vpiParameter:
/* If we are skipping all pamaeters then just return. */
if (skip) return;
size = vpi_get(vpiSize, item);
/* Declare the parameter in the VCD file. */
name = vpi_get_str(vpiName, item);
prefix = is_escaped_id(name) ? "\\" : "";
ident = strdup(vcdid);
gen_new_vcd_id();
/* Make an info item to go in the vcd_const_list. */
info = malloc(sizeof(*info));
info->item = item;
info->ident = ident;
info->scheduled = 0;
info->dmp_next = 0;
info->next = vcd_const_list;
vcd_const_list = info;
info->cb = NULL;
/* Generate the $var record. Now the parameter is declared. */
fprintf(dump_file, "$var %s %u %s %s%s $end\n",
type, size, ident, prefix, name);
break;
case vpiModule:
case vpiGenScope:
case vpiFunction:
@ -697,7 +760,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
/* Value */
vpiNamedEvent,
vpiNet,
/* vpiParameter, */
vpiParameter,
vpiReg,
vpiVariables,
/* Scope */

View File

@ -133,10 +133,9 @@ objects.
The syntax of a parameter is:
<label> .param/str <name>, <value>;
<label> .param/b <name>, <value> [<msb>,<lsb>];
<label> .param/l <name>, <value> [<msb>,<lsb>];
<label> .param/r <name>, <value>;
<label> .param/str <name> <local-flag> <file-idx> <lineno>, <value>;
<label> .param/l <name> <local-flag> <file-idx> <lineno>, <value>;
<label> .param/r <name> <local-flag> <file-idx> <lineno>, <value>;
The <name> is a string that names the parameter. The name is placed in
the current scope as a vpiParameter object. The .param suffix
@ -144,7 +143,6 @@ specifies the parameter type.
.param/str -- The parameter has a string value
.param/l -- The parameter has a logic vector value
.param/b -- The parameter has a boolean vector value
.param/r -- The parameter has a real value
The value, then, is appropriate for the data type. For example: