diff --git a/Documentation/developer/regression_tests.rst b/Documentation/developer/regression_tests.rst index 8f8eec7db..4f833c38f 100644 --- a/Documentation/developer/regression_tests.rst +++ b/Documentation/developer/regression_tests.rst @@ -77,3 +77,17 @@ iverilog-args (optional) If this is specified, it is a list of strings that are passed as arguments to the iverilog command line. + +vvp-args (optional) +^^^^^^^^^^^^^^^^^^^^ + +If this is specified, it is a list of strings that are passed as arguments to +the vvp command. These arguments go before the vvp input file that is to be +run. + +vvp-args-extended (optional) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If this is specified, it is a lost of strings that are passed as arguments to +the vvp command. These are extended arguments, and are placed after the vvp +input file that is being run. This is where you place things like plusargs. diff --git a/Documentation/usage/vvp_flags.rst b/Documentation/usage/vvp_flags.rst index 482aab064..87eb4a9ff 100644 --- a/Documentation/usage/vvp_flags.rst +++ b/Documentation/usage/vvp_flags.rst @@ -82,6 +82,13 @@ behavior. Generate LXT or LXT2format instead of VCD format waveform dumps. The LXT2 format is more advanced. +* -dumpfile= + + Set the default dumpfile. If unspecified, the default is "dump". This + command line flag allows you do change it. If no suffix is specified, + then the suffix will be chosen based on the dump type. In any case, the + $dumpfile system task overrides this flag. + SDF Support ^^^^^^^^^^^ diff --git a/ivtest/gold/dumpfile-iverilog-stderr.gold b/ivtest/gold/dumpfile-iverilog-stderr.gold new file mode 100644 index 000000000..e69de29bb diff --git a/ivtest/gold/dumpfile-iverilog-stdout.gold b/ivtest/gold/dumpfile-iverilog-stdout.gold new file mode 100644 index 000000000..e69de29bb diff --git a/ivtest/gold/dumpfile-vvp-stderr.gold b/ivtest/gold/dumpfile-vvp-stderr.gold new file mode 100644 index 000000000..e69de29bb diff --git a/ivtest/gold/dumpfile-vvp-stdout.gold b/ivtest/gold/dumpfile-vvp-stdout.gold new file mode 100644 index 000000000..86219d705 --- /dev/null +++ b/ivtest/gold/dumpfile-vvp-stdout.gold @@ -0,0 +1,2 @@ +VCD info: dumpfile foo.vcd opened for output. +ivltests/dumpfile.v:11: $finish called at 30 (1s) diff --git a/ivtest/ivltests/dumpfile.v b/ivtest/ivltests/dumpfile.v new file mode 100644 index 000000000..de6284219 --- /dev/null +++ b/ivtest/ivltests/dumpfile.v @@ -0,0 +1,15 @@ +// Github Issue #202 + +module main; + reg clk = 0; + + initial begin + //$dumpfile("foo"); // We really want to test the command line flag + $dumpvars(0, main); + #10 clk <= 1; + #10 clk <= 0; + #10 $finish; + + end + +endmodule // main diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index eb22d756a..71ec08878 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -20,6 +20,7 @@ dffsynth8 vvp_tests/dffsynth8.json dffsynth9 vvp_tests/dffsynth9.json dffsynth10 vvp_tests/dffsynth10.json dffsynth11 vvp_tests/dffsynth11.json +dumpfile vvp_tests/dumpfile.json macro_str_esc vvp_tests/macro_str_esc.json memsynth1 vvp_tests/memsynth1.json struct_packed_write_read vvp_tests/struct_packed_write_read.json diff --git a/ivtest/run_ivl.py b/ivtest/run_ivl.py index 6e5821bc4..06e2c0b93 100644 --- a/ivtest/run_ivl.py +++ b/ivtest/run_ivl.py @@ -18,7 +18,10 @@ def assemble_iverilog_cmd(source: str, it_dir: str, args: list) -> list: def assemble_vvp_cmd(args: list = [], plusargs: list = []) -> list: - res = ["vvp", os.path.join("work", "a.out")] + res = ["vvp"] + res = res + args + res.append(os.path.join("work", "a.out")) + res = res + plusargs return res @@ -130,6 +133,8 @@ def do_run_normal(options : dict, expected_fail : bool) -> list: it_key = options['key'] it_dir = options['directory'] it_iverilog_args = options['iverilog_args'] + it_vvp_args = options['vvp_args'] + it_vvp_args_extended = options['vvp_args_extended'] it_gold = options['gold'] it_diff = options['diff'] @@ -144,7 +149,7 @@ def do_run_normal(options : dict, expected_fail : bool) -> list: return [1, "Failed - Compile failed"] # run the vvp command - vvp_cmd = assemble_vvp_cmd() + vvp_cmd = assemble_vvp_cmd(it_vvp_args, it_vvp_args_extended) vvp_res = subprocess.run(vvp_cmd, capture_output=True) log_results(it_key, "vvp", vvp_res); diff --git a/ivtest/vvp_reg.py b/ivtest/vvp_reg.py index a8f47d365..91243edec 100755 --- a/ivtest/vvp_reg.py +++ b/ivtest/vvp_reg.py @@ -45,7 +45,9 @@ def process_test(item: list) -> str: 'source' : it_dict['source'], 'modulename' : None, 'gold' : it_dict.get('gold', None), - 'diff' : None + 'diff' : None, + 'vvp_args' : it_dict.get('vvp-args', [ ]), + 'vvp_args_extended' : it_dict.get('vvp-args-extended', [ ]) } if it_type == "NI": diff --git a/ivtest/vvp_tests/dumpfile.json b/ivtest/vvp_tests/dumpfile.json new file mode 100644 index 000000000..26952c828 --- /dev/null +++ b/ivtest/vvp_tests/dumpfile.json @@ -0,0 +1,6 @@ +{ + "type" : "normal", + "source" : "dumpfile.v", + "gold" : "dumpfile", + "vvp-args-extended" : [ "-vcd", "-dumpfile=foo" ] +} diff --git a/vpi/sys_fst.c b/vpi/sys_fst.c index f01771629..1797dc7d7 100644 --- a/vpi/sys_fst.c +++ b/vpi/sys_fst.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2023 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -32,7 +32,6 @@ # include # include "ivl_alloc.h" -static char *dump_path = NULL; static int dump_no_date = 0; static struct fstContext *dump_file = NULL; @@ -114,7 +113,6 @@ struct vcd_names_list_s fst_tab = { 0, 0, 0, 0 }; struct vcd_names_list_s fst_var = { 0, 0, 0, 0 }; -static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ static PLI_UINT64 dumpvars_time; __inline__ static int dump_header_pending(void) { @@ -224,8 +222,7 @@ static PLI_INT32 finish_cb(p_cb_data cause) vcd_names_delete(&fst_tab); vcd_names_delete(&fst_var); nexus_ident_delete(); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return 0; } @@ -346,18 +343,17 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static void open_dumpfile(vpiHandle callh) { - if (dump_path == 0) dump_path = strdup("dump.fst"); + char* use_dump_path = vcd_get_dump_path("fst"); - dump_file = fstWriterCreate(dump_path, 1); + dump_file = fstWriterCreate(use_dump_path, 1); if (dump_file == 0) { vpi_printf("FST Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Unable to open %s for output.\n", dump_path); + vpi_printf("Unable to open %s for output.\n", use_dump_path); vpip_set_return_value(1); vpi_control(vpiFinish, 1); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return; } else { int prec = vpi_get(vpiTimePrecision, 0); @@ -367,7 +363,7 @@ static void open_dumpfile(vpiHandle callh) char scale_buf[65]; vpi_printf("FST info: dumpfile %s opened for output.\n", - dump_path); + use_dump_path); time(&walltime); @@ -381,10 +377,10 @@ static void open_dumpfile(vpiHandle callh) prec -= 1; } - if (!dump_no_date) - fstWriterSetDate(dump_file, asctime(localtime(&walltime))); - else - fstWriterSetDate(dump_file, ""); + if (!dump_no_date) + fstWriterSetDate(dump_file, asctime(localtime(&walltime))); + else + fstWriterSetDate(dump_file, ""); fstWriterSetVersion(dump_file, "Icarus Verilog"); sprintf(scale_buf, "\t%u%s\n", scale, units_names[udx]); fstWriterSetTimescaleFromString(dump_file, scale_buf); @@ -403,37 +399,8 @@ static void open_dumpfile(vpiHandle callh) static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - char *path; - - /* $dumpfile must be called before $dumpvars starts! */ - if (dumpvars_status != 0) { - char msg[64]; - snprintf(msg, sizeof(msg), "FST warning: %s:%d:", - vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - msg[sizeof(msg)-1] = 0; - vpi_printf("%s %s called after $dumpvars started,\n", msg, name); - vpi_printf("%*s using existing file (%s).\n", - (int) strlen(msg), " ", dump_path); - vpi_free_object(argv); - return 0; - } - - path = get_filename_with_suffix(callh, name, vpi_scan(argv), "fst"); - vpi_free_object(argv); - if (! path) return 0; - - if (dump_path) { - vpi_printf("FST warning: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Overriding dump file %s with %s.\n", dump_path, path); - free(dump_path); - } - dump_path = path; - - return 0; + (void)name; + return sys_dumpfile_common("FST", "fst"); } static PLI_INT32 sys_dumpflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index 66d66dbe7..fc632db8f 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2023 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -35,7 +35,6 @@ # include "ivl_alloc.h" -static char *dump_path = NULL; static struct lt_trace *dump_file = NULL; static struct t_vpi_time zero_delay = { vpiSimTime, 0, 0, 0.0 }; @@ -197,7 +196,6 @@ static void show_this_item_x(struct vcd_info*info) struct vcd_names_list_s lxt_tab; -static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ static PLI_UINT64 dumpvars_time; __inline__ static int dump_header_pending(void) { @@ -314,8 +312,7 @@ static PLI_INT32 finish_cb(p_cb_data cause) vcd_names_delete(&lxt_tab); nexus_ident_delete(); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return 0; } @@ -442,24 +439,23 @@ static void *close_dumpfile(void) static void open_dumpfile(vpiHandle callh) { - if (dump_path == 0) dump_path = strdup("dump.lxt"); + char* use_dump_path = vcd_get_dump_path("lxt"); - dump_file = lt_init(dump_path); + dump_file = lt_init(use_dump_path); if (dump_file == 0) { vpi_printf("LXT Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Unable to open %s for output.\n", dump_path); + vpi_printf("Unable to open %s for output.\n", use_dump_path); vpip_set_return_value(1); vpi_control(vpiFinish, 1); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return; } else { int prec = vpi_get(vpiTimePrecision, 0); vpi_printf("LXT info: dumpfile %s opened for output.\n", - dump_path); + use_dump_path); assert(prec >= -15); lt_set_timescale(dump_file, prec); @@ -473,37 +469,8 @@ static void open_dumpfile(vpiHandle callh) static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - char *path; - - /* $dumpfile must be called before $dumpvars starts! */ - if (dumpvars_status != 0) { - char msg[64]; - snprintf(msg, sizeof(msg), "LXT warning: %s:%d:", - vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - msg[sizeof(msg)-1] = 0; - vpi_printf("%s %s called after $dumpvars started,\n", msg, name); - vpi_printf("%*s using existing file (%s).\n", - (int) strlen(msg), " ", dump_path); - vpi_free_object(argv); - return 0; - } - - path = get_filename_with_suffix(callh, name, vpi_scan(argv), "lxt"); - vpi_free_object(argv); - if (! path) return 0; - - if (dump_path) { - vpi_printf("LXT warning: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Overriding dump file %s with %s.\n", dump_path, path); - free(dump_path); - } - dump_path = path; - - return 0; + (void)name; + return sys_dumpfile_common("LXT", "lxt"); } /* diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index ff470eb20..65fe6dd5d 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2023 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -35,7 +35,6 @@ # include "ivl_alloc.h" -static char *dump_path = NULL; static struct lxt2_wr_trace *dump_file = NULL; static void* lxt2_thread(void*arg); @@ -244,7 +243,6 @@ static void show_this_item_x(struct vcd_info*info) } -static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ static PLI_UINT64 dumpvars_time; __inline__ static int dump_header_pending(void) { @@ -349,8 +347,7 @@ static PLI_INT32 finish_cb(p_cb_data cause) vcd_scope_names_delete(); nexus_ident_delete(); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return 0; } @@ -479,9 +476,9 @@ static void *close_dumpfile(void) static void open_dumpfile(vpiHandle callh) { off_t use_file_size_limit = lxt2_file_size_limit; - if (dump_path == 0) dump_path = strdup("dump.lx2"); + char* use_dump_path = vcd_get_dump_path("lx2"); - dump_file = lxt2_wr_init(dump_path); + dump_file = lxt2_wr_init(use_dump_path); if (getenv("LXT_FILE_SIZE_LIMIT")) { const char*limit_string = getenv("LXT_FILE_SIZE_LIMIT"); @@ -499,17 +496,16 @@ static void open_dumpfile(vpiHandle callh) if (dump_file == 0) { vpi_printf("LXT2 Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Unable to open %s for output.\n", dump_path); + vpi_printf("Unable to open %s for output.\n", use_dump_path); vpip_set_return_value(1); vpi_control(vpiFinish, 1); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return; } else { int prec = vpi_get(vpiTimePrecision, 0); vpi_printf("LXT2 info: dumpfile %s opened for output.\n", - dump_path); + use_dump_path); assert(prec >= -15); lxt2_wr_set_timescale(dump_file, prec); @@ -526,37 +522,8 @@ static void open_dumpfile(vpiHandle callh) static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - char *path; - - /* $dumpfile must be called before $dumpvars starts! */ - if (dumpvars_status != 0) { - char msg[64]; - snprintf(msg, sizeof(msg), "LXT2 warning: %s:%d:", - vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - msg[sizeof(msg)-1] = 0; - vpi_printf("%s %s called after $dumpvars started,\n", msg, name); - vpi_printf("%*s using existing file (%s).\n", - (int) strlen(msg), " ", dump_path); - vpi_free_object(argv); - return 0; - } - - path = get_filename_with_suffix(callh, name, vpi_scan(argv), "lx2"); - vpi_free_object(argv); - if (! path) return 0; - - if (dump_path) { - vpi_printf("LXT2 warning: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Overriding dump file %s with %s.\n", dump_path, path); - free(dump_path); - } - dump_path = path; - - return 0; + (void)name; + return sys_dumpfile_common("LXT2", "lx2"); } /* diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index b9fb61029..222970a81 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -104,11 +104,11 @@ char *get_filename(vpiHandle callh, const char *name, vpiHandle file) return strdup(val.value.str); } -char* get_filename_with_suffix(vpiHandle callh, const char *name, vpiHandle file, const char*suff) +/* + * Create a new copy of the path with the suffix appended. + */ +char* attach_suffix_to_filename(char *path, const char*suff) { - char*path = get_filename(callh, name, file); - if (path == 0) return 0; - /* If the name already has a suffix, then don't replace it or add another suffix. Just return this path. */ char*tailp = strrchr(path, '.'); @@ -124,6 +124,14 @@ char* get_filename_with_suffix(vpiHandle callh, const char *name, vpiHandle file return new_path; } +char* get_filename_with_suffix(vpiHandle callh, const char *name, vpiHandle file, const char*suff) +{ + char*path = get_filename(callh, name, file); + if (path == 0) return 0; + + return attach_suffix_to_filename(path, suff); +} + void check_for_extra_args(vpiHandle argv, vpiHandle callh, const char *name, const char *arg_str, unsigned opt) { diff --git a/vpi/sys_priv.h b/vpi/sys_priv.h index 473a5650e..dea7d55ac 100644 --- a/vpi/sys_priv.h +++ b/vpi/sys_priv.h @@ -41,6 +41,7 @@ extern char *as_escaped(char *arg); extern char *get_filename(vpiHandle callh, const char *name, vpiHandle file); extern char *get_filename_with_suffix(vpiHandle callh, const char*name, vpiHandle file, const char*suff); +extern char *attach_suffix_to_filename(char *path, const char*suff); extern void check_for_extra_args(vpiHandle argv, vpiHandle callh, const char *name, const char *arg_str, unsigned opt); diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 23b2c9142..1067b238c 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -19,6 +19,7 @@ # include "vpi_config.h" # include "vpi_user.h" +# include "vcd_priv.h" # include # include # include @@ -149,6 +150,8 @@ static void sys_lxt_or_vcd_register(void) } else if (strcmp(vlog_info.argv[idx],"-none") == 0) { dumper = "none"; + } else if (strncmp(vlog_info.argv[idx],"-dumpfile=",10) == 0) { + vcd_set_dump_path_default(vlog_info.argv[idx]+10); } } diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index 13eea5e5d..1d7b1638d 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2023 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -31,7 +31,6 @@ # include # include "ivl_alloc.h" -static char *dump_path = NULL; static FILE *dump_file = NULL; static int dump_no_date = 0; @@ -158,7 +157,6 @@ struct vcd_names_list_s vcd_tab = { 0, 0, 0, 0 }; struct vcd_names_list_s vcd_var = { 0, 0, 0, 0 }; -static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ static PLI_UINT64 dumpvars_time; __inline__ static int dump_header_pending(void) { @@ -283,8 +281,7 @@ static PLI_INT32 finish_cb(p_cb_data cause) vcd_names_delete(&vcd_tab); vcd_names_delete(&vcd_var); nexus_ident_delete(); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return 0; } @@ -408,18 +405,17 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static void open_dumpfile(vpiHandle callh) { - if (dump_path == 0) dump_path = strdup("dump.vcd"); + char* use_dump_path = vcd_get_dump_path("vcd"); - dump_file = fopen(dump_path, "w"); + dump_file = fopen(use_dump_path, "w"); if (dump_file == 0) { vpi_printf("VCD Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Unable to open %s for output.\n", dump_path); + vpi_printf("Unable to open %s for output.\n", use_dump_path); vpip_set_return_value(1); vpi_control(vpiFinish, 1); - free(dump_path); - dump_path = 0; + vcd_free_dump_path(); return; } else { int prec = vpi_get(vpiTimePrecision, 0); @@ -428,7 +424,7 @@ static void open_dumpfile(vpiHandle callh) time_t walltime; vpi_printf("VCD info: dumpfile %s opened for output.\n", - dump_path); + use_dump_path); time(&walltime); @@ -458,37 +454,8 @@ static void open_dumpfile(vpiHandle callh) static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - char *path; - - /* $dumpfile must be called before $dumpvars starts! */ - if (dumpvars_status != 0) { - char msg[64]; - snprintf(msg, sizeof(msg), "VCD warning: %s:%d:", - vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - msg[sizeof(msg)-1] = 0; - vpi_printf("%s %s called after $dumpvars started,\n", msg, name); - vpi_printf("%*s using existing file (%s).\n", - (int) strlen(msg), " ", dump_path); - vpi_free_object(argv); - return 0; - } - - path = get_filename_with_suffix(callh, name, vpi_scan(argv), "vcd"); - vpi_free_object(argv); - if (! path) return 0; - - if (dump_path) { - vpi_printf("VCD warning: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("Overriding dump file %s with %s.\n", dump_path, path); - free(dump_path); - } - dump_path = path; - - return 0; + (void) name; + return sys_dumpfile_common("VCD", "vcd"); } static PLI_INT32 sys_dumpflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) diff --git a/vpi/vcd_priv.c b/vpi/vcd_priv.c index ea01e0a4b..f508a16f3 100644 --- a/vpi/vcd_priv.c +++ b/vpi/vcd_priv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2023 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -27,6 +27,10 @@ #include #include "stringheap.h" +static const char* vcd_dump_path_default = "dump"; +static char* vcd_dump_path = NULL; +int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ + int is_escaped_id(const char *name) { assert(name); @@ -220,3 +224,63 @@ PLI_INT32 sys_dumpvars_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } + +void vcd_set_dump_path_default(const char*text) +{ + vcd_dump_path_default = text; +} + +char* vcd_get_dump_path(const char*suffix) +{ + if (vcd_dump_path) + return vcd_dump_path; + + vcd_dump_path = attach_suffix_to_filename(strdup(vcd_dump_path_default), suffix); + return vcd_dump_path; +} + +void vcd_free_dump_path(void) +{ + free(vcd_dump_path); + vcd_dump_path = NULL; +} + +/* + * Common implementation of $dumpfile() for the various dumper types. + * string argument is the title to use in error messages. + */ +PLI_INT32 sys_dumpfile_common(const char*title, const char*suffix) +{ + static const char* name = "$dumpfile"; + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + char *path; + + /* $dumpfile must be called before $dumpvars starts! */ + if (dumpvars_status != 0) { + char msg[64]; + snprintf(msg, sizeof(msg), "%s warning: %s:%d:", title, + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + msg[sizeof(msg)-1] = 0; + vpi_printf("%s %s called after $dumpvars started,\n", msg, name); + vpi_printf("%*s using existing file (%s).\n", + (int) strlen(msg), " ", vcd_dump_path); + vpi_free_object(argv); + return 0; + } + + path = get_filename_with_suffix(callh, name, vpi_scan(argv), suffix); + vpi_free_object(argv); + if (! path) return 0; + + if (vcd_dump_path) { + vpi_printf("%s warning: %s:%d: ", title, vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("Overriding dump file %s with %s.\n", vcd_dump_path, path); + free(vcd_dump_path); + } + vcd_dump_path = path; + + return 0; +} diff --git a/vpi/vcd_priv.h b/vpi/vcd_priv.h index 629b9ed05..791043dc1 100644 --- a/vpi/vcd_priv.h +++ b/vpi/vcd_priv.h @@ -1,7 +1,7 @@ #ifndef IVL_vcd_priv_H #define IVL_vcd_priv_H /* - * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2023 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -129,6 +129,15 @@ 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); +/* + * Common implementation of the sys_dumpfile calltf. + */ +EXTERN PLI_INT32 sys_dumpfile_common(const char*title, const char*suffix); +EXTERN void vcd_set_dump_path_default(const char*text); +EXTERN char* vcd_get_dump_path(const char*suffix); +EXTERN void vcd_free_dump_path(void); +EXTERN int dumpvars_status; + /* * 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