From 0288f3c2ceb5ec153596ec50d24edca9970cea1a Mon Sep 17 00:00:00 2001 From: Aleksi Korsman Date: Mon, 17 Aug 2026 17:31:39 +0300 Subject: [PATCH 1/5] dump_waves property to generate waveform without gui --- rtl/__init__.py | 16 ++++++++++++++ rtl/ghdl/ghdl.py | 44 +++++++++++++++++++++++++------------- rtl/questasim/questasim.py | 14 ++++++++++++ rtl/testbench_common.py | 2 +- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/rtl/__init__.py b/rtl/__init__.py index db75282..1a6cde2 100644 --- a/rtl/__init__.py +++ b/rtl/__init__.py @@ -103,6 +103,22 @@ def interactive_rtl(self): def interactive_rtl(self, value): self._interactive_rtl = value + @property + def dump_waves(self): + """True | False (default) + + Generate a VCD waveform dumpfile without opening a waveform viewer. + If interactive_rtl is True, that takes precedence and this has + no effect.""" + + if not hasattr(self, "_dump_waves"): + self._dump_waves = False + return self._dump_waves + + @dump_waves.setter + def dump_waves(self, value): + self._dump_waves = value + @property def lsf_submission(self): """ diff --git a/rtl/ghdl/ghdl.py b/rtl/ghdl/ghdl.py index 4a8a422..d5bde51 100644 --- a/rtl/ghdl/ghdl.py +++ b/rtl/ghdl/ghdl.py @@ -83,16 +83,15 @@ def ghdl_rtlcmd(self): interactive_string = "" self.print_log(type="I", msg="No interactive control file set.") - if not self.interactive_rtl: - rtlsimcmd = ( - "ghdl -r --std=08 --workdir=" - + self.rtlworkpath - + " tb_" - + self.name - + " " - + controlstring - ) - else: + vcdstring = ( + " --vcd=" + + self.rtlsimpath + + "/" + + self.name + + "_dump.vcd" + ) + + if self.interactive_rtl: submission = "" # Local execution rtlsimcmd = ( "ghdl -r --std=08 --workdir=" @@ -101,11 +100,7 @@ def ghdl_rtlcmd(self): + "tb_" + self.name + controlstring - + " --vcd=" - + self.rtlsimpath - + "/" - + self.name - + "_dump.vcd" + + vcdstring + " && gtkwave " + interactive_string + " " @@ -114,6 +109,25 @@ def ghdl_rtlcmd(self): + self.name + "_dump.vcd" ) + elif self.dump_waves: + rtlsimcmd = ( + "ghdl -r --std=08 --workdir=" + + self.rtlworkpath + + " " + + "tb_" + + self.name + + controlstring + + vcdstring + ) + else: + rtlsimcmd = ( + "ghdl -r --std=08 --workdir=" + + self.rtlworkpath + + " tb_" + + self.name + + " " + + controlstring + ) self._rtlcmd = ( vhdlcompcmd diff --git a/rtl/questasim/questasim.py b/rtl/questasim/questasim.py index c422f78..9c39e49 100644 --- a/rtl/questasim/questasim.py +++ b/rtl/questasim/questasim.py @@ -123,6 +123,19 @@ def questasim_rtlcmd(self): interactive_string = ' -do "run -all; quit;"' self.print_log(type="I", msg="No interactive control file set.") + if self.dump_waves and not self.interactive_rtl: + vcdstring = ( + ' -do "vcd file ' + + self.rtlsimpath + + "/" + + self.name + + "_dump.vcd; vcd add -r /tb_" + + self.name + + '/*;"' + ) + else: + vcdstring = "" + # Choose command if not self.interactive_rtl: rtlsimcmd = ( @@ -135,6 +148,7 @@ def questasim_rtlcmd(self): + vlogsimargs + " work.tb_" + self.name + + vcdstring + controlstring ) else: diff --git a/rtl/testbench_common.py b/rtl/testbench_common.py index a6e915c..2625fa6 100644 --- a/rtl/testbench_common.py +++ b/rtl/testbench_common.py @@ -161,7 +161,7 @@ def dumpfile(self): if ( self.parent.model == "icarus" or self.parent.model == "verilator" - ) and self.parent.interactive_rtl: + ) and (self.parent.interactive_rtl or self.parent.dump_waves): dump_str = "// Generates dumpfile\n" dump_str += "initial begin\n" dump_str += ( From 60bf0eeb7c350195a37d7e4988c721ccda4c06c2 Mon Sep 17 00:00:00 2001 From: Aleksi Korsman Date: Tue, 18 Aug 2026 09:37:51 +0300 Subject: [PATCH 2/5] Define a property for dumpfile name and location --- rtl/__init__.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/rtl/__init__.py b/rtl/__init__.py index 1a6cde2..e1abeef 100644 --- a/rtl/__init__.py +++ b/rtl/__init__.py @@ -119,6 +119,30 @@ def dump_waves(self): def dump_waves(self, value): self._dump_waves = value + @property + def dumpfile_name(self): + """String (default '_dump.vcd') + + Basename of the VCD waveform dumpfile generated by interactive_rtl or + dump_waves. Set this to override the default name.""" + + if not hasattr(self, "_dumpfile_name"): + self._dumpfile_name = self.name + "_dump.vcd" + return self._dumpfile_name + + @dumpfile_name.setter + def dumpfile_name(self, value): + self._dumpfile_name = value + + @property + def dumpfilepath(self): + """String + + Full path to the VCD waveform dumpfile, i.e. dumpfile_name located in + rtlsimpath.""" + + return os.path.join(self.rtlsimpath, self.dumpfile_name) + @property def lsf_submission(self): """ From 56ab2f43aa493bbc527d98b4a0fec1a3dd750078 Mon Sep 17 00:00:00 2001 From: Aleksi Korsman Date: Tue, 18 Aug 2026 09:39:53 +0300 Subject: [PATCH 3/5] Preserve dumpfile when dump_waves=True --- rtl/__init__.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/rtl/__init__.py b/rtl/__init__.py index e1abeef..38491de 100644 --- a/rtl/__init__.py +++ b/rtl/__init__.py @@ -414,12 +414,19 @@ def rtlsimpath(self): return self._rtlsimpath def delete_rtlsimpath(self): - """Deletes all files in rtlsimpath""" + """Deletes all files in rtlsimpath. + + ``self.preserve_rtlfiles`` preserves all files under rtlsimpath from deletion. + ``self.dump_waves`` preserves the waveform dump file. + """ + dumpfilename = self.dumpfile_name if os.path.exists(self.rtlsimpath): try: for target in os.listdir(self.rtlsimpath): targetpath = "%s/%s" % (self.rtlsimpath, target) - if self.preserve_rtlfiles: + if self.preserve_rtlfiles or ( + self.dump_waves and target == dumpfilename + ): self.print_log( type="I", msg="Preserving %s" % targetpath ) @@ -432,7 +439,7 @@ def delete_rtlsimpath(self): except: self.print_log(type="W", msg="Could not remove %s" % targetpath) - if not self.preserve_rtlfiles: + if not self.preserve_rtlfiles and not self.dump_waves: try: shutil.rmtree(self.rtlsimpath) self.print_log( From 5b62c130a99e158cd1b6d0fbe96f0eceb358062d Mon Sep 17 00:00:00 2001 From: Aleksi Korsman Date: Tue, 18 Aug 2026 09:40:28 +0300 Subject: [PATCH 4/5] Use the new property instead of hardcoded name for wave dump --- rtl/ghdl/ghdl.py | 13 ++----------- rtl/icarus/icarus.py | 5 +---- rtl/questasim/questasim.py | 6 ++---- rtl/testbench_common.py | 6 +----- rtl/verilator/verilator.py | 5 +---- 5 files changed, 7 insertions(+), 28 deletions(-) diff --git a/rtl/ghdl/ghdl.py b/rtl/ghdl/ghdl.py index d5bde51..4fbe8bb 100644 --- a/rtl/ghdl/ghdl.py +++ b/rtl/ghdl/ghdl.py @@ -83,13 +83,7 @@ def ghdl_rtlcmd(self): interactive_string = "" self.print_log(type="I", msg="No interactive control file set.") - vcdstring = ( - " --vcd=" - + self.rtlsimpath - + "/" - + self.name - + "_dump.vcd" - ) + vcdstring = " --vcd=" + self.dumpfilepath if self.interactive_rtl: submission = "" # Local execution @@ -104,10 +98,7 @@ def ghdl_rtlcmd(self): + " && gtkwave " + interactive_string + " " - + self.rtlsimpath - + "/" - + self.name - + "_dump.vcd" + + self.dumpfilepath ) elif self.dump_waves: rtlsimcmd = ( diff --git a/rtl/icarus/icarus.py b/rtl/icarus/icarus.py index a8f0cf4..4e66672 100644 --- a/rtl/icarus/icarus.py +++ b/rtl/icarus/icarus.py @@ -77,10 +77,7 @@ def icarus_rtlcmd(self): + " && gtkwave " + dostring + " " - + self.rtlsimpath - + "/" - + self.name - + "_dump.vcd" + + self.dumpfilepath ) else: rtlsimcmd = ( diff --git a/rtl/questasim/questasim.py b/rtl/questasim/questasim.py index 9c39e49..96ddac0 100644 --- a/rtl/questasim/questasim.py +++ b/rtl/questasim/questasim.py @@ -126,10 +126,8 @@ def questasim_rtlcmd(self): if self.dump_waves and not self.interactive_rtl: vcdstring = ( ' -do "vcd file ' - + self.rtlsimpath - + "/" - + self.name - + "_dump.vcd; vcd add -r /tb_" + + self.dumpfilepath + + "; vcd add -r /tb_" + self.name + '/*;"' ) diff --git a/rtl/testbench_common.py b/rtl/testbench_common.py index 2625fa6..d2a6539 100644 --- a/rtl/testbench_common.py +++ b/rtl/testbench_common.py @@ -165,11 +165,7 @@ def dumpfile(self): dump_str = "// Generates dumpfile\n" dump_str += "initial begin\n" dump_str += ( - ' $dumpfile("' - + self.parent.rtlsimpath - + "/" - + self.parent.name - + '_dump.vcd");\n' + ' $dumpfile("' + self.parent.dumpfilepath + '");\n' ) dump_str += " $dumpvars(0, tb_" + self.parent.name + ");\nend \n" else: diff --git a/rtl/verilator/verilator.py b/rtl/verilator/verilator.py index 2d2c09b..4fe002f 100644 --- a/rtl/verilator/verilator.py +++ b/rtl/verilator/verilator.py @@ -84,10 +84,7 @@ def verilator_rtlcmd(self): + " && gtkwave " + dostring + " " - + self.rtlsimpath - + "/" - + self.name - + "_dump.vcd" + + self.dumpfilepath ) else: rtlsimcmd = "cd " + self.rtlworkpath + " && ./Vtb_" + self.name From 9c08c895d0dd8639014f96f351326c87d423120e Mon Sep 17 00:00:00 2001 From: Aleksi Korsman Date: Wed, 19 Aug 2026 12:58:06 +0300 Subject: [PATCH 5/5] Fix questa --- rtl/questasim/questasim.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rtl/questasim/questasim.py b/rtl/questasim/questasim.py index 96ddac0..eb54e37 100644 --- a/rtl/questasim/questasim.py +++ b/rtl/questasim/questasim.py @@ -127,9 +127,7 @@ def questasim_rtlcmd(self): vcdstring = ( ' -do "vcd file ' + self.dumpfilepath - + "; vcd add -r /tb_" - + self.name - + '/*;"' + + '; vcd add -r *;"' ) else: vcdstring = ""