diff --git a/ivtest/gold/array_dump.vcd.gold b/ivtest/gold/array_dump.vcd.gold index da8c9312d..4c78ece41 100644 --- a/ivtest/gold/array_dump.vcd.gold +++ b/ivtest/gold/array_dump.vcd.gold @@ -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 # diff --git a/ivtest/gold/br_gh156.vcd.gold b/ivtest/gold/br_gh156.vcd.gold new file mode 100644 index 000000000..ccac9620e --- /dev/null +++ b/ivtest/gold/br_gh156.vcd.gold @@ -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 diff --git a/ivtest/gold/dump_memword.vcd b/ivtest/gold/dump_memword.vcd index 03de017d5..501fd5231 100644 --- a/ivtest/gold/dump_memword.vcd +++ b/ivtest/gold/dump_memword.vcd @@ -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 ! diff --git a/ivtest/gold/pr2859628.vcd.gold b/ivtest/gold/pr2859628.vcd.gold index 36c6406bb..1fbe9ed1e 100644 --- a/ivtest/gold/pr2859628.vcd.gold +++ b/ivtest/gold/pr2859628.vcd.gold @@ -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 " diff --git a/ivtest/gold/vcd-dup.vcd.gold b/ivtest/gold/vcd-dup.vcd.gold index 2439e1a37..3e0235580 100644 --- a/ivtest/gold/vcd-dup.vcd.gold +++ b/ivtest/gold/vcd-dup.vcd.gold @@ -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/ diff --git a/ivtest/ivltests/br_gh156.v b/ivtest/ivltests/br_gh156.v new file mode 100644 index 000000000..296711232 --- /dev/null +++ b/ivtest/ivltests/br_gh156.v @@ -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 diff --git a/ivtest/regress-vlg.list b/ivtest/regress-vlg.list index 7c019c309..2f4ce90ad 100644 --- a/ivtest/regress-vlg.list +++ b/ivtest/regress-vlg.list @@ -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 diff --git a/vpi/sys_fst.c b/vpi/sys_fst.c index 0b3a423a6..ea471a5c4 100644 --- a/vpi/sys_fst.c +++ b/vpi/sys_fst.c @@ -38,26 +38,17 @@ static struct fstContext *dump_file = NULL; static struct t_vpi_time zero_delay = { vpiSimTime, 0, 0, 0.0 }; -struct vcd_info { - vpiHandle item; - vpiHandle cb; - struct t_vpi_time time; - struct vcd_info *next; - struct vcd_info *dmp_next; - fstHandle handle; - int scheduled; -}; - - +DECLARE_VCD_INFO(vcd_info, fstHandle); static struct vcd_info *vcd_list = NULL; +static struct vcd_info *vcd_const_list = NULL; static struct vcd_info *vcd_dmp_list = NULL; + static PLI_UINT64 vcd_cur_time = 0; static int dump_is_off = 0; static long dump_limit = 0; static int dump_is_full = 0; static int finish_status = 0; - static enum lxm_optimum_mode_e { LXM_NONE = 0, LXM_SPACE = 1, @@ -82,11 +73,11 @@ static void show_this_item(struct vcd_info*info) if (type == vpiRealVar) { value.format = vpiRealVal; vpi_get_value(info->item, &value); - fstWriterEmitValueChange(dump_file, info->handle, &value.value.real); + fstWriterEmitValueChange(dump_file, info->ident, &value.value.real); } else { value.format = vpiBinStrVal; vpi_get_value(info->item, &value); - fstWriterEmitValueChange(dump_file, info->handle, (type != vpiNamedEvent) ? value.value.str : "1"); + fstWriterEmitValueChange(dump_file, info->ident, (type != vpiNamedEvent) ? value.value.str : "1"); } } @@ -98,14 +89,14 @@ static void show_this_item_x(struct vcd_info*info) if (type == vpiRealVar) { /* Some tools dump nothing here...? */ double mynan = strtod("NaN", NULL); - fstWriterEmitValueChange(dump_file, info->handle, &mynan); + fstWriterEmitValueChange(dump_file, info->ident, &mynan); } else if (type == vpiNamedEvent) { /* Do nothing for named events. */ } else { int siz = vpi_get(vpiSize, info->item); char *xmem = malloc(siz); memset(xmem, 'x', siz); - fstWriterEmitValueChange(dump_file, info->handle, xmem); + fstWriterEmitValueChange(dump_file, info->ident, xmem); free(xmem); } } @@ -126,26 +117,6 @@ __inline__ static int dump_header_pending(void) return dumpvars_status != 2; } -/* - * This function writes out all the traced variables, whether they - * changed or not. - */ -static void vcd_checkpoint(void) -{ - struct vcd_info*cur; - - for (cur = vcd_list ; cur ; cur = cur->next) - show_this_item(cur); -} - -static void vcd_checkpoint_x(void) -{ - struct vcd_info*cur; - - for (cur = vcd_list ; cur ; cur = cur->next) - show_this_item_x(cur); -} - static PLI_INT32 variable_cb_2(p_cb_data cause) { struct vcd_info* info = vcd_dmp_list; @@ -212,7 +183,8 @@ static PLI_INT32 dumpvars_cb(p_cb_data cause) if (!dump_is_off) { fstWriterEmitTimeChange(dump_file, dumpvars_time); /* nothing to do for $dumpvars... */ - vcd_checkpoint(); + ITERATE_VCD_INFO(vcd_const_list, vcd_info, next, show_this_item); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item); /* ...nothing to do for $end */ } @@ -240,6 +212,11 @@ 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(cur); + } + vcd_const_list = 0; vcd_names_delete(&fst_tab); vcd_names_delete(&fst_var); nexus_ident_delete(); @@ -303,7 +280,7 @@ static PLI_INT32 sys_dumpoff_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } fstWriterEmitDumpActive(dump_file, 0); /* $dumpoff */ - vcd_checkpoint_x(); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item_x); return 0; } @@ -332,7 +309,7 @@ static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } fstWriterEmitDumpActive(dump_file, 1); /* $dumpon */ - vcd_checkpoint(); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item); return 0; } @@ -358,7 +335,7 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } /* nothing to do for $dumpall... */ - vcd_checkpoint(); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item); return 0; } @@ -574,10 +551,6 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) /* Generate the $var or $scope commands. */ switch (item_type) { - case vpiParameter: - vpi_printf("FST sorry: $dumpvars: can not dump parameters.\n"); - break; - case vpiNamedEvent: case vpiIntegerVar: case vpiBitVar: @@ -648,7 +621,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) info->time.type = vpiSimTime; info->item = item; - info->handle = new_ident; + info->ident = new_ident; info->scheduled = 0; cb.time = &info->time; @@ -667,6 +640,37 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) break; + case vpiParameter: + + /* If we are skipping all pamaeters then just return. */ + if (skip) return; + + /* Skip this signal if it has already been included. + * This can only happen for implicitly given signals. */ + if (vcd_names_search(&fst_var, fullname)) return; + + name = vpi_get_str(vpiName, item); + if (is_escaped_id(name)) { + escname = malloc(strlen(name) + 2); + sprintf(escname, "\\%s", name); + } else escname = strdup(name); + + size = vpi_get(vpiSize, item); + dir = FST_VD_IMPLICIT; + new_ident = fstWriterCreateVar(dump_file, type, + dir, size, escname, 0); + free(escname); + + info = malloc(sizeof(*info)); + info->item = item; + info->ident = new_ident; + info->scheduled = 0; + info->dmp_next = 0; + info->next = vcd_const_list; + info->cb = NULL; + vcd_const_list = info; + break; + case vpiModule: case vpiPackage: case vpiGenScope: @@ -683,7 +687,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) /* Value */ vpiNamedEvent, vpiNet, - /* vpiParameter, */ + vpiParameter, vpiReg, vpiVariables, /* Scope */ diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index 1229304d3..0a72e9ea0 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -37,19 +37,21 @@ static int dump_no_date = 0; static struct t_vpi_time zero_delay = { vpiSimTime, 0, 0, 0.0 }; -struct vcd_info { - vpiHandle item; - vpiHandle cb; - struct t_vpi_time time; - const char *ident; - struct vcd_info *next; - struct vcd_info *dmp_next; - int scheduled; -}; - - +/* + * 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. + */ +DECLARE_VCD_INFO(vcd_info, const char*); +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; static int dump_is_off = 0; static long dump_limit = 0; @@ -158,25 +160,6 @@ __inline__ static int dump_header_pending(void) return dumpvars_status != 2; } -/* - * This function writes out all the traced variables, whether they - * changed or not. - */ -static void vcd_checkpoint(void) -{ - struct vcd_info*cur; - - for (cur = vcd_list ; cur ; cur = cur->next) - show_this_item(cur); -} - -static void vcd_checkpoint_x(void) -{ - struct vcd_info*cur; - - for (cur = vcd_list ; cur ; cur = cur->next) - show_this_item_x(cur); -} static PLI_INT32 variable_cb_2(p_cb_data cause) { @@ -232,6 +215,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,9 +232,15 @@ 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"); + ITERATE_VCD_INFO(vcd_const_list, vcd_info, next, show_this_item); + fprintf(dump_file, "$end\n"); + fprintf(dump_file, "#%" PLI_UINT64_FMT "\n", dumpvars_time); + fprintf(dump_file, "$dumpvars\n"); - vcd_checkpoint(); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item); fprintf(dump_file, "$end\n"); } @@ -275,6 +269,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(); @@ -338,7 +338,7 @@ static PLI_INT32 sys_dumpoff_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } fprintf(dump_file, "$dumpoff\n"); - vcd_checkpoint_x(); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item_x); fprintf(dump_file, "$end\n"); return 0; @@ -368,7 +368,7 @@ static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } fprintf(dump_file, "$dumpon\n"); - vcd_checkpoint(); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item); fprintf(dump_file, "$end\n"); return 0; @@ -395,7 +395,7 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } fprintf(dump_file, "$dumpall\n"); - vcd_checkpoint(); + ITERATE_VCD_INFO(vcd_list, vcd_info, next, show_this_item); fprintf(dump_file, "$end\n"); return 0; @@ -601,10 +601,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 +614,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 +679,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 +721,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) /* Value */ vpiNamedEvent, vpiNet, - /* vpiParameter, */ + vpiParameter, vpiReg, vpiVariables, /* Scope */ diff --git a/vpi/vcd_priv.h b/vpi/vcd_priv.h index 43430c490..629b9ed05 100644 --- a/vpi/vcd_priv.h +++ b/vpi/vcd_priv.h @@ -129,6 +129,35 @@ EXTERN void vcd_work_emit_bits(struct lxt2_wr_symbol*sym, const char*bits); /* The compiletf routines are common for the VCD, LXT and LXT2 dumpers. */ EXTERN PLI_INT32 sys_dumpvars_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); +/* + * 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. + */ +#define DECLARE_VCD_INFO(type_name, ident_type) \ + struct type_name { \ + vpiHandle item; \ + vpiHandle cb;\ + struct t_vpi_time time; \ + struct vcd_info *next; \ + struct vcd_info *dmp_next; \ + int scheduled; \ + ident_type ident; \ + } + +#define ITERATE_VCD_INFO(use_list, use_type, use_next, method) \ + do { \ + struct use_type*cur; \ + for (cur = use_list ; cur ; cur = cur->use_next) \ + method(cur); \ + } while (0) + + #undef EXTERN #endif /* IVL_vcd_priv_H */ diff --git a/vvp/README.txt b/vvp/README.txt index db3ee0cbd..26938b188 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -133,10 +133,9 @@ objects. The syntax of a parameter is: -