From 6f3beca5fbe8fd828d22b0b68d04d05c7c705e40 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 29 Apr 2026 20:58:33 -0700 Subject: [PATCH 001/102] FST can dump packages --- ivtest/.gitignore | 1 + ivtest/gold/br_gh710d-vvp-stdout.gold | 1 + ivtest/regress-vvp.list | 1 + ivtest/vvp_tests/br_gh710d.json | 7 +++++++ 4 files changed, 10 insertions(+) create mode 100644 ivtest/gold/br_gh710d-vvp-stdout.gold create mode 100644 ivtest/vvp_tests/br_gh710d.json diff --git a/ivtest/.gitignore b/ivtest/.gitignore index 612f61d30..0482bb8d0 100644 --- a/ivtest/.gitignore +++ b/ivtest/.gitignore @@ -34,4 +34,5 @@ tmp_blif.vvp dump.vcd dump.lxt dump.lx2 +dump.fst foo.vcd diff --git a/ivtest/gold/br_gh710d-vvp-stdout.gold b/ivtest/gold/br_gh710d-vvp-stdout.gold new file mode 100644 index 000000000..ce8f6d257 --- /dev/null +++ b/ivtest/gold/br_gh710d-vvp-stdout.gold @@ -0,0 +1 @@ +FST info: dumpfile dump.fst opened for output. diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index fadf124b2..2cde03b79 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -31,6 +31,7 @@ br_gh703 vvp_tests/br_gh703.json br_gh710a vvp_tests/br_gh710a.json br_gh710b vvp_tests/br_gh710b.json br_gh710c vvp_tests/br_gh710c.json +br_gh710d vvp_tests/br_gh710d.json br_gh939 vvp_tests/br_gh939.json br_gh1001 vvp_tests/br_gh1001.json br_gh1018 vvp_tests/br_gh1018.json diff --git a/ivtest/vvp_tests/br_gh710d.json b/ivtest/vvp_tests/br_gh710d.json new file mode 100644 index 000000000..18d7f106b --- /dev/null +++ b/ivtest/vvp_tests/br_gh710d.json @@ -0,0 +1,7 @@ +{ + "type" : "normal", + "source" : "br_gh710.v", + "gold" : "br_gh710d", + "iverilog-args" : [ "-g2009" ], + "vvp-args-extended" : [ "-fst" ] +} From 68f461f5a98ef6b41366d991edd0161b04f10ea4 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 29 Apr 2026 13:09:05 +0200 Subject: [PATCH 002/102] configure.ac: Sort and reformat the list of generated config files If there is only one file per line, it is easier to add additional files. --- configure.ac | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a397d47d9..fa480039c 100644 --- a/configure.ac +++ b/configure.ac @@ -390,5 +390,26 @@ then AC_MSG_ERROR(cannot configure white space in libdir: $libdir) fi AC_MSG_RESULT(ok) -AC_CONFIG_FILES([Makefile ivlpp/Makefile vhdlpp/Makefile vvp/Makefile vpi/Makefile driver/Makefile driver-vpi/Makefile cadpli/Makefile libveriuser/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-vvp/Makefile tgt-vhdl/Makefile tgt-fpga/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vlog95/Makefile tgt-pcb/Makefile tgt-blif/Makefile tgt-sizer/Makefile]) +AC_CONFIG_FILES([ + Makefile + cadpli/Makefile + driver-vpi/Makefile + driver/Makefile + ivlpp/Makefile + libveriuser/Makefile + tgt-blif/Makefile + tgt-fpga/Makefile + tgt-null/Makefile + tgt-pal/Makefile + tgt-pcb/Makefile + tgt-sizer/Makefile + tgt-stub/Makefile + tgt-verilog/Makefile + tgt-vhdl/Makefile + tgt-vlog95/Makefile + tgt-vvp/Makefile + vhdlpp/Makefile + vpi/Makefile + vvp/Makefile +]) AC_OUTPUT From 10b5f70e71efc70497d404c86b14fb3470c18769 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 18 Mar 2026 09:22:46 +0100 Subject: [PATCH 003/102] Move version info into configure.ac and generate version_base.h from template --- Makefile.in | 7 +++++-- configure.ac | 14 +++++++++++++- driver/Makefile.in | 2 +- ivlpp/Makefile.in | 2 +- scripts/CREATE_BRANCH.sh | 22 ++++++++++++---------- scripts/CREATE_RELEASE.sh | 22 ++++++++++++---------- scripts/CREATE_VERSION.sh | 2 +- version_base.h => version_base.h.in | 11 ++++++----- 8 files changed, 51 insertions(+), 31 deletions(-) rename version_base.h => version_base.h.in (52%) diff --git a/Makefile.in b/Makefile.in index 160af3de5..06bb13f65 100644 --- a/Makefile.in +++ b/Makefile.in @@ -169,7 +169,7 @@ clean: rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps rm -f iverilog_man.ps iverilog_man.pdf iverilog_man_`./version.exe %M_%n`.pdf rm -f parse.output syn-rules.output dosify$(BUILDEXT) ivl@EXEEXT@ check.vvp - rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc + rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc version_base.h rm -rf dep rm -f version.exe @@ -251,7 +251,10 @@ iverilog-vpi: $(srcdir)/iverilog-vpi.sh Makefile chmod +x $@ endif -version.exe: $(srcdir)/version.c $(srcdir)/version_base.h version_tag.h +version_base.h: $(srcdir)/version_base.h.in config.status + ./config.status --file=$@ + +version.exe: $(srcdir)/version.c version_base.h version_tag.h $(BUILDCC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o version.exe -I. -I$(srcdir) $(srcdir)/version.c %.o: %.cc config.h | dep diff --git a/configure.ac b/configure.ac index fa480039c..e741eb1e3 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,18 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT + AC_CONFIG_MACRO_DIRS([m4]) +dnl Define project version +m4_define([VER_MAJOR], [14]) +m4_define([VER_MINOR], [0]) +m4_define([VER_EXTRA], [devel]) + +AC_INIT([iverilog], [VER_MAJOR.VER_MINOR (VER_EXTRA)]) +AC_SUBST([VERSION_MAJOR], [VER_MAJOR]) +AC_SUBST([VERSION_MINOR], [VER_MINOR]) +AC_SUBST([VERSION_EXTRA], [" (VER_EXTRA)"]) +AC_SUBST([VERSION], ["VER_MAJOR.VER_MINOR (VER_EXTRA)"]) + AC_CONFIG_SRCDIR([netlist.h]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([_pli_types.h]) @@ -408,6 +419,7 @@ AC_CONFIG_FILES([ tgt-vhdl/Makefile tgt-vlog95/Makefile tgt-vvp/Makefile + version_base.h vhdlpp/Makefile vpi/Makefile vvp/Makefile diff --git a/driver/Makefile.in b/driver/Makefile.in index 38ab633a9..46caaf609 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -96,7 +96,7 @@ cfparse%c cfparse%h: $(srcdir)/cfparse%y $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep -main.o: main.c globals.h $(srcdir)/../version_base.h ../version_tag.h Makefile | dep +main.o: main.c globals.h ../version_base.h ../version_tag.h Makefile | dep $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c -DIVL_ROOT='"@libdir@/ivl$(suffix)"' -DIVL_SUFFIX='"$(suffix)"' -DIVL_INC='"@includedir@"' -DIVL_LIB='"@libdir@"' -DDLLIB='"@DLLIB@"' -DIVL_INCLUDE_INSTALL_DIR="\"$(realpath $(DESTDIR)/$(includedir))\"" $(srcdir)/main.c mv $*.d dep diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index 2fa327d26..7fdd9e2fb 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -89,4 +89,4 @@ uninstall: rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/ivlpp@EXEEXT@" lexor.o: lexor.c globals.h -main.o: main.c globals.h $(srcdir)/../version_base.h ../version_tag.h +main.o: main.c globals.h ../version_base.h ../version_tag.h diff --git a/scripts/CREATE_BRANCH.sh b/scripts/CREATE_BRANCH.sh index e35546072..440ff0800 100644 --- a/scripts/CREATE_BRANCH.sh +++ b/scripts/CREATE_BRANCH.sh @@ -5,10 +5,10 @@ # # 1. It creates a new branch with the proper name. # -# 2. It then updates the version_base.h to match this version. It likely +# 2. It then updates the configure.ac to match this version. It likely # already does, but it is incorrectly marked as devel instead of stable. # -# 3. It updates the default suffix in aclocal.m4 to match the branch. +# 3. It updates the default suffix in m4/ax_enable_suffix.m4 to match the branch. # # Now manually push the new branch to the master repository. # @@ -27,7 +27,8 @@ case $1 in esac major=$1 - +minor=0 +extra="stable" branch="v${major}-branch" branch_exists=`git ls-remote --heads origin $branch` @@ -39,16 +40,17 @@ fi echo "Creating branch $branch" git checkout -b $branch -echo "Updating version_base.h..." -sed -i -E "s/(define\s+VERSION_MAJOR\s+).*/\1$major/" version_base.h -sed -i -E "s/(define\s+VERSION_MINOR\s+).*/\10/" version_base.h -sed -i -E "s/(define\s+VERSION_EXTRA\s+).*/\1\" \(stable\)\"/" version_base.h +file=configure.ac +echo "Updating $file..." +sed -i -E "s/(m4_define\(\[VER_MAJOR\],[[:space:]]*\[)[^]]*(\]\))/\1$major\2/" $file +sed -i -E "s/(m4_define\(\[VER_MINOR\],[[:space:]]*\[)[^]]*(\]\))/\1$minor\2/" $file +sed -i -E "s/(m4_define\(\[VER_EXTRA\],[[:space:]]*\[)[^]]*(\]\))/\1$extra\2/" $file -echo "Updating aclocal.m4..." -sed -i -E "s/(install_suffix='-)dev/\1$major/" aclocal.m4 +echo "Updating m4/ax_enable_suffix.m4..." +sed -i -E "s/(install_suffix='-)dev/\1$major/" m4/ax_enable_suffix.m4 echo "Adding updated files to the new branch..." -git add version_base.h aclocal.m4 +git add configure.ac m4/ax_enable_suffix.m4 git commit -m "Creating new branch $branch" echo "Done" diff --git a/scripts/CREATE_RELEASE.sh b/scripts/CREATE_RELEASE.sh index 9bff3b652..9da7dad02 100644 --- a/scripts/CREATE_RELEASE.sh +++ b/scripts/CREATE_RELEASE.sh @@ -4,10 +4,10 @@ # based on the first and second argument passed to the script, which should # be the desired major and minor numbers for the release. Before creating the # tag, autoconf.sh will be run to create the configure and lexor_keyword.cc -# files, the version_base.h and verilog.spec files will be updated to reflect -# the new release ID and a release_tag.h file will be created in the top level -# directory to provide the VERSION_TAG macro. After creating the tag, the -# configure, lexor_keywords.cc, and release_tag.h files will be deleted. +# files, the verilog.spec file will be updated to reflect the new release ID +# and a release_tag.h file will be created in the top level directory to +# provide the VERSION_TAG macro. After creating the tag, the configure, +# lexor_keywords.cc, and release_tag.h files will be deleted. # # The complete steps to publish a release are: # @@ -44,6 +44,13 @@ if [ -n "$tag_exists" ] ; then exit 1 fi +extra="stable" +file=configure.ac +echo "Updating $file..." +sed -i -E "s/(m4_define\(\[VER_MAJOR\],[[:space:]]*\[)[^]]*(\]\))/\1$major\2/" $file +sed -i -E "s/(m4_define\(\[VER_MINOR\],[[:space:]]*\[)[^]]*(\]\))/\1$minor\2/" $file +sed -i -E "s/(m4_define\(\[VER_EXTRA\],[[:space:]]*\[)[^]]*(\]\))/\1$extra\2/" $file + echo "Executing autoconf.sh..." sh autoconf.sh if [ $? -ne 0 ] ; then @@ -51,11 +58,6 @@ if [ $? -ne 0 ] ; then exit 1 fi -echo "Updating version_base.h..." -sed -i -E "s/(define\s+VERSION_MAJOR\s+).*/\1$major/" version_base.h -sed -i -E "s/(define\s+VERSION_MINOR\s+).*/\1$minor/" version_base.h -sed -i -E "s/(define\s+VERSION_EXTRA\s+).*/\1\" \(stable\)\"/" version_base.h - echo "Updating verilog.spec..." sed -i -E "s/(define\s+major\s+).*/\1$major/" verilog.spec sed -i -E "s/(define\s+minor\s+).*/\1$minor/" verilog.spec @@ -66,7 +68,7 @@ echo "#define VERSION_TAG \"$tag\"" > release_tag.h echo "Adding files and creating the tag..." git add -f configure lexor_keyword.cc vhdlpp/lexor_keyword.cc -git add version_base.h verilog.spec release_tag.h +git add configure.ac verilog.spec release_tag.h git commit -m "Creating release $tag" git tag -a -m "Release $major.$minor" $tag diff --git a/scripts/CREATE_VERSION.sh b/scripts/CREATE_VERSION.sh index 450f21370..8cecaba62 100644 --- a/scripts/CREATE_VERSION.sh +++ b/scripts/CREATE_VERSION.sh @@ -1,6 +1,6 @@ #!/bin/sh -# This script manually creates a version.h file. +# This script manually creates a version_tag.h file. # # It is used when creating a MinGW executable from a Cygwin # hosted git repository. It assumes that git is available. diff --git a/version_base.h b/version_base.h.in similarity index 52% rename from version_base.h rename to version_base.h.in index 46b0e93eb..750e8c02e 100644 --- a/version_base.h +++ b/version_base.h.in @@ -1,16 +1,17 @@ #ifndef VERSION /* - * Edit this definition in version_base.in to define the base version - * number for the compiled result. + * This file is generated from version_base.h.in by the build system + * + * WARNING! All changes made in this file will be lost when recompiling! */ -# define VERSION_MAJOR 14 -# define VERSION_MINOR 0 +#define VERSION_MAJOR @VERSION_MAJOR@ +#define VERSION_MINOR @VERSION_MINOR@ /* * This will be appended to the version. Use this to mark development * versions and the like. */ -# define VERSION_EXTRA " (devel)" +# define VERSION_EXTRA "@VERSION_EXTRA@" # define VERSION_STRINGIFY(x) #x # define VERSION_STR(a,b,extra) VERSION_STRINGIFY(a.b) extra From 92d345ddb2836d753112d271a013034bea0ab698 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Thu, 9 Apr 2026 16:51:17 +0200 Subject: [PATCH 004/102] Use autoconf variables in generated man and pdf output --- Makefile.in | 13 +++++++------ configure.ac | 6 ++++++ driver-vpi/Makefile.in | 5 ++--- driver/Makefile.in | 5 ++--- driver/iverilog.man.in | 2 +- iverilog-vpi.man.in | 2 +- vvp/Makefile.in | 5 ++--- vvp/vvp.man.in | 2 +- 8 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Makefile.in b/Makefile.in index 06bb13f65..249f85c78 100644 --- a/Makefile.in +++ b/Makefile.in @@ -36,6 +36,8 @@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ datarootdir = @datarootdir@ +VERSION_MAJOR = @VERSION_MAJOR@ +VERSION_MINOR = @VERSION_MINOR@ SUBDIRS = ivlpp vhdlpp vvp vpi tgt-null tgt-stub tgt-vvp \ tgt-vhdl tgt-vlog95 tgt-pcb tgt-blif tgt-sizer driver @@ -167,7 +169,7 @@ clean: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true rm -f *.o parse.cc parse.h lexor.cc rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps - rm -f iverilog_man.ps iverilog_man.pdf iverilog_man_`./version.exe %M_%n`.pdf + rm -f iverilog_man.ps iverilog_man.pdf iverilog_man_$(VERSION_MAJOR)_$(VERSION_MINOR).pdf rm -f parse.output syn-rules.output dosify$(BUILDEXT) ivl@EXEEXT@ check.vvp rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc version_base.h rm -rf dep @@ -283,9 +285,8 @@ lexor_keyword.o: lexor_keyword.cc parse.h lexor_keyword.cc: $(srcdir)/lexor_keyword.gperf gperf -o -i 7 -C -k 1-4,6,9,$$ -H keyword_hash -N check_identifier -t $< > $@ || (rm -f $@ ; false) -iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in version.exe - ./version.exe `head -1 $<`'\n' > $@ - tail -n +2 $< >> $@ +iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in config.status + ./config.status --file=$@ iverilog-vpi.ps: iverilog-vpi.man $(MAN) -t ./$< > $@ @@ -296,9 +297,9 @@ iverilog-vpi.pdf: iverilog-vpi.ps iverilog_man.ps: driver/iverilog.man vvp/vvp.man iverilog-vpi.man $(GROFF) -man -rC1 -rD1 -T ps $^ > $@ -iverilog_man.pdf: iverilog_man.ps version.exe +iverilog_man.pdf: iverilog_man.ps $(PS2PDF) $< $@ - cp $@ iverilog_man_`./version.exe %M_%n`.pdf + cp $@ iverilog-vpi.man_$(VERSION_MAJOR)_$(VERSION_MINOR).pdf # For VERSION_TAG in driver/main.c, first try git-describe, then look for a # release_tag.h file in the source tree (included in snapshots and releases), diff --git a/configure.ac b/configure.ac index e741eb1e3..363010118 100644 --- a/configure.ac +++ b/configure.ac @@ -12,6 +12,8 @@ AC_SUBST([VERSION_MAJOR], [VER_MAJOR]) AC_SUBST([VERSION_MINOR], [VER_MINOR]) AC_SUBST([VERSION_EXTRA], [" (VER_EXTRA)"]) AC_SUBST([VERSION], ["VER_MAJOR.VER_MINOR (VER_EXTRA)"]) +# used in res.rc +AC_SUBST([PRODUCTVERSION], ["VER_MAJOR,VER_MINOR,0,0"]) AC_CONFIG_SRCDIR([netlist.h]) AC_CONFIG_HEADERS([config.h]) @@ -405,7 +407,10 @@ AC_CONFIG_FILES([ Makefile cadpli/Makefile driver-vpi/Makefile + driver-vpi/res.rc driver/Makefile + driver/iverilog.man + iverilog-vpi.man ivlpp/Makefile libveriuser/Makefile tgt-blif/Makefile @@ -423,5 +428,6 @@ AC_CONFIG_FILES([ vhdlpp/Makefile vpi/Makefile vvp/Makefile + vvp/vvp.man ]) AC_OUTPUT diff --git a/driver-vpi/Makefile.in b/driver-vpi/Makefile.in index bb8d66bc2..6a0790cf6 100644 --- a/driver-vpi/Makefile.in +++ b/driver-vpi/Makefile.in @@ -95,9 +95,8 @@ else endif # Windows specific... -res.rc: $(srcdir)/res.rc.in ../version.exe - sed -e 's;@PRODUCTVERSION@;'`../version.exe '%M,%n,0,0'`';' \ - $(srcdir)/res.rc.in > $@ +res.rc: $(srcdir)/res.rc.in ../config.status + cd ..; ./config.status --file=driver-vpi/$@ res.o: res.rc $(WINDRES) -i res.rc -o res.o diff --git a/driver/Makefile.in b/driver/Makefile.in index 46caaf609..73f79100f 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -102,9 +102,8 @@ main.o: main.c globals.h ../version_base.h ../version_tag.h Makefile | dep cflexor.o: cflexor.c cfparse.h -iverilog.man: $(srcdir)/iverilog.man.in ../version.exe - ../version.exe `head -1 $<`'\n' > $@ - tail -n +2 $< >> $@ +iverilog.man: $(srcdir)/iverilog.man.in ../config.status + cd ..; ./config.status --file=driver/$@ iverilog.ps: iverilog.man $(MAN) -t ./$< > $@ diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 21dbf72dc..4ff682a48 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -1,4 +1,4 @@ -.TH iverilog 1 "Jan 13th, 2026" "" "Version %M.%n%E" +.TH iverilog 1 "Jan 13th, 2026" "" "Version @VERSION@" .SH NAME iverilog - Icarus Verilog compiler diff --git a/iverilog-vpi.man.in b/iverilog-vpi.man.in index 23741e1c2..13a85a586 100644 --- a/iverilog-vpi.man.in +++ b/iverilog-vpi.man.in @@ -1,4 +1,4 @@ -.TH iverilog-vpi 1 "Jan 13th, 2026" "" "Version %M.%n%E" +.TH iverilog-vpi 1 "Jan 13th, 2026" "" "Version @VERSION@" .SH NAME iverilog-vpi - Compile front end for VPI modules diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 0ae99b13b..30f85fdf3 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -186,9 +186,8 @@ parse%cc parse%h: $(srcdir)/parse%y lexor.cc: $(srcdir)/lexor.lex $(LEX) -s -o$@ $< -vvp.man: $(srcdir)/vvp.man.in ../version.exe - ../version.exe `head -1 $<`'\n' > $@ - tail -n +2 $< >> $@ +vvp.man: $(srcdir)/vvp.man.in ../config.status + cd ..; ./config.status --file=vvp/$@ vvp.ps: vvp.man $(MAN) -t ./$< > $@ diff --git a/vvp/vvp.man.in b/vvp/vvp.man.in index c7d64d9b4..8da9ef816 100644 --- a/vvp/vvp.man.in +++ b/vvp/vvp.man.in @@ -1,4 +1,4 @@ -.TH vvp 1 "Jan 13th, 2026" "" "Version %M.%n %E" +.TH vvp 1 "Jan 13th, 2026" "" "Version @VERSION@" .SH NAME vvp - Icarus Verilog vvp runtime engine From 731891b58f4cff40a5934d4dac941836773c8342 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Thu, 9 Apr 2026 17:07:04 +0200 Subject: [PATCH 005/102] Update documentation to clarify that 'version.exe' is no longer used --- Documentation/developer/version_stamps.rst | 2 +- Documentation/usage/installation.rst | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Documentation/developer/version_stamps.rst b/Documentation/developer/version_stamps.rst index 3e84ddb37..5342d9aff 100644 --- a/Documentation/developer/version_stamps.rst +++ b/Documentation/developer/version_stamps.rst @@ -17,7 +17,7 @@ the "make version" target, or automatically if the version_tag.h file doesn't exist at all. This implies that a "make version" is something worth doing when you do a "git pull" or create commits. -The files below are now edited by the Makefile and the version.exe program: +The files below are now edited by the Makefile: * iverilog-vpi.man -- The .TH tag has a version string * driver/iverilog.man -- The .TH tag has a version string diff --git a/Documentation/usage/installation.rst b/Documentation/usage/installation.rst index 090f020f0..e79d26fa5 100644 --- a/Documentation/usage/installation.rst +++ b/Documentation/usage/installation.rst @@ -373,7 +373,5 @@ Next, compile with the command:: $ make -The configure generated the cross compiler flags, but there are a few -bits that need to be compiled with the native compiler. (version.exe -for example is used by the build process but is not installed.) The +The configure generated the cross compiler flags. The configure script should have gotten all that right. From 49eaafe886edc85d064df40be7ef2dce034b108f Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 29 Apr 2026 13:01:59 +0200 Subject: [PATCH 006/102] Remove support for creating 'version.exe' from the build system Since this functionality has now been taken over by the build system and is no longer needed, it can be removed from the build system. --- Makefile.in | 6 +--- version.c | 85 ----------------------------------------------------- 2 files changed, 1 insertion(+), 90 deletions(-) delete mode 100644 version.c diff --git a/Makefile.in b/Makefile.in index 249f85c78..f94707363 100644 --- a/Makefile.in +++ b/Makefile.in @@ -134,7 +134,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o PTimingCheck.o \ PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT) -all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man +all: dep config.h _pli_types.h version_tag.h version_base.h ivl@EXEEXT@ iverilog-vpi.man $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true # In the windows world, the installer will need a dosify program to @@ -173,7 +173,6 @@ clean: rm -f parse.output syn-rules.output dosify$(BUILDEXT) ivl@EXEEXT@ check.vvp rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc version_base.h rm -rf dep - rm -f version.exe distclean: clean $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true @@ -256,9 +255,6 @@ endif version_base.h: $(srcdir)/version_base.h.in config.status ./config.status --file=$@ -version.exe: $(srcdir)/version.c version_base.h version_tag.h - $(BUILDCC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o version.exe -I. -I$(srcdir) $(srcdir)/version.c - %.o: %.cc config.h | dep $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep/$*.d diff --git a/version.c b/version.c deleted file mode 100644 index 64e4178c2..000000000 --- a/version.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2009-2015 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 - * General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -# include "version_base.h" -# include "version_tag.h" -# include -# include - -static void run_string(const char*txt) -{ - const char*cp = txt; - while (*cp) { - if (cp[0] == '%' && cp[1] != 0) { - switch (cp[1]) { - case 'M': - fprintf(stdout, "%d", VERSION_MAJOR); - break; - case 'n': - fprintf(stdout, "%d", VERSION_MINOR); - break; - case 'E': - fprintf(stdout, "%s", VERSION_EXTRA); - break; - case 'T': - fprintf(stdout, "%s", VERSION_TAG); - break; - case '%': - putc('%', stdout); - break; - default: - break; - } - cp += 2; - - } else if (cp[0] == '\\' && cp[1] != 0) { - switch (cp[1]) { - case 'n': - putc('\n', stdout); - break; - default: - putc(cp[1], stdout); - break; - } - cp += 2; - - } else { - putc(cp[0], stdout); - cp += 1; - } - } -} - -int main(int argc, char*argv[]) -{ - int idx; - - if (argc == 1) { - printf("%s\n", VERSION); - return 0; - } - - run_string(argv[1]); - for (idx = 2 ; idx < argc ; idx += 1) { - printf(" "); - run_string(argv[idx]); - } - - return 0; -} From c14c73dd9a734cede1684ddfa0c2c97342e98d63 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 27 Apr 2026 13:57:03 +0200 Subject: [PATCH 007/102] ivtest: Integration of regression tests into the build system Replace .github/test.sh with a unified set of targets installed via `make check-*` in ivtest/, thereby removing CI-specific test coordination. This avoids duplication in the regression logic and ensures consistent execution between local and CI environments. PLI1-dependent tests are now correctly controlled via `configure --enable-libveriuser`. Currently, the regression suite still depends on an iverilog package, which must be installed manually at the location specified with `configure --prefix=*`. Afterward, the complete regression suite (VVP, VPI, and Python tests) can be run via `make check-installed` and individual checks can be run with `check-installed-vpi`, `check-installed-vvp` and `check-installed-vvp-py`. --- .github/test.sh | 20 ----------- .github/workflows/test.yml | 12 +++---- Makefile.in | 8 ++++- configure.ac | 1 + ivtest/Makefile.in | 70 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 28 deletions(-) delete mode 100755 .github/test.sh create mode 100644 ivtest/Makefile.in diff --git a/.github/test.sh b/.github/test.sh deleted file mode 100755 index 362020f3d..000000000 --- a/.github/test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env sh - -echo "Using the bundled ivtest to run regression tests." -echo " pwd = $(pwd)" - -cd ivtest - -status=0 - -perl vvp_reg.pl || status=1 - -if [ "x$1" = "xno-pli1" ] ; then - perl vpi_reg.pl || status=1 -else - perl vpi_reg.pl --with-pli1 || status=1 -fi - -python3 vvp_reg.py || status=1 - -exit $status diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5197876b9..3dfaa7f89 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,8 @@ jobs: sudo make install - name: Test - run: ./.github/test.sh + run: | + make check-installed lin: @@ -64,7 +65,8 @@ jobs: sudo make install - name: Test - run: ./.github/test.sh + run: + make check-installed - name: Documentation run: | @@ -120,11 +122,7 @@ jobs: - name: Test run: | - if [ ${{ matrix.msystem }} = "CLANG64" ] ; then - ./.github/test.sh no-pli1 - else - ./.github/test.sh - fi + make check-installed - uses: actions/upload-artifact@v4 with: diff --git a/Makefile.in b/Makefile.in index f94707363..86ede6b2e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -40,7 +40,8 @@ VERSION_MAJOR = @VERSION_MAJOR@ VERSION_MINOR = @VERSION_MINOR@ SUBDIRS = ivlpp vhdlpp vvp vpi tgt-null tgt-stub tgt-vvp \ - tgt-vhdl tgt-vlog95 tgt-pcb tgt-blif tgt-sizer driver + tgt-vhdl tgt-vlog95 tgt-pcb tgt-blif tgt-sizer driver \ + ivtest # Only run distclean for these directories. NOTUSED = tgt-fpga tgt-pal tgt-verilog @@ -165,6 +166,9 @@ else $(ENV_VVP) vvp/vvp -M- -M./vpi ./check.vvp | grep 'Hello, World' endif +check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py: + $(MAKE) -C ivtest $@ + clean: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true rm -f *.o parse.cc parse.h lexor.cc @@ -407,3 +411,5 @@ uninstall: -include $(patsubst %.o, dep/%.d, $O) + +.PHONY: check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py diff --git a/configure.ac b/configure.ac index 363010118..b260ceb5d 100644 --- a/configure.ac +++ b/configure.ac @@ -412,6 +412,7 @@ AC_CONFIG_FILES([ driver/iverilog.man iverilog-vpi.man ivlpp/Makefile + ivtest/Makefile libveriuser/Makefile tgt-blif/Makefile tgt-fpga/Makefile diff --git a/ivtest/Makefile.in b/ivtest/Makefile.in new file mode 100644 index 000000000..ba7667d07 --- /dev/null +++ b/ivtest/Makefile.in @@ -0,0 +1,70 @@ +# +# This source code is free software; you can redistribute it +# and/or modify it in source code form under the terms of the GNU +# Library General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +SHELL = /bin/sh + +abs_srcdir=@abs_srcdir@ +srcdir=@srcdir@ +suffix = @install_suffix@ +ifeq (@install_suffix@,) +opts = +else +opts = --suffix=$(suffix) +endif + +all: + +check: + +check-installed: + @status=0; \ + $(MAKE) check-installed-vpi || status=1; \ + $(MAKE) check-installed-vvp || status=1; \ + $(MAKE) check-installed-vvp-py || status=1; \ + exit $$status + +check-installed-vpi: + @echo "Running vpi_reg.pl" +ifeq (@LIBVERIUSER@,yes) + cd $(abs_srcdir); perl vpi_reg.pl --with-pli1 $(opts) +else + cd $(abs_srcdir); perl vpi_reg.pl $(opts) +endif + +check-installed-vvp: + @echo "Running vvp_reg.pl" + cd $(abs_srcdir); perl vvp_reg.pl $(opts) + +check-installed-vvp-py: + @echo "Running vvp_reg.py" + cd $(abs_srcdir); python3 vvp_reg.py $(opts) + +clean: + rm -f $(srcdir)/*.vpi + rm -rf $(srcdir)/log $(srcdir)/vpi_log $(srcdir)/work + +distclean: clean + rm -f Makefile + +install: + +uninstall: + +Makefile: $(srcdir)/Makefile.in ../config.status + cd ..; ./config.status --file=ivtest/$@ + +.PHONY: check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py From 6c52271afae9cfebb3c3270bf37d409e29b23138 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 30 Apr 2026 08:30:50 -0700 Subject: [PATCH 008/102] Reorder check-installed targets --- ivtest/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivtest/Makefile.in b/ivtest/Makefile.in index ba7667d07..a68469b04 100644 --- a/ivtest/Makefile.in +++ b/ivtest/Makefile.in @@ -32,9 +32,9 @@ check: check-installed: @status=0; \ - $(MAKE) check-installed-vpi || status=1; \ $(MAKE) check-installed-vvp || status=1; \ $(MAKE) check-installed-vvp-py || status=1; \ + $(MAKE) check-installed-vpi || status=1; \ exit $$status check-installed-vpi: From 08461986026bde71ffa7a8ee50973720def1d9a5 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sat, 2 May 2026 06:20:58 +0200 Subject: [PATCH 009/102] Makefile.in, driver/Makefile.in: fix setup of generated doc types for iverilog* This resolves an issue where the man page is built even if the 'man' program is not installed. --- Makefile.in | 35 ++++++++++++----------------------- driver/Makefile.in | 38 +++++++++++++++----------------------- 2 files changed, 27 insertions(+), 46 deletions(-) diff --git a/Makefile.in b/Makefile.in index 86ede6b2e..648e78f74 100644 --- a/Makefile.in +++ b/Makefile.in @@ -71,8 +71,8 @@ libdir = @libdir@ # This is actually the directory where we install our own header files. # It is a little different from the generic includedir. includedir = @includedir@/iverilog$(suffix) -mandir = @mandir@ -pdfdir = @docdir@ +man1dir = @mandir@/man1 +docdir = @docdir@ dllib=@DLLIB@ @@ -325,26 +325,15 @@ version_tag.h version: echo '#define VERSION_TAG ""' > version_tag.h; \ fi +INSTALL_DOC = +ifneq ($(MAN),none) +INSTALL_DOC += installman +ifneq ($(PS2PDF),none) ifeq (@MINGW32@,yes) -ifeq ($(MAN),none) -INSTALL_DOC = installman -INSTALL_PDFDIR = $(prefix) -else -ifeq ($(PS2PDF),none) -INSTALL_DOC = installman -INSTALL_PDFDIR = $(prefix) -else -INSTALL_DOC = installpdf installman -INSTALL_PDFDIR = $(pdfdir) -all: dep iverilog-vpi.pdf +INSTALL_DOC += installpdf +all: iverilog-vpi.pdf endif endif -INSTALL_DOCDIR = $(mandir)/man1 -else -INSTALL_DOC = installman -INSTALL_DOCDIR = $(mandir)/man1 -INSTALL_PDFDIR = $(prefix) -endif ifeq (@MINGW32@,yes) WIN32_INSTALL = @@ -392,8 +381,8 @@ installdirs: $(srcdir)/mkinstalldirs "$(DESTDIR)$(includedir)" \ "$(DESTDIR)$(libdir)/ivl$(suffix)" \ "$(DESTDIR)$(libdir)/ivl$(suffix)/include" \ - "$(DESTDIR)$(INSTALL_DOCDIR)" \ - "$(DESTDIR)$(INSTALL_PDFDIR)" + "$(DESTDIR)$(docdir)" \ + "$(DESTDIR)$(man1dir)" uninstall: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true @@ -406,8 +395,8 @@ uninstall: for f in ivl_target.h vpi_user.h _pli_types.h sv_vpi_user.h acc_user.h veriuser.h; \ do rm -f "$(DESTDIR)$(includedir)/$$f"; done -test X$(suffix) = X || rmdir "$(DESTDIR)$(includedir)" - rm -f "$(DESTDIR)$(mandir)/man1/iverilog-vpi$(suffix).1" \ - "$(DESTDIR)$(pdfdir)/iverilog-vpi$(suffix).pdf" + rm -f "$(DESTDIR)$(man1dir)/iverilog-vpi$(suffix).1" \ + "$(DESTDIR)$(docdir)/iverilog-vpi$(suffix).pdf" -include $(patsubst %.o, dep/%.d, $O) diff --git a/driver/Makefile.in b/driver/Makefile.in index 73f79100f..f0c6831ce 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -29,8 +29,8 @@ VPATH = $(srcdir) bindir = $(exec_prefix)/bin libdir = $(exec_prefix)/lib includedir = $(prefix)/include -mandir = @mandir@ -pdfdir = @docdir@ +man1dir = @mandir@/man1 +docdir = @docdir@ dllib=@DLLIB@ @@ -111,25 +111,15 @@ iverilog.ps: iverilog.man iverilog.pdf: iverilog.ps $(PS2PDF) $< $@ +INSTALL_DOC = +ifneq ($(MAN),none) +INSTALL_DOC += installman +ifneq ($(PS2PDF),none) ifeq (@MINGW32@,yes) -ifeq ($(MAN),none) -INSTALL_DOC = installman -INSTALL_PDFDIR = $(prefix) -else -ifeq ($(PS2PDF),none) -INSTALL_DOC = installman -INSTALL_PDFDIR = $(prefix) -else -INSTALL_DOC = installpdf installman -INSTALL_PDFDIR = $(pdfdir) +INSTALL_DOC += installpdf all: iverilog.pdf endif endif -INSTALL_DOCDIR = $(mandir)/man1 -else -INSTALL_DOC = installman -INSTALL_DOCDIR = $(mandir)/man1 -INSTALL_PDFDIR = $(prefix) endif install: all installdirs installfiles @@ -138,21 +128,23 @@ F = ./iverilog@EXEEXT@ \ $(INSTALL_DOC) installman: iverilog.man installdirs - $(INSTALL_DATA) iverilog.man "$(DESTDIR)$(mandir)/man1/iverilog$(suffix).1" + $(INSTALL_DATA) iverilog.man "$(DESTDIR)$(man1dir)/iverilog$(suffix).1" installpdf: iverilog.pdf installdirs - $(INSTALL_DATA) iverilog.pdf "$(DESTDIR)$(pdfdir)/iverilog$(suffix).pdf" + $(INSTALL_DATA) iverilog.pdf "$(DESTDIR)$(docdir)/iverilog$(suffix).pdf" installfiles: $(F) | installdirs $(INSTALL_PROGRAM) ./iverilog@EXEEXT@ "$(DESTDIR)$(bindir)/iverilog$(suffix)@EXEEXT@" installdirs: $(srcdir)/../mkinstalldirs - $(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" \ - "$(DESTDIR)$(INSTALL_DOCDIR)" \ - "$(DESTDIR)$(INSTALL_PDFDIR)" + $(srcdir)/../mkinstalldirs \ + "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(docdir)" \ + "$(DESTDIR)$(man1dir)" uninstall: rm -f "$(DESTDIR)$(bindir)/iverilog$(suffix)@EXEEXT@" - rm -f "$(DESTDIR)$(mandir)/man1/iverilog$(suffix).1" "$(DESTDIR)$(pdfdir)/iverilog$(suffix).pdf" + rm -f "$(DESTDIR)$(man1dir)/iverilog$(suffix).1" \ + "$(DESTDIR)$(docdir)/iverilog$(suffix).pdf" -include $(patsubst %.o, dep/%.d, $O) From 9b42bf0df68cbf71832fc1ce1ce9bd8338c0ac0e Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sat, 2 May 2026 12:41:56 +0200 Subject: [PATCH 010/102] Makefile.in, vvp/Makefile.in: introduce ivl_includedir This variable was introduced to avoid conflicts with the existing `includedir` variable, which is used for the general include directory. --- Makefile.in | 22 +++++++++++----------- vvp/Makefile.in | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Makefile.in b/Makefile.in index 648e78f74..6b83c4977 100644 --- a/Makefile.in +++ b/Makefile.in @@ -70,7 +70,7 @@ bindir = @bindir@ libdir = @libdir@ # This is actually the directory where we install our own header files. # It is a little different from the generic includedir. -includedir = @includedir@/iverilog$(suffix) +ivl_includedir = @includedir@/iverilog$(suffix) man1dir = @mandir@/man1 docdir = @docdir@ @@ -251,7 +251,7 @@ iverilog-vpi: $(srcdir)/iverilog-vpi.sh Makefile -e 's;@IVCFLAGS@;$(CFLAGS);' \ -e 's;@IVCXXFLAGS@;$(CXXFLAGS);' \ -e 's;@IVCTARGETFLAGS@;$(CTARGETFLAGS);' \ - -e 's;@INCLUDEDIR@;$(includedir);' \ + -e 's;@INCLUDEDIR@;$(ivl_includedir);' \ -e 's;@LIBDIR@;@libdir@;' $< > $@ chmod +x $@ endif @@ -369,16 +369,16 @@ installfiles: $(F) | installdirs $(INSTALL_PROGRAM) ./ivl@EXEEXT@ "$(DESTDIR)$(libdir)/ivl$(suffix)/ivl@EXEEXT@" $(INSTALL_DATA) $(srcdir)/constants.vams "$(DESTDIR)$(libdir)/ivl$(suffix)/include/constants.vams" $(INSTALL_DATA) $(srcdir)/disciplines.vams "$(DESTDIR)$(libdir)/ivl$(suffix)/include/disciplines.vams" - $(INSTALL_DATA) $(srcdir)/ivl_target.h "$(DESTDIR)$(includedir)/ivl_target.h" - $(INSTALL_DATA) ./_pli_types.h "$(DESTDIR)$(includedir)/_pli_types.h" - $(INSTALL_DATA) $(srcdir)/sv_vpi_user.h "$(DESTDIR)$(includedir)/sv_vpi_user.h" - $(INSTALL_DATA) $(srcdir)/vpi_user.h "$(DESTDIR)$(includedir)/vpi_user.h" - $(INSTALL_DATA) $(srcdir)/acc_user.h "$(DESTDIR)$(includedir)/acc_user.h" - $(INSTALL_DATA) $(srcdir)/veriuser.h "$(DESTDIR)$(includedir)/veriuser.h" + $(INSTALL_DATA) $(srcdir)/ivl_target.h "$(DESTDIR)$(ivl_includedir)/ivl_target.h" + $(INSTALL_DATA) ./_pli_types.h "$(DESTDIR)$(ivl_includedir)/_pli_types.h" + $(INSTALL_DATA) $(srcdir)/sv_vpi_user.h "$(DESTDIR)$(ivl_includedir)/sv_vpi_user.h" + $(INSTALL_DATA) $(srcdir)/vpi_user.h "$(DESTDIR)$(ivl_includedir)/vpi_user.h" + $(INSTALL_DATA) $(srcdir)/acc_user.h "$(DESTDIR)$(ivl_includedir)/acc_user.h" + $(INSTALL_DATA) $(srcdir)/veriuser.h "$(DESTDIR)$(ivl_includedir)/veriuser.h" installdirs: $(srcdir)/mkinstalldirs $(srcdir)/mkinstalldirs "$(DESTDIR)$(bindir)" \ - "$(DESTDIR)$(includedir)" \ + "$(DESTDIR)$(ivl_includedir)" \ "$(DESTDIR)$(libdir)/ivl$(suffix)" \ "$(DESTDIR)$(libdir)/ivl$(suffix)/include" \ "$(DESTDIR)$(docdir)" \ @@ -393,8 +393,8 @@ uninstall: for f in verilog$(suffix) iverilog-vpi$(suffix) gverilog$(suffix)@EXEEXT@; \ do rm -f "$(DESTDIR)$(bindir)/$$f"; done for f in ivl_target.h vpi_user.h _pli_types.h sv_vpi_user.h acc_user.h veriuser.h; \ - do rm -f "$(DESTDIR)$(includedir)/$$f"; done - -test X$(suffix) = X || rmdir "$(DESTDIR)$(includedir)" + do rm -f "$(DESTDIR)$(ivl_includedir)/$$f"; done + -test X$(suffix) = X || rmdir "$(DESTDIR)$(ivl_includedir)" rm -f "$(DESTDIR)$(man1dir)/iverilog-vpi$(suffix).1" \ "$(DESTDIR)$(docdir)/iverilog-vpi$(suffix).pdf" diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 30f85fdf3..c924dda85 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -31,7 +31,7 @@ libdir = @libdir@ mandir = @mandir@ # This is actually the directory where we install our own header files. # It is a little different from the generic includedir. -includedir = @includedir@/iverilog$(suffix) +ivl_includedir = @includedir@/iverilog$(suffix) pdfdir = @docdir@ # For a cross compile these defines will need to be set accordingly. @@ -235,7 +235,7 @@ installfiles: $(F) | installdirs $(INSTALL_PROGRAM) ./vvp@EXEEXT@ "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@" ifeq (@LIBVVP@,yes) $(INSTALL_PROGRAM) ./libvvp$(suffix).$(SLEXT) "$(DESTDIR)$(SLDIR)/libvvp$(suffix).$(SLEXT)" - $(INSTALL_DATA) $(srcdir)/libvvp.h "$(DESTDIR)$(includedir)/libvvp.h" + $(INSTALL_DATA) $(srcdir)/libvvp.h "$(DESTDIR)$(ivl_includedir)/libvvp.h" endif installdirs: $(srcdir)/../mkinstalldirs @@ -250,7 +250,7 @@ uninstall: $(UNINSTALL32) rm -f "$(DESTDIR)$(mandir)/man1/vvp$(suffix).1" "$(DESTDIR)$(pdfdir)/vvp$(suffix).pdf" ifeq (@LIBVVP@,yes) rm -f "$(DESTDIR)$(SLDIR)/libvvp$(suffix).$(SLEXT)" - rm -f "$(DESTDIR)$(includedir)/libvvp.h" + rm -f "$(DESTDIR)$(ivl_includedir)/libvvp.h" endif -include $(patsubst %.o, dep/%.d, $O) From 181cb7b2edf377d4cb7d00303e5d4890f8cabe86 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sat, 2 May 2026 12:48:06 +0200 Subject: [PATCH 011/102] iverilog-vpi: Consolidate creation in driver-vpi This change standardizes the creation of iverilog-vpi-related targets, which now follow the same pattern as the iverilog targets in the 'driver' subdirectory. --- Makefile.in | 75 ++-------------- configure.ac | 2 +- driver-vpi/Makefile.in | 88 +++++++++++++++++-- .../iverilog-vpi.man.in | 0 iverilog-vpi.sh => driver-vpi/iverilog-vpi.sh | 0 5 files changed, 89 insertions(+), 76 deletions(-) rename iverilog-vpi.man.in => driver-vpi/iverilog-vpi.man.in (100%) rename iverilog-vpi.sh => driver-vpi/iverilog-vpi.sh (100%) diff --git a/Makefile.in b/Makefile.in index 6b83c4977..cce69c1e6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,11 +51,7 @@ else NOTUSED += libveriuser cadpli endif -ifeq (@MINGW32@,yes) SUBDIRS += driver-vpi -else -NOTUSED += driver-vpi -endif # To get the version headers to build correctly we only want to look # for C++ files in the source directory. All other files will require @@ -71,8 +67,6 @@ libdir = @libdir@ # This is actually the directory where we install our own header files. # It is a little different from the generic includedir. ivl_includedir = @includedir@/iverilog$(suffix) -man1dir = @mandir@/man1 -docdir = @docdir@ dllib=@DLLIB@ @@ -135,7 +129,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o PTimingCheck.o \ PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT) -all: dep config.h _pli_types.h version_tag.h version_base.h ivl@EXEEXT@ iverilog-vpi.man +all: dep config.h _pli_types.h version_tag.h version_base.h ivl@EXEEXT@ $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true # In the windows world, the installer will need a dosify program to @@ -172,7 +166,7 @@ check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py: clean: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true rm -f *.o parse.cc parse.h lexor.cc - rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps + rm -f ivl.exp rm -f iverilog_man.ps iverilog_man.pdf iverilog_man_$(VERSION_MAJOR)_$(VERSION_MINOR).pdf rm -f parse.output syn-rules.output dosify$(BUILDEXT) ivl@EXEEXT@ check.vvp rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc version_base.h @@ -239,23 +233,6 @@ ivl@EXEEXT@: $O $(CXX) $(LDFLAGS) -o ivl@EXEEXT@ $O $(dllib) endif -ifeq (@MINGW32@,no) -all: iverilog-vpi - -iverilog-vpi: $(srcdir)/iverilog-vpi.sh Makefile - sed -e 's;@SHARED@;@shared@;' -e 's;@PIC@;@PICFLAG@;' \ - -e 's;@ENABLE_PLI1@;@LIBVERIUSER@;' \ - -e 's;@SUFFIX@;$(suffix);' \ - -e 's;@IVCC@;$(CC);' \ - -e 's;@IVCXX@;$(CXX);' \ - -e 's;@IVCFLAGS@;$(CFLAGS);' \ - -e 's;@IVCXXFLAGS@;$(CXXFLAGS);' \ - -e 's;@IVCTARGETFLAGS@;$(CTARGETFLAGS);' \ - -e 's;@INCLUDEDIR@;$(ivl_includedir);' \ - -e 's;@LIBDIR@;@libdir@;' $< > $@ - chmod +x $@ -endif - version_base.h: $(srcdir)/version_base.h.in config.status ./config.status --file=$@ @@ -285,16 +262,7 @@ lexor_keyword.o: lexor_keyword.cc parse.h lexor_keyword.cc: $(srcdir)/lexor_keyword.gperf gperf -o -i 7 -C -k 1-4,6,9,$$ -H keyword_hash -N check_identifier -t $< > $@ || (rm -f $@ ; false) -iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in config.status - ./config.status --file=$@ - -iverilog-vpi.ps: iverilog-vpi.man - $(MAN) -t ./$< > $@ - -iverilog-vpi.pdf: iverilog-vpi.ps - $(PS2PDF) $< $@ - -iverilog_man.ps: driver/iverilog.man vvp/vvp.man iverilog-vpi.man +iverilog_man.ps: driver/iverilog.man vvp/vvp.man driver-vpi/iverilog-vpi.man $(GROFF) -man -rC1 -rD1 -T ps $^ > $@ iverilog_man.pdf: iverilog_man.ps @@ -325,22 +293,6 @@ version_tag.h version: echo '#define VERSION_TAG ""' > version_tag.h; \ fi -INSTALL_DOC = -ifneq ($(MAN),none) -INSTALL_DOC += installman -ifneq ($(PS2PDF),none) -ifeq (@MINGW32@,yes) -INSTALL_DOC += installpdf -all: iverilog-vpi.pdf -endif -endif - -ifeq (@MINGW32@,yes) -WIN32_INSTALL = -else -WIN32_INSTALL = installwin32 -endif - install: all installdirs installfiles $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true @@ -352,18 +304,7 @@ F = ./ivl@EXEEXT@ \ $(srcdir)/sv_vpi_user.h \ $(srcdir)/vpi_user.h \ $(srcdir)/acc_user.h \ - $(srcdir)/veriuser.h \ - $(INSTALL_DOC) \ - $(WIN32_INSTALL) - -installwin32: ./iverilog-vpi installdirs - $(INSTALL_SCRIPT) ./iverilog-vpi "$(DESTDIR)$(bindir)/iverilog-vpi$(suffix)" - -installman: iverilog-vpi.man installdirs - $(INSTALL_DATA) iverilog-vpi.man "$(DESTDIR)$(mandir)/man1/iverilog-vpi$(suffix).1" - -installpdf: iverilog-vpi.pdf installdirs - $(INSTALL_DATA) iverilog-vpi.pdf "$(DESTDIR)$(pdfdir)/iverilog-vpi$(suffix).pdf" + $(srcdir)/veriuser.h installfiles: $(F) | installdirs $(INSTALL_PROGRAM) ./ivl@EXEEXT@ "$(DESTDIR)$(libdir)/ivl$(suffix)/ivl@EXEEXT@" @@ -380,9 +321,7 @@ installdirs: $(srcdir)/mkinstalldirs $(srcdir)/mkinstalldirs "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(ivl_includedir)" \ "$(DESTDIR)$(libdir)/ivl$(suffix)" \ - "$(DESTDIR)$(libdir)/ivl$(suffix)/include" \ - "$(DESTDIR)$(docdir)" \ - "$(DESTDIR)$(man1dir)" + "$(DESTDIR)$(libdir)/ivl$(suffix)/include" uninstall: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true @@ -390,13 +329,11 @@ uninstall: do rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/$$f"; done -rmdir "$(DESTDIR)$(libdir)/ivl$(suffix)/include" -rmdir "$(DESTDIR)$(libdir)/ivl$(suffix)" - for f in verilog$(suffix) iverilog-vpi$(suffix) gverilog$(suffix)@EXEEXT@; \ + for f in verilog$(suffix) gverilog$(suffix)@EXEEXT@; \ do rm -f "$(DESTDIR)$(bindir)/$$f"; done for f in ivl_target.h vpi_user.h _pli_types.h sv_vpi_user.h acc_user.h veriuser.h; \ do rm -f "$(DESTDIR)$(ivl_includedir)/$$f"; done -test X$(suffix) = X || rmdir "$(DESTDIR)$(ivl_includedir)" - rm -f "$(DESTDIR)$(man1dir)/iverilog-vpi$(suffix).1" \ - "$(DESTDIR)$(docdir)/iverilog-vpi$(suffix).pdf" -include $(patsubst %.o, dep/%.d, $O) diff --git a/configure.ac b/configure.ac index b260ceb5d..6b8d7a4e5 100644 --- a/configure.ac +++ b/configure.ac @@ -407,10 +407,10 @@ AC_CONFIG_FILES([ Makefile cadpli/Makefile driver-vpi/Makefile + driver-vpi/iverilog-vpi.man driver-vpi/res.rc driver/Makefile driver/iverilog.man - iverilog-vpi.man ivlpp/Makefile ivtest/Makefile libveriuser/Makefile diff --git a/driver-vpi/Makefile.in b/driver-vpi/Makefile.in index 6a0790cf6..7d7f2d359 100644 --- a/driver-vpi/Makefile.in +++ b/driver-vpi/Makefile.in @@ -31,7 +31,11 @@ suffix = @install_suffix@ bindir = $(exec_prefix)/bin libdir = $(exec_prefix)/lib includedir = $(prefix)/include -mandir = @mandir@ +# This is actually the directory where we install our own header files. +# It is a little different from the generic includedir. +ivl_includedir = @includedir@/iverilog$(suffix) +man1dir = @mandir@/man1 +docdir = @docdir@ dllib=@DLLIB@ @@ -39,8 +43,11 @@ CC = @CC@ HOSTCC := @CC@ WINDRES = @WINDRES@ INSTALL = @INSTALL@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ +MAN = @MAN@ +PS2PDF = @PS2PDF@ ifeq (@srcdir@,.) INCLUDE_PATH = -I. -I.. @@ -48,19 +55,36 @@ else INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif -CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ +CPPFLAGS = @DEFS@ $(INCLUDE_PATH) @CPPFLAGS@ CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ -LDFLAGS = @LDFLAGS@ +PICFLAGS = @PICFLAG@ +LDFLAGS = @rdynamic@ @LDFLAGS@ O = main.o res.o +ifeq (@MINGW32@,yes) all: iverilog-vpi@EXEEXT@ +else +all: iverilog-vpi +endif + +INSTALL_DOC = +ifneq ($(MAN),none) +INSTALL_DOC += installman +ifneq ($(PS2PDF),none) +ifeq (@MINGW32@,yes) +INSTALL_DOC += installpdf +all: iverilog-vpi.pdf +endif +endif +endif check: all clean: - rm -f *.o config.h iverilog-vpi@EXEEXT@ res.rc + rm -f *.o config.h iverilog-vpi@EXEEXT@ iverilog-vpi \ + iverilog-vpi.man iverilog-vpi.ps iverilog-vpi.pdf res.rc distclean: clean rm -f Makefile config.log @@ -75,8 +99,24 @@ cppcheck: main.c config.h Makefile: $(srcdir)/Makefile.in ../config.status cd ..; ./config.status --file=driver-vpi/$@ +ifeq (@MINGW32@,yes) iverilog-vpi@EXEEXT@: $O $(CC) $(LDFLAGS) $O -o iverilog-vpi@EXEEXT@ @EXTRALIBS@ +endif +ifeq (@MINGW32@,no) +iverilog-vpi: $(srcdir)/iverilog-vpi.sh ../config.status + sed -e 's;@SHARED@;@shared@;' -e 's;@PIC@;@PICFLAG@;' \ + -e 's;@ENABLE_PLI1@;@LIBVERIUSER@;' \ + -e 's;@SUFFIX@;$(suffix);' \ + -e 's;@IVCC@;$(CC);' \ + -e 's;@IVCXX@;@CXX@;' \ + -e 's;@IVCFLAGS@;$(CFLAGS);' \ + -e 's;@IVCXXFLAGS@;$(CXXFLAGS);' \ + -e 's;@IVCTARGETFLAGS@;@CTARGETFLAGS@;' \ + -e 's;@INCLUDEDIR@;$(ivl_includedir);' \ + -e 's;@LIBDIR@;@libdir@;' $< > $@ + chmod +x $@ +endif main.o: $(srcdir)/main.c config.h $(CC) $(CPPFLAGS) $(CFLAGS) -c $(srcdir)/main.c @@ -102,12 +142,32 @@ res.o: res.rc $(WINDRES) -i res.rc -o res.o # +iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in ../config.status + cd ..; ./config.status --file=driver-vpi/$@ + +iverilog-vpi.ps: iverilog-vpi.man + $(MAN) -t ./$< > $@ + +iverilog-vpi.pdf: iverilog-vpi.ps + $(PS2PDF) $< $@ + install: all installdirs installfiles -F = ./iverilog-vpi@EXEEXT@ +F = $(INSTALL_DOC) +ifeq (@MINGW32@,yes) +F += ./iverilog-vpi@EXEEXT@ +endif +ifeq (@MINGW32@,no) +F += ./iverilog-vpi +endif installfiles: $(F) | installdirs +ifeq (@MINGW32@,yes) $(INSTALL_PROGRAM) ./iverilog-vpi@EXEEXT@ "$(DESTDIR)$(bindir)/iverilog-vpi$(suffix)@EXEEXT@" +endif +ifeq (@MINGW32@,no) + $(INSTALL_SCRIPT) ./iverilog-vpi "$(DESTDIR)$(bindir)/iverilog-vpi$(suffix)" +endif ifeq (@WIN32@,yes) ifneq ($(HOSTCC),$(CC)) $(INSTALL_PROGRAM) $(shell $(HOSTCC) --print-file-name=libwinpthread-1.dll) "$(DESTDIR)$(bindir)" @@ -116,8 +176,24 @@ ifneq ($(HOSTCC),$(CC)) endif endif +installman: iverilog-vpi.man installdirs + $(INSTALL_DATA) iverilog-vpi.man "$(DESTDIR)$(man1dir)/iverilog-vpi$(suffix).1" + +installpdf: iverilog-vpi.pdf installdirs + $(INSTALL_DATA) iverilog-vpi.pdf "$(DESTDIR)$(docdir)/iverilog-vpi$(suffix).pdf" + installdirs: $(srcdir)/../mkinstalldirs - $(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" + $(srcdir)/../mkinstalldirs \ + "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(docdir)" \ + "$(DESTDIR)$(man1dir)" uninstall: +ifeq (@MINGW32@,yes) rm -f $(DESTDIR)$(bindir)/iverilog-vpi$(suffix)@EXEEXT@ +endif +ifeq (@MINGW32@,no) + rm -f $(DESTDIR)$(bindir)/iverilog-vpi$(suffix) +endif + rm -f "$(DESTDIR)$(man1dir)/iverilog-vpi$(suffix).1" \ + "$(DESTDIR)$(docdir)/iverilog-vpi$(suffix).pdf" diff --git a/iverilog-vpi.man.in b/driver-vpi/iverilog-vpi.man.in similarity index 100% rename from iverilog-vpi.man.in rename to driver-vpi/iverilog-vpi.man.in diff --git a/iverilog-vpi.sh b/driver-vpi/iverilog-vpi.sh similarity index 100% rename from iverilog-vpi.sh rename to driver-vpi/iverilog-vpi.sh From 11c619e265fc5977e8c46826607fccfb2f3147d0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 2 May 2026 17:54:10 -0700 Subject: [PATCH 012/102] Fix drive strength in net declaration parsing The drive strength of a net must be declared between the net type and the data type. E.g. wire (weak0, strong1) [7:0] x; The current implementation expects the drive strength after the data type. Update the parser to fix this. Signed-off-by: Lars-Peter Clausen --- parse.y | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parse.y b/parse.y index d1767a86b..0daadfeaf 100644 --- a/parse.y +++ b/parse.y @@ -4954,14 +4954,14 @@ module_item /* This form doesn't have the range, but does have strengths. This gives strength to the assignment drivers. */ - | attribute_list_opt net_type data_type_or_implicit drive_strength net_decl_assigns ';' - { data_type_t*data_type = $3; - pform_check_net_data_type(@2, $2, $3); + | attribute_list_opt net_type drive_strength data_type_or_implicit net_decl_assigns ';' + { data_type_t*data_type = $4; + pform_check_net_data_type(@2, $2, $4); if (data_type == 0) { data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); FILE_NAME(data_type, @2); } - pform_makewire(@2, 0, $4, $5, $2, data_type, $1); + pform_makewire(@2, 0, $3, $5, $2, data_type, $1); delete $1; } From be3be03fec91c8245f57a750559696f0086a32a6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 2 May 2026 17:54:50 -0700 Subject: [PATCH 013/102] Add regression test for drive strength net declarations Check that drive strength can be specified between the net type and the data type in a net declaration and that vector gate arrays resolve strengths correctly. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/drive_strength4.v | 62 +++++++++++++++++++++++++++ ivtest/regress-vvp.list | 1 + ivtest/vvp_tests/drive_strength4.json | 4 ++ 3 files changed, 67 insertions(+) create mode 100644 ivtest/ivltests/drive_strength4.v create mode 100644 ivtest/vvp_tests/drive_strength4.json diff --git a/ivtest/ivltests/drive_strength4.v b/ivtest/ivltests/drive_strength4.v new file mode 100644 index 000000000..5e90987fa --- /dev/null +++ b/ivtest/ivltests/drive_strength4.v @@ -0,0 +1,62 @@ +// Check that drive strength can be specified between the net type and the data +// type in a net declaration and that vector gate arrays resolve strengths +// correctly. + +module test; + + reg [7:0] pullval; + wire (weak0, weak1) [7:0] value = pullval; + + reg [7:0] en0; + reg [7:0] en1; + reg failed = 1'b0; + + `define check(expr, val) \ + if ((expr) !== (val)) begin \ + $display("FAILED(%0d): `%s`, expected %0h, got %0h", `__LINE__, \ + `"expr`", (val), (expr)); \ + failed = 1'b1; \ + end + + buf (highz0, strong1) drive0 [7:0] (value, en0); + not (strong0, highz1) drive1 [7:0] (value, en1); + + initial begin + en0 = 8'h00; + en1 = 8'h00; + + pullval = 8'hff; + #1 `check(value, 8'hff) + + pullval = 8'h00; + #1 `check(value, 8'h00) + + en0 = 8'haa; + pullval = 8'hff; + #1 `check(value, 8'hff) + + pullval = 8'h00; + #1 `check(value, 8'haa) + + en0 = 8'h00; + en1 = 8'hff; + pullval = 8'hff; + #1 `check(value, 8'h00) + + pullval = 8'h00; + #1 `check(value, 8'h00) + + en0 = 8'hff; + en1 = 8'hff; + pullval = 8'hff; + #1 `check(value, 8'hxx) + + pullval = 8'h00; + #1 `check(value, 8'hxx) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 2cde03b79..0e71d0d6c 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -118,6 +118,7 @@ dffsynth8 vvp_tests/dffsynth8.json dffsynth9 vvp_tests/dffsynth9.json dffsynth10 vvp_tests/dffsynth10.json dffsynth11 vvp_tests/dffsynth11.json +drive_strength4 vvp_tests/drive_strength4.json dumpfile vvp_tests/dumpfile.json early_sig_elab1 vvp_tests/early_sig_elab1.json early_sig_elab2 vvp_tests/early_sig_elab2.json diff --git a/ivtest/vvp_tests/drive_strength4.json b/ivtest/vvp_tests/drive_strength4.json new file mode 100644 index 000000000..73b273742 --- /dev/null +++ b/ivtest/vvp_tests/drive_strength4.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "drive_strength4.v" +} From d39e81e1d1205fb364bb4213cff7f11fb7b9e355 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 2 May 2026 16:58:14 -0700 Subject: [PATCH 014/102] Reject non-assignable unpacked array output port expressions Output port expressions must support continuous assignment. Assignment patterns for unpacked array output ports are currently elaborated as temporary arrays and the connection is silently discarded. Report an error instead. Signed-off-by: Lars-Peter Clausen --- elaborate.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/elaborate.cc b/elaborate.cc index 6839156da..ca06c018c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1202,6 +1202,17 @@ void elaborate_unpacked_port(Design *des, NetScope *scope, NetNet *port_net, PExpr *expr, NetNet::PortType port_type, const Module *mod, unsigned int port_idx) { + if (port_type == NetNet::POUTPUT && !dynamic_cast (expr)) { + perm_string port_name = mod->get_port_name(port_idx); + cerr << expr->get_fileline() << ": error: Output port expression" + " must support a continuous assignment." << endl; + cerr << expr->get_fileline() << ": : Port " + << port_idx + 1 << " (" << port_name << ") of " + << mod->mod_name() << " is connected to " << *expr << endl; + des->errors += 1; + return; + } + NetNet *expr_net = elaborate_unpacked_array(des, scope, *expr, port_net, expr); if (!expr_net) { From 8519a3035440e65d9c78224ab57fceb415b549f1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 2 May 2026 16:58:33 -0700 Subject: [PATCH 015/102] Add regression test for unpacked array output port expressions Check that assignment patterns cannot be connected directly to unpacked array output ports. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/module_port_array_fail1.v | 17 +++++++++++++++++ ivtest/regress-vvp.list | 1 + ivtest/vvp_tests/module_port_array_fail1.json | 5 +++++ 3 files changed, 23 insertions(+) create mode 100644 ivtest/ivltests/module_port_array_fail1.v create mode 100644 ivtest/vvp_tests/module_port_array_fail1.json diff --git a/ivtest/ivltests/module_port_array_fail1.v b/ivtest/ivltests/module_port_array_fail1.v new file mode 100644 index 000000000..4d6483ec0 --- /dev/null +++ b/ivtest/ivltests/module_port_array_fail1.v @@ -0,0 +1,17 @@ +// Check that an output array port expression must be assignable. + +module M ( + output int out [0:1] +); + + initial begin + out = '{3, 4}; + end + +endmodule + +module test; + + M i_m('{1, 2}); // Error: output expression is not assignable + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 0e71d0d6c..c4f96dfa7 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -152,6 +152,7 @@ mix_reset-synth vvp_tests/mix_reset-synth.json module_ordered_list1 vvp_tests/module_ordered_list1.json module_ordered_list2 vvp_tests/module_ordered_list2.json module_port_array1 vvp_tests/module_port_array1.json +module_port_array_fail1 vvp_tests/module_port_array_fail1.json module_port_array_init1 vvp_tests/module_port_array_init1.json monitor4 vvp_tests/monitor4.json non-polymorphic-abs vvp_tests/non-polymorphic-abs.json diff --git a/ivtest/vvp_tests/module_port_array_fail1.json b/ivtest/vvp_tests/module_port_array_fail1.json new file mode 100644 index 000000000..a7a343dca --- /dev/null +++ b/ivtest/vvp_tests/module_port_array_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "module_port_array_fail1.v", + "iverilog-args" : [ "-g2009" ] +} From 272cf91eaefb72cc7c89cdee1972f7255f208f2c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 19 Jun 2023 11:36:59 -0700 Subject: [PATCH 016/102] Support assignment of string literals to byte arrays SystemVerilog defines a special case that allows to assign string literals to byte arrays. Each character of the string is copied to 1 element of the byte array. The size of string literal and the byte array does not have to match. If the string literal is longer it is truncated. If it is shorter it will be padded with null-bytes. The assignment is done left aligned, the first character ends up in the left most entry of the array. This means the order will differ whether the array is declared with ascending or descending element order. Signed-off-by: Lars-Peter Clausen --- PExpr.h | 6 +++- elab_expr.cc | 86 +++++++++++++++++++++++++++++++++++++++++++++++++--- elaborate.cc | 3 +- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/PExpr.h b/PExpr.h index 78c3055bb..586509f08 100644 --- a/PExpr.h +++ b/PExpr.h @@ -690,12 +690,16 @@ class PEString : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, width_mode_t&mode) override; - virtual NetEConst*elaborate_expr(Design*des, NetScope*scope, + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, ivl_type_t type, unsigned flags) const override; virtual NetEConst*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, unsigned) const override; + NetExpr *elaborate_expr_uarray_(Design *des, NetScope *scope, + const netuarray_t *uarray_type, + const std::vector &dims, + unsigned int cur_dim) const; private: char*text_; }; diff --git a/elab_expr.cc b/elab_expr.cc index 671381e62..0902f5be1 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -344,6 +344,9 @@ NetExpr* PEAssignPattern::elaborate_expr_uarray_(Design *des, NetScope *scope, if (const auto ap = dynamic_cast(parms_[idx])) { expr = ap->elaborate_expr_uarray_(des, scope, uarray_type, dims, cur_dim, need_const); + } else if (auto s = dynamic_cast(parms_[idx])) { + expr = s->elaborate_expr_uarray_(des, scope, uarray_type, + dims, cur_dim); } else if (dynamic_cast(parms_[idx])) { cerr << get_fileline() << ": sorry: " << "Array concatenation is not yet supported." @@ -6986,13 +6989,86 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&) return expr_width_; } -NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned) const +NetExpr* PEString::elaborate_expr_uarray_(Design *des, NetScope *, + const netuarray_t *uarray_type, + const std::vector &dims, + unsigned int cur_dim) const { - NetECString*tmp = new NetECString(value()); - tmp->cast_signed(signed_flag_); - tmp->set_line(*this); + // This is a special case. The LRM allows string literals to be + // assigned to unpacked arrays of bytes. + const auto element_type = uarray_type->element_type(); - return tmp; + if (dims.size() - 1 != cur_dim || !element_type->packed() || + element_type->base_type() != IVL_VT_BOOL || + element_type->packed_width() != 8 || !element_type->get_signed()) { + cerr << get_fileline() << ": error: " + << "String literal can not be implicitly cast to the target type." + << endl; + des->errors++; + return nullptr; + } + + + // The size doesn't have to match. Elements are copied left aligned, which + // is different from assignments of string literals to packed arrays where + // they are copied right aligned. + + vector elem_exprs(dims[cur_dim].width()); + bool asc = dims[cur_dim].get_msb() < dims[cur_dim].get_lsb(); + unsigned int elem_idx = asc ? 0 : elem_exprs.size() - 1; + + verinum text_val(text_); + + if (text_val.len() > elem_exprs.size() * 8) { + cerr << get_fileline() << ": warning: " + << "Target array smaller than assigned value. " + << "Value will be truncated." << endl; + } + + for (unsigned int i = 0; i < min((size_t)text_val.len() / 8, elem_exprs.size()); i++) { + verinum val(text_val >> (text_val.len() - 8 - i * 8), 8); + val.has_sign(true); + + elem_exprs[elem_idx] = new NetEConst(element_type, val); + + if (asc) + elem_idx++; + else + elem_idx--; + } + + // Add padding if necessary + for (unsigned int i = text_val.len() / 8; i < elem_exprs.size(); i++) { + verinum val(verinum::V0, 8); + val.has_sign(true); + + elem_exprs[elem_idx] = new NetEConst(element_type, val); + + if (asc) + elem_idx++; + else + elem_idx--; + } + + return new NetEArrayPattern(uarray_type, elem_exprs); +} + +NetExpr* PEString::elaborate_expr(Design *des, NetScope *scope, ivl_type_t type, unsigned) const +{ + NetExpr *expr; + + auto uarray_type = dynamic_cast(type); + if (uarray_type) { + expr = elaborate_expr_uarray_(des, scope, uarray_type, + uarray_type->static_dimensions(), 0); + } else { + expr = new NetECString(value()); + expr->cast_signed(signed_flag_); + } + + if (expr) + expr->set_line(*this); + return expr; } /* diff --git a/elaborate.cc b/elaborate.cc index ca06c018c..ab091d170 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -266,7 +266,8 @@ NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &l << endl; des->errors++; return nullptr; - } else if (dynamic_cast (expr)) { + } else if (dynamic_cast (expr) || + dynamic_cast (expr)) { auto net_expr = elaborate_rval_expr(des, scope, lval->array_type(), expr); if (! net_expr) return nullptr; expr_net = net_expr->synthesize(des, scope, net_expr); From d59e2c97bac5dd853123acb8584bf833d4f3ae46 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sat, 2 May 2026 14:39:32 +0200 Subject: [PATCH 017/102] Add missing autoconf macro for generating header stamp files Fixes #1334 Fixup for commit 804e06cce. --- aclocal.m4 | 1 + m4/_ac_am_config_header_hook.m4 | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 m4/_ac_am_config_header_hook.m4 diff --git a/aclocal.m4 b/aclocal.m4 index 5f2a09eb8..32ca987c3 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -12,6 +12,7 @@ # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_include([m4/_ac_am_config_header_hook.m4]) m4_include([m4/_ax_c_underscores_match_if.m4]) m4_include([m4/ax_c99_strtod.m4]) m4_include([m4/ax_c_picflag.m4]) diff --git a/m4/_ac_am_config_header_hook.m4 b/m4/_ac_am_config_header_hook.m4 new file mode 100644 index 000000000..b0113a7eb --- /dev/null +++ b/m4/_ac_am_config_header_hook.m4 @@ -0,0 +1,13 @@ +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp file name are based on the header name. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[ +_config_header=$1 +_stamp_name=stamp-`expr //$_config_header : '.*/\([[^./]]*\)\.[[^./]]*$'`-h +echo "timestamp for $_config_header" > `AS_DIRNAME(["$_config_header"])`/[]$_stamp_name +]) #_AC_AM_CONFIG_HEADER_HOOK From f8e20f5a099bfb54c2f242abe5e4a2846df09faf Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 4 May 2026 21:23:01 +0200 Subject: [PATCH 018/102] Makefile.in: remove obsolete dependency Fixup for commit 49eaafe88 from #1331 --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 86ede6b2e..69dbee892 100644 --- a/Makefile.in +++ b/Makefile.in @@ -190,7 +190,7 @@ ifneq (@srcdir@,.) endif rm -rf autom4te.cache -cppcheck: $(O:.o=.cc) $(srcdir)/dosify.c $(srcdir)/version.c +cppcheck: $(O:.o=.cc) $(srcdir)/dosify.c cppcheck --enable=all --std=c99 --std=c++11 -f \ --check-level=exhaustive \ --suppressions-list=$(srcdir)/cppcheck-global.sup \ From 41c34232094859e978998e9951a5c79c3275cd73 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 7 Jan 2024 18:45:03 -0800 Subject: [PATCH 019/102] vvp: Implement `vvp_vector4_t` xor operator `vvp_vector4_t` has word wide in-place operators for and and or, but not for xor. Add `operator ^=` using the same internal word representation. Signed-off-by: Lars-Peter Clausen --- vvp/vvp_net.cc | 24 ++++++++++++++++++++++++ vvp/vvp_net.h | 1 + 2 files changed, 25 insertions(+) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index ee1e123a1..23f9de4ef 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1964,6 +1964,30 @@ vvp_vector4_t& vvp_vector4_t::operator |= (const vvp_vector4_t&that) return *this; } +vvp_vector4_t& vvp_vector4_t::operator ^= (const vvp_vector4_t&that) +{ + // The truth table is: + // 00 01 11 10 + // 00 00 01 11 11 + // 01 01 00 11 11 + // 11 11 11 11 11 + // 10 11 11 11 11 + if (size_ <= BITS_PER_WORD) { + unsigned long bval = bbits_val_ | that.bbits_val_; + bbits_val_ = bval; + abits_val_ = (abits_val_ ^ that.abits_val_) | bval; + } else { + unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD; + for (unsigned idx = 0; idx < words ; idx += 1) { + unsigned long bval = bbits_ptr_[idx] | that.bbits_ptr_[idx]; + bbits_ptr_[idx] = bval; + abits_ptr_[idx] = (abits_ptr_[idx] ^ that.abits_ptr_[idx]) | bval; + } + } + + return *this; +} + /* * Add an integer to the vvp_vector4_t in place, bit by bit so that * there is no size limitations. diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 5d0e77e2f..197406bb7 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -323,6 +323,7 @@ class vvp_vector4_t { void invert(); vvp_vector4_t& operator &= (const vvp_vector4_t&that); vvp_vector4_t& operator |= (const vvp_vector4_t&that); + vvp_vector4_t& operator ^= (const vvp_vector4_t&that); vvp_vector4_t& operator += (int64_t); private: From cf53479ba23af5419c7ce3db4ec5ec7f80dddc90 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 7 Jan 2024 18:45:41 -0800 Subject: [PATCH 020/102] vvp: vthread: Use word wide vector operations The vthread binary logic opcodes update vectors bit by bit. Use the in-place `vvp_vector4_t` operators instead. This reuses the word wide implementation and avoids per-bit `value()` and `set_bit()` calls. Signed-off-by: Lars-Peter Clausen --- vvp/vthread.cc | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index de7578b00..1ef7aaf76 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4491,13 +4491,9 @@ bool of_NAND(vthread_t thr, vvp_code_t) vvp_vector4_t valr = thr->pop_vec4(); vvp_vector4_t&vall = thr->peek_vec4(); assert(vall.size() == valr.size()); - unsigned wid = vall.size(); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - vvp_bit4_t lb = vall.value(idx); - vvp_bit4_t rb = valr.value(idx); - vall.set_bit(idx, ~(lb&rb)); - } + vall &= valr; + vall.invert(); return true; } @@ -4755,13 +4751,9 @@ bool of_NOR(vthread_t thr, vvp_code_t) vvp_vector4_t valr = thr->pop_vec4(); vvp_vector4_t&vall = thr->peek_vec4(); assert(vall.size() == valr.size()); - unsigned wid = vall.size(); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - vvp_bit4_t lb = vall.value(idx); - vvp_bit4_t rb = valr.value(idx); - vall.set_bit(idx, ~(lb|rb)); - } + vall |= valr; + vall.invert(); return true; } @@ -6564,14 +6556,9 @@ bool of_XNOR(vthread_t thr, vvp_code_t) vvp_vector4_t valr = thr->pop_vec4(); vvp_vector4_t&vall = thr->peek_vec4(); assert(vall.size() == valr.size()); - unsigned wid = vall.size(); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - - vvp_bit4_t lb = vall.value(idx); - vvp_bit4_t rb = valr.value(idx); - vall.set_bit(idx, ~(lb ^ rb)); - } + vall ^= valr; + vall.invert(); return true; } @@ -6584,14 +6571,8 @@ bool of_XOR(vthread_t thr, vvp_code_t) vvp_vector4_t valr = thr->pop_vec4(); vvp_vector4_t&vall = thr->peek_vec4(); assert(vall.size() == valr.size()); - unsigned wid = vall.size(); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - - vvp_bit4_t lb = vall.value(idx); - vvp_bit4_t rb = valr.value(idx); - vall.set_bit(idx, lb ^ rb); - } + vall ^= valr; return true; } From 0f454ff548f4815a79a6746c6093409b035610b5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 7 Jan 2024 20:20:08 -0800 Subject: [PATCH 021/102] vvp: Use word wide vector operations for logic functors The logic functors combine their input vectors bit by bit. Use the in-place `vvp_vector4_t` operators for the vector operation and invert the result once for the inverted functors. Signed-off-by: Lars-Peter Clausen --- vvp/logic.cc | 54 ++++++++++++---------------------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/vvp/logic.cc b/vvp/logic.cc index 458cc6cb6..9b9a83e41 100644 --- a/vvp/logic.cc +++ b/vvp/logic.cc @@ -94,21 +94,11 @@ void vvp_fun_and::run_run() vvp_vector4_t result (input_[0]); - for (unsigned idx = 0 ; idx < result.size() ; idx += 1) { - vvp_bit4_t bitbit = result.value(idx); - for (unsigned pdx = 1 ; pdx < 4 ; pdx += 1) { - if (input_[pdx].size() < idx) { - bitbit = BIT4_X; - break; - } + for (unsigned pdx = 1 ; pdx < 4 ; pdx += 1) + result &= input_[pdx]; - bitbit = bitbit & input_[pdx].value(idx); - } - - if (invert_) - bitbit = ~bitbit; - result.set_bit(idx, bitbit); - } + if (invert_) + result.invert(); ptr->send_vec4(result, 0); } @@ -535,21 +525,11 @@ void vvp_fun_or::run_run() vvp_vector4_t result (input_[0]); - for (unsigned idx = 0 ; idx < result.size() ; idx += 1) { - vvp_bit4_t bitbit = result.value(idx); - for (unsigned pdx = 1 ; pdx < 4 ; pdx += 1) { - if (input_[pdx].size() < idx) { - bitbit = BIT4_X; - break; - } + for (unsigned pdx = 1 ; pdx < 4 ; pdx += 1) + result |= input_[pdx]; - bitbit = bitbit | input_[pdx].value(idx); - } - - if (invert_) - bitbit = ~bitbit; - result.set_bit(idx, bitbit); - } + if (invert_) + result.invert(); ptr->send_vec4(result, 0); } @@ -571,21 +551,11 @@ void vvp_fun_xor::run_run() vvp_vector4_t result (input_[0]); - for (unsigned idx = 0 ; idx < result.size() ; idx += 1) { - vvp_bit4_t bitbit = result.value(idx); - for (unsigned pdx = 1 ; pdx < 4 ; pdx += 1) { - if (input_[pdx].size() < idx) { - bitbit = BIT4_X; - break; - } + for (unsigned pdx = 1 ; pdx < 4 ; pdx += 1) + result ^= input_[pdx]; - bitbit = bitbit ^ input_[pdx].value(idx); - } - - if (invert_) - bitbit = ~bitbit; - result.set_bit(idx, bitbit); - } + if (invert_) + result.invert(); ptr->send_vec4(result, 0); } From 6ffb4b9a3ab6428297aaef86a697580e09b9525d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 2 May 2026 15:59:19 -0700 Subject: [PATCH 022/102] Add regression tests for string literals assigned to byte arrays Check that string literals can be assigned to byte arrays. Check that invalid target array types are reported as errors. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_byte_array_string1.v | 45 ++++++++++++++ ivtest/ivltests/sv_byte_array_string2.v | 61 +++++++++++++++++++ ivtest/ivltests/sv_byte_array_string3.v | 46 ++++++++++++++ ivtest/ivltests/sv_byte_array_string4.v | 39 ++++++++++++ ivtest/ivltests/sv_byte_array_string_fail1.v | 8 +++ ivtest/ivltests/sv_byte_array_string_fail2.v | 8 +++ ivtest/ivltests/sv_byte_array_string_fail3.v | 17 ++++++ ivtest/ivltests/sv_byte_array_string_fail4.v | 8 +++ ivtest/ivltests/sv_byte_array_string_fail5.v | 8 +++ ivtest/regress-vvp.list | 9 +++ ivtest/vvp_tests/sv_byte_array_string1.json | 5 ++ ivtest/vvp_tests/sv_byte_array_string2.json | 5 ++ ivtest/vvp_tests/sv_byte_array_string3.json | 5 ++ ivtest/vvp_tests/sv_byte_array_string4.json | 5 ++ .../vvp_tests/sv_byte_array_string_fail1.json | 5 ++ .../vvp_tests/sv_byte_array_string_fail2.json | 5 ++ .../vvp_tests/sv_byte_array_string_fail3.json | 5 ++ .../vvp_tests/sv_byte_array_string_fail4.json | 5 ++ .../vvp_tests/sv_byte_array_string_fail5.json | 5 ++ 19 files changed, 294 insertions(+) create mode 100644 ivtest/ivltests/sv_byte_array_string1.v create mode 100644 ivtest/ivltests/sv_byte_array_string2.v create mode 100644 ivtest/ivltests/sv_byte_array_string3.v create mode 100644 ivtest/ivltests/sv_byte_array_string4.v create mode 100644 ivtest/ivltests/sv_byte_array_string_fail1.v create mode 100644 ivtest/ivltests/sv_byte_array_string_fail2.v create mode 100644 ivtest/ivltests/sv_byte_array_string_fail3.v create mode 100644 ivtest/ivltests/sv_byte_array_string_fail4.v create mode 100644 ivtest/ivltests/sv_byte_array_string_fail5.v create mode 100644 ivtest/vvp_tests/sv_byte_array_string1.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string2.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string3.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string4.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string_fail1.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string_fail2.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string_fail3.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string_fail4.json create mode 100644 ivtest/vvp_tests/sv_byte_array_string_fail5.json diff --git a/ivtest/ivltests/sv_byte_array_string1.v b/ivtest/ivltests/sv_byte_array_string1.v new file mode 100644 index 000000000..bb0e621eb --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string1.v @@ -0,0 +1,45 @@ +// Check that string literals can be assigned to one-dimensional byte arrays. + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + byte desc [3:0] = "AB\n"; + byte asc [0:3]; + byte unsized [4]; + + assign asc = "AB\n"; + + initial begin + #1; + + `check(desc[3], 8'h41); + `check(desc[2], 8'h42); + `check(desc[1], 8'h0a); + `check(desc[0], 8'h00); + + `check(asc[0], 8'h41); + `check(asc[1], 8'h42); + `check(asc[2], 8'h0a); + `check(asc[3], 8'h00); + + unsized = "AB\n"; + `check(unsized[0], 8'h41); + `check(unsized[1], 8'h42); + `check(unsized[2], 8'h0a); + `check(unsized[3], 8'h00); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string2.v b/ivtest/ivltests/sv_byte_array_string2.v new file mode 100644 index 000000000..001a38830 --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string2.v @@ -0,0 +1,61 @@ +// Check that string literals can be assigned to nested byte arrays using +// assignment patterns. + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + byte desc [0:1][3:0] = '{"AB\n", "CD\t"}; + byte asc [1:0][0:3]; + byte unsized [2][4]; + + assign asc = '{"AB\n", "CD\t"}; + + initial begin + #1; + + `check(desc[0][3], 8'h41); + `check(desc[0][2], 8'h42); + `check(desc[0][1], 8'h0a); + `check(desc[0][0], 8'h00); + + `check(desc[1][3], 8'h43); + `check(desc[1][2], 8'h44); + `check(desc[1][1], 8'h09); + `check(desc[1][0], 8'h00); + + `check(asc[0][0], 8'h43); + `check(asc[0][1], 8'h44); + `check(asc[0][2], 8'h09); + `check(asc[0][3], 8'h00); + + `check(asc[1][0], 8'h41); + `check(asc[1][1], 8'h42); + `check(asc[1][2], 8'h0a); + `check(asc[1][3], 8'h00); + + unsized = '{"AB\n", "CD\t"}; + `check(unsized[0][0], 8'h41); + `check(unsized[0][1], 8'h42); + `check(unsized[0][2], 8'h0a); + `check(unsized[0][3], 8'h00); + + `check(unsized[1][0], 8'h43); + `check(unsized[1][1], 8'h44); + `check(unsized[1][2], 8'h09); + `check(unsized[1][3], 8'h00); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string3.v b/ivtest/ivltests/sv_byte_array_string3.v new file mode 100644 index 000000000..27ba42748 --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string3.v @@ -0,0 +1,46 @@ +// Check that string literals shorter than the target byte array are padded +// with null bytes. + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + byte desc [3:0] = "AB"; + byte asc [0:3]; + byte unsized [4]; + + assign asc = "AB"; + + initial begin + #1; + + `check(desc[3], 8'h41); + `check(desc[2], 8'h42); + `check(desc[1], 8'h00); + `check(desc[0], 8'h00); + + `check(asc[0], 8'h41); + `check(asc[1], 8'h42); + `check(asc[2], 8'h00); + `check(asc[3], 8'h00); + + unsized = "AB"; + `check(unsized[0], 8'h41); + `check(unsized[1], 8'h42); + `check(unsized[2], 8'h00); + `check(unsized[3], 8'h00); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string4.v b/ivtest/ivltests/sv_byte_array_string4.v new file mode 100644 index 000000000..0797f2fd3 --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string4.v @@ -0,0 +1,39 @@ +// Check that string literals longer than the target byte array are truncated. + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + byte desc [1:0] = "ABC"; + byte asc [0:1]; + byte unsized [2]; + + assign asc = "ABC"; + + initial begin + #1; + + `check(desc[1], 8'h41); + `check(desc[0], 8'h42); + + `check(asc[0], 8'h41); + `check(asc[1], 8'h42); + + unsized = "ABCD"; + `check(unsized[0], 8'h41); + `check(unsized[1], 8'h42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string_fail1.v b/ivtest/ivltests/sv_byte_array_string_fail1.v new file mode 100644 index 000000000..6f53c54ed --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string_fail1.v @@ -0,0 +1,8 @@ +// Check that string literals cannot be assigned to unpacked arrays whose +// element type is 4-state. + +module test; + + logic [7:0] value [0:3] = "AB"; // Error: target element type is 4-state + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string_fail2.v b/ivtest/ivltests/sv_byte_array_string_fail2.v new file mode 100644 index 000000000..16a04116e --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string_fail2.v @@ -0,0 +1,8 @@ +// Check that string literals cannot be assigned directly to multi-dimensional +// byte arrays. + +module test; + + byte value [0:1][0:3] = "AB"; // Error: string is not nested + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string_fail3.v b/ivtest/ivltests/sv_byte_array_string_fail3.v new file mode 100644 index 000000000..990fcca7f --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string_fail3.v @@ -0,0 +1,17 @@ +// Check that string literals cannot be connected to output byte array ports. + +module M ( + output byte out [0:1] +); + + initial begin + out = "CD"; + end + +endmodule + +module test; + + M i_m("AB"); // Error: output expression is not assignable + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string_fail4.v b/ivtest/ivltests/sv_byte_array_string_fail4.v new file mode 100644 index 000000000..886a0761b --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string_fail4.v @@ -0,0 +1,8 @@ +// Check that string literals cannot be assigned to unpacked arrays whose +// element type is narrower than 8 bits. + +module test; + + bit [6:0] value [0:3] = "AB"; // Error: target element type is too narrow + +endmodule diff --git a/ivtest/ivltests/sv_byte_array_string_fail5.v b/ivtest/ivltests/sv_byte_array_string_fail5.v new file mode 100644 index 000000000..86ddac25b --- /dev/null +++ b/ivtest/ivltests/sv_byte_array_string_fail5.v @@ -0,0 +1,8 @@ +// Check that string literals cannot be assigned to unpacked arrays whose +// element type is wider than 8 bits. + +module test; + + bit [8:0] value [0:3] = "AB"; // Error: target element type is too wide + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index c4f96dfa7..1dafa1a1f 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -226,6 +226,15 @@ sv_array_cassign6 vvp_tests/sv_array_cassign6.json sv_array_cassign7 vvp_tests/sv_array_cassign7.json sv_array_cassign8 vvp_tests/sv_array_cassign8.json sv_automatic_2state vvp_tests/sv_automatic_2state.json +sv_byte_array_string1 vvp_tests/sv_byte_array_string1.json +sv_byte_array_string2 vvp_tests/sv_byte_array_string2.json +sv_byte_array_string3 vvp_tests/sv_byte_array_string3.json +sv_byte_array_string4 vvp_tests/sv_byte_array_string4.json +sv_byte_array_string_fail1 vvp_tests/sv_byte_array_string_fail1.json +sv_byte_array_string_fail2 vvp_tests/sv_byte_array_string_fail2.json +sv_byte_array_string_fail3 vvp_tests/sv_byte_array_string_fail3.json +sv_byte_array_string_fail4 vvp_tests/sv_byte_array_string_fail4.json +sv_byte_array_string_fail5 vvp_tests/sv_byte_array_string_fail5.json sv_chained_constructor1 vvp_tests/sv_chained_constructor1.json sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json diff --git a/ivtest/vvp_tests/sv_byte_array_string1.json b/ivtest/vvp_tests/sv_byte_array_string1.json new file mode 100644 index 000000000..92f9ead44 --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_byte_array_string1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string2.json b/ivtest/vvp_tests/sv_byte_array_string2.json new file mode 100644 index 000000000..8d1280a4b --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_byte_array_string2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string3.json b/ivtest/vvp_tests/sv_byte_array_string3.json new file mode 100644 index 000000000..87dfe0e1e --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_byte_array_string3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string4.json b/ivtest/vvp_tests/sv_byte_array_string4.json new file mode 100644 index 000000000..aef296194 --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string4.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_byte_array_string4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string_fail1.json b/ivtest/vvp_tests/sv_byte_array_string_fail1.json new file mode 100644 index 000000000..51aaf0658 --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_byte_array_string_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string_fail2.json b/ivtest/vvp_tests/sv_byte_array_string_fail2.json new file mode 100644 index 000000000..000b19b4c --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_byte_array_string_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string_fail3.json b/ivtest/vvp_tests/sv_byte_array_string_fail3.json new file mode 100644 index 000000000..b9c693937 --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_byte_array_string_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string_fail4.json b/ivtest/vvp_tests/sv_byte_array_string_fail4.json new file mode 100644 index 000000000..a4c171738 --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_byte_array_string_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_byte_array_string_fail5.json b/ivtest/vvp_tests/sv_byte_array_string_fail5.json new file mode 100644 index 000000000..a6a741748 --- /dev/null +++ b/ivtest/vvp_tests/sv_byte_array_string_fail5.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_byte_array_string_fail5.v", + "iverilog-args" : [ "-g2005-sv" ] +} From f559a056725ffb8bebe6b5b983ca40be0905c72f Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 6 May 2026 21:24:14 -0700 Subject: [PATCH 023/102] Net arrays are not supported for Verilog 95 --- ivtest/vvp_tests/sv_byte_array_string1.json | 7 ++++++- ivtest/vvp_tests/sv_byte_array_string2.json | 7 ++++++- ivtest/vvp_tests/sv_byte_array_string3.json | 7 ++++++- ivtest/vvp_tests/sv_byte_array_string4.json | 7 ++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ivtest/vvp_tests/sv_byte_array_string1.json b/ivtest/vvp_tests/sv_byte_array_string1.json index 92f9ead44..a2006f981 100644 --- a/ivtest/vvp_tests/sv_byte_array_string1.json +++ b/ivtest/vvp_tests/sv_byte_array_string1.json @@ -1,5 +1,10 @@ { "type" : "normal", "source" : "sv_byte_array_string1.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE", + "iverilog-args" : [ "-pallowsigned=1" ] + } } diff --git a/ivtest/vvp_tests/sv_byte_array_string2.json b/ivtest/vvp_tests/sv_byte_array_string2.json index 8d1280a4b..87bf891eb 100644 --- a/ivtest/vvp_tests/sv_byte_array_string2.json +++ b/ivtest/vvp_tests/sv_byte_array_string2.json @@ -1,5 +1,10 @@ { "type" : "normal", "source" : "sv_byte_array_string2.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE", + "iverilog-args" : [ "-pallowsigned=1" ] + } } diff --git a/ivtest/vvp_tests/sv_byte_array_string3.json b/ivtest/vvp_tests/sv_byte_array_string3.json index 87dfe0e1e..02e0f4f31 100644 --- a/ivtest/vvp_tests/sv_byte_array_string3.json +++ b/ivtest/vvp_tests/sv_byte_array_string3.json @@ -1,5 +1,10 @@ { "type" : "normal", "source" : "sv_byte_array_string3.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE", + "iverilog-args" : [ "-pallowsigned=1" ] + } } diff --git a/ivtest/vvp_tests/sv_byte_array_string4.json b/ivtest/vvp_tests/sv_byte_array_string4.json index aef296194..412e46c7e 100644 --- a/ivtest/vvp_tests/sv_byte_array_string4.json +++ b/ivtest/vvp_tests/sv_byte_array_string4.json @@ -1,5 +1,10 @@ { "type" : "normal", "source" : "sv_byte_array_string4.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE", + "iverilog-args" : [ "-pallowsigned=1" ] + } } From d8e7cd4037e93a6627ccdab921ec14be041ab01b Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 7 May 2026 19:33:45 -0700 Subject: [PATCH 024/102] iverilog-vpi is not in the main directory --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index d813549d4..504961169 100644 --- a/Makefile.in +++ b/Makefile.in @@ -169,7 +169,7 @@ clean: rm -f ivl.exp rm -f iverilog_man.ps iverilog_man.pdf iverilog_man_$(VERSION_MAJOR)_$(VERSION_MINOR).pdf rm -f parse.output syn-rules.output dosify$(BUILDEXT) ivl@EXEEXT@ check.vvp - rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc version_base.h + rm -f lexor_keyword.cc libivl.a libvpi.a syn-rules.cc version_base.h rm -rf dep distclean: clean From e4c4247266c706c15bd68c63e22f6e0b862f9552 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 7 May 2026 19:40:23 -0700 Subject: [PATCH 025/102] Fix the full PDF document name --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 504961169..751334d6a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -267,7 +267,7 @@ iverilog_man.ps: driver/iverilog.man vvp/vvp.man driver-vpi/iverilog-vpi.man iverilog_man.pdf: iverilog_man.ps $(PS2PDF) $< $@ - cp $@ iverilog-vpi.man_$(VERSION_MAJOR)_$(VERSION_MINOR).pdf + cp $@ iverilog_man_$(VERSION_MAJOR)_$(VERSION_MINOR).pdf # For VERSION_TAG in driver/main.c, first try git-describe, then look for a # release_tag.h file in the source tree (included in snapshots and releases), From 48242818b3adffdb69406265e7c7353957939532 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 5 Jun 2022 19:42:43 +0200 Subject: [PATCH 026/102] vvp: Improve reduction operator performance The vvp reduction operators evaluate their input bit by bit. This is expensive for wide vectors. Add word wide reduction helpers to `vvp_vector4_t` and use them for both reduction functors and vthread reduction opcodes. Signed-off-by: Lars-Peter Clausen --- vvp/reduce.cc | 44 ++++---------------- vvp/vthread.cc | 109 ++++++------------------------------------------- vvp/vvp_net.cc | 99 ++++++++++++++++++++++++++++++++++++++++++++ vvp/vvp_net.h | 4 ++ 4 files changed, 122 insertions(+), 134 deletions(-) diff --git a/vvp/reduce.cc b/vvp/reduce.cc index 37afc1ea5..39362e5fb 100644 --- a/vvp/reduce.cc +++ b/vvp/reduce.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2005-2026 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 @@ -97,12 +97,7 @@ vvp_reduce_and::~vvp_reduce_and() vvp_bit4_t vvp_reduce_and::calculate_result() const { - vvp_bit4_t res = BIT4_1; - - for (unsigned idx = 0 ; idx < bits_.size() ; idx += 1) - res = res & bits_.value(idx); - - return res; + return bits_.reduce_and(); } class vvp_reduce_or : public vvp_reduce_base { @@ -123,12 +118,7 @@ vvp_reduce_or::~vvp_reduce_or() vvp_bit4_t vvp_reduce_or::calculate_result() const { - vvp_bit4_t res = BIT4_0; - - for (unsigned idx = 0 ; idx < bits_.size() ; idx += 1) - res = res | bits_.value(idx); - - return res; + return bits_.reduce_or(); } class vvp_reduce_xor : public vvp_reduce_base { @@ -149,12 +139,7 @@ vvp_reduce_xor::~vvp_reduce_xor() vvp_bit4_t vvp_reduce_xor::calculate_result() const { - vvp_bit4_t res = BIT4_0; - - for (unsigned idx = 0 ; idx < bits_.size() ; idx += 1) - res = res ^ bits_.value(idx); - - return res; + return bits_.reduce_xor(); } class vvp_reduce_nand : public vvp_reduce_base { @@ -175,12 +160,7 @@ vvp_reduce_nand::~vvp_reduce_nand() vvp_bit4_t vvp_reduce_nand::calculate_result() const { - vvp_bit4_t res = BIT4_1; - - for (unsigned idx = 0 ; idx < bits_.size() ; idx += 1) - res = res & bits_.value(idx); - - return ~res; + return ~bits_.reduce_and(); } class vvp_reduce_nor : public vvp_reduce_base { @@ -201,12 +181,7 @@ vvp_reduce_nor::~vvp_reduce_nor() vvp_bit4_t vvp_reduce_nor::calculate_result() const { - vvp_bit4_t res = BIT4_0; - - for (unsigned idx = 0 ; idx < bits_.size() ; idx += 1) - res = res | bits_.value(idx); - - return ~res; + return ~bits_.reduce_or(); } class vvp_reduce_xnor : public vvp_reduce_base { @@ -227,12 +202,7 @@ vvp_reduce_xnor::~vvp_reduce_xnor() vvp_bit4_t vvp_reduce_xnor::calculate_result() const { - vvp_bit4_t res = BIT4_0; - - for (unsigned idx = 0 ; idx < bits_.size() ; idx += 1) - res = res ^ bits_.value(idx); - - return ~res; + return ~bits_.reduce_xor(); } static void make_reduce(char*label, vvp_net_fun_t*red, const struct symb_s&arg) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 1ef7aaf76..cd3b679fe 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4576,24 +4576,8 @@ bool of_NOOP(vthread_t, vvp_code_t) */ bool of_NORR(vthread_t thr, vvp_code_t) { - vvp_vector4_t val = thr->pop_vec4(); - - vvp_bit4_t lb = BIT4_1; - - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - - vvp_bit4_t rb = val.value(idx); - if (rb == BIT4_1) { - lb = BIT4_0; - break; - } - - if (rb != BIT4_0) - lb = BIT4_X; - } - - vvp_vector4_t res (1, lb); - thr->push_vec4(res); + vvp_vector4_t&val = thr->peek_vec4(); + val = vvp_vector4_t(1, ~val.reduce_or()); return true; } @@ -4613,23 +4597,8 @@ bool of_NULL(vthread_t thr, vvp_code_t) */ bool of_ANDR(vthread_t thr, vvp_code_t) { - vvp_vector4_t val = thr->pop_vec4(); - - vvp_bit4_t lb = BIT4_1; - - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - vvp_bit4_t rb = val.value(idx); - if (rb == BIT4_0) { - lb = BIT4_0; - break; - } - - if (rb != 1) - lb = BIT4_X; - } - - vvp_vector4_t res (1, lb); - thr->push_vec4(res); + vvp_vector4_t&val = thr->peek_vec4(); + val = vvp_vector4_t(1, val.reduce_and()); return true; } @@ -4639,23 +4608,8 @@ bool of_ANDR(vthread_t thr, vvp_code_t) */ bool of_NANDR(vthread_t thr, vvp_code_t) { - vvp_vector4_t val = thr->pop_vec4(); - - vvp_bit4_t lb = BIT4_0; - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - - vvp_bit4_t rb = val.value(idx); - if (rb == BIT4_0) { - lb = BIT4_1; - break; - } - - if (rb != BIT4_1) - lb = BIT4_X; - } - - vvp_vector4_t res (1, lb); - thr->push_vec4(res); + vvp_vector4_t&val = thr->peek_vec4(); + val = vvp_vector4_t(1, ~val.reduce_and()); return true; } @@ -4665,22 +4619,9 @@ bool of_NANDR(vthread_t thr, vvp_code_t) */ bool of_ORR(vthread_t thr, vvp_code_t) { - vvp_vector4_t val = thr->pop_vec4(); + vvp_vector4_t&val = thr->peek_vec4(); + val = vvp_vector4_t(1, val.reduce_or()); - vvp_bit4_t lb = BIT4_0; - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - vvp_bit4_t rb = val.value(idx); - if (rb == BIT4_1) { - lb = BIT4_1; - break; - } - - if (rb != BIT4_0) - lb = BIT4_X; - } - - vvp_vector4_t res (1, lb); - thr->push_vec4(res); return true; } @@ -4689,22 +4630,9 @@ bool of_ORR(vthread_t thr, vvp_code_t) */ bool of_XORR(vthread_t thr, vvp_code_t) { - vvp_vector4_t val = thr->pop_vec4(); + vvp_vector4_t&val = thr->peek_vec4(); + val = vvp_vector4_t(1, val.reduce_xor()); - vvp_bit4_t lb = BIT4_0; - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - - vvp_bit4_t rb = val.value(idx); - if (rb == BIT4_1) - lb = ~lb; - else if (rb != BIT4_0) { - lb = BIT4_X; - break; - } - } - - vvp_vector4_t res (1, lb); - thr->push_vec4(res); return true; } @@ -4713,22 +4641,9 @@ bool of_XORR(vthread_t thr, vvp_code_t) */ bool of_XNORR(vthread_t thr, vvp_code_t) { - vvp_vector4_t val = thr->pop_vec4(); + vvp_vector4_t&val = thr->peek_vec4(); + val = vvp_vector4_t(1, ~val.reduce_xor()); - vvp_bit4_t lb = BIT4_1; - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - - vvp_bit4_t rb = val.value(idx); - if (rb == BIT4_1) - lb = ~lb; - else if (rb != BIT4_0) { - lb = BIT4_X; - break; - } - } - - vvp_vector4_t res (1, lb); - thr->push_vec4(res); return true; } diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 23f9de4ef..30efa58cc 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1905,6 +1905,105 @@ void vvp_vector4_t::invert() } } +#define BIT_MASK(n) ((n) ? ((~0UL) >> (BITS_PER_WORD - (n))) : ~0UL) + +vvp_bit4_t vvp_vector4_t::reduce_or() const +{ + unsigned long mask = BIT_MASK(size_ % BITS_PER_WORD); + vvp_bit4_t res = BIT4_0; + + if (size_ <= BITS_PER_WORD) { + if ((abits_val_ & ~bbits_val_ & mask) != 0UL) + return BIT4_1; + if ((bbits_val_ & mask) != 0UL) + return BIT4_X; + } else { + unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD; + unsigned idx; + for (idx = 0; idx < words - 1; idx += 1) { + if ((abits_ptr_[idx] & ~bbits_ptr_[idx]) != 0UL) + return BIT4_1; + if (bbits_ptr_[idx] != 0UL) + res = BIT4_X; + } + if ((abits_ptr_[idx] & ~bbits_ptr_[idx] & mask) != 0UL) + return BIT4_1; + if ((bbits_ptr_[idx] & mask) != 0UL) + res = BIT4_X; + } + + return res; +} + +vvp_bit4_t vvp_vector4_t::reduce_and() const +{ + unsigned long mask = BIT_MASK(size_ % BITS_PER_WORD); + vvp_bit4_t res = BIT4_1; + + if (size_ <= BITS_PER_WORD) { + if ((abits_val_ | bbits_val_ | ~mask) != ~0UL) + return BIT4_0; + if ((bbits_val_ & mask) != 0UL) + return BIT4_X; + } else { + unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD; + unsigned idx; + for (idx = 0; idx < words - 1; idx += 1) { + if ((abits_ptr_[idx] | bbits_ptr_[idx]) != ~0UL) + return BIT4_0; + if (bbits_ptr_[idx] != 0UL) + res = BIT4_X; + } + if ((abits_ptr_[idx] | bbits_ptr_[idx] | ~mask) != ~0UL) + return BIT4_0; + if ((bbits_ptr_[idx] & mask) != 0UL) + res = BIT4_X; + } + + return res; +} + +static unsigned long parity(unsigned long val) +{ +#if defined(__GNUC__) + // The compiler builtin can use target-specific CPU instructions. + return __builtin_parityl(val); +#else +#if ULONG_MAX > 0xffffffffUL + val ^= val >> 32; +#endif + val ^= val >> 16; + val ^= val >> 8; + val ^= val >> 4; + + return (0x6996 >> (val & 0xf)) & 1; +#endif +} + +vvp_bit4_t vvp_vector4_t::reduce_xor() const +{ + unsigned long mask = BIT_MASK(size_ % BITS_PER_WORD); + + if (size_ <= BITS_PER_WORD) { + if ((bbits_val_ & mask) != 0UL) + return BIT4_X; + return parity(abits_val_ & mask) ? BIT4_1 : BIT4_0; + } else { + unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD; + unsigned long val_a = 0UL; + unsigned idx; + for (idx = 0; idx < words - 1; idx += 1) { + if (bbits_ptr_[idx] != 0UL) + return BIT4_X; + val_a ^= abits_ptr_[idx]; + } + if ((bbits_ptr_[idx] & mask) != 0UL) + return BIT4_X; + val_a ^= abits_ptr_[idx] & mask; + return parity(val_a) ? BIT4_1 : BIT4_0; + } +} + vvp_vector4_t& vvp_vector4_t::operator &= (const vvp_vector4_t&that) { // The truth table is: diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 197406bb7..f6beeb095 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -326,6 +326,10 @@ class vvp_vector4_t { vvp_vector4_t& operator ^= (const vvp_vector4_t&that); vvp_vector4_t& operator += (int64_t); + vvp_bit4_t reduce_or() const; + vvp_bit4_t reduce_and() const; + vvp_bit4_t reduce_xor() const; + private: // Number of vvp_bit4_t bits that can be shoved into a word. enum { BITS_PER_WORD = 8*sizeof(unsigned long) }; From c2b63e69a468e604bd402da49a6a4feaac66c91b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Jul 2023 15:22:36 -0700 Subject: [PATCH 027/102] Allow lifetime specifier for variables declared in packages The LRM allows to add a lifetime specified for variables declared in package scope. It is not particular useful since only static lifetime is allowed. But it is legal syntax, so support it. Signed-off-by: Lars-Peter Clausen --- parse.y | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/parse.y b/parse.y index 0daadfeaf..10184aeff 100644 --- a/parse.y +++ b/parse.y @@ -1283,22 +1283,24 @@ constraint_set /* IEEE1800-2005 A.1.9 */ ; data_declaration /* IEEE1800-2005: A.2.1.3 */ - : attribute_list_opt K_const_opt data_type list_of_variable_decl_assignments ';' - { data_type_t *data_type = $3; - if (!data_type) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @3); - } - pform_makewire(@3, 0, str_strength, $4, NetNet::IMPLICIT_REG, data_type, - $1, $2); - } - | attribute_list_opt K_const_opt K_var data_type_or_implicit list_of_variable_decl_assignments ';' + : attribute_list_opt K_const_opt variable_lifetime_opt data_type list_of_variable_decl_assignments ';' { data_type_t *data_type = $4; + if (!data_type) { + data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); + FILE_NAME(data_type, @4); + } + pform_makewire(@4, 0, str_strength, $5, NetNet::IMPLICIT_REG, data_type, + $1, $2); + var_lifetime = LexicalScope::INHERITED; + } + | attribute_list_opt K_const_opt K_var variable_lifetime_opt data_type_or_implicit list_of_variable_decl_assignments ';' + { data_type_t *data_type = $5; if (!data_type) { data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); FILE_NAME(data_type, @3); } - pform_make_var(@3, $5, data_type, $1, $2); + pform_make_var(@3, $6, data_type, $1, $2); + var_lifetime = LexicalScope::INHERITED; } | attribute_list_opt K_event event_variable_list ';' { if ($3) pform_make_events(@2, $3); @@ -2705,10 +2707,16 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ variable_lifetime_opt : lifetime - { if (pform_requires_sv(@1, "Overriding default variable lifetime") && - $1 != pform_peek_scope()->default_lifetime) { - yyerror(@1, "sorry: Overriding the default variable lifetime " - "is not yet supported."); + { LexicalScope*scope = pform_peek_scope(); + if (dynamic_cast(scope)) { + if ($1 == LexicalScope::AUTOMATIC) { + yyerror(@1, "error: automatic lifetime is not allowed for " + "variables declared in packages."); + } + } else if (pform_requires_sv(@1, "Overriding default variable lifetime") && + $1 != scope->default_lifetime) { + yyerror(@1, "sorry: Overriding the default variable " + "lifetime is not yet supported."); } var_lifetime = $1; } From 81222402c71d6b65e073d2c2b4b8a629756ce3a4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 6 May 2026 22:18:43 -0700 Subject: [PATCH 028/102] Add regression tests for package variable lifetimes Check that package variables can use explicit static lifetime. Check that automatic lifetime is rejected for package variables. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_package_lifetime.v | 40 +++++++++++++++++++ ivtest/ivltests/sv_package_lifetime_fail.v | 6 +++ ivtest/regress-vvp.list | 2 + ivtest/vvp_tests/sv_package_lifetime.json | 5 +++ .../vvp_tests/sv_package_lifetime_fail.json | 5 +++ 5 files changed, 58 insertions(+) create mode 100644 ivtest/ivltests/sv_package_lifetime.v create mode 100644 ivtest/ivltests/sv_package_lifetime_fail.v create mode 100644 ivtest/vvp_tests/sv_package_lifetime.json create mode 100644 ivtest/vvp_tests/sv_package_lifetime_fail.json diff --git a/ivtest/ivltests/sv_package_lifetime.v b/ivtest/ivltests/sv_package_lifetime.v new file mode 100644 index 000000000..12b3b3338 --- /dev/null +++ b/ivtest/ivltests/sv_package_lifetime.v @@ -0,0 +1,40 @@ +// Check that static lifetime can be specified for variables declared in a +// package. + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + +package P; + static int x = 1; + const static int y = 2; + var static z; + var static logic [3:0] w = 4'h3; +endpackage + +package automatic Q; + int a = 4; + static int b = 5; +endpackage + +module test; + import P::*; + import Q::*; + + bit failed = 1'b0; + + initial begin + `check(x, 1) + `check(y, 2) + `check(z, 1'bx) + `check(w, 4'h3) + `check(a, 4) + `check(b, 5) + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_package_lifetime_fail.v b/ivtest/ivltests/sv_package_lifetime_fail.v new file mode 100644 index 000000000..3b44251e3 --- /dev/null +++ b/ivtest/ivltests/sv_package_lifetime_fail.v @@ -0,0 +1,6 @@ +// Check that automatic lifetime cannot be specified for variables declared in +// a package. + +package P; + automatic int x; +endpackage diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 1dafa1a1f..e9c9a1633 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -280,6 +280,8 @@ sv_module_port1 vvp_tests/sv_module_port1.json sv_module_port2 vvp_tests/sv_module_port2.json sv_module_port3 vvp_tests/sv_module_port3.json sv_module_port4 vvp_tests/sv_module_port4.json +sv_package_lifetime vvp_tests/sv_package_lifetime.json +sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json sv_parameter_type vvp_tests/sv_parameter_type.json sv_queue_assign_op vvp_tests/sv_queue_assign_op.json sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json diff --git a/ivtest/vvp_tests/sv_package_lifetime.json b/ivtest/vvp_tests/sv_package_lifetime.json new file mode 100644 index 000000000..b59df3399 --- /dev/null +++ b/ivtest/vvp_tests/sv_package_lifetime.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_package_lifetime.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_package_lifetime_fail.json b/ivtest/vvp_tests/sv_package_lifetime_fail.json new file mode 100644 index 000000000..8a0e7f1e4 --- /dev/null +++ b/ivtest/vvp_tests/sv_package_lifetime_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_package_lifetime_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} From 3d8f906bddfd7ef85349f60458dd8609f7139457 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 8 May 2026 05:34:13 -0700 Subject: [PATCH 029/102] Update Copyright that was missed for a few files --- PExpr.h | 2 +- elaborate.cc | 2 +- lexor.lex | 2 +- vvp/logic.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PExpr.h b/PExpr.h index 586509f08..290b0f093 100644 --- a/PExpr.h +++ b/PExpr.h @@ -1,7 +1,7 @@ #ifndef IVL_PExpr_H #define IVL_PExpr_H /* - * Copyright (c) 1998-2025 Stephen Williams + * Copyright (c) 1998-2026 Stephen Williams * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it diff --git a/elaborate.cc b/elaborate.cc index ab091d170..5216ad7b7 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2026 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it diff --git a/lexor.lex b/lexor.lex index 8f6c87a4b..f48149b94 100644 --- a/lexor.lex +++ b/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1998-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2026 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 diff --git a/vvp/logic.cc b/vvp/logic.cc index 9b9a83e41..06285c41f 100644 --- a/vvp/logic.cc +++ b/vvp/logic.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2026 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 From e212ea1a1cea330d0a8742db7e7c58df8da35df6 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 8 May 2026 05:53:18 -0700 Subject: [PATCH 030/102] package liftime test needs signed for vlog95 testing --- ivtest/vvp_tests/sv_package_lifetime.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ivtest/vvp_tests/sv_package_lifetime.json b/ivtest/vvp_tests/sv_package_lifetime.json index b59df3399..1c284869e 100644 --- a/ivtest/vvp_tests/sv_package_lifetime.json +++ b/ivtest/vvp_tests/sv_package_lifetime.json @@ -1,5 +1,8 @@ { "type" : "normal", "source" : "sv_package_lifetime.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "iverilog-args" : [ "-pallowsigned=1" ] + } } From 71ce460caa3ae614d1e57215188570dab2ac907a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 9 May 2026 19:05:18 -0700 Subject: [PATCH 031/102] elab: Remove redundant enum parameter width handling `PEIdent::test_width_parameter_()` has a special case for `NetEConstEnum` that queries the enum base type directly. This was needed when enum constants kept their enum type separately from the `NetExpr` type. Commit f63a16232974 ("Provide data type for more NetExpr subclasses") made `NetEConstEnum` attach the enum type to the `NetExpr`. The generic parameter width path now gets the same type, width and signedness as the special case. Remove the redundant special case and use the common path for enum constants as well. Signed-off-by: Lars-Peter Clausen --- elab_expr.cc | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 0902f5be1..6c3a9cfe2 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -4231,20 +4231,6 @@ NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope, unsigned PEIdent::test_width_parameter_(const NetExpr *par, width_mode_t&mode) { - // The width of an enumeration literal is the width of the - // enumeration base. - if (const NetEConstEnum*par_enum = dynamic_cast (par)) { - const netenum_t*use_enum = par_enum->enumeration(); - ivl_assert(*this, use_enum != 0); - - expr_type_ = use_enum->base_type(); - expr_width_ = use_enum->packed_width(); - min_width_ = expr_width_; - signed_flag_ = par_enum->has_sign(); - - return expr_width_; - } - expr_type_ = par->expr_type(); expr_width_ = par->expr_width(); min_width_ = expr_width_; From c963809709acd4f0dfdfc9fa0f39dc52b644047f Mon Sep 17 00:00:00 2001 From: Jose Tejada Date: Sun, 10 May 2026 14:45:33 +0200 Subject: [PATCH 032/102] feat(sv): support interface-typed module ports --- Module.cc | 13 +- Module.h | 16 ++ PGate.h | 9 + elab_expr.cc | 3 + elab_net.cc | 3 + elab_sig.cc | 32 +++ elaborate.cc | 265 +++++++++++------- ..._missing_modport_fail-iverilog-stderr.gold | 2 + ...ort_missing_type_fail-iverilog-stderr.gold | 2 + ...port_input_write_fail-iverilog-stderr.gold | 2 + ...interface_actual_fail-iverilog-stderr.gold | 2 + ..._unlisted_member_fail-iverilog-stderr.gold | 3 + ..._port_wrong_type_fail-iverilog-stderr.gold | 2 + ivtest/ivltests/sv_interface_port_basic.v | 47 ++++ .../sv_interface_port_missing_modport_fail.v | 22 ++ .../sv_interface_port_missing_type_fail.v | 11 + ..._interface_port_modport_input_write_fail.v | 22 ++ ...interface_port_non_interface_actual_fail.v | 22 ++ .../sv_interface_port_unlisted_member_fail.v | 25 ++ .../sv_interface_port_wrong_type_fail.v | 28 ++ ivtest/regress-vvp.list | 7 + ivtest/vvp_tests/sv_interface_port_basic.json | 5 + ...v_interface_port_missing_modport_fail.json | 6 + .../sv_interface_port_missing_type_fail.json | 6 + ...terface_port_modport_input_write_fail.json | 6 + ...erface_port_non_interface_actual_fail.json | 6 + ...v_interface_port_unlisted_member_fail.json | 6 + .../sv_interface_port_wrong_type_fail.json | 6 + net_scope.cc | 33 +++ netlist.h | 22 ++ netmisc.h | 19 ++ parse.y | 48 +++- pform.cc | 27 ++ pform.h | 8 + symbol_search.cc | 72 +++++ vvp/Makefile.in | 4 + 36 files changed, 710 insertions(+), 102 deletions(-) create mode 100644 ivtest/gold/sv_interface_port_missing_modport_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_modport_input_write_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_non_interface_actual_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_unlisted_member_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_wrong_type_fail-iverilog-stderr.gold create mode 100644 ivtest/ivltests/sv_interface_port_basic.v create mode 100644 ivtest/ivltests/sv_interface_port_missing_modport_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_missing_type_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_modport_input_write_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_non_interface_actual_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_unlisted_member_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_wrong_type_fail.v create mode 100644 ivtest/vvp_tests/sv_interface_port_basic.json create mode 100644 ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_missing_type_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json diff --git a/Module.cc b/Module.cc index 6aefe59ab..5babfb973 100644 --- a/Module.cc +++ b/Module.cc @@ -28,6 +28,11 @@ using namespace std; list Module::user_defparms; +Module::port_t::port_t() +: port_kind(P_SIGNAL), default_value(0), lexical_pos(0) +{ +} + /* n is a permallocated string. */ Module::Module(LexicalScope*parent, perm_string n) : PScopeExtra(n, parent) @@ -63,12 +68,18 @@ const vector& Module::get_port(unsigned idx) const ivl_assert(*this, idx < ports.size()); static const vector zero; - if (ports[idx]) + if (ports[idx] && !ports[idx]->is_interface_port()) return ports[idx]->expr; else return zero; } +const Module::port_t* Module::get_port_info(unsigned idx) const +{ + ivl_assert(*this, idx < ports.size()); + return ports[idx]; +} + unsigned Module::find_port(const char*name) const { ivl_assert(*this, name != 0); diff --git a/Module.h b/Module.h index eecfbe781..2713be544 100644 --- a/Module.h +++ b/Module.h @@ -65,9 +65,24 @@ class Module : public PScopeExtra, public PNamedItem { default value. */ public: struct port_t { + enum port_kind_t { P_SIGNAL, P_INTERFACE }; + + port_t(); + + port_kind_t port_kind; perm_string name; std::vector expr; PExpr*default_value; + + /* Interface formal port metadata. For signal ports these + fields are empty/zero. The modport name is optional in the + representation, although the parser initially only accepts + the explicit interface_type.modport form. */ + perm_string interface_type; + perm_string modport_name; + unsigned lexical_pos; + + bool is_interface_port() const { return port_kind == P_INTERFACE; } }; public: @@ -148,6 +163,7 @@ class Module : public PScopeExtra, public PNamedItem { unsigned port_count() const; const std::vector& get_port(unsigned idx) const; + const port_t* get_port_info(unsigned idx) const; unsigned find_port(const char*name) const; // Return port name ("" for undeclared port) diff --git a/PGate.h b/PGate.h index 59c09954c..88e0d8c57 100644 --- a/PGate.h +++ b/PGate.h @@ -241,6 +241,15 @@ class PGModule : public PGate { void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const; void elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const; bool elaborate_sig_mod_(Design*des, NetScope*scope, const Module*mod) const; + bool bind_interface_ports_(Design*des, const Module*mod, + NetScope*parent_scope, NetScope*instance_scope, + const std::vector&pins, + const std::vector&pins_fromwc) const; + bool match_module_ports_(Design*des, const Module*mod, + NetScope*scope, + std::vector&pins, + std::vector&pins_fromwc, + std::vector&pins_is_explicitly_not_connected) const; // Not currently used. #if 0 bool elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const; diff --git a/elab_expr.cc b/elab_expr.cc index 0902f5be1..32751c0b4 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -4747,6 +4747,9 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, // If the identifier names a signal (a variable or a net) // then create a NetESignal node to handle it. if (sr.net != 0) { + if (!check_interface_modport_access(this, des, sr, false)) + return 0; + if (NEED_CONST & flags) { cerr << get_fileline() << ": error: A reference to a net " "or variable (`" << path_ << "') is not allowed in " diff --git a/elab_net.cc b/elab_net.cc index 6ec75d067..dc9dc9782 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -557,6 +557,9 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, return 0; } + if (!check_interface_modport_access(this, des, sr, true)) + return 0; + if (debug_elaborate) { cerr << get_fileline() << ": " << __func__ << ": " << "Found l-value path_=" << path_ diff --git a/elab_sig.cc b/elab_sig.cc index 5b8ed476b..d0b202ae0 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -44,6 +44,7 @@ # include "netqueue.h" # include "netscalar.h" # include "util.h" +# include "parse_api.h" # include "ivl_assert.h" using namespace std; @@ -298,6 +299,28 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const if (pp == 0) continue; + if (pp->is_interface_port()) { + map::const_iterator mod = + pform_modules.find(pp->interface_type); + if (mod == pform_modules.end() || !mod->second->is_interface) { + cerr << get_fileline() << ": error: Interface port " + << pp->name << " uses unknown interface type `" + << pp->interface_type << "'." << endl; + des->errors += 1; + continue; + } + + if (pp->modport_name.str() && + mod->second->modports.find(pp->modport_name) == mod->second->modports.end()) { + cerr << get_fileline() << ": error: Interface port " + << pp->name << " uses unknown modport `" + << pp->modport_name << "' of interface `" + << pp->interface_type << "'." << endl; + des->errors += 1; + } + continue; + } + // The port has a name and an array of expressions. The // expression are all identifiers that should reference // wires within the scope. @@ -456,6 +479,12 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope, NetScope::scope_vec_t instance = scope->instance_arrays[get_name()]; + vectorpins (rmod->port_count()); + vectorpins_fromwc (rmod->port_count(), false); + vectorpins_is_explicitly_not_connected (rmod->port_count(), false); + flag &= match_module_ports_(des, rmod, scope, pins, pins_fromwc, + pins_is_explicitly_not_connected); + for (unsigned idx = 0 ; idx < instance.size() ; idx += 1) { // I know a priori that the elaborate_scope created the scope // already, so just look it up as a child of the current scope. @@ -471,6 +500,9 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope, } ivl_assert(*this, my_scope->parent() == scope); + if (!bind_interface_ports_(des, rmod, scope, my_scope, pins, pins_fromwc)) + flag = false; + if (! rmod->elaborate_sig(des, my_scope)) flag = false; diff --git a/elaborate.cc b/elaborate.cc index 5216ad7b7..8c12940d1 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1248,6 +1248,164 @@ void elaborate_unpacked_port(Design *des, NetScope *scope, NetNet *port_net, assign_unpacked_with_bufz(des, scope, port_net, port_net, expr_net); } +bool PGModule::match_module_ports_(Design*des, const Module*rmod, + NetScope*scope, + vector&pins, + vector&pins_fromwc, + vector&pins_is_explicitly_not_connected) const +{ + if (pins_) { + unsigned nexp = rmod->port_count(); + + for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { + if (pins_[idx].name[0] == '*') { + for (unsigned j = 0 ; j < nexp ; j += 1) { + if (rmod->ports[j] && !pins[j] && !pins_is_explicitly_not_connected[j]) { + pins_fromwc[j] = true; + pform_name_t path_; + path_.push_back(name_component_t(rmod->ports[j]->name)); + symbol_search_results sr; + symbol_search(this, des, scope, path_, UINT_MAX, &sr); + if (sr.net != 0) { + pins[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true); + pins[j]->set_lineno(get_lineno()); + pins[j]->set_file(get_file()); + } + } + } + continue; + } + + unsigned pidx = rmod->find_port(pins_[idx].name); + if (pidx == nexp) { + cerr << get_fileline() << ": error: port ``" << + pins_[idx].name << "'' is not a port of " + << get_name() << "." << endl; + des->errors += 1; + continue; + } + + if (pins_fromwc[pidx]) { + delete pins[pidx]; + pins_fromwc[pidx] = false; + + } else if (pins[pidx]) { + cerr << get_fileline() << ": error: port ``" << + pins_[idx].name << "'' already bound." << + endl; + des->errors += 1; + continue; + } + + pins[pidx] = pins_[idx].parm; + if (!pins[pidx]) + pins_is_explicitly_not_connected[pidx] = true; + } + + } else if (pin_count() == 0) { + for (unsigned idx = 0 ; idx < rmod->port_count() ; idx += 1) + pins[idx] = 0; + + } else { + if (pin_count() > rmod->port_count()) { + cerr << get_fileline() << ": error: Wrong number " + "of ports. Expecting at most " << rmod->port_count() << + ", got " << pin_count() << "." + << endl; + des->errors += 1; + return false; + } + + std::copy(get_pins().begin(), get_pins().end(), pins.begin()); + } + + return true; +} + +bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, + NetScope*parent_scope, + NetScope*instance_scope, + const vector&pins, + const vector&pins_fromwc) const +{ + bool flag = true; + + for (unsigned idx = 0 ; idx < rmod->port_count() ; idx += 1) { + const Module::port_t*port = rmod->get_port_info(idx); + if (!port || !port->is_interface_port()) + continue; + + if (pins_fromwc[idx]) { + cerr << get_fileline() << ": sorry: Wildcard connection " + "to interface port `" << port->name + << "' is not yet supported." << endl; + des->errors += 1; + flag = false; + continue; + } + + if (!pins[idx]) { + cerr << get_fileline() << ": error: Interface port `" + << port->name << "' of module " << rmod->mod_name() + << " is not connected." << endl; + des->errors += 1; + flag = false; + continue; + } + + const PEIdent*actual_ident = dynamic_cast(pins[idx]); + if (!actual_ident || actual_ident->path().package || + actual_ident->path().name.size() != 1 || + !actual_ident->path().name.front().index.empty()) { + cerr << pins[idx]->get_fileline() << ": error: Interface port `" + << port->name << "' must be connected to a simple " + "interface instance name." << endl; + des->errors += 1; + flag = false; + continue; + } + + perm_string actual_name = actual_ident->path().name.front().name; + NetScope*actual_scope = parent_scope->child(hname_t(actual_name)); + if (!actual_scope) + actual_scope = parent_scope->find_interface_port_alias_scope(actual_name); + + if (!actual_scope || !actual_scope->is_interface()) { + cerr << pins[idx]->get_fileline() << ": error: Actual for " + "interface port `" << port->name + << "' is not an interface instance." << endl; + des->errors += 1; + flag = false; + continue; + } + + if (actual_scope->module_name() != port->interface_type) { + cerr << pins[idx]->get_fileline() << ": error: Interface port `" + << port->name << "' expects interface type `" + << port->interface_type << "' but actual `" << actual_name + << "' has type `" << actual_scope->module_name() << "'." << endl; + des->errors += 1; + flag = false; + continue; + } + + map::const_iterator mod = + pform_modules.find(port->interface_type); + const PModport*modport = 0; + if (mod != pform_modules.end()) { + map::const_iterator mp = + mod->second->modports.find(port->modport_name); + if (mp != mod->second->modports.end()) + modport = mp->second; + } + + instance_scope->add_interface_port_alias(port->name, actual_scope, + modport); + } + + return flag; +} + /* * Instantiate a module by recursively elaborating it. Set the path of * the recursive elaboration so that signal names get properly @@ -1274,103 +1432,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const vectorpins_fromwc (rmod->port_count(), false); vectorpins_is_explicitly_not_connected (rmod->port_count(), false); - // If the instance has a pins_ member, then we know we are - // binding by name. Therefore, make up a pins array that - // reflects the positions of the named ports. - if (pins_) { - unsigned nexp = rmod->port_count(); - - // Scan the bindings, matching them with port names. - for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { - - // Handle wildcard named port - if (pins_[idx].name[0] == '*') { - for (unsigned j = 0 ; j < nexp ; j += 1) { - if (rmod->ports[j] && !pins[j] && !pins_is_explicitly_not_connected[j]) { - pins_fromwc[j] = true; - pform_name_t path_; - path_.push_back(name_component_t(rmod->ports[j]->name)); - symbol_search_results sr; - symbol_search(this, des, scope, path_, UINT_MAX, &sr); - if (sr.net != 0) { - pins[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true); - pins[j]->set_lineno(get_lineno()); - pins[j]->set_file(get_file()); - } - } - } - continue; - } - - // Given a binding, look at the module port names - // for the position that matches the binding name. - unsigned pidx = rmod->find_port(pins_[idx].name); - - // If the port name doesn't exist, the find_port - // method will return the port count. Detect that - // as an error. - if (pidx == nexp) { - cerr << get_fileline() << ": error: port ``" << - pins_[idx].name << "'' is not a port of " - << get_name() << "." << endl; - des->errors += 1; - continue; - } - - // If I am overriding a wildcard port, delete and - // override it - if (pins_fromwc[pidx]) { - delete pins[pidx]; - pins_fromwc[pidx] = false; - - // If I already explicitly bound something to - // this port, then the pins array will already - // have a pointer value where I want to place this - // expression. - } else if (pins[pidx]) { - cerr << get_fileline() << ": error: port ``" << - pins_[idx].name << "'' already bound." << - endl; - des->errors += 1; - continue; - } - - // OK, do the binding by placing the expression in - // the right place. - pins[pidx] = pins_[idx].parm; - if (!pins[pidx]) - pins_is_explicitly_not_connected[pidx] = true; - } - - - } else if (pin_count() == 0) { - - /* Handle the special case that no ports are - connected. It is possible that this is an empty - connect-by-name list, so we'll allow it and assume - that is the case. */ - - for (unsigned idx = 0 ; idx < rmod->port_count() ; idx += 1) - pins[idx] = 0; - - } else { - - /* Otherwise, this is a positional list of port - connections. Use as many ports as provided. Trailing - missing ports will be left unconnect or use the default - value if one is available */ - - if (pin_count() > rmod->port_count()) { - cerr << get_fileline() << ": error: Wrong number " - "of ports. Expecting at most " << rmod->port_count() << - ", got " << pin_count() << "." - << endl; - des->errors += 1; - return; - } - - std::copy(get_pins().begin(), get_pins().end(), pins.begin()); - } + if (!match_module_ports_(des, rmod, scope, pins, pins_fromwc, + pins_is_explicitly_not_connected)) + return; // Elaborate these instances of the module. The recursive // elaboration causes the module to generate a netlist with @@ -1403,6 +1467,13 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const bool using_default = false; perm_string port_name = rmod->get_port_name(idx); + const Module::port_t*port_info = rmod->get_port_info(idx); + if (port_info && port_info->is_interface_port()) { + for (unsigned inst = 0 ; inst < instance.size() ; inst += 1) + instance[inst]->add_module_port_info(idx, port_name, + PortType::PIMPLICIT, 0); + continue; + } // If the port is unconnected, substitute the default // value. The parser ensures that a default value only diff --git a/ivtest/gold/sv_interface_port_missing_modport_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_missing_modport_fail-iverilog-stderr.gold new file mode 100644 index 000000000..7b28ae5f5 --- /dev/null +++ b/ivtest/gold/sv_interface_port_missing_modport_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_missing_modport_fail.v:18: error: Interface port bus uses unknown modport `consumer' of interface `bus_if'. +1 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold new file mode 100644 index 000000000..601207b55 --- /dev/null +++ b/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. +1 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_modport_input_write_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_modport_input_write_fail-iverilog-stderr.gold new file mode 100644 index 000000000..f8f61b1f6 --- /dev/null +++ b/ivtest/gold/sv_interface_port_modport_input_write_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_modport_input_write_fail.v:21: error: Cannot assign to input modport member `value' through interface port `bus'. +1 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_non_interface_actual_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_non_interface_actual_fail-iverilog-stderr.gold new file mode 100644 index 000000000..4c603b47c --- /dev/null +++ b/ivtest/gold/sv_interface_port_non_interface_actual_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_non_interface_actual_fail.v:9: error: Actual for interface port `bus' is not an interface instance. +Elaboration failed diff --git a/ivtest/gold/sv_interface_port_unlisted_member_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_unlisted_member_fail-iverilog-stderr.gold new file mode 100644 index 000000000..4295dc034 --- /dev/null +++ b/ivtest/gold/sv_interface_port_unlisted_member_fail-iverilog-stderr.gold @@ -0,0 +1,3 @@ +ivltests/sv_interface_port_unlisted_member_fail.v:24: error: Interface member `hidden' is not listed in modport `consumer'. +ivltests/sv_interface_port_unlisted_member_fail.v:24: error: Unable to elaborate r-value: bus.hidden +2 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_wrong_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_wrong_type_fail-iverilog-stderr.gold new file mode 100644 index 000000000..44e3c706c --- /dev/null +++ b/ivtest/gold/sv_interface_port_wrong_type_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_wrong_type_fail.v:9: error: Interface port `bus' expects interface type `bus_if' but actual `bus' has type `other_if'. +Elaboration failed diff --git a/ivtest/ivltests/sv_interface_port_basic.v b/ivtest/ivltests/sv_interface_port_basic.v new file mode 100644 index 000000000..a9054a523 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_basic.v @@ -0,0 +1,47 @@ +// This tests a SystemVerilog interface-typed module port with an +// explicit modport and a named actual interface instance connection. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + logic [7:0] lhs; + logic [7:0] rhs; + + bus_if bus(); + + add_if dut(.bus(bus)); + + assign bus.lhs = lhs; + assign bus.rhs = rhs; + + initial begin + lhs = 8'd5; + rhs = 8'd7; + #1; + if (bus.sum !== 9'd12) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +interface bus_if #(parameter WIDTH = 8) (); + logic [WIDTH-1:0] lhs; + logic [WIDTH-1:0] rhs; + logic [WIDTH:0] sum; + + modport consumer( + input lhs, + input rhs, + output sum + ); + +endinterface + +module add_if #(parameter WIDTH = 8) ( + bus_if.consumer bus +); + assign bus.sum = bus.lhs + bus.rhs; +endmodule diff --git a/ivtest/ivltests/sv_interface_port_missing_modport_fail.v b/ivtest/ivltests/sv_interface_port_missing_modport_fail.v new file mode 100644 index 000000000..b1fa58f7b --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_missing_modport_fail.v @@ -0,0 +1,22 @@ +// This tests the diagnostic path for an interface-typed module port +// that names a modport missing from the interface definition. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + bus_user dut(.bus(bus)); +endmodule + +interface bus_if (); + logic value; + + modport producer(output value); +endinterface + +module bus_user( + bus_if.consumer bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_missing_type_fail.v new file mode 100644 index 000000000..df1a5a513 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_missing_type_fail.v @@ -0,0 +1,11 @@ +// This tests the diagnostic path for an interface-typed module port +// whose interface type name is not declared. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module bus_user( + missing_if.consumer bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_modport_input_write_fail.v b/ivtest/ivltests/sv_interface_port_modport_input_write_fail.v new file mode 100644 index 000000000..d08f9016d --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_modport_input_write_fail.v @@ -0,0 +1,22 @@ +// This tests rejection of an assignment through a member declared input +// by the selected interface modport. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + bus_user dut(.bus(bus)); +endmodule + +interface bus_if (); + logic value; + + modport consumer(input value); +endinterface + +module bus_user( + bus_if.consumer bus +); + assign bus.value = 1'b1; +endmodule diff --git a/ivtest/ivltests/sv_interface_port_non_interface_actual_fail.v b/ivtest/ivltests/sv_interface_port_non_interface_actual_fail.v new file mode 100644 index 000000000..018f14543 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_non_interface_actual_fail.v @@ -0,0 +1,22 @@ +// This tests rejection of a non-interface actual connected to an +// interface-typed module port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + logic value; + bus_user dut(.bus(value)); +endmodule + +interface bus_if (); + logic value; + + modport consumer(input value); +endinterface + +module bus_user( + bus_if.consumer bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_unlisted_member_fail.v b/ivtest/ivltests/sv_interface_port_unlisted_member_fail.v new file mode 100644 index 000000000..3457e330c --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_unlisted_member_fail.v @@ -0,0 +1,25 @@ +// This tests rejection of access to an interface member that is not +// listed in the selected modport. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + bus_user dut(.bus(bus)); +endmodule + +interface bus_if (); + logic visible; + logic hidden; + + modport consumer(input visible); +endinterface + +module bus_user( + bus_if.consumer bus +); + logic sample; + + assign sample = bus.hidden; +endmodule diff --git a/ivtest/ivltests/sv_interface_port_wrong_type_fail.v b/ivtest/ivltests/sv_interface_port_wrong_type_fail.v new file mode 100644 index 000000000..33dfc40b1 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_wrong_type_fail.v @@ -0,0 +1,28 @@ +// This tests rejection of an actual interface instance whose type does +// not match the interface type of the formal module port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + other_if bus(); + bus_user dut(.bus(bus)); +endmodule + +interface bus_if (); + logic value; + + modport consumer(input value); +endinterface + +interface other_if (); + logic value; + + modport consumer(input value); +endinterface + +module bus_user( + bus_if.consumer bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index e9c9a1633..22f0917b6 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -269,6 +269,13 @@ sv_default_port_value3 vvp_tests/sv_default_port_value3.json sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json sv_interface vvp_tests/sv_interface.json +sv_interface_port_basic vvp_tests/sv_interface_port_basic.json +sv_interface_port_missing_type_fail vvp_tests/sv_interface_port_missing_type_fail.json +sv_interface_port_missing_modport_fail vvp_tests/sv_interface_port_missing_modport_fail.json +sv_interface_port_non_interface_actual_fail vvp_tests/sv_interface_port_non_interface_actual_fail.json +sv_interface_port_wrong_type_fail vvp_tests/sv_interface_port_wrong_type_fail.json +sv_interface_port_modport_input_write_fail vvp_tests/sv_interface_port_modport_input_write_fail.json +sv_interface_port_unlisted_member_fail vvp_tests/sv_interface_port_unlisted_member_fail.json sv_literals vvp_tests/sv_literals.json sv_mixed_assign1 vvp_tests/sv_mixed_assign1.json sv_mixed_assign2 vvp_tests/sv_mixed_assign2.json diff --git a/ivtest/vvp_tests/sv_interface_port_basic.json b/ivtest/vvp_tests/sv_interface_port_basic.json new file mode 100644 index 000000000..33eef112d --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_basic.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_basic.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json b/ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json new file mode 100644 index 000000000..a86412965 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_missing_modport_fail.v", + "gold" : "sv_interface_port_missing_modport_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json new file mode 100644 index 000000000..f43ed1e1c --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_missing_type_fail.v", + "gold" : "sv_interface_port_missing_type_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json b/ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json new file mode 100644 index 000000000..10d17db33 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_modport_input_write_fail.v", + "gold" : "sv_interface_port_modport_input_write_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json b/ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json new file mode 100644 index 000000000..786b3e11d --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_non_interface_actual_fail.v", + "gold" : "sv_interface_port_non_interface_actual_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json b/ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json new file mode 100644 index 000000000..802f08a7e --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_unlisted_member_fail.v", + "gold" : "sv_interface_port_unlisted_member_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json b/ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json new file mode 100644 index 000000000..d0d34c17b --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_wrong_type_fail.v", + "gold" : "sv_interface_port_wrong_type_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/net_scope.cc b/net_scope.cc index d90b49b82..6292817a2 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -812,6 +812,37 @@ const NetScope* NetScope::child(const hname_t&name) const return cur->second; } +void NetScope::add_interface_port_alias(perm_string formal_name, + NetScope*actual_scope, + const PModport*modport) +{ + ivl_assert(*this, actual_scope); + interface_port_aliases_[formal_name] = interface_port_alias_t(actual_scope, modport); +} + +const NetScope::interface_port_alias_t* +NetScope::find_interface_port_alias(perm_string formal_name) const +{ + map::const_iterator cur; + cur = interface_port_aliases_.find(formal_name); + if (cur == interface_port_aliases_.end()) + return 0; + + return &cur->second; +} + +NetScope* NetScope::find_interface_port_alias_scope(perm_string formal_name) const +{ + const interface_port_alias_t*cur = find_interface_port_alias(formal_name); + return cur? cur->actual_scope : 0; +} + +const PModport* NetScope::find_interface_port_modport(perm_string formal_name) const +{ + const interface_port_alias_t*cur = find_interface_port_alias(formal_name); + return cur? cur->modport : 0; +} + /* Helper function to see if the given scope is defined in a class and if * so return the class scope. */ const NetScope* NetScope::get_class_scope() const @@ -867,6 +898,8 @@ bool NetScope::symbol_exists(perm_string sym) return true; if (find_event(sym)) return true; + if (find_interface_port_alias(sym)) + return true; return false; } diff --git a/netlist.h b/netlist.h index d1eb80764..7011c5a9f 100644 --- a/netlist.h +++ b/netlist.h @@ -79,6 +79,7 @@ class NetEvWait; class PClass; class PExpr; class PFunction; +class PModport; class PPackage; class PTaskFunc; class PWire; @@ -1043,6 +1044,26 @@ class NetScope : public Definitions, public Attrib { const NetScope* parent() const { return up_; } const NetScope* child(const hname_t&name) const; + struct interface_port_alias_t { + interface_port_alias_t() : actual_scope(0), modport(0) { } + interface_port_alias_t(NetScope*actual, const PModport*mp) + : actual_scope(actual), modport(mp) { } + + NetScope*actual_scope; + const PModport*modport; + }; + + /* Interface-typed module formals are represented as aliases to + concrete interface instance scopes. These are deliberately kept + out of the real child-scope map; only alias-aware lookup paths + should traverse them. */ + void add_interface_port_alias(perm_string formal_name, + NetScope*actual_scope, + const PModport*modport); + const interface_port_alias_t* find_interface_port_alias(perm_string formal_name) const; + NetScope* find_interface_port_alias_scope(perm_string formal_name) const; + const PModport* find_interface_port_modport(perm_string formal_name) const; + /* A helper function to find the enclosing class scope. */ const NetScope* get_class_scope() const; @@ -1347,6 +1368,7 @@ class NetScope : public Definitions, public Attrib { NetScope*unit_; NetScope*up_; std::map children_; + std::map interface_port_aliases_; unsigned lcounter_; bool need_const_func_, is_const_func_, is_auto_, is_cell_, calls_stask_; diff --git a/netmisc.h b/netmisc.h index be460ad04..ff4aa0e01 100644 --- a/netmisc.h +++ b/netmisc.h @@ -50,6 +50,9 @@ struct symbol_search_results { type = 0; eve = 0; decl_after_use = 0; + interface_alias_scope = 0; + interface_alias_target = 0; + interface_alias_modport = 0; } inline bool is_scope() const { @@ -76,6 +79,10 @@ struct symbol_search_results { return "nothing found"; } + inline bool through_interface_alias() const { + return interface_alias_target != 0; + } + // Scope where symbol was located. This is set in all cases, // assuming the search succeeded. NetScope*scope; @@ -93,6 +100,14 @@ struct symbol_search_results { // one is retained. const LineInfo*decl_after_use; + // If lookup traversed an interface-typed formal port alias, these + // fields describe the alias edge. The resolved object remains in the + // normal scope/net/parameter/event fields. + NetScope*interface_alias_scope; + perm_string interface_alias_name; + NetScope*interface_alias_target; + const PModport*interface_alias_modport; + // Store bread crumbs of the search here. The path_tail is the parts // of the original path that were not found, or are after an object // (and so are probably members or methods). @@ -128,6 +143,10 @@ extern bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, const pform_scoped_name_t &path, unsigned lexical_pos, struct symbol_search_results*res); +extern bool check_interface_modport_access(const LineInfo *li, Design *des, + const symbol_search_results &res, + bool is_write); + /* * This function transforms an expression by either zero or sign extending * the high bits until the expression has the desired width. This may mean diff --git a/parse.y b/parse.y index 10184aeff..99949e7ee 100644 --- a/parse.y +++ b/parse.y @@ -461,6 +461,29 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, return port; } +Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, + char *modport, char *id, + std::list *attributes) +{ + pform_requires_sv(loc, "Interface port declaration"); + + Module::port_t *port = pform_module_interface_port_reference( + loc, lex_strings.make(type), lex_strings.make(modport), + lex_strings.make(id)); + + delete[] type; + delete[] modport; + delete[] id; + + pform_module_define_interface_port(loc, port, attributes); + + port_declaration_context.port_type = NetNet::NOT_A_PORT; + port_declaration_context.port_net_type = NetNet::NONE; + port_declaration_context.data_type = nullptr; + + return port; +} + %} %union { @@ -4603,10 +4626,20 @@ list_of_port_declarations { std::vector *ports = $1; Module::port_t* port; - port = module_declare_port(@4, $4, port_declaration_context.port_type, - port_declaration_context.port_net_type, - port_declaration_context.data_type, - $5, $6, $3); + if (port_declaration_context.port_type == NetNet::NOT_A_PORT) { + yyerror(@4, "error: Incomplete interface port declaration."); + delete[]$4; + delete $5; + delete $6; + delete $3; + port = 0; + } else { + port = module_declare_port(@4, $4, + port_declaration_context.port_type, + port_declaration_context.port_net_type, + port_declaration_context.data_type, + $5, $6, $3); + } ports->push_back(port); $$ = ports; } @@ -4622,6 +4655,9 @@ port_declaration : attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt { $$ = module_declare_port(@5, $5, $2, $3, $4, $6, $7, $1); } + | attribute_list_opt IDENTIFIER '.' IDENTIFIER IDENTIFIER + { $$ = module_declare_interface_port(@5, $2, $4, $5, $1); + } | attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt { pform_requires_sv(@4, "Partial ANSI port declaration"); $$ = module_declare_port(@4, $4, port_declaration_context.port_type, @@ -5715,6 +5751,10 @@ port : port_reference { $$ = $1; } + | IDENTIFIER '.' IDENTIFIER IDENTIFIER + { $$ = module_declare_interface_port(@4, $1, $3, $4, 0); + } + /* This syntax attaches an external name to the port reference so that the caller can bind by name to non-trivial port references. The port_t object gets its PWire from the diff --git a/pform.cc b/pform.cc index c7e337b63..affc5c775 100644 --- a/pform.cc +++ b/pform.cc @@ -1386,6 +1386,33 @@ Module::port_t* pform_module_port_reference(const struct vlltype&loc, return ptmp; } +Module::port_t* pform_module_interface_port_reference( + const struct vlltype&loc, + perm_string interface_type, + perm_string modport_name, + perm_string name) +{ + Module::port_t*ptmp = new Module::port_t; + + ptmp->port_kind = Module::port_t::P_INTERFACE; + ptmp->name = name; + ptmp->interface_type = interface_type; + ptmp->modport_name = modport_name; + ptmp->lexical_pos = loc.lexical_pos; + + return ptmp; +} + +void pform_module_define_interface_port(const struct vlltype&loc, + Module::port_t*port, + list*attr) +{ + ivl_assert(loc, port); + ivl_assert(loc, port->is_interface_port()); + + delete attr; +} + void pform_module_set_ports(vector*ports) { assert(! pform_cur_module.empty()); diff --git a/pform.h b/pform.h index f7d5b491b..2f83c5541 100644 --- a/pform.h +++ b/pform.h @@ -167,6 +167,14 @@ extern void pform_module_define_port(const struct vlltype&li, extern Module::port_t* pform_module_port_reference(const struct vlltype&loc, perm_string name); +extern Module::port_t* pform_module_interface_port_reference( + const struct vlltype&loc, + perm_string interface_type, + perm_string modport_name, + perm_string name); +extern void pform_module_define_interface_port(const struct vlltype&loc, + Module::port_t*port, + std::list*attr); extern void pform_endmodule(const char*, bool inside_celldefine, Module::UCDriveType uc_drive_def); diff --git a/symbol_search.cc b/symbol_search.cc index 61a28d4ec..7b83dd664 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -25,6 +25,7 @@ # include "compiler.h" # include "PPackage.h" # include "PWire.h" +# include "PModport.h" # include "ivl_assert.h" using namespace std; @@ -75,6 +76,25 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, if (! flag) return false; + if (res->net && res->path_tail.empty() && !res->path_head.empty()) { + name_component_t prefix_tail = res->path_head.back(); + if (prefix_tail.index.empty() && + res->scope->child_byname(prefix_tail.name)) { + bool eval_flag = false; + hname_t path_item = eval_path_component(des, start_scope, + prefix_tail, eval_flag); + if (eval_flag) { + cerr << li->get_fileline() << ": XXXXX: Errors evaluating scope index" << endl; + } else if (NetScope*chld = res->scope->child(path_item)) { + if (chld->is_interface()) { + res->scope = chld; + res->net = 0; + res->type = 0; + } + } + } + } + // The prefix is found to be something besides a scope. Put the // tail into the path_tail of the result, and return success. The // caller needs to deal with that tail bit. Note that the @@ -292,6 +312,27 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, } } + if (path_tail.index.empty()) { + if (const NetScope::interface_port_alias_t*alias = + scope->find_interface_port_alias(path_tail.name)) { + path.push_back(path_tail); + res->scope = alias->actual_scope; + res->path_head = path; + res->interface_alias_scope = scope; + res->interface_alias_name = path_tail.name; + res->interface_alias_target = alias->actual_scope; + res->interface_alias_modport = alias->modport; + + if (debug_scopes || debug_elaborate) { + cerr << li->get_fileline() << ": symbol_search: " + << "Interface alias " << path_tail.name + << " -> " << scope_path(alias->actual_scope) << endl; + } + + return true; + } + } + // Don't scan up if we are searching within a prefixed scope. if (prefix_scope) break; @@ -387,3 +428,34 @@ bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, return symbol_search(li, des, search_scope, path.name, lexical_pos, res, search_scope, prefix_scope); } + +bool check_interface_modport_access(const LineInfo *li, Design *des, + const symbol_search_results &res, + bool is_write) +{ + if (!res.through_interface_alias() || !res.interface_alias_modport || !res.net) + return true; + + const PModport *modport = res.interface_alias_modport; + perm_string member = res.net->name(); + map::const_iterator cur = + modport->simple_ports.find(member); + + if (cur == modport->simple_ports.end()) { + cerr << li->get_fileline() << ": error: Interface member `" + << member << "' is not listed in modport `" + << modport->name() << "'." << endl; + des->errors += 1; + return false; + } + + if (is_write && cur->second.first == NetNet::PINPUT) { + cerr << li->get_fileline() << ": error: Cannot assign to input " + "modport member `" << member << "' through interface port `" + << res.interface_alias_name << "'." << endl; + des->errors += 1; + return false; + } + + return true; +} diff --git a/vvp/Makefile.in b/vvp/Makefile.in index c924dda85..a9315c8b5 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -135,6 +135,10 @@ Makefile: $(srcdir)/Makefile.in dep: mkdir dep +# Older dependency files may refer to ivl_dlfcn.h from before the +# shared dlopen wrapper was moved to the top-level source directory. +ivl_dlfcn.h: $(srcdir)/../ivl_dlfcn.h + ifeq (@LIBVVP@,yes) CPPFLAGS+= -fpic From 39072cd4523da6dc4536bfec1d599188cbc5b41b Mon Sep 17 00:00:00 2001 From: Jose Tejada Date: Sun, 10 May 2026 16:34:21 +0200 Subject: [PATCH 033/102] feat(interface): broaden interface port binding --- elaborate.cc | 48 ++++++++++++------- ...warding_restrict_fail-iverilog-stderr.gold | 3 ++ ...onal_unconnected_fail-iverilog-stderr.gold | 2 + ...ted_missing_type_fail-iverilog-stderr.gold | 2 + .../ivltests/sv_interface_port_forwarding.v | 41 ++++++++++++++++ ..._interface_port_forwarding_restrict_fail.v | 31 ++++++++++++ .../sv_interface_port_plain_ansi_regression.v | 29 +++++++++++ .../ivltests/sv_interface_port_positional.v | 33 +++++++++++++ ...terface_port_positional_unconnected_fail.v | 19 ++++++++ ...v_interface_port_typedef_ansi_regression.v | 31 ++++++++++++ .../sv_interface_port_unmodported_basic.v | 40 ++++++++++++++++ ...rface_port_unmodported_missing_type_fail.v | 11 +++++ ivtest/ivltests/sv_interface_port_wildcard.v | 33 +++++++++++++ ivtest/regress-vvp.list | 9 ++++ .../sv_interface_port_forwarding.json | 5 ++ ...terface_port_forwarding_restrict_fail.json | 6 +++ ..._interface_port_plain_ansi_regression.json | 5 ++ .../sv_interface_port_positional.json | 5 ++ ...face_port_positional_unconnected_fail.json | 6 +++ ...nterface_port_typedef_ansi_regression.json | 5 ++ .../sv_interface_port_unmodported_basic.json | 5 ++ ...ce_port_unmodported_missing_type_fail.json | 6 +++ .../vvp_tests/sv_interface_port_wildcard.json | 5 ++ parse.y | 13 ++++- 24 files changed, 374 insertions(+), 19 deletions(-) create mode 100644 ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold create mode 100644 ivtest/ivltests/sv_interface_port_forwarding.v create mode 100644 ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_plain_ansi_regression.v create mode 100644 ivtest/ivltests/sv_interface_port_positional.v create mode 100644 ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v create mode 100644 ivtest/ivltests/sv_interface_port_unmodported_basic.v create mode 100644 ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_wildcard.v create mode 100644 ivtest/vvp_tests/sv_interface_port_forwarding.json create mode 100644 ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json create mode 100644 ivtest/vvp_tests/sv_interface_port_positional.json create mode 100644 ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json create mode 100644 ivtest/vvp_tests/sv_interface_port_unmodported_basic.json create mode 100644 ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_wildcard.json diff --git a/elaborate.cc b/elaborate.cc index 8c12940d1..bd6354164 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -51,6 +51,7 @@ # include "netscalar.h" # include "netclass.h" # include "netmisc.h" +# include "PModport.h" # include "util.h" # include "parse_api.h" # include "compiler.h" @@ -1261,12 +1262,14 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, if (pins_[idx].name[0] == '*') { for (unsigned j = 0 ; j < nexp ; j += 1) { if (rmod->ports[j] && !pins[j] && !pins_is_explicitly_not_connected[j]) { - pins_fromwc[j] = true; pform_name_t path_; path_.push_back(name_component_t(rmod->ports[j]->name)); symbol_search_results sr; symbol_search(this, des, scope, path_, UINT_MAX, &sr); - if (sr.net != 0) { + if (sr.net != 0 || + (rmod->ports[j]->is_interface_port() && + sr.scope != 0 && sr.scope->is_interface())) { + pins_fromwc[j] = true; pins[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true); pins[j]->set_lineno(get_lineno()); pins[j]->set_file(get_file()); @@ -1326,7 +1329,7 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, NetScope*parent_scope, NetScope*instance_scope, const vector&pins, - const vector&pins_fromwc) const + const vector&) const { bool flag = true; @@ -1335,15 +1338,6 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, if (!port || !port->is_interface_port()) continue; - if (pins_fromwc[idx]) { - cerr << get_fileline() << ": sorry: Wildcard connection " - "to interface port `" << port->name - << "' is not yet supported." << endl; - des->errors += 1; - flag = false; - continue; - } - if (!pins[idx]) { cerr << get_fileline() << ": error: Interface port `" << port->name << "' of module " << rmod->mod_name() @@ -1367,8 +1361,15 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, perm_string actual_name = actual_ident->path().name.front().name; NetScope*actual_scope = parent_scope->child(hname_t(actual_name)); - if (!actual_scope) - actual_scope = parent_scope->find_interface_port_alias_scope(actual_name); + const PModport*actual_modport = 0; + if (!actual_scope) { + const NetScope::interface_port_alias_t*actual_alias = + parent_scope->find_interface_port_alias(actual_name); + if (actual_alias) { + actual_scope = actual_alias->actual_scope; + actual_modport = actual_alias->modport; + } + } if (!actual_scope || !actual_scope->is_interface()) { cerr << pins[idx]->get_fileline() << ": error: Actual for " @@ -1391,14 +1392,27 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, map::const_iterator mod = pform_modules.find(port->interface_type); - const PModport*modport = 0; - if (mod != pform_modules.end()) { + const PModport*formal_modport = 0; + if (port->modport_name.str() && mod != pform_modules.end()) { map::const_iterator mp = mod->second->modports.find(port->modport_name); if (mp != mod->second->modports.end()) - modport = mp->second; + formal_modport = mp->second; } + if (actual_modport && formal_modport && + actual_modport->name() != formal_modport->name()) { + cerr << pins[idx]->get_fileline() << ": error: Interface port `" + << port->name << "' cannot forward actual `" << actual_name + << "' restricted by modport `" << actual_modport->name() + << "' to formal modport `" << formal_modport->name() + << "'." << endl; + des->errors += 1; + flag = false; + continue; + } + + const PModport*modport = formal_modport? formal_modport : actual_modport; instance_scope->add_interface_port_alias(port->name, actual_scope, modport); } diff --git a/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold new file mode 100644 index 000000000..90758da05 --- /dev/null +++ b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold @@ -0,0 +1,3 @@ +ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Interface member `hidden' is not listed in modport `consumer'. +ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Unable to elaborate r-value: bus.hidden +2 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold new file mode 100644 index 000000000..8fc0533db --- /dev/null +++ b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_positional_unconnected_fail.v:7: error: Interface port `bus' of module bus_user is not connected. +Elaboration failed diff --git a/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold new file mode 100644 index 000000000..24caf2d27 --- /dev/null +++ b/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_unmodported_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. +1 error(s) during elaboration. diff --git a/ivtest/ivltests/sv_interface_port_forwarding.v b/ivtest/ivltests/sv_interface_port_forwarding.v new file mode 100644 index 000000000..9fb52a87b --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_forwarding.v @@ -0,0 +1,41 @@ +// This tests forwarding an interface-typed formal port to a child +// module while preserving the parent-facing modport view. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + + assign bus.value = 1'b1; + parent dut(.bus(bus)); + + initial begin + #1; + if (bus.mirror !== 1'b1) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module parent( + bus_if.consumer bus +); + child u_child(.bus(bus)); +endmodule + +module child( + bus_if bus +); + assign bus.mirror = bus.value; +endmodule + +interface bus_if (); + logic value; + logic mirror; + logic hidden; + + modport consumer(input value, output mirror); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v new file mode 100644 index 000000000..79a1ced9f --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v @@ -0,0 +1,31 @@ +// This tests that forwarding an interface formal cannot widen access +// beyond the parent-facing modport restriction. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + parent dut(.bus(bus)); +endmodule + +module parent( + bus_if.consumer bus +); + child u_child(.bus(bus)); +endmodule + +module child( + bus_if bus +); + logic sample; + + assign sample = bus.hidden; +endmodule + +interface bus_if (); + logic value; + logic hidden; + + modport consumer(input value); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_plain_ansi_regression.v b/ivtest/ivltests/sv_interface_port_plain_ansi_regression.v new file mode 100644 index 000000000..30ab169a2 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_plain_ansi_regression.v @@ -0,0 +1,29 @@ +// This protects ordinary partial ANSI port parsing near interface +// formal grammar. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + logic [3:0] value; + logic [3:0] result; + + plain dut(value, result); + + initial begin + value = 4'ha; + #1; + if (result !== 4'ha) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module plain( + input logic [3:0] value, + output logic [3:0] result +); + assign result = value; +endmodule diff --git a/ivtest/ivltests/sv_interface_port_positional.v b/ivtest/ivltests/sv_interface_port_positional.v new file mode 100644 index 000000000..d0cb7d057 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_positional.v @@ -0,0 +1,33 @@ +// This tests positional binding of an interface-typed module port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + + assign bus.value = 1'b1; + bus_user dut(bus); + + initial begin + #1; + if (bus.sample !== 1'b1) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module bus_user( + bus_if.consumer bus +); + assign bus.sample = bus.value; +endmodule + +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v new file mode 100644 index 000000000..5b9627b52 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v @@ -0,0 +1,19 @@ +// This tests rejection of an unconnected positional interface port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_user dut(); +endmodule + +module bus_user( + bus_if.consumer bus +); +endmodule + +interface bus_if (); + logic value; + + modport consumer(input value); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v b/ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v new file mode 100644 index 000000000..0fc169015 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_typedef_ansi_regression.v @@ -0,0 +1,31 @@ +// This protects typedef-based ANSI ports from being interpreted as +// interface-typed formals. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +typedef logic [3:0] nibble_t; + +module test; + nibble_t value; + nibble_t result; + + typed dut(value, result); + + initial begin + value = 4'h6; + #1; + if (result !== 4'h6) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module typed( + input nibble_t value, + output nibble_t result +); + assign result = value; +endmodule diff --git a/ivtest/ivltests/sv_interface_port_unmodported_basic.v b/ivtest/ivltests/sv_interface_port_unmodported_basic.v new file mode 100644 index 000000000..c8bad7778 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_unmodported_basic.v @@ -0,0 +1,40 @@ +// This tests a concrete interface-typed module port without an explicit +// modport restriction. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + logic [7:0] lhs; + logic [7:0] rhs; + + bus_if bus(); + + add_if dut(.bus(bus)); + + assign bus.lhs = lhs; + assign bus.rhs = rhs; + + initial begin + lhs = 8'd9; + rhs = 8'd4; + #1; + if (bus.sum !== 9'd13) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module add_if( + bus_if bus +); + assign bus.sum = bus.lhs + bus.rhs; +endmodule + +interface bus_if (); + logic [7:0] lhs; + logic [7:0] rhs; + logic [8:0] sum; +endinterface diff --git a/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v new file mode 100644 index 000000000..b02bb3985 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v @@ -0,0 +1,11 @@ +// This tests the diagnostic path for an unmodported interface-typed +// module port whose interface type name is not declared. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module bus_user( + missing_if bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_wildcard.v b/ivtest/ivltests/sv_interface_port_wildcard.v new file mode 100644 index 000000000..e13630fb6 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_wildcard.v @@ -0,0 +1,33 @@ +// This tests wildcard binding of an interface-typed module port. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module test; + bus_if bus(); + + assign bus.value = 1'b1; + bus_user dut(.*); + + initial begin + #1; + if (bus.sample !== 1'b1) begin + $display("FAILED"); + $finish; + end + $display("PASSED"); + end +endmodule + +module bus_user( + bus_if.consumer bus +); + assign bus.sample = bus.value; +endmodule + +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 22f0917b6..638d8877f 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -276,6 +276,15 @@ sv_interface_port_non_interface_actual_fail vvp_tests/sv_interface_port_non_inte sv_interface_port_wrong_type_fail vvp_tests/sv_interface_port_wrong_type_fail.json sv_interface_port_modport_input_write_fail vvp_tests/sv_interface_port_modport_input_write_fail.json sv_interface_port_unlisted_member_fail vvp_tests/sv_interface_port_unlisted_member_fail.json +sv_interface_port_unmodported_basic vvp_tests/sv_interface_port_unmodported_basic.json +sv_interface_port_unmodported_missing_type_fail vvp_tests/sv_interface_port_unmodported_missing_type_fail.json +sv_interface_port_forwarding vvp_tests/sv_interface_port_forwarding.json +sv_interface_port_forwarding_restrict_fail vvp_tests/sv_interface_port_forwarding_restrict_fail.json +sv_interface_port_positional vvp_tests/sv_interface_port_positional.json +sv_interface_port_positional_unconnected_fail vvp_tests/sv_interface_port_positional_unconnected_fail.json +sv_interface_port_wildcard vvp_tests/sv_interface_port_wildcard.json +sv_interface_port_plain_ansi_regression vvp_tests/sv_interface_port_plain_ansi_regression.json +sv_interface_port_typedef_ansi_regression vvp_tests/sv_interface_port_typedef_ansi_regression.json sv_literals vvp_tests/sv_literals.json sv_mixed_assign1 vvp_tests/sv_mixed_assign1.json sv_mixed_assign2 vvp_tests/sv_mixed_assign2.json diff --git a/ivtest/vvp_tests/sv_interface_port_forwarding.json b/ivtest/vvp_tests/sv_interface_port_forwarding.json new file mode 100644 index 000000000..5983d5d82 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_forwarding.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_forwarding.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json b/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json new file mode 100644 index 000000000..4e26953b8 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_forwarding_restrict_fail.v", + "gold" : "sv_interface_port_forwarding_restrict_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json b/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json new file mode 100644 index 000000000..56b84fc13 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_plain_ansi_regression.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_positional.json b/ivtest/vvp_tests/sv_interface_port_positional.json new file mode 100644 index 000000000..66f253f1d --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_positional.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_positional.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json b/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json new file mode 100644 index 000000000..07880369e --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_positional_unconnected_fail.v", + "gold" : "sv_interface_port_positional_unconnected_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json b/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json new file mode 100644 index 000000000..7b7d719a6 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_typedef_ansi_regression.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json new file mode 100644 index 000000000..01423ed0a --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_unmodported_basic.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json new file mode 100644 index 000000000..d00e41cec --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_unmodported_missing_type_fail.v", + "gold" : "sv_interface_port_unmodported_missing_type_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_wildcard.json b/ivtest/vvp_tests/sv_interface_port_wildcard.json new file mode 100644 index 000000000..d34e83b0e --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_wildcard.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_wildcard.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/parse.y b/parse.y index 99949e7ee..3257e7761 100644 --- a/parse.y +++ b/parse.y @@ -468,11 +468,13 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, pform_requires_sv(loc, "Interface port declaration"); Module::port_t *port = pform_module_interface_port_reference( - loc, lex_strings.make(type), lex_strings.make(modport), + loc, lex_strings.make(type), + modport ? lex_strings.make(modport) : perm_string(), lex_strings.make(id)); delete[] type; - delete[] modport; + if (modport) + delete[] modport; delete[] id; pform_module_define_interface_port(loc, port, attributes); @@ -4658,6 +4660,9 @@ port_declaration | attribute_list_opt IDENTIFIER '.' IDENTIFIER IDENTIFIER { $$ = module_declare_interface_port(@5, $2, $4, $5, $1); } + | attribute_list_opt IDENTIFIER IDENTIFIER + { $$ = module_declare_interface_port(@3, $2, 0, $3, $1); + } | attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt { pform_requires_sv(@4, "Partial ANSI port declaration"); $$ = module_declare_port(@4, $4, port_declaration_context.port_type, @@ -5755,6 +5760,10 @@ port { $$ = module_declare_interface_port(@4, $1, $3, $4, 0); } + | IDENTIFIER IDENTIFIER + { $$ = module_declare_interface_port(@2, $1, 0, $2, 0); + } + /* This syntax attaches an external name to the port reference so that the caller can bind by name to non-trivial port references. The port_t object gets its PWire from the From 2228e31a6a742ad6f3a89c7b263535437aedafcc Mon Sep 17 00:00:00 2001 From: Jose Tejada Date: Sun, 10 May 2026 17:08:35 +0200 Subject: [PATCH 034/102] refactor(interface): share port resolution paths --- Module.cc | 47 +++++++++++++++++++++++++ Module.h | 13 +++++++ elab_sig.cc | 20 ++--------- elaborate.cc | 97 ++++++++++++++++++++++++++++++++-------------------- net_scope.cc | 12 ------- netlist.h | 2 -- 6 files changed, 122 insertions(+), 69 deletions(-) diff --git a/Module.cc b/Module.cc index 5babfb973..212fe87ad 100644 --- a/Module.cc +++ b/Module.cc @@ -21,8 +21,11 @@ # include "Module.h" # include "PGate.h" +# include "PModport.h" # include "PWire.h" +# include "parse_api.h" # include "ivl_assert.h" +# include using namespace std; @@ -33,6 +36,50 @@ Module::port_t::port_t() { } +bool resolve_interface_formal_port(const LineInfo*li, Design*des, + const Module::port_t*port, + interface_formal_port_t&res, + bool emit_errors) +{ + ivl_assert(*li, port); + ivl_assert(*li, port->is_interface_port()); + + res = interface_formal_port_t(); + + map::const_iterator mod = + pform_modules.find(port->interface_type); + if (mod == pform_modules.end() || !mod->second->is_interface) { + if (emit_errors) { + cerr << li->get_fileline() << ": error: Interface port " + << port->name << " uses unknown interface type `" + << port->interface_type << "'." << endl; + des->errors += 1; + } + return false; + } + + res.module = mod->second; + + if (port->modport_name.str()) { + map::const_iterator mp = + mod->second->modports.find(port->modport_name); + if (mp == mod->second->modports.end()) { + if (emit_errors) { + cerr << li->get_fileline() << ": error: Interface port " + << port->name << " uses unknown modport `" + << port->modport_name << "' of interface `" + << port->interface_type << "'." << endl; + des->errors += 1; + } + return false; + } + + res.modport = mp->second; + } + + return true; +} + /* n is a permallocated string. */ Module::Module(LexicalScope*parent, perm_string n) : PScopeExtra(n, parent) diff --git a/Module.h b/Module.h index 2713be544..ac9f3da5d 100644 --- a/Module.h +++ b/Module.h @@ -43,6 +43,7 @@ class PFunction; class PWire; class PProcess; class Design; +class LineInfo; class NetScope; /* @@ -197,4 +198,16 @@ class Module : public PScopeExtra, public PNamedItem { Module& operator= (const Module&); }; +struct interface_formal_port_t { + interface_formal_port_t() : module(0), modport(0) { } + + const Module*module; + const PModport*modport; +}; + +extern bool resolve_interface_formal_port(const LineInfo*li, Design*des, + const Module::port_t*port, + interface_formal_port_t&res, + bool emit_errors); + #endif /* IVL_Module_H */ diff --git a/elab_sig.cc b/elab_sig.cc index d0b202ae0..1526e1426 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -300,24 +300,8 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const continue; if (pp->is_interface_port()) { - map::const_iterator mod = - pform_modules.find(pp->interface_type); - if (mod == pform_modules.end() || !mod->second->is_interface) { - cerr << get_fileline() << ": error: Interface port " - << pp->name << " uses unknown interface type `" - << pp->interface_type << "'." << endl; - des->errors += 1; - continue; - } - - if (pp->modport_name.str() && - mod->second->modports.find(pp->modport_name) == mod->second->modports.end()) { - cerr << get_fileline() << ": error: Interface port " - << pp->name << " uses unknown modport `" - << pp->modport_name << "' of interface `" - << pp->interface_type << "'." << endl; - des->errors += 1; - } + interface_formal_port_t formal; + resolve_interface_formal_port(this, des, pp, formal, true); continue; } diff --git a/elaborate.cc b/elaborate.cc index bd6354164..e8de36fc3 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1325,6 +1325,48 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, return true; } +struct interface_actual_scope_t { + interface_actual_scope_t() : scope(0), modport(0) { } + + NetScope*scope; + const PModport*modport; + perm_string display_name; +}; + +static bool resolve_interface_actual_scope(const PExpr*actual, + NetScope*parent_scope, + Design*des, + interface_actual_scope_t&res) +{ + res = interface_actual_scope_t(); + + const PEIdent*actual_ident = dynamic_cast(actual); + if (!actual_ident || actual_ident->path().package || + actual_ident->path().name.size() != 1 || + !actual_ident->path().name.front().index.empty()) { + return false; + } + + res.display_name = actual_ident->path().name.front().name; + + symbol_search_results sr; + symbol_search(actual, des, parent_scope, actual_ident->path(), + actual_ident->lexical_pos(), &sr); + + res.scope = sr.scope; + if (sr.through_interface_alias()) + res.modport = sr.interface_alias_modport; + else if (NetScope*child = parent_scope->child(hname_t(res.display_name))) + res.scope = child; + else if (const NetScope::interface_port_alias_t*alias = + parent_scope->find_interface_port_alias(res.display_name)) { + res.scope = alias->actual_scope; + res.modport = alias->modport; + } + + return true; +} + bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, NetScope*parent_scope, NetScope*instance_scope, @@ -1347,10 +1389,8 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, continue; } - const PEIdent*actual_ident = dynamic_cast(pins[idx]); - if (!actual_ident || actual_ident->path().package || - actual_ident->path().name.size() != 1 || - !actual_ident->path().name.front().index.empty()) { + interface_actual_scope_t actual; + if (!resolve_interface_actual_scope(pins[idx], parent_scope, des, actual)) { cerr << pins[idx]->get_fileline() << ": error: Interface port `" << port->name << "' must be connected to a simple " "interface instance name." << endl; @@ -1359,19 +1399,7 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, continue; } - perm_string actual_name = actual_ident->path().name.front().name; - NetScope*actual_scope = parent_scope->child(hname_t(actual_name)); - const PModport*actual_modport = 0; - if (!actual_scope) { - const NetScope::interface_port_alias_t*actual_alias = - parent_scope->find_interface_port_alias(actual_name); - if (actual_alias) { - actual_scope = actual_alias->actual_scope; - actual_modport = actual_alias->modport; - } - } - - if (!actual_scope || !actual_scope->is_interface()) { + if (!actual.scope || !actual.scope->is_interface()) { cerr << pins[idx]->get_fileline() << ": error: Actual for " "interface port `" << port->name << "' is not an interface instance." << endl; @@ -1380,40 +1408,35 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, continue; } - if (actual_scope->module_name() != port->interface_type) { + interface_formal_port_t formal; + resolve_interface_formal_port(pins[idx], des, port, formal, false); + if (!formal.module) + continue; + + if (actual.scope->module_name() != formal.module->mod_name()) { cerr << pins[idx]->get_fileline() << ": error: Interface port `" << port->name << "' expects interface type `" - << port->interface_type << "' but actual `" << actual_name - << "' has type `" << actual_scope->module_name() << "'." << endl; + << port->interface_type << "' but actual `" << actual.display_name + << "' has type `" << actual.scope->module_name() << "'." << endl; des->errors += 1; flag = false; continue; } - map::const_iterator mod = - pform_modules.find(port->interface_type); - const PModport*formal_modport = 0; - if (port->modport_name.str() && mod != pform_modules.end()) { - map::const_iterator mp = - mod->second->modports.find(port->modport_name); - if (mp != mod->second->modports.end()) - formal_modport = mp->second; - } - - if (actual_modport && formal_modport && - actual_modport->name() != formal_modport->name()) { + if (actual.modport && formal.modport && + actual.modport->name() != formal.modport->name()) { cerr << pins[idx]->get_fileline() << ": error: Interface port `" - << port->name << "' cannot forward actual `" << actual_name - << "' restricted by modport `" << actual_modport->name() - << "' to formal modport `" << formal_modport->name() + << port->name << "' cannot forward actual `" << actual.display_name + << "' restricted by modport `" << actual.modport->name() + << "' to formal modport `" << formal.modport->name() << "'." << endl; des->errors += 1; flag = false; continue; } - const PModport*modport = formal_modport? formal_modport : actual_modport; - instance_scope->add_interface_port_alias(port->name, actual_scope, + const PModport*modport = formal.modport? formal.modport : actual.modport; + instance_scope->add_interface_port_alias(port->name, actual.scope, modport); } diff --git a/net_scope.cc b/net_scope.cc index 6292817a2..0719bcc6c 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -831,18 +831,6 @@ NetScope::find_interface_port_alias(perm_string formal_name) const return &cur->second; } -NetScope* NetScope::find_interface_port_alias_scope(perm_string formal_name) const -{ - const interface_port_alias_t*cur = find_interface_port_alias(formal_name); - return cur? cur->actual_scope : 0; -} - -const PModport* NetScope::find_interface_port_modport(perm_string formal_name) const -{ - const interface_port_alias_t*cur = find_interface_port_alias(formal_name); - return cur? cur->modport : 0; -} - /* Helper function to see if the given scope is defined in a class and if * so return the class scope. */ const NetScope* NetScope::get_class_scope() const diff --git a/netlist.h b/netlist.h index 7011c5a9f..4b465fd13 100644 --- a/netlist.h +++ b/netlist.h @@ -1061,8 +1061,6 @@ class NetScope : public Definitions, public Attrib { NetScope*actual_scope, const PModport*modport); const interface_port_alias_t* find_interface_port_alias(perm_string formal_name) const; - NetScope* find_interface_port_alias_scope(perm_string formal_name) const; - const PModport* find_interface_port_modport(perm_string formal_name) const; /* A helper function to find the enclosing class scope. */ const NetScope* get_class_scope() const; From 417ab5444574594dbfa7774416b6a346b5d5044a Mon Sep 17 00:00:00 2001 From: Jose Tejada Date: Sun, 10 May 2026 17:30:54 +0200 Subject: [PATCH 035/102] feat(interface): support interface port arrays --- Module.cc | 2 +- Module.h | 1 + elaborate.cc | 221 +++++++++++++++++- ...modport_restrict_fail-iverilog-stderr.gold | 2 + ...ay_size_mismatch_fail-iverilog-stderr.gold | 2 + .../ivltests/sv_interface_port_array_basic.v | 46 ++++ ...terface_port_array_modport_restrict_fail.v | 16 ++ ..._interface_port_array_size_mismatch_fail.v | 13 ++ .../sv_interface_port_indexed_actual.v | 33 +++ ...v_interface_port_indexed_actual_generate.v | 43 ++++ ivtest/regress-vvp.list | 5 + .../sv_interface_port_array_basic.json | 5 + ...face_port_array_modport_restrict_fail.json | 6 + ...terface_port_array_size_mismatch_fail.json | 6 + .../sv_interface_port_indexed_actual.json | 5 + ...nterface_port_indexed_actual_generate.json | 5 + net_scope.cc | 40 ++++ netlist.h | 8 + parse.y | 19 +- pform.cc | 4 +- pform.h | 3 +- symbol_search.cc | 25 ++ 22 files changed, 491 insertions(+), 19 deletions(-) create mode 100644 ivtest/gold/sv_interface_port_array_modport_restrict_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_array_size_mismatch_fail-iverilog-stderr.gold create mode 100644 ivtest/ivltests/sv_interface_port_array_basic.v create mode 100644 ivtest/ivltests/sv_interface_port_array_modport_restrict_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_array_size_mismatch_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_indexed_actual.v create mode 100644 ivtest/ivltests/sv_interface_port_indexed_actual_generate.v create mode 100644 ivtest/vvp_tests/sv_interface_port_array_basic.json create mode 100644 ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_indexed_actual.json create mode 100644 ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json diff --git a/Module.cc b/Module.cc index 212fe87ad..957822743 100644 --- a/Module.cc +++ b/Module.cc @@ -32,7 +32,7 @@ using namespace std; list Module::user_defparms; Module::port_t::port_t() -: port_kind(P_SIGNAL), default_value(0), lexical_pos(0) +: port_kind(P_SIGNAL), default_value(0), interface_unpacked_dimensions(0), lexical_pos(0) { } diff --git a/Module.h b/Module.h index ac9f3da5d..62082ab68 100644 --- a/Module.h +++ b/Module.h @@ -81,6 +81,7 @@ class Module : public PScopeExtra, public PNamedItem { the explicit interface_type.modport form. */ perm_string interface_type; perm_string modport_name; + std::list*interface_unpacked_dimensions; unsigned lexical_pos; bool is_interface_port() const { return port_kind == P_INTERFACE; } diff --git a/elaborate.cc b/elaborate.cc index e8de36fc3..5fa150c15 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1333,6 +1333,48 @@ struct interface_actual_scope_t { perm_string display_name; }; +struct interface_actual_array_t { + std::map elements; + perm_string display_name; +}; + +static long interface_array_index(unsigned idx, long left, long right) +{ + long low = left < right ? left : right; + long high = left < right ? right : left; + return low < high ? low + idx : low - idx; +} + +static bool interface_formal_range(const Module::port_t*port, + Design*des, NetScope*scope, + const LineInfo*li, + long&left, long&right, + unsigned&count) +{ + if (!port->interface_unpacked_dimensions) { + left = 0; + right = 0; + count = 1; + return true; + } + + if (port->interface_unpacked_dimensions->size() != 1) { + cerr << li->get_fileline() << ": sorry: Interface port `" + << port->name << "' uses a multidimensional array, which " + "is not supported." << endl; + des->errors += 1; + return false; + } + + if (!evaluate_range(des, scope, li, + port->interface_unpacked_dimensions->front(), + left, right)) + return false; + + count = left > right ? left - right + 1 : right - left + 1; + return true; +} + static bool resolve_interface_actual_scope(const PExpr*actual, NetScope*parent_scope, Design*des, @@ -1343,11 +1385,50 @@ static bool resolve_interface_actual_scope(const PExpr*actual, const PEIdent*actual_ident = dynamic_cast(actual); if (!actual_ident || actual_ident->path().package || actual_ident->path().name.size() != 1 || - !actual_ident->path().name.front().index.empty()) { + actual_ident->path().name.front().index.size() > 1) { return false; } - res.display_name = actual_ident->path().name.front().name; + const name_component_t&comp = actual_ident->path().name.front(); + res.display_name = comp.name; + + if (!comp.index.empty()) { + if (comp.index.front().sel != index_component_t::SEL_BIT) { + cerr << actual->get_fileline() << ": sorry: Interface array " + << "slice actuals are not supported." << endl; + des->errors += 1; + return true; + } + + bool error_flag = false; + hname_t actual_name = eval_path_component(des, parent_scope, + comp, error_flag); + if (error_flag) + return true; + + if (NetScope*child = parent_scope->child(actual_name)) + res.scope = child; + else if (actual_name.has_numbers()) { + const NetScope::interface_port_alias_t*alias = + parent_scope->find_interface_port_alias_element( + comp.name, actual_name.peek_number(0)); + if (alias) { + res.scope = alias->actual_scope; + res.modport = alias->modport; + } + } + + if (!res.scope) { + symbol_search_results sr; + symbol_search(actual, des, parent_scope, actual_ident->path(), + actual_ident->lexical_pos(), &sr); + res.scope = sr.scope; + if (sr.through_interface_alias()) + res.modport = sr.interface_alias_modport; + } + + return true; + } symbol_search_results sr; symbol_search(actual, des, parent_scope, actual_ident->path(), @@ -1367,6 +1448,49 @@ static bool resolve_interface_actual_scope(const PExpr*actual, return true; } +static bool resolve_interface_actual_array(const PExpr*actual, + NetScope*parent_scope, + interface_actual_array_t&res) +{ + res = interface_actual_array_t(); + + const PEIdent*actual_ident = dynamic_cast(actual); + if (!actual_ident || actual_ident->path().package || + actual_ident->path().name.size() != 1 || + !actual_ident->path().name.front().index.empty()) + return false; + + perm_string name = actual_ident->path().name.front().name; + res.display_name = name; + + for (NetScope*scope = parent_scope ; scope ; scope = scope->parent()) { + map::const_iterator arr = + scope->instance_arrays.find(name); + if (arr != scope->instance_arrays.end()) { + for (unsigned idx = 0 ; idx < arr->second.size() ; idx += 1) { + NetScope*inst = arr->second[idx]; + if (!inst) + return false; + hname_t hname = inst->fullname(); + if (!hname.has_numbers()) + return false; + res.elements[hname.peek_number(0)] = + NetScope::interface_port_alias_t(inst, 0); + } + return true; + } + + const map*alias_arr = + scope->find_interface_port_alias_array(name); + if (alias_arr) { + res.elements = *alias_arr; + return true; + } + } + + return false; +} + bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, NetScope*parent_scope, NetScope*instance_scope, @@ -1389,6 +1513,94 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, continue; } + long formal_left = 0; + long formal_right = 0; + unsigned formal_count = 1; + if (!interface_formal_range(port, des, instance_scope, pins[idx], + formal_left, formal_right, formal_count)) { + flag = false; + continue; + } + bool formal_is_array = port->interface_unpacked_dimensions != 0; + + interface_formal_port_t formal; + resolve_interface_formal_port(pins[idx], des, port, formal, false); + if (!formal.module) + continue; + + if (formal_is_array) { + interface_actual_array_t actual_array; + if (!resolve_interface_actual_array(pins[idx], parent_scope, actual_array)) { + cerr << pins[idx]->get_fileline() << ": error: Interface " + << "array port `" << port->name << "' must be " + "connected to an interface instance array." << endl; + des->errors += 1; + flag = false; + continue; + } + + if (actual_array.elements.size() != formal_count) { + cerr << pins[idx]->get_fileline() << ": error: Interface " + << "array port `" << port->name << "' expects " + << formal_count << " element(s) but actual `" + << actual_array.display_name << "' has " + << actual_array.elements.size() << " element(s)." << endl; + des->errors += 1; + flag = false; + continue; + } + + unsigned pos = 0; + bool array_ok = true; + for (map::const_iterator cur = + actual_array.elements.begin() + ; cur != actual_array.elements.end() ; ++cur, ++pos) { + NetScope*actual_scope = cur->second.actual_scope; + if (!actual_scope || !actual_scope->is_interface()) { + cerr << pins[idx]->get_fileline() << ": error: Actual " + << "element for interface array port `" + << port->name << "' is not an interface instance." << endl; + des->errors += 1; + array_ok = false; + continue; + } + + if (actual_scope->module_name() != formal.module->mod_name()) { + cerr << pins[idx]->get_fileline() << ": error: Interface " + << "array port `" << port->name + << "' expects interface type `" << port->interface_type + << "' but actual `" << actual_array.display_name + << "' has element type `" << actual_scope->module_name() + << "'." << endl; + des->errors += 1; + array_ok = false; + continue; + } + + if (cur->second.modport && formal.modport && + cur->second.modport->name() != formal.modport->name()) { + cerr << pins[idx]->get_fileline() << ": error: Interface " + << "array port `" << port->name + << "' cannot forward actual `" << actual_array.display_name + << "' restricted by modport `" << cur->second.modport->name() + << "' to formal modport `" << formal.modport->name() + << "'." << endl; + des->errors += 1; + array_ok = false; + continue; + } + + const PModport*modport = formal.modport? + formal.modport : cur->second.modport; + long formal_index = interface_array_index(pos, formal_left, formal_right); + instance_scope->add_interface_port_alias_element( + port->name, formal_index, actual_scope, modport); + } + + flag = flag && array_ok; + continue; + } + interface_actual_scope_t actual; if (!resolve_interface_actual_scope(pins[idx], parent_scope, des, actual)) { cerr << pins[idx]->get_fileline() << ": error: Interface port `" @@ -1408,11 +1620,6 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, continue; } - interface_formal_port_t formal; - resolve_interface_formal_port(pins[idx], des, port, formal, false); - if (!formal.module) - continue; - if (actual.scope->module_name() != formal.module->mod_name()) { cerr << pins[idx]->get_fileline() << ": error: Interface port `" << port->name << "' expects interface type `" diff --git a/ivtest/gold/sv_interface_port_array_modport_restrict_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_array_modport_restrict_fail-iverilog-stderr.gold new file mode 100644 index 000000000..5228fdac6 --- /dev/null +++ b/ivtest/gold/sv_interface_port_array_modport_restrict_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_array_modport_restrict_fail.v:10: error: Cannot assign to input modport member `value' through interface port `bus'. +1 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_array_size_mismatch_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_array_size_mismatch_fail-iverilog-stderr.gold new file mode 100644 index 000000000..ded548edf --- /dev/null +++ b/ivtest/gold/sv_interface_port_array_size_mismatch_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_array_size_mismatch_fail.v:12: error: Interface array port `bus' expects 2 element(s) but actual `buses' has 1 element(s). +Elaboration failed diff --git a/ivtest/ivltests/sv_interface_port_array_basic.v b/ivtest/ivltests/sv_interface_port_array_basic.v new file mode 100644 index 000000000..6915b8c14 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_array_basic.v @@ -0,0 +1,46 @@ +// This tests a one-dimensional interface formal array connected to a +// whole interface instance array, then indexed inside the receiving +// module. + +interface bus_if (); + logic [7:0] value; + modport producer(output value); + modport consumer(input value); +endinterface + +module drive(input [7:0] val, bus_if.producer bus); + assign bus.value = val; +endmodule + +module sample(output [7:0] y, bus_if.consumer bus); + assign y = bus.value; +endmodule + +module child_array(output [7:0] y0, output [7:0] y1, + bus_if.consumer bus[2]); + sample c0(.y(y0), .bus(bus[0])); + sample c1(.y(y1), .bus(bus[1])); +endmodule + +module test; + bus_if buses[2](); + wire [7:0] y0; + wire [7:0] y1; + + drive d0(8'd21, buses[0]); + drive d1(8'd42, buses[1]); + child_array dut(.bus(buses), .y0(y0), .y1(y1)); + + initial begin + #1; + if (y0 !== 8'd21) begin + $display("FAILED: y0=%0d", y0); + $finish; + end + if (y1 !== 8'd42) begin + $display("FAILED: y1=%0d", y1); + $finish; + end + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_interface_port_array_modport_restrict_fail.v b/ivtest/ivltests/sv_interface_port_array_modport_restrict_fail.v new file mode 100644 index 000000000..5a5e96fc9 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_array_modport_restrict_fail.v @@ -0,0 +1,16 @@ +// This tests that modport restrictions apply through indexed interface +// formal array elements. + +interface bus_if (); + logic value; + modport consumer(input value); +endinterface + +module bad(bus_if.consumer bus[1]); + assign bus[0].value = 1'b1; +endmodule + +module test; + bus_if buses[1](); + bad dut(.bus(buses)); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_array_size_mismatch_fail.v b/ivtest/ivltests/sv_interface_port_array_size_mismatch_fail.v new file mode 100644 index 000000000..af2338918 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_array_size_mismatch_fail.v @@ -0,0 +1,13 @@ +// This tests rejection of a whole interface array actual whose size +// does not match the formal interface array size. + +interface bus_if (); +endinterface + +module child(bus_if bus[2]); +endmodule + +module test; + bus_if buses[1](); + child dut(.bus(buses)); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_indexed_actual.v b/ivtest/ivltests/sv_interface_port_indexed_actual.v new file mode 100644 index 000000000..979ef7fbb --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_indexed_actual.v @@ -0,0 +1,33 @@ +// This tests connecting a scalar interface-typed formal to one element +// of an interface instance array. + +interface bus_if (); + logic [7:0] value; + modport producer(output value); + modport consumer(input value); +endinterface + +module drive(input [7:0] val, bus_if.producer bus); + assign bus.value = val; +endmodule + +module sample(output [7:0] y, bus_if.consumer bus); + assign y = bus.value; +endmodule + +module test; + bus_if buses[2](); + wire [7:0] y; + + drive d0(8'd37, buses[0]); + sample s0(.bus(buses[0]), .y(y)); + + initial begin + #1; + if (y !== 8'd37) begin + $display("FAILED: y=%0d", y); + $finish; + end + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_interface_port_indexed_actual_generate.v b/ivtest/ivltests/sv_interface_port_indexed_actual_generate.v new file mode 100644 index 000000000..2ec7690b5 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_indexed_actual_generate.v @@ -0,0 +1,43 @@ +// This tests connecting scalar interface-typed formals to interface +// array elements selected by generated constant indices. + +interface bus_if (); + logic [7:0] value; + modport producer(output value); + modport consumer(input value); +endinterface + +module drive(input [7:0] val, bus_if.producer bus); + assign bus.value = val; +endmodule + +module sample(output [7:0] y, bus_if.consumer bus); + assign y = bus.value; +endmodule + +module test; + bus_if buses[2](); + wire [7:0] y[2]; + + genvar i; + generate + for (i = 0; i < 2; i = i + 1) begin : gen + localparam [7:0] VAL = 8'd11 + i; + drive d(VAL, buses[i]); + sample s(.y(y[i]), .bus(buses[i])); + end + endgenerate + + initial begin + #1; + if (y[0] !== 8'd11) begin + $display("FAILED: y[0]=%0d", y[0]); + $finish; + end + if (y[1] !== 8'd12) begin + $display("FAILED: y[1]=%0d", y[1]); + $finish; + end + $display("PASSED"); + end +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 638d8877f..d205e357e 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -283,6 +283,11 @@ sv_interface_port_forwarding_restrict_fail vvp_tests/sv_interface_port_forwardin sv_interface_port_positional vvp_tests/sv_interface_port_positional.json sv_interface_port_positional_unconnected_fail vvp_tests/sv_interface_port_positional_unconnected_fail.json sv_interface_port_wildcard vvp_tests/sv_interface_port_wildcard.json +sv_interface_port_indexed_actual vvp_tests/sv_interface_port_indexed_actual.json +sv_interface_port_indexed_actual_generate vvp_tests/sv_interface_port_indexed_actual_generate.json +sv_interface_port_array_basic vvp_tests/sv_interface_port_array_basic.json +sv_interface_port_array_modport_restrict_fail vvp_tests/sv_interface_port_array_modport_restrict_fail.json +sv_interface_port_array_size_mismatch_fail vvp_tests/sv_interface_port_array_size_mismatch_fail.json sv_interface_port_plain_ansi_regression vvp_tests/sv_interface_port_plain_ansi_regression.json sv_interface_port_typedef_ansi_regression vvp_tests/sv_interface_port_typedef_ansi_regression.json sv_literals vvp_tests/sv_literals.json diff --git a/ivtest/vvp_tests/sv_interface_port_array_basic.json b/ivtest/vvp_tests/sv_interface_port_array_basic.json new file mode 100644 index 000000000..72ff9a89f --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_array_basic.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_array_basic.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json b/ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json new file mode 100644 index 000000000..01f2e561c --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_array_modport_restrict_fail.v", + "gold" : "sv_interface_port_array_modport_restrict_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json b/ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json new file mode 100644 index 000000000..1876f1bd4 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_array_size_mismatch_fail.v", + "gold" : "sv_interface_port_array_size_mismatch_fail", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_indexed_actual.json b/ivtest/vvp_tests/sv_interface_port_indexed_actual.json new file mode 100644 index 000000000..0d0064b63 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_indexed_actual.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_indexed_actual.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json b/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json new file mode 100644 index 000000000..f8532856c --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_interface_port_indexed_actual_generate.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/net_scope.cc b/net_scope.cc index 0719bcc6c..3c9c5cd3d 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -831,6 +831,44 @@ NetScope::find_interface_port_alias(perm_string formal_name) const return &cur->second; } +void NetScope::add_interface_port_alias_element(perm_string formal_name, + long index, + NetScope*actual_scope, + const PModport*modport) +{ + ivl_assert(*this, actual_scope); + interface_port_alias_arrays_[formal_name][index] = + interface_port_alias_t(actual_scope, modport); +} + +const NetScope::interface_port_alias_t* +NetScope::find_interface_port_alias_element(perm_string formal_name, + long index) const +{ + map >::const_iterator arr; + arr = interface_port_alias_arrays_.find(formal_name); + if (arr == interface_port_alias_arrays_.end()) + return 0; + + map::const_iterator cur; + cur = arr->second.find(index); + if (cur == arr->second.end()) + return 0; + + return &cur->second; +} + +const map* +NetScope::find_interface_port_alias_array(perm_string formal_name) const +{ + map >::const_iterator cur; + cur = interface_port_alias_arrays_.find(formal_name); + if (cur == interface_port_alias_arrays_.end()) + return 0; + + return &cur->second; +} + /* Helper function to see if the given scope is defined in a class and if * so return the class scope. */ const NetScope* NetScope::get_class_scope() const @@ -888,6 +926,8 @@ bool NetScope::symbol_exists(perm_string sym) return true; if (find_interface_port_alias(sym)) return true; + if (find_interface_port_alias_array(sym)) + return true; return false; } diff --git a/netlist.h b/netlist.h index 4b465fd13..b3baec96a 100644 --- a/netlist.h +++ b/netlist.h @@ -1061,6 +1061,13 @@ class NetScope : public Definitions, public Attrib { NetScope*actual_scope, const PModport*modport); const interface_port_alias_t* find_interface_port_alias(perm_string formal_name) const; + void add_interface_port_alias_element(perm_string formal_name, + long index, + NetScope*actual_scope, + const PModport*modport); + const interface_port_alias_t* find_interface_port_alias_element(perm_string formal_name, + long index) const; + const std::map* find_interface_port_alias_array(perm_string formal_name) const; /* A helper function to find the enclosing class scope. */ const NetScope* get_class_scope() const; @@ -1367,6 +1374,7 @@ class NetScope : public Definitions, public Attrib { NetScope*up_; std::map children_; std::map interface_port_aliases_; + std::map > interface_port_alias_arrays_; unsigned lcounter_; bool need_const_func_, is_const_func_, is_auto_, is_cell_, calls_stask_; diff --git a/parse.y b/parse.y index 3257e7761..96830851a 100644 --- a/parse.y +++ b/parse.y @@ -463,6 +463,7 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, char *modport, char *id, + std::list *udims, std::list *attributes) { pform_requires_sv(loc, "Interface port declaration"); @@ -470,7 +471,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, Module::port_t *port = pform_module_interface_port_reference( loc, lex_strings.make(type), modport ? lex_strings.make(modport) : perm_string(), - lex_strings.make(id)); + lex_strings.make(id), udims); delete[] type; if (modport) @@ -4657,11 +4658,11 @@ port_declaration : attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt { $$ = module_declare_port(@5, $5, $2, $3, $4, $6, $7, $1); } - | attribute_list_opt IDENTIFIER '.' IDENTIFIER IDENTIFIER - { $$ = module_declare_interface_port(@5, $2, $4, $5, $1); + | attribute_list_opt IDENTIFIER '.' IDENTIFIER IDENTIFIER dimensions_opt + { $$ = module_declare_interface_port(@5, $2, $4, $5, $6, $1); } - | attribute_list_opt IDENTIFIER IDENTIFIER - { $$ = module_declare_interface_port(@3, $2, 0, $3, $1); + | attribute_list_opt IDENTIFIER IDENTIFIER dimensions_opt + { $$ = module_declare_interface_port(@3, $2, 0, $3, $4, $1); } | attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt { pform_requires_sv(@4, "Partial ANSI port declaration"); @@ -5756,12 +5757,12 @@ port : port_reference { $$ = $1; } - | IDENTIFIER '.' IDENTIFIER IDENTIFIER - { $$ = module_declare_interface_port(@4, $1, $3, $4, 0); + | IDENTIFIER '.' IDENTIFIER IDENTIFIER dimensions_opt + { $$ = module_declare_interface_port(@4, $1, $3, $4, $5, 0); } - | IDENTIFIER IDENTIFIER - { $$ = module_declare_interface_port(@2, $1, 0, $2, 0); + | IDENTIFIER IDENTIFIER dimensions_opt + { $$ = module_declare_interface_port(@2, $1, 0, $2, $3, 0); } /* This syntax attaches an external name to the port reference so diff --git a/pform.cc b/pform.cc index affc5c775..e001914b7 100644 --- a/pform.cc +++ b/pform.cc @@ -1390,7 +1390,8 @@ Module::port_t* pform_module_interface_port_reference( const struct vlltype&loc, perm_string interface_type, perm_string modport_name, - perm_string name) + perm_string name, + list*udims) { Module::port_t*ptmp = new Module::port_t; @@ -1398,6 +1399,7 @@ Module::port_t* pform_module_interface_port_reference( ptmp->name = name; ptmp->interface_type = interface_type; ptmp->modport_name = modport_name; + ptmp->interface_unpacked_dimensions = udims; ptmp->lexical_pos = loc.lexical_pos; return ptmp; diff --git a/pform.h b/pform.h index 2f83c5541..95d60d458 100644 --- a/pform.h +++ b/pform.h @@ -171,7 +171,8 @@ extern Module::port_t* pform_module_interface_port_reference( const struct vlltype&loc, perm_string interface_type, perm_string modport_name, - perm_string name); + perm_string name, + std::list*udims = 0); extern void pform_module_define_interface_port(const struct vlltype&loc, Module::port_t*port, std::list*attr); diff --git a/symbol_search.cc b/symbol_search.cc index 7b83dd664..d05aa8ce9 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -331,6 +331,31 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, return true; } + } else { + bool flag = false; + hname_t path_item = eval_path_component(des, start_scope, path_tail, flag); + if (!flag && path_item.has_numbers() == 1) { + if (const NetScope::interface_port_alias_t*alias = + scope->find_interface_port_alias_element(path_tail.name, + path_item.peek_number(0))) { + path.push_back(path_tail); + res->scope = alias->actual_scope; + res->path_head = path; + res->interface_alias_scope = scope; + res->interface_alias_name = path_tail.name; + res->interface_alias_target = alias->actual_scope; + res->interface_alias_modport = alias->modport; + + if (debug_scopes || debug_elaborate) { + cerr << li->get_fileline() << ": symbol_search: " + << "Interface alias " << path_tail.name + << "[" << path_item.peek_number(0) << "]" + << " -> " << scope_path(alias->actual_scope) << endl; + } + + return true; + } + } } // Don't scan up if we are searching within a prefixed scope. From 5240790480c6b278fc712653c044fe748dad8d48 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 10 May 2026 14:44:16 -0700 Subject: [PATCH 036/102] Fix/update latest cppcheck issues --- cadpli/cppcheck.sup | 2 +- cppcheck.sup | 29 +++++++++------- driver/cppcheck.sup | 9 ++--- elab_expr.cc | 2 +- ivlpp/lexor.lex | 3 +- net_func_eval.cc | 4 +-- synth2.cc | 2 +- tgt-pcb/cppcheck.sup | 1 + tgt-vvp/vvp_scope.c | 4 +-- vpi/cppcheck.sup | 81 ++++++++++++++++++++++---------------------- vpi/sys_display.c | 4 +-- vvp/cppcheck.sup | 17 +++++----- vvp/vthread.cc | 2 +- 13 files changed, 82 insertions(+), 78 deletions(-) diff --git a/cadpli/cppcheck.sup b/cadpli/cppcheck.sup index d08cd7dd5..8a7dbd07e 100644 --- a/cadpli/cppcheck.sup +++ b/cadpli/cppcheck.sup @@ -4,4 +4,4 @@ nullPointerOutOfMemory:cadpli.c:53 nullPointerOutOfMemory:cadpli.c:54 // Unused function -unusedFunction:ivl_dlfcn.h:73 +unusedFunction:ivl_dlfcn.h:87 diff --git a/cppcheck.sup b/cppcheck.sup index 360f39ef5..1147d347e 100644 --- a/cppcheck.sup +++ b/cppcheck.sup @@ -10,13 +10,14 @@ nullPointerOutOfMemory ctuuninitvar:parse_misc.cc:61 // Skip strdup() not constant. -constVariablePointer:main.cc:400 -constVariablePointer:main.cc:404 -constVariablePointer:main.cc:654 +constVariablePointer:main.cc:415 +constVariablePointer:main.cc:419 +constVariablePointer:main.cc:669 // const auto should be const constVariablePointer:elab_expr.cc:344 -constVariablePointer:elab_expr.cc:413 +constVariablePointer:elab_expr.cc:347 +constVariablePointer:elab_expr.cc:416 // The reference cannot be const since it is updated in the calling function. constParameterReference:net_udp.cc:37 @@ -31,26 +32,27 @@ functionStatic:net_link.cc:193 functionStatic:libmisc/StringHeap.cc // Skip not initialized in the constructor for target scope +uninitMemberVar:t-dll.cc:41 uninitMemberVar:t-dll.cc:109 // By convention we put statics at the top scope. variableScope:pform.cc:3461 // These are correct and are used to find the base (zero) pin. -thisSubtraction:netlist.h:5309 -thisSubtraction:netlist.h:5318 +thisSubtraction:netlist.h:5310 +thisSubtraction:netlist.h:5319 // This is used when running a debugger // debugger_release -knownConditionTrueFalse:main.cc:931 +knownConditionTrueFalse:main.cc:949 // These should be checked, but are not real issues -knownConditionTrueFalse:elaborate.cc:7621 +knownConditionTrueFalse:elaborate.cc:7633 knownConditionTrueFalse:elab_sig.cc:271 knownConditionTrueFalse:elab_sig.cc:338 // Yes, it's a duplicate -duplicateCondition:elaborate.cc:7672 +duplicateCondition:elaborate.cc:7684 // To complicated to use std::find_if() useStlAlgorithm:map_named_args.cc:38 @@ -59,7 +61,7 @@ useStlAlgorithm:map_named_args.cc:38 derefInvalidIterator:netmisc.cc:420 // By convention we put statics at the top scope. -variableScope:t-dll.cc:2377 +variableScope:t-dll.cc:2309 // We check memory allocation with valgrind unsafeClassCanLeak:libmisc/StringHeap.h:79 @@ -720,7 +722,7 @@ unusedFunction:Statement.h:192 // chain_args() unusedFunction:Statement.h:341 // gn_modules_nest() -unusedFunction:compiler.h:228 +unusedFunction:compiler.h:245 // driven_mask() unusedFunction:link_const.cc:275 // find_root_scope() @@ -732,7 +734,7 @@ unusedFunction:net_link.cc:689 // get_def_fileline() unusedFunction:net_scope.cc:201 // get_module_port_info() -unusedFunction:net_scope.cc:591 +unusedFunction:net_scope.cc:599 // find_link_signal() unusedFunction:netlist.cc:111 // find_link() @@ -756,13 +758,14 @@ unusedFunction:t-dll-expr.cc:55 // mul_expr_by_const_() unusedFunction:t-dll-expr.cc:91 // net_assign() -unusedFunction:t-dll.cc:2368 +unusedFunction:t-dll.cc:2300 // is_before() unusedFunction:verinum.cc:588 // Errors/limitations in the generated yacc and lex files constVariablePointer: cstyleCast: +duplicateBreak: nullPointer: redundantInitialization: syntaxError: diff --git a/driver/cppcheck.sup b/driver/cppcheck.sup index f33c05c09..70838cc38 100644 --- a/driver/cppcheck.sup +++ b/driver/cppcheck.sup @@ -1,10 +1,10 @@ // cppcheck is wrong this is correct usage -syntaxError:main.c:405 -syntaxError:main.c:408 +syntaxError:main.c:410 +syntaxError:main.c:413 // cppcheck is missing the code adds a \0 at the previous location. -knownConditionTrueFalse:main.c:1086 -redundantAssignment:main.c:1085 +knownConditionTrueFalse:main.c:1123 +redundantAssignment:main.c:1122 // Skip all memory issues since they should be handled by ivl_alloc.h memleakOnRealloc @@ -21,6 +21,7 @@ constVariablePointer:cfparse.c knownConditionTrueFalse:cfparse.c sizeofwithnumericparameter:cfparse.c constVariablePointer: +duplicateBreak: nullPointer: redundantInitialization: staticFunction: diff --git a/elab_expr.cc b/elab_expr.cc index 0902f5be1..265e0e8d6 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -344,7 +344,7 @@ NetExpr* PEAssignPattern::elaborate_expr_uarray_(Design *des, NetScope *scope, if (const auto ap = dynamic_cast(parms_[idx])) { expr = ap->elaborate_expr_uarray_(des, scope, uarray_type, dims, cur_dim, need_const); - } else if (auto s = dynamic_cast(parms_[idx])) { + } else if (const auto s = dynamic_cast(parms_[idx])) { expr = s->elaborate_expr_uarray_(des, scope, uarray_type, dims, cur_dim); } else if (dynamic_cast(parms_[idx])) { diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index b20d27119..6da2aaafe 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1692,7 +1692,6 @@ static void expand_using_args(void) char* head; char* tail; char* dest; - int arg; int length; if (def_argc > cur_macro->argc) { @@ -1721,7 +1720,7 @@ static void expand_using_args(void) if (*tail != ARG_MARK) { tail++; } else { - arg = tail[1]; assert(arg < def_argc); + int arg = tail[1]; assert(arg < def_argc); const char*use_argv; int use_argl; diff --git a/net_func_eval.cc b/net_func_eval.cc index 19327ea27..c116d0043 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2026 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 @@ -525,7 +525,7 @@ bool NetBlock::evaluate_function(const LineInfo&loc, map&use_context_map = use_local_context_map? local_context_map : context_map; bool flag = true; - NetProc*cur = last_; + const NetProc*cur = last_; do { cur = cur->next_; if (debug_eval_tree) { diff --git a/synth2.cc b/synth2.cc index f44f87f76..b5f92a7d5 100644 --- a/synth2.cc +++ b/synth2.cc @@ -360,7 +360,7 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, return false; } - NetNet*lsig = lval_->sig(); + const NetNet*lsig = lval_->sig(); if (!lsig) { cerr << get_fileline() << ": error: " "NetAssignBase::synth_async on unsupported lval "; diff --git a/tgt-pcb/cppcheck.sup b/tgt-pcb/cppcheck.sup index 789847374..b79920b11 100644 --- a/tgt-pcb/cppcheck.sup +++ b/tgt-pcb/cppcheck.sup @@ -13,6 +13,7 @@ constParameterPointer:fp.cc knownConditionTrueFalse:fp.cc constVariablePointer:fp_lex.cc cstyleCast:fp_lex.cc +duplicateBreak:fp_lex.cc nullPointer:fp_lex.cc redundantInitialization:fp_lex.cc unusedFunction:fp_lex.cc diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 467ae6d8a..5600e1abd 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2026 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 @@ -912,7 +912,7 @@ static void draw_equiv_impl_in_scope(ivl_net_logic_t lptr) unsigned ninp; const char *lval; const char *rval; - const char*ltype = "?"; + const char *ltype; assert(width_of_nexus(ivl_logic_pin(lptr, 0)) == 1); diff --git a/vpi/cppcheck.sup b/vpi/cppcheck.sup index 30a59239e..078495990 100644 --- a/vpi/cppcheck.sup +++ b/vpi/cppcheck.sup @@ -63,7 +63,6 @@ constParameterPointer:fstapi.c constVariablePointer:fstapi.c duplicateConditionalAssign:fstapi.c knownConditionTrueFalse:fstapi.c -memleak:fstapi.c missingInclude:fst_win_unistd.h:50 nullPointer:fstapi.c shiftTooManyBits:fstapi.c @@ -75,85 +74,85 @@ uselessAssignmentPtrArg:fstapi.c variableScope:fstapi.c // These functions are not used by Icarus // fstReaderClrFacProcessMask() -unusedFunction:fstapi.c:3513 +unusedFunction:fstapi.c:3514 // fstReaderClrFacProcessMaskAll() -unusedFunction:fstapi.c:3533 +unusedFunction:fstapi.c:3534 // fstReaderGetAliasCount() -unusedFunction:fstapi.c:3578 +unusedFunction:fstapi.c:3579 // fstReaderGetCurrentFlatScope() -unusedFunction:fstapi.c:3392 +unusedFunction:fstapi.c:3393 // fstReaderGetCurrentScopeLen() -unusedFunction:fstapi.c:3465 +unusedFunction:fstapi.c:3466 // fstReaderGetCurrentScopeUserInfo() -unusedFunction:fstapi.c:3401 +unusedFunction:fstapi.c:3402 // fstReaderGetDateString() -unusedFunction:fstapi.c:3598 +unusedFunction:fstapi.c:3599 // fstReaderGetDoubleEndianMatchState() -unusedFunction:fstapi.c:3588 +unusedFunction:fstapi.c:3589 // fstReaderGetDumpActivityChangeTime() -unusedFunction:fstapi.c:3618 +unusedFunction:fstapi.c:3619 // fstReaderGetDumpActivityChangeValue() -unusedFunction:fstapi.c:3627 +unusedFunction:fstapi.c:3628 // fstReaderGetEndTime() -unusedFunction:fstapi.c:3553 +unusedFunction:fstapi.c:3554 // fstReaderGetFacProcessMask() -unusedFunction:fstapi.c:3486 +unusedFunction:fstapi.c:3487 // fstReaderGetFileType() -unusedFunction:fstapi.c:3603 +unusedFunction:fstapi.c:3604 // fstReaderGetFseekFailed() -unusedFunction:fstapi.c:3474 +unusedFunction:fstapi.c:3475 // fstReaderGetMaxHandle() -unusedFunction:fstapi.c:3573 +unusedFunction:fstapi.c:3574 // fstReaderGetMemoryUsedByWriter() -unusedFunction:fstapi.c:3558 +unusedFunction:fstapi.c:3559 // fstReaderGetNumberDumpActivityChanges() -unusedFunction:fstapi.c:3613 +unusedFunction:fstapi.c:3614 // fstReaderGetScopeCount() -unusedFunction:fstapi.c:3563 +unusedFunction:fstapi.c:3564 // fstReaderGetStartTime() -unusedFunction:fstapi.c:3548 +unusedFunction:fstapi.c:3549 // fstReaderGetTimescale() -unusedFunction:fstapi.c:3543 +unusedFunction:fstapi.c:3544 // fstReaderGetTimezero() -unusedFunction:fstapi.c:3608 +unusedFunction:fstapi.c:3609 // fstReaderGetValueChangeSectionCount() -unusedFunction:fstapi.c:3583 +unusedFunction:fstapi.c:3584 // fstReaderGetValueFromHandleAtTime() -unusedFunction:fstapi.c:5952 +unusedFunction:fstapi.c:5953 // fstReaderGetVarCount() -unusedFunction:fstapi.c:3568 +unusedFunction:fstapi.c:3569 // fstReaderGetVersionString() -unusedFunction:fstapi.c:3593 +unusedFunction:fstapi.c:3594 // fstReaderIterBlocks() -unusedFunction:fstapi.c:4832 +unusedFunction:fstapi.c:4833 // fstReaderIterBlocksSetNativeDoublesOnCallback() -unusedFunction:fstapi.c:3659 +unusedFunction:fstapi.c:3660 // fstReaderIterateHier() -unusedFunction:fstapi.c:3872 +unusedFunction:fstapi.c:3873 // fstReaderIterateHierRewind() -unusedFunction:fstapi.c:3856 +unusedFunction:fstapi.c:3857 // fstReaderOpen() -unusedFunction:fstapi.c:4728 +unusedFunction:fstapi.c:4729 // fstReaderOpenForUtilitiesOnly() -unusedFunction:fstapi.c:4721 +unusedFunction:fstapi.c:4722 // fstReaderPushScope() -unusedFunction:fstapi.c:3435 +unusedFunction:fstapi.c:3436 // fstReaderResetScope() -unusedFunction:fstapi.c:3427 +unusedFunction:fstapi.c:3428 // fstReaderSetFacProcessMask() -unusedFunction:fstapi.c:3500 +unusedFunction:fstapi.c:3501 // fstReaderSetFacProcessMaskAll() -unusedFunction:fstapi.c:3526 +unusedFunction:fstapi.c:3527 // fstReaderSetLimitTimeRange() -unusedFunction:fstapi.c:3636 +unusedFunction:fstapi.c:3637 // fstReaderSetUnlimitedTimeRange() -unusedFunction:fstapi.c:3645 +unusedFunction:fstapi.c:3646 // fstReaderSetVcdExtensions() -unusedFunction:fstapi.c:3652 +unusedFunction:fstapi.c:3653 // fstUtilityExtractEnumTableFromString() -unusedFunction:fstapi.c:6930 +unusedFunction:fstapi.c:6931 // fstUtilityFreeEnumTable() -unusedFunction:fstapi.c:6995 +unusedFunction:fstapi.c:6996 // fstWriterCreateEnumTable() unusedFunction:fstapi.c:2715 // fstWriterCreateVar2() diff --git a/vpi/sys_display.c b/vpi/sys_display.c index dad17f127..d5b3f2923 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -838,7 +838,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", info->filename, info->lineno, info->name, fmtb); } else { - PLI_INT32 veclen, word, elem, bits, byte; + PLI_INT32 veclen, word, elem, byte; char *cp; veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32; @@ -849,7 +849,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, for (word = 0; word < veclen; word += 1) { /* Write the aval followed by the bval in endian order. */ for (elem = 0; elem < 2; elem += 1) { - bits = *(&value.value.vector[word].aval+elem); + PLI_INT32 bits = *(&value.value.vector[word].aval+elem); #ifdef WORDS_BIGENDIAN for (byte = 3; byte >= 0; byte -= 1) { #else diff --git a/vvp/cppcheck.sup b/vvp/cppcheck.sup index 39319c661..128d0ab86 100644 --- a/vvp/cppcheck.sup +++ b/vvp/cppcheck.sup @@ -37,8 +37,8 @@ useInitializationList:delay.cc:513 constParameterPointer:vpi_priv.cc:1458 // Operator new/delete are static so cannot override -duplInheritedMember:vvp_net.h:1476 -duplInheritedMember:vvp_net.h:1477 +duplInheritedMember:vvp_net.h:1481 +duplInheritedMember:vvp_net.h:1482 duplInheritedMember:vvp_net_sig.h:187 duplInheritedMember:vvp_net_sig.h:188 duplInheritedMember:vvp_net_sig.h:253 @@ -154,10 +154,10 @@ redundantAssignment:vpi_modules.cc:117 invalidScanfArgType_int:compile.cc:597 invalidScanfArgType_int:compile.cc:603 invalidScanfArgType_int:compile.cc:609 -invalidScanfArgType_int:vthread.cc:4545 -invalidScanfArgType_int:vthread.cc:4548 -invalidScanfArgType_int:vthread.cc:4551 -invalidScanfArgType_int:vthread.cc:4554 +invalidScanfArgType_int:vthread.cc:4541 +invalidScanfArgType_int:vthread.cc:4544 +invalidScanfArgType_int:vthread.cc:4547 +invalidScanfArgType_int:vthread.cc:4550 // The new() operator is always used to allocate space for this class and // pool is defined there. @@ -227,14 +227,15 @@ unusedFunction:vvp_net.cc:1752 // as_string() unusedFunction:vvp_net.cc:1855 // fully_featured_resolv_() -unusedFunction:vvp_net.cc:3581 +unusedFunction:vvp_net.cc:3704 // words() -unusedFunction:vvp_net.h:595 +unusedFunction:vvp_net.h:600 // force_vec8() unusedFunction:vvp_net_sig.cc:128 // Unused functions from the lexor duplicateBreak:lexor.lex +duplicateBreak:lexor.cc unusedStructMember:lexor.lex constVariablePointer:lexor.cc cstyleCast:lexor.cc diff --git a/vvp/vthread.cc b/vvp/vthread.cc index cd3b679fe..98cd41a99 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -6139,7 +6139,7 @@ bool of_STORE_STRA(vthread_t thr, vvp_code_t cp) bool of_STORE_VEC4(vthread_t thr, vvp_code_t cp) { vvp_net_ptr_t ptr(cp->net, 0); - vvp_signal_value*sig = dynamic_cast (cp->net->fil); + const vvp_signal_value*sig = dynamic_cast (cp->net->fil); unsigned off_index = cp->bit_idx[0]; unsigned int wid = cp->bit_idx[1]; From fde4ef85c138b1e1e0c4398a6713e1ed0f549fe2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 10 May 2026 14:53:36 -0700 Subject: [PATCH 037/102] elab: Use common new array initializer elaboration here are two separate paths `PENewArray::elaborate_expr()`, one for assignment patterns and one for everything else. But since since commit 5ca058bfb ("Add support for darray initialisation from another darray"). The two paths have been effectively the same. Both call `elaborate_expr()` on the init values with the same parameters. The only difference is the regular path casts the type to `netarray_t`, but that doesn't really do anything since it gets passed to a function that takes a `ivl_type_t`, so is immediately cast back to the base type. The comment on the regular path is also outdated since it still refers to the tpre 5ca058bfb code. Remove the branching and route it through the same path. Signed-off-by: Lars-Peter Clausen --- elab_expr.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 0902f5be1..ecdcda361 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -6654,19 +6654,8 @@ NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*scope, NetExpr*size = size_->elaborate_expr(des, scope, use_wid, flags); NetExpr*init_val = 0; - if (dynamic_cast (init_)) { - // Special case: the initial value expression is an - // array_pattern. Elaborate the expression like the - // r-value to an assignment to array. + if (init_) { init_val = init_->elaborate_expr(des, scope, ntype, flags); - - } else if (init_) { - // Regular case: The initial value is an - // expression. Elaborate the expression as an element - // type. The run-time will assign this value to each element. - const netarray_t*array_type = dynamic_cast (ntype); - - init_val = init_->elaborate_expr(des, scope, array_type, flags); } NetENew*tmp = new NetENew(ntype, size, init_val); From 13d5155e88f505e76c70f45a7b7e2b1f5f728af5 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 10 May 2026 15:18:21 -0700 Subject: [PATCH 038/102] Docopt is no longer used in the Python test script --- .github/workflows/test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3dfaa7f89..60777bd6a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,6 @@ jobs: - name: Install dependencies run: | brew install bison - pip3 install --break-system-packages docopt - name: Build, check and install run: | @@ -55,7 +54,7 @@ jobs: - name: Install dependencies run: | sudo apt update -qq - sudo apt install -y make g++ git bison flex gperf libreadline-dev libbz2-dev autoconf python3-sphinx python3-docopt + sudo apt install -y make g++ git bison flex gperf libreadline-dev libbz2-dev autoconf python3-sphinx - name: Build, check and install run: | From ba74c7b5ad49e36440d45383559c1152a1a56095 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 10 May 2026 21:21:32 -0700 Subject: [PATCH 039/102] Reject `real` array indices Array indices must be integral expressions. Using a real valued expression as an unpacked array index currently reaches the vvp real expression code and triggers an assert. Packed bit and part select indices already report an elaboration error for real expressions since commit 2249d224deaa ("Bit/part selects cannot have real index expressions"). Do the same for unpacked array indices. Signed-off-by: Lars-Peter Clausen --- netmisc.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index 9e4162800..66e852820 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2026 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 @@ -509,8 +509,15 @@ void indices_to_expressions(Design*des, NetScope*scope, NetExpr*word_index = elab_and_eval(des, scope, cur->msb, -1, need_const); - if (word_index == 0) + if (!word_index) { flags.invalid = true; + } else if (word_index->expr_type() == IVL_VT_REAL) { + cerr << cur->msb->get_fileline() << ": error: " + << "Array index expression cannot be a real value." + << endl; + des->errors += 1; + flags.invalid = true; + } // Track if we detect any non-constant expressions // here. This may allow for a special case. From ea57b6dd9ac8b8563498ce69c10471e76ae81403 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 10 May 2026 22:12:36 -0700 Subject: [PATCH 040/102] Add regression test for real array index error Check that using a real valued expression as an array index is rejected during elaboration. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/array_index_real_fail.v | 12 ++++++++++++ ivtest/regress-vvp.list | 1 + ivtest/vvp_tests/array_index_real_fail.json | 4 ++++ 3 files changed, 17 insertions(+) create mode 100644 ivtest/ivltests/array_index_real_fail.v create mode 100644 ivtest/vvp_tests/array_index_real_fail.json diff --git a/ivtest/ivltests/array_index_real_fail.v b/ivtest/ivltests/array_index_real_fail.v new file mode 100644 index 000000000..763e24ee9 --- /dev/null +++ b/ivtest/ivltests/array_index_real_fail.v @@ -0,0 +1,12 @@ +// Check that real expressions can not be used as array indices. + +module test; + + reg [1:0] a[1:0]; + real r; + + initial begin + a[r] = 2'b10; + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index e9c9a1633..13b3a3bf8 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -6,6 +6,7 @@ always4A vvp_tests/always4A.json always4B vvp_tests/always4B.json analog1 vvp_tests/analog1.json analog2 vvp_tests/analog2.json +array_index_real_fail vvp_tests/array_index_real_fail.json array_packed_sysfunct vvp_tests/array_packed_sysfunct.json array_packed_value_list vvp_tests/array_packed_value_list.json array_packed_write_read vvp_tests/array_packed_write_read.json diff --git a/ivtest/vvp_tests/array_index_real_fail.json b/ivtest/vvp_tests/array_index_real_fail.json new file mode 100644 index 000000000..a4b453e0a --- /dev/null +++ b/ivtest/vvp_tests/array_index_real_fail.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "array_index_real_fail.v" +} From 377881b72361370fa79c3a843ce7edcb51f28cc2 Mon Sep 17 00:00:00 2001 From: Jose Tejada Date: Mon, 11 May 2026 07:44:43 +0200 Subject: [PATCH 041/102] fix(interface): address port array review feedback --- elaborate.cc | 41 +++++++++++++++---- ...warding_restrict_fail-iverilog-stderr.gold | 4 +- ...ort_missing_type_fail-iverilog-stderr.gold | 2 - ...onal_unconnected_fail-iverilog-stderr.gold | 2 +- ...ted_missing_type_fail-iverilog-stderr.gold | 2 - .../ivltests/sv_interface_port_forwarding.v | 16 ++++---- ..._interface_port_forwarding_restrict_fail.v | 14 +++---- .../sv_interface_port_missing_type_fail.v | 11 ----- .../ivltests/sv_interface_port_positional.v | 14 +++---- ...terface_port_positional_unconnected_fail.v | 12 +++--- .../sv_interface_port_unmodported_basic.v | 12 +++--- ...rface_port_unmodported_missing_type_fail.v | 11 ----- ivtest/ivltests/sv_interface_port_wildcard.v | 14 +++---- ivtest/regress-vvp.list | 2 - .../sv_interface_port_array_basic.json | 2 +- ...face_port_array_modport_restrict_fail.json | 2 +- ...terface_port_array_size_mismatch_fail.json | 2 +- ivtest/vvp_tests/sv_interface_port_basic.json | 2 +- .../sv_interface_port_forwarding.json | 2 +- ...terface_port_forwarding_restrict_fail.json | 2 +- .../sv_interface_port_indexed_actual.json | 2 +- ...nterface_port_indexed_actual_generate.json | 2 +- ...v_interface_port_missing_modport_fail.json | 2 +- .../sv_interface_port_missing_type_fail.json | 6 --- ...terface_port_modport_input_write_fail.json | 2 +- ...erface_port_non_interface_actual_fail.json | 2 +- ..._interface_port_plain_ansi_regression.json | 2 +- .../sv_interface_port_positional.json | 2 +- ...face_port_positional_unconnected_fail.json | 2 +- ...nterface_port_typedef_ansi_regression.json | 2 +- ...v_interface_port_unlisted_member_fail.json | 2 +- .../sv_interface_port_unmodported_basic.json | 2 +- ...ce_port_unmodported_missing_type_fail.json | 6 --- .../vvp_tests/sv_interface_port_wildcard.json | 2 +- .../sv_interface_port_wrong_type_fail.json | 2 +- lexor.lex | 11 +++++ net_scope.cc | 9 ++-- netlist.h | 2 +- parse.y | 28 ++++++++----- parse_misc.h | 5 +++ pform.cc | 8 ++++ symbol_search.cc | 2 +- vvp/Makefile.in | 4 -- 43 files changed, 142 insertions(+), 134 deletions(-) delete mode 100644 ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold delete mode 100644 ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold delete mode 100644 ivtest/ivltests/sv_interface_port_missing_type_fail.v delete mode 100644 ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v delete mode 100644 ivtest/vvp_tests/sv_interface_port_missing_type_fail.json delete mode 100644 ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json diff --git a/elaborate.cc b/elaborate.cc index 5fa150c15..8efdfc8bd 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1255,13 +1255,19 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, vector&pins_fromwc, vector&pins_is_explicitly_not_connected) const { + // If the instance has a pins_ member, then we know we are + // binding by name. Therefore, make up a pins array that + // reflects the positions of the named ports. if (pins_) { unsigned nexp = rmod->port_count(); + // Scan the bindings, matching them with port names. for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { + // Handle wildcard named port. if (pins_[idx].name[0] == '*') { for (unsigned j = 0 ; j < nexp ; j += 1) { if (rmod->ports[j] && !pins[j] && !pins_is_explicitly_not_connected[j]) { + pins_fromwc[j] = true; pform_name_t path_; path_.push_back(name_component_t(rmod->ports[j]->name)); symbol_search_results sr; @@ -1269,7 +1275,6 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, if (sr.net != 0 || (rmod->ports[j]->is_interface_port() && sr.scope != 0 && sr.scope->is_interface())) { - pins_fromwc[j] = true; pins[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true); pins[j]->set_lineno(get_lineno()); pins[j]->set_file(get_file()); @@ -1279,7 +1284,13 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, continue; } + // Given a binding, look at the module port names + // for the position that matches the binding name. unsigned pidx = rmod->find_port(pins_[idx].name); + + // If the port name doesn't exist, the find_port + // method will return the port count. Detect that + // as an error. if (pidx == nexp) { cerr << get_fileline() << ": error: port ``" << pins_[idx].name << "'' is not a port of " @@ -1288,10 +1299,16 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, continue; } + // If I am overriding a wildcard port, delete and + // override it. if (pins_fromwc[pidx]) { delete pins[pidx]; pins_fromwc[pidx] = false; + // If I already explicitly bound something to + // this port, then the pins array will already + // have a pointer value where I want to place this + // expression. } else if (pins[pidx]) { cerr << get_fileline() << ": error: port ``" << pins_[idx].name << "'' already bound." << @@ -1300,16 +1317,26 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, continue; } + // OK, do the binding by placing the expression in + // the right place. pins[pidx] = pins_[idx].parm; if (!pins[pidx]) pins_is_explicitly_not_connected[pidx] = true; } } else if (pin_count() == 0) { + /* Handle the special case that no ports are + connected. It is possible that this is an empty + connect-by-name list, so we'll allow it and assume + that is the case. */ for (unsigned idx = 0 ; idx < rmod->port_count() ; idx += 1) pins[idx] = 0; } else { + /* Otherwise, this is a positional list of port + connections. Use as many ports as provided. Trailing + missing ports will be left unconnect or use the default + value if one is available. */ if (pin_count() > rmod->port_count()) { cerr << get_fileline() << ": error: Wrong number " "of ports. Expecting at most " << rmod->port_count() << @@ -1326,7 +1353,7 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, } struct interface_actual_scope_t { - interface_actual_scope_t() : scope(0), modport(0) { } + interface_actual_scope_t() : scope(nullptr), modport(nullptr) { } NetScope*scope; const PModport*modport; @@ -1464,8 +1491,7 @@ static bool resolve_interface_actual_array(const PExpr*actual, res.display_name = name; for (NetScope*scope = parent_scope ; scope ; scope = scope->parent()) { - map::const_iterator arr = - scope->instance_arrays.find(name); + auto arr = scope->instance_arrays.find(name); if (arr != scope->instance_arrays.end()) { for (unsigned idx = 0 ; idx < arr->second.size() ; idx += 1) { NetScope*inst = arr->second[idx]; @@ -1475,7 +1501,7 @@ static bool resolve_interface_actual_array(const PExpr*actual, if (!hname.has_numbers()) return false; res.elements[hname.peek_number(0)] = - NetScope::interface_port_alias_t(inst, 0); + NetScope::interface_port_alias_t(inst, nullptr); } return true; } @@ -1521,7 +1547,7 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, flag = false; continue; } - bool formal_is_array = port->interface_unpacked_dimensions != 0; + bool formal_is_array = port->interface_unpacked_dimensions != nullptr; interface_formal_port_t formal; resolve_interface_formal_port(pins[idx], des, port, formal, false); @@ -1552,8 +1578,7 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, unsigned pos = 0; bool array_ok = true; - for (map::const_iterator cur = - actual_array.elements.begin() + for (auto cur = actual_array.elements.begin() ; cur != actual_array.elements.end() ; ++cur, ++pos) { NetScope*actual_scope = cur->second.actual_scope; if (!actual_scope || !actual_scope->is_interface()) { diff --git a/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold index 90758da05..05a2a50ec 100644 --- a/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold +++ b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold @@ -1,3 +1,3 @@ -ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Interface member `hidden' is not listed in modport `consumer'. -ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Unable to elaborate r-value: bus.hidden +ivltests/sv_interface_port_forwarding_restrict_fail.v:30: error: Interface member `hidden' is not listed in modport `consumer'. +ivltests/sv_interface_port_forwarding_restrict_fail.v:30: error: Unable to elaborate r-value: bus.hidden 2 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold deleted file mode 100644 index 601207b55..000000000 --- a/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold +++ /dev/null @@ -1,2 +0,0 @@ -ivltests/sv_interface_port_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. -1 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold index 8fc0533db..4201c3c5e 100644 --- a/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold +++ b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold @@ -1,2 +1,2 @@ -ivltests/sv_interface_port_positional_unconnected_fail.v:7: error: Interface port `bus' of module bus_user is not connected. +ivltests/sv_interface_port_positional_unconnected_fail.v:13: error: Interface port `bus' of module bus_user is not connected. Elaboration failed diff --git a/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold deleted file mode 100644 index 24caf2d27..000000000 --- a/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold +++ /dev/null @@ -1,2 +0,0 @@ -ivltests/sv_interface_port_unmodported_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. -1 error(s) during elaboration. diff --git a/ivtest/ivltests/sv_interface_port_forwarding.v b/ivtest/ivltests/sv_interface_port_forwarding.v index 9fb52a87b..58cd1bc81 100644 --- a/ivtest/ivltests/sv_interface_port_forwarding.v +++ b/ivtest/ivltests/sv_interface_port_forwarding.v @@ -4,6 +4,14 @@ // This file is placed into the Public Domain, for any use, without // warranty. +interface bus_if (); + logic value; + logic mirror; + logic hidden; + + modport consumer(input value, output mirror); +endinterface + module test; bus_if bus(); @@ -31,11 +39,3 @@ module child( ); assign bus.mirror = bus.value; endmodule - -interface bus_if (); - logic value; - logic mirror; - logic hidden; - - modport consumer(input value, output mirror); -endinterface diff --git a/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v index 79a1ced9f..a0fb3ab79 100644 --- a/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v +++ b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v @@ -4,6 +4,13 @@ // This file is placed into the Public Domain, for any use, without // warranty. +interface bus_if (); + logic value; + logic hidden; + + modport consumer(input value); +endinterface + module test; bus_if bus(); parent dut(.bus(bus)); @@ -22,10 +29,3 @@ module child( assign sample = bus.hidden; endmodule - -interface bus_if (); - logic value; - logic hidden; - - modport consumer(input value); -endinterface diff --git a/ivtest/ivltests/sv_interface_port_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_missing_type_fail.v deleted file mode 100644 index df1a5a513..000000000 --- a/ivtest/ivltests/sv_interface_port_missing_type_fail.v +++ /dev/null @@ -1,11 +0,0 @@ -// This tests the diagnostic path for an interface-typed module port -// whose interface type name is not declared. -// -// This file is placed into the Public Domain, for any use, without -// warranty. - -module bus_user( - missing_if.consumer bus -); - initial $display("FAILED"); -endmodule diff --git a/ivtest/ivltests/sv_interface_port_positional.v b/ivtest/ivltests/sv_interface_port_positional.v index d0cb7d057..8b6d47551 100644 --- a/ivtest/ivltests/sv_interface_port_positional.v +++ b/ivtest/ivltests/sv_interface_port_positional.v @@ -3,6 +3,13 @@ // This file is placed into the Public Domain, for any use, without // warranty. +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface + module test; bus_if bus(); @@ -24,10 +31,3 @@ module bus_user( ); assign bus.sample = bus.value; endmodule - -interface bus_if (); - logic value; - logic sample; - - modport consumer(input value, output sample); -endinterface diff --git a/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v index 5b9627b52..90e17871a 100644 --- a/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v +++ b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v @@ -3,6 +3,12 @@ // This file is placed into the Public Domain, for any use, without // warranty. +interface bus_if (); + logic value; + + modport consumer(input value); +endinterface + module test; bus_user dut(); endmodule @@ -11,9 +17,3 @@ module bus_user( bus_if.consumer bus ); endmodule - -interface bus_if (); - logic value; - - modport consumer(input value); -endinterface diff --git a/ivtest/ivltests/sv_interface_port_unmodported_basic.v b/ivtest/ivltests/sv_interface_port_unmodported_basic.v index c8bad7778..aa981cf2f 100644 --- a/ivtest/ivltests/sv_interface_port_unmodported_basic.v +++ b/ivtest/ivltests/sv_interface_port_unmodported_basic.v @@ -4,6 +4,12 @@ // This file is placed into the Public Domain, for any use, without // warranty. +interface bus_if (); + logic [7:0] lhs; + logic [7:0] rhs; + logic [8:0] sum; +endinterface + module test; logic [7:0] lhs; logic [7:0] rhs; @@ -32,9 +38,3 @@ module add_if( ); assign bus.sum = bus.lhs + bus.rhs; endmodule - -interface bus_if (); - logic [7:0] lhs; - logic [7:0] rhs; - logic [8:0] sum; -endinterface diff --git a/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v deleted file mode 100644 index b02bb3985..000000000 --- a/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v +++ /dev/null @@ -1,11 +0,0 @@ -// This tests the diagnostic path for an unmodported interface-typed -// module port whose interface type name is not declared. -// -// This file is placed into the Public Domain, for any use, without -// warranty. - -module bus_user( - missing_if bus -); - initial $display("FAILED"); -endmodule diff --git a/ivtest/ivltests/sv_interface_port_wildcard.v b/ivtest/ivltests/sv_interface_port_wildcard.v index e13630fb6..693e702ed 100644 --- a/ivtest/ivltests/sv_interface_port_wildcard.v +++ b/ivtest/ivltests/sv_interface_port_wildcard.v @@ -3,6 +3,13 @@ // This file is placed into the Public Domain, for any use, without // warranty. +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface + module test; bus_if bus(); @@ -24,10 +31,3 @@ module bus_user( ); assign bus.sample = bus.value; endmodule - -interface bus_if (); - logic value; - logic sample; - - modport consumer(input value, output sample); -endinterface diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index d205e357e..9fd43c39b 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -270,14 +270,12 @@ sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json sv_interface vvp_tests/sv_interface.json sv_interface_port_basic vvp_tests/sv_interface_port_basic.json -sv_interface_port_missing_type_fail vvp_tests/sv_interface_port_missing_type_fail.json sv_interface_port_missing_modport_fail vvp_tests/sv_interface_port_missing_modport_fail.json sv_interface_port_non_interface_actual_fail vvp_tests/sv_interface_port_non_interface_actual_fail.json sv_interface_port_wrong_type_fail vvp_tests/sv_interface_port_wrong_type_fail.json sv_interface_port_modport_input_write_fail vvp_tests/sv_interface_port_modport_input_write_fail.json sv_interface_port_unlisted_member_fail vvp_tests/sv_interface_port_unlisted_member_fail.json sv_interface_port_unmodported_basic vvp_tests/sv_interface_port_unmodported_basic.json -sv_interface_port_unmodported_missing_type_fail vvp_tests/sv_interface_port_unmodported_missing_type_fail.json sv_interface_port_forwarding vvp_tests/sv_interface_port_forwarding.json sv_interface_port_forwarding_restrict_fail vvp_tests/sv_interface_port_forwarding_restrict_fail.json sv_interface_port_positional vvp_tests/sv_interface_port_positional.json diff --git a/ivtest/vvp_tests/sv_interface_port_array_basic.json b/ivtest/vvp_tests/sv_interface_port_array_basic.json index 72ff9a89f..e6cc98c0c 100644 --- a/ivtest/vvp_tests/sv_interface_port_array_basic.json +++ b/ivtest/vvp_tests/sv_interface_port_array_basic.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_array_basic.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json b/ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json index 01f2e561c..262a5e80a 100644 --- a/ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_array_modport_restrict_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_array_modport_restrict_fail.v", "gold" : "sv_interface_port_array_modport_restrict_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json b/ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json index 1876f1bd4..2e9c815f8 100644 --- a/ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_array_size_mismatch_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_array_size_mismatch_fail.v", "gold" : "sv_interface_port_array_size_mismatch_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_basic.json b/ivtest/vvp_tests/sv_interface_port_basic.json index 33eef112d..2c45baa13 100644 --- a/ivtest/vvp_tests/sv_interface_port_basic.json +++ b/ivtest/vvp_tests/sv_interface_port_basic.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_basic.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_forwarding.json b/ivtest/vvp_tests/sv_interface_port_forwarding.json index 5983d5d82..5642f3d7e 100644 --- a/ivtest/vvp_tests/sv_interface_port_forwarding.json +++ b/ivtest/vvp_tests/sv_interface_port_forwarding.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_forwarding.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json b/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json index 4e26953b8..96d4040ef 100644 --- a/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_forwarding_restrict_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_forwarding_restrict_fail.v", "gold" : "sv_interface_port_forwarding_restrict_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_indexed_actual.json b/ivtest/vvp_tests/sv_interface_port_indexed_actual.json index 0d0064b63..8ea7b2d4f 100644 --- a/ivtest/vvp_tests/sv_interface_port_indexed_actual.json +++ b/ivtest/vvp_tests/sv_interface_port_indexed_actual.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_indexed_actual.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json b/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json index f8532856c..7fb5875fa 100644 --- a/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json +++ b/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_indexed_actual_generate.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json b/ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json index a86412965..86f475edc 100644 --- a/ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_missing_modport_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_missing_modport_fail.v", "gold" : "sv_interface_port_missing_modport_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json deleted file mode 100644 index f43ed1e1c..000000000 --- a/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type" : "CE", - "source" : "sv_interface_port_missing_type_fail.v", - "gold" : "sv_interface_port_missing_type_fail", - "iverilog-args" : [ "-g2012" ] -} diff --git a/ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json b/ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json index 10d17db33..401281de9 100644 --- a/ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_modport_input_write_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_modport_input_write_fail.v", "gold" : "sv_interface_port_modport_input_write_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json b/ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json index 786b3e11d..0fbfdea28 100644 --- a/ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_non_interface_actual_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_non_interface_actual_fail.v", "gold" : "sv_interface_port_non_interface_actual_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json b/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json index 56b84fc13..89a8d8039 100644 --- a/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json +++ b/ivtest/vvp_tests/sv_interface_port_plain_ansi_regression.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_plain_ansi_regression.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_positional.json b/ivtest/vvp_tests/sv_interface_port_positional.json index 66f253f1d..bd2e7ad3a 100644 --- a/ivtest/vvp_tests/sv_interface_port_positional.json +++ b/ivtest/vvp_tests/sv_interface_port_positional.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_positional.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json b/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json index 07880369e..6403f0a87 100644 --- a/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_positional_unconnected_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_positional_unconnected_fail.v", "gold" : "sv_interface_port_positional_unconnected_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json b/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json index 7b7d719a6..ea864c616 100644 --- a/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json +++ b/ivtest/vvp_tests/sv_interface_port_typedef_ansi_regression.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_typedef_ansi_regression.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json b/ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json index 802f08a7e..880858381 100644 --- a/ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_unlisted_member_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_unlisted_member_fail.v", "gold" : "sv_interface_port_unlisted_member_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json index 01423ed0a..97611b589 100644 --- a/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json +++ b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_unmodported_basic.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json deleted file mode 100644 index d00e41cec..000000000 --- a/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type" : "CE", - "source" : "sv_interface_port_unmodported_missing_type_fail.v", - "gold" : "sv_interface_port_unmodported_missing_type_fail", - "iverilog-args" : [ "-g2012" ] -} diff --git a/ivtest/vvp_tests/sv_interface_port_wildcard.json b/ivtest/vvp_tests/sv_interface_port_wildcard.json index d34e83b0e..11daa24f7 100644 --- a/ivtest/vvp_tests/sv_interface_port_wildcard.json +++ b/ivtest/vvp_tests/sv_interface_port_wildcard.json @@ -1,5 +1,5 @@ { "type" : "normal", "source" : "sv_interface_port_wildcard.v", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json b/ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json index d0d34c17b..6c3f2096c 100644 --- a/ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json +++ b/ivtest/vvp_tests/sv_interface_port_wrong_type_fail.json @@ -2,5 +2,5 @@ "type" : "CE", "source" : "sv_interface_port_wrong_type_fail.v", "gold" : "sv_interface_port_wrong_type_fail", - "iverilog-args" : [ "-g2012" ] + "iverilog-args" : [ "-g2005-sv" ] } diff --git a/lexor.lex b/lexor.lex index f48149b94..97e07560c 100644 --- a/lexor.lex +++ b/lexor.lex @@ -417,6 +417,13 @@ TU [munpf] } } + /* If this identifier names a previously declared interface, then + return this as an INTERFACE_IDENTIFIER instead. */ + if (rc == IDENTIFIER && gn_system_verilog()) { + if (pform_test_interface_identifier(yylval.text)) + rc = INTERFACE_IDENTIFIER; + } + /* If this identifier names a previously declared type, then return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { @@ -442,6 +449,10 @@ TU [munpf] return PACKAGE_IDENTIFIER; } } + if (gn_system_verilog()) { + if (pform_test_interface_identifier(yylval.text)) + return INTERFACE_IDENTIFIER; + } if (gn_system_verilog()) { if (typedef_t*type = pform_test_type_identifier(yylloc, yylval.text)) { yylval.type_identifier.text = yylval.text; diff --git a/net_scope.cc b/net_scope.cc index 3c9c5cd3d..ec9d6f912 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -845,13 +845,11 @@ const NetScope::interface_port_alias_t* NetScope::find_interface_port_alias_element(perm_string formal_name, long index) const { - map >::const_iterator arr; - arr = interface_port_alias_arrays_.find(formal_name); + auto arr = interface_port_alias_arrays_.find(formal_name); if (arr == interface_port_alias_arrays_.end()) return 0; - map::const_iterator cur; - cur = arr->second.find(index); + auto cur = arr->second.find(index); if (cur == arr->second.end()) return 0; @@ -861,8 +859,7 @@ NetScope::find_interface_port_alias_element(perm_string formal_name, const map* NetScope::find_interface_port_alias_array(perm_string formal_name) const { - map >::const_iterator cur; - cur = interface_port_alias_arrays_.find(formal_name); + auto cur = interface_port_alias_arrays_.find(formal_name); if (cur == interface_port_alias_arrays_.end()) return 0; diff --git a/netlist.h b/netlist.h index b3baec96a..cfaeba861 100644 --- a/netlist.h +++ b/netlist.h @@ -1045,7 +1045,7 @@ class NetScope : public Definitions, public Attrib { const NetScope* child(const hname_t&name) const; struct interface_port_alias_t { - interface_port_alias_t() : actual_scope(0), modport(0) { } + interface_port_alias_t() : actual_scope(nullptr), modport(nullptr) { } interface_port_alias_t(NetScope*actual, const PModport*mp) : actual_scope(actual), modport(mp) { } diff --git a/parse.y b/parse.y index 96830851a..792454140 100644 --- a/parse.y +++ b/parse.y @@ -606,7 +606,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, enum typedef_t::basic_type typedef_basic_type; }; -%token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL +%token IDENTIFIER INTERFACE_IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL %token TYPE_IDENTIFIER %token PACKAGE_IDENTIFIER %token DISCIPLINE_IDENTIFIER @@ -4658,10 +4658,10 @@ port_declaration : attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt { $$ = module_declare_port(@5, $5, $2, $3, $4, $6, $7, $1); } - | attribute_list_opt IDENTIFIER '.' IDENTIFIER IDENTIFIER dimensions_opt + | attribute_list_opt INTERFACE_IDENTIFIER '.' IDENTIFIER IDENTIFIER dimensions_opt { $$ = module_declare_interface_port(@5, $2, $4, $5, $6, $1); } - | attribute_list_opt IDENTIFIER IDENTIFIER dimensions_opt + | attribute_list_opt INTERFACE_IDENTIFIER IDENTIFIER dimensions_opt { $$ = module_declare_interface_port(@3, $2, 0, $3, $4, $1); } | attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt @@ -5207,6 +5207,13 @@ module_item delete[]$2; } + | attribute_list_opt + INTERFACE_IDENTIFIER parameter_value_opt gate_instance_list ';' + { perm_string tmp1 = lex_strings.make($2); + pform_make_modgates(@2, tmp1, $3, $4, $1); + delete[]$2; + } + | attribute_list_opt IDENTIFIER parameter_value_opt error ';' { yyerror(@2, "error: Invalid module instantiation"); @@ -5214,6 +5221,13 @@ module_item if ($1) delete $1; } + | attribute_list_opt + INTERFACE_IDENTIFIER parameter_value_opt error ';' + { yyerror(@2, "error: Invalid module instantiation"); + delete[]$2; + if ($1) delete $1; + } + /* Continuous assignment can have an optional drive strength, then an optional delay3 that applies to all the assignments in the cont_assign_list. */ @@ -5757,14 +5771,6 @@ port : port_reference { $$ = $1; } - | IDENTIFIER '.' IDENTIFIER IDENTIFIER dimensions_opt - { $$ = module_declare_interface_port(@4, $1, $3, $4, $5, 0); - } - - | IDENTIFIER IDENTIFIER dimensions_opt - { $$ = module_declare_interface_port(@2, $1, 0, $2, $3, 0); - } - /* This syntax attaches an external name to the port reference so that the caller can bind by name to non-trivial port references. The port_t object gets its PWire from the diff --git a/parse_misc.h b/parse_misc.h index 23547e85c..b669a9af0 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -92,6 +92,11 @@ extern void lex_in_package_scope(PPackage*pkg); extern typedef_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt); extern typedef_t* pform_test_type_identifier(PPackage*pkg, const char*txt); +/* + * Test if this identifier is a previously declared interface name. + */ +extern bool pform_test_interface_identifier(const char*txt); + /* * Test if this identifier is a package name. The pform needs to help * the lexor here because the parser detects packages and saves them. diff --git a/pform.cc b/pform.cc index e001914b7..0ef02563f 100644 --- a/pform.cc +++ b/pform.cc @@ -926,6 +926,14 @@ typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) return 0; } +bool pform_test_interface_identifier(const char*txt) +{ + perm_string name = lex_strings.make(txt); + map::const_iterator cur = pform_modules.find(name); + + return cur != pform_modules.end() && cur->second->is_interface; +} + PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list &parms) diff --git a/symbol_search.cc b/symbol_search.cc index d05aa8ce9..3aaf06e1b 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -331,7 +331,7 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, return true; } - } else { + } else if (scope->find_interface_port_alias_array(path_tail.name)) { bool flag = false; hname_t path_item = eval_path_component(des, start_scope, path_tail, flag); if (!flag && path_item.has_numbers() == 1) { diff --git a/vvp/Makefile.in b/vvp/Makefile.in index a9315c8b5..c924dda85 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -135,10 +135,6 @@ Makefile: $(srcdir)/Makefile.in dep: mkdir dep -# Older dependency files may refer to ivl_dlfcn.h from before the -# shared dlopen wrapper was moved to the top-level source directory. -ivl_dlfcn.h: $(srcdir)/../ivl_dlfcn.h - ifeq (@LIBVVP@,yes) CPPFLAGS+= -fpic From 1ea5f72496f4b8d03acdc554f804d0c2b6552c82 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 11 May 2026 13:12:10 +0200 Subject: [PATCH 042/102] Makefile.in: 'version_base.h' must not be deleted when running `make clean` Since this file, just like 'config.h', is generated by autoconf, it should only be deleted in the `distclean` target. Also since the project does not currently use automake, manual maintenance of the timestamp file for 'version_base.h' is required. Fixup for commit 10b5f70e7 from #1331 --- Makefile.in | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 751334d6a..9779cc1d5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -169,7 +169,7 @@ clean: rm -f ivl.exp rm -f iverilog_man.ps iverilog_man.pdf iverilog_man_$(VERSION_MAJOR)_$(VERSION_MINOR).pdf rm -f parse.output syn-rules.output dosify$(BUILDEXT) ivl@EXEEXT@ check.vvp - rm -f lexor_keyword.cc libivl.a libvpi.a syn-rules.cc version_base.h + rm -f lexor_keyword.cc libivl.a libvpi.a syn-rules.cc rm -rf dep distclean: clean @@ -178,6 +178,7 @@ distclean: clean rm -f Makefile config.status config.log config.cache rm -f stamp-config-h config.h rm -f stamp-_pli_types-h _pli_types.h + rm -f stamp-version_base-h version_base.h ifneq (@srcdir@,.) rm -f version_tag.h check.conf rmdir $(SUBDIRS) $(NOTUSED) @@ -215,6 +216,11 @@ stamp-_pli_types-h: $(srcdir)/_pli_types.h.in config.status ./config.status _pli_types.h _pli_types.h: stamp-_pli_types-h +stamp-version_base-h: $(srcdir)/version_base.h.in config.status + @rm -f $@ + ./config.status version_base.h +version_base.h: stamp-version_base-h + $(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 cd $(srcdir) && autoconf From a52bef20edcd8a473264a9538967d43db029e36d Mon Sep 17 00:00:00 2001 From: Haowei Hsu Date: Mon, 11 May 2026 20:48:58 +0800 Subject: [PATCH 043/102] docs: switch docs to shibuya theme and install via venv - change documentation theme from `alabaster` to `shibuya` - add pinned Documentation requirements for `sphinx` and `shibuya` - update workflows to create `.venv` and install with `requirements.txt` - ignore common virtual environment directories (`.conda` and `.venv`) --- .github/workflows/deploy_docs.yml | 7 ++++++- .github/workflows/test.yml | 7 ++++++- .gitignore | 4 ++++ Documentation/conf.py | 2 +- Documentation/requirements.txt | 2 ++ 5 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 Documentation/requirements.txt diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index 1641fec05..7abfd6fbf 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -19,10 +19,15 @@ jobs: - name: Install dependencies run: | sudo apt update -qq - sudo apt install -y make autoconf python3-sphinx + sudo apt install -y make autoconf python3-venv + python3 -m venv .venv + . .venv/bin/activate + pip install --upgrade pip + pip install -r Documentation/requirements.txt - name: Make Documentation run: | + . .venv/bin/activate cd Documentation make html diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 60777bd6a..3b9f2f1cf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,7 +54,11 @@ jobs: - name: Install dependencies run: | sudo apt update -qq - sudo apt install -y make g++ git bison flex gperf libreadline-dev libbz2-dev autoconf python3-sphinx + sudo apt install -y make g++ git bison flex gperf libreadline-dev libbz2-dev autoconf python3-venv + python3 -m venv .venv + . .venv/bin/activate + pip install --upgrade pip + pip install -r Documentation/requirements.txt - name: Build, check and install run: | @@ -69,6 +73,7 @@ jobs: - name: Documentation run: | + . .venv/bin/activate cd Documentation make html diff --git a/.gitignore b/.gitignore index 319b3c199..4547e8487 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ *.swp *~ +# Virtual environments +.conda/ +.venv/ + # Top level generic files tags TAGS diff --git a/Documentation/conf.py b/Documentation/conf.py index 282a520c4..b50c3ea7f 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -76,7 +76,7 @@ highlight_language = 'none' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = 'shibuya' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/Documentation/requirements.txt b/Documentation/requirements.txt new file mode 100644 index 000000000..66dfcfe5a --- /dev/null +++ b/Documentation/requirements.txt @@ -0,0 +1,2 @@ +sphinx==8.1.3 +shibuya==2026.1.9 From 56afcb6e75ed5b31d59af6f816c65f4e0a08d917 Mon Sep 17 00:00:00 2001 From: Jose Tejada Date: Mon, 11 May 2026 22:25:32 +0200 Subject: [PATCH 044/102] fix(interface): allow forward interface port types --- ...warding_restrict_fail-iverilog-stderr.gold | 4 +- ...ort_missing_type_fail-iverilog-stderr.gold | 2 + ...onal_unconnected_fail-iverilog-stderr.gold | 2 +- ...ted_missing_type_fail-iverilog-stderr.gold | 2 + .../ivltests/sv_interface_port_forwarding.v | 16 ++++---- ..._interface_port_forwarding_restrict_fail.v | 14 +++---- .../sv_interface_port_missing_type_fail.v | 11 ++++++ .../ivltests/sv_interface_port_positional.v | 14 +++---- ...terface_port_positional_unconnected_fail.v | 12 +++--- .../sv_interface_port_unmodported_basic.v | 12 +++--- ...rface_port_unmodported_missing_type_fail.v | 11 ++++++ ivtest/ivltests/sv_interface_port_wildcard.v | 14 +++---- ivtest/regress-vvp.list | 2 + .../sv_interface_port_missing_type_fail.json | 6 +++ ...ce_port_unmodported_missing_type_fail.json | 6 +++ lexor.lex | 38 ++++++++++++++++++- parse.y | 18 +++++---- parse_misc.h | 7 ++++ 18 files changed, 137 insertions(+), 54 deletions(-) create mode 100644 ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold create mode 100644 ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold create mode 100644 ivtest/ivltests/sv_interface_port_missing_type_fail.v create mode 100644 ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v create mode 100644 ivtest/vvp_tests/sv_interface_port_missing_type_fail.json create mode 100644 ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json diff --git a/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold index 05a2a50ec..90758da05 100644 --- a/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold +++ b/ivtest/gold/sv_interface_port_forwarding_restrict_fail-iverilog-stderr.gold @@ -1,3 +1,3 @@ -ivltests/sv_interface_port_forwarding_restrict_fail.v:30: error: Interface member `hidden' is not listed in modport `consumer'. -ivltests/sv_interface_port_forwarding_restrict_fail.v:30: error: Unable to elaborate r-value: bus.hidden +ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Interface member `hidden' is not listed in modport `consumer'. +ivltests/sv_interface_port_forwarding_restrict_fail.v:23: error: Unable to elaborate r-value: bus.hidden 2 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold new file mode 100644 index 000000000..601207b55 --- /dev/null +++ b/ivtest/gold/sv_interface_port_missing_type_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. +1 error(s) during elaboration. diff --git a/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold index 4201c3c5e..8fc0533db 100644 --- a/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold +++ b/ivtest/gold/sv_interface_port_positional_unconnected_fail-iverilog-stderr.gold @@ -1,2 +1,2 @@ -ivltests/sv_interface_port_positional_unconnected_fail.v:13: error: Interface port `bus' of module bus_user is not connected. +ivltests/sv_interface_port_positional_unconnected_fail.v:7: error: Interface port `bus' of module bus_user is not connected. Elaboration failed diff --git a/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold b/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold new file mode 100644 index 000000000..24caf2d27 --- /dev/null +++ b/ivtest/gold/sv_interface_port_unmodported_missing_type_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/sv_interface_port_unmodported_missing_type_fail.v:7: error: Interface port bus uses unknown interface type `missing_if'. +1 error(s) during elaboration. diff --git a/ivtest/ivltests/sv_interface_port_forwarding.v b/ivtest/ivltests/sv_interface_port_forwarding.v index 58cd1bc81..9fb52a87b 100644 --- a/ivtest/ivltests/sv_interface_port_forwarding.v +++ b/ivtest/ivltests/sv_interface_port_forwarding.v @@ -4,14 +4,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic mirror; - logic hidden; - - modport consumer(input value, output mirror); -endinterface - module test; bus_if bus(); @@ -39,3 +31,11 @@ module child( ); assign bus.mirror = bus.value; endmodule + +interface bus_if (); + logic value; + logic mirror; + logic hidden; + + modport consumer(input value, output mirror); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v index a0fb3ab79..79a1ced9f 100644 --- a/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v +++ b/ivtest/ivltests/sv_interface_port_forwarding_restrict_fail.v @@ -4,13 +4,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic hidden; - - modport consumer(input value); -endinterface - module test; bus_if bus(); parent dut(.bus(bus)); @@ -29,3 +22,10 @@ module child( assign sample = bus.hidden; endmodule + +interface bus_if (); + logic value; + logic hidden; + + modport consumer(input value); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_missing_type_fail.v new file mode 100644 index 000000000..df1a5a513 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_missing_type_fail.v @@ -0,0 +1,11 @@ +// This tests the diagnostic path for an interface-typed module port +// whose interface type name is not declared. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module bus_user( + missing_if.consumer bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_positional.v b/ivtest/ivltests/sv_interface_port_positional.v index 8b6d47551..d0cb7d057 100644 --- a/ivtest/ivltests/sv_interface_port_positional.v +++ b/ivtest/ivltests/sv_interface_port_positional.v @@ -3,13 +3,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic sample; - - modport consumer(input value, output sample); -endinterface - module test; bus_if bus(); @@ -31,3 +24,10 @@ module bus_user( ); assign bus.sample = bus.value; endmodule + +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v index 90e17871a..5b9627b52 100644 --- a/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v +++ b/ivtest/ivltests/sv_interface_port_positional_unconnected_fail.v @@ -3,12 +3,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - - modport consumer(input value); -endinterface - module test; bus_user dut(); endmodule @@ -17,3 +11,9 @@ module bus_user( bus_if.consumer bus ); endmodule + +interface bus_if (); + logic value; + + modport consumer(input value); +endinterface diff --git a/ivtest/ivltests/sv_interface_port_unmodported_basic.v b/ivtest/ivltests/sv_interface_port_unmodported_basic.v index aa981cf2f..c8bad7778 100644 --- a/ivtest/ivltests/sv_interface_port_unmodported_basic.v +++ b/ivtest/ivltests/sv_interface_port_unmodported_basic.v @@ -4,12 +4,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic [7:0] lhs; - logic [7:0] rhs; - logic [8:0] sum; -endinterface - module test; logic [7:0] lhs; logic [7:0] rhs; @@ -38,3 +32,9 @@ module add_if( ); assign bus.sum = bus.lhs + bus.rhs; endmodule + +interface bus_if (); + logic [7:0] lhs; + logic [7:0] rhs; + logic [8:0] sum; +endinterface diff --git a/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v b/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v new file mode 100644 index 000000000..b02bb3985 --- /dev/null +++ b/ivtest/ivltests/sv_interface_port_unmodported_missing_type_fail.v @@ -0,0 +1,11 @@ +// This tests the diagnostic path for an unmodported interface-typed +// module port whose interface type name is not declared. +// +// This file is placed into the Public Domain, for any use, without +// warranty. + +module bus_user( + missing_if bus +); + initial $display("FAILED"); +endmodule diff --git a/ivtest/ivltests/sv_interface_port_wildcard.v b/ivtest/ivltests/sv_interface_port_wildcard.v index 693e702ed..e13630fb6 100644 --- a/ivtest/ivltests/sv_interface_port_wildcard.v +++ b/ivtest/ivltests/sv_interface_port_wildcard.v @@ -3,13 +3,6 @@ // This file is placed into the Public Domain, for any use, without // warranty. -interface bus_if (); - logic value; - logic sample; - - modport consumer(input value, output sample); -endinterface - module test; bus_if bus(); @@ -31,3 +24,10 @@ module bus_user( ); assign bus.sample = bus.value; endmodule + +interface bus_if (); + logic value; + logic sample; + + modport consumer(input value, output sample); +endinterface diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 9fd43c39b..d205e357e 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -270,12 +270,14 @@ sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json sv_interface vvp_tests/sv_interface.json sv_interface_port_basic vvp_tests/sv_interface_port_basic.json +sv_interface_port_missing_type_fail vvp_tests/sv_interface_port_missing_type_fail.json sv_interface_port_missing_modport_fail vvp_tests/sv_interface_port_missing_modport_fail.json sv_interface_port_non_interface_actual_fail vvp_tests/sv_interface_port_non_interface_actual_fail.json sv_interface_port_wrong_type_fail vvp_tests/sv_interface_port_wrong_type_fail.json sv_interface_port_modport_input_write_fail vvp_tests/sv_interface_port_modport_input_write_fail.json sv_interface_port_unlisted_member_fail vvp_tests/sv_interface_port_unlisted_member_fail.json sv_interface_port_unmodported_basic vvp_tests/sv_interface_port_unmodported_basic.json +sv_interface_port_unmodported_missing_type_fail vvp_tests/sv_interface_port_unmodported_missing_type_fail.json sv_interface_port_forwarding vvp_tests/sv_interface_port_forwarding.json sv_interface_port_forwarding_restrict_fail vvp_tests/sv_interface_port_forwarding_restrict_fail.json sv_interface_port_positional vvp_tests/sv_interface_port_positional.json diff --git a/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json new file mode 100644 index 000000000..bc986c918 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_missing_type_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_missing_type_fail.v", + "gold" : "sv_interface_port_missing_type_fail", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json b/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json new file mode 100644 index 000000000..e35cde0c3 --- /dev/null +++ b/ivtest/vvp_tests/sv_interface_port_unmodported_missing_type_fail.json @@ -0,0 +1,6 @@ +{ + "type" : "CE", + "source" : "sv_interface_port_unmodported_missing_type_fail.v", + "gold" : "sv_interface_port_unmodported_missing_type_fail", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/lexor.lex b/lexor.lex index 97e07560c..0e0c2646c 100644 --- a/lexor.lex +++ b/lexor.lex @@ -120,6 +120,8 @@ static list keyword_mask_stack; static int comment_enter; static bool in_module = false; static bool in_UDP = false; +static bool in_module_port_list = false; +static bool module_port_list_start = false; bool in_celldefine = false; UCDriveType uc_drive = UCD_NONE; static int ts_state = 0; @@ -139,6 +141,12 @@ void lex_in_package_scope(PPackage*pkg) in_package_scope = pkg; } +void lex_in_module_port_list(bool flag) +{ + in_module_port_list = flag; + module_port_list_start = flag; +} + %} %x CCOMMENT @@ -160,6 +168,7 @@ void lex_in_package_scope(PPackage*pkg) %x REAL_SCALE W [ \t\b\f\r]+ +ID [a-zA-Z_][a-zA-Z0-9$_]* S [afpnumkKMGT] @@ -335,7 +344,7 @@ TU [munpf] "z0" { return K_edge_descriptor; } "z1" { return K_edge_descriptor; } -[a-zA-Z_][a-zA-Z0-9$_]* { +{ID} { int rc = lexor_keyword_code(yytext, yyleng); switch (rc) { case IDENTIFIER: @@ -434,6 +443,22 @@ TU [munpf] } } + if (rc == IDENTIFIER && gn_system_verilog() && + in_module_port_list && module_port_list_start) { + char save_ch = *yy_c_buf_p; + *yy_c_buf_p = yy_hold_char; + const char*cp = yy_c_buf_p; + while (*cp == ' ' || *cp == '\t' || *cp == '\b' || + *cp == '\f' || *cp == '\r' || *cp == '\n') + cp += 1; + if (*cp == '.' || isalpha(static_cast(*cp)) || + *cp == '_' || *cp == '\\') + rc = INTERFACE_IDENTIFIER; + *yy_c_buf_p = save_ch; + } + + if (in_module_port_list) + module_port_list_start = false; return rc; } @@ -906,7 +931,16 @@ TU [munpf] `{W} { VLerror(yylloc, "error: Stray tic (`) here. Perhaps you put white " "space between the tic and preprocessor directive?"); } -. { return yytext[0]; } +. { + if (in_module_port_list) { + if (yytext[0] == '(' || yytext[0] == ',') + module_port_list_start = true; + else if (yytext[0] != ')' && yytext[0] != '[' && + yytext[0] != ']' && yytext[0] != ':') + module_port_list_start = false; + } + return yytext[0]; +} /* Final catchall. something got lost or mishandled. */ /* XXX Should we tell the user something about the lexical state? */ diff --git a/parse.y b/parse.y index 792454140..aa6fc0a97 100644 --- a/parse.y +++ b/parse.y @@ -4781,9 +4781,11 @@ module port_declaration_context_init(); } module_package_import_list_opt module_parameter_port_list_opt + { lex_in_module_port_list(true); } module_port_list_opt + { lex_in_module_port_list(false); } module_attribute_foreign ';' - { pform_module_set_ports($8); } + { pform_module_set_ports($9); } timeunits_declaration_opt { pform_set_scope_timescale(@2); } module_item_list_opt @@ -4806,16 +4808,16 @@ module } // Check that program/endprogram and module/endmodule // keywords match. - if ($2 != $15) { + if ($2 != $17) { switch ($2) { case K_module: - yyerror(@15, "error: module not closed by endmodule."); + yyerror(@17, "error: module not closed by endmodule."); break; case K_program: - yyerror(@15, "error: program not closed by endprogram."); + yyerror(@17, "error: program not closed by endprogram."); break; case K_interface: - yyerror(@15, "error: interface not closed by endinterface."); + yyerror(@17, "error: interface not closed by endinterface."); break; default: break; @@ -4831,13 +4833,13 @@ module // module. switch ($2) { case K_module: - check_end_label(@17, "module", $4, $17); + check_end_label(@19, "module", $4, $19); break; case K_program: - check_end_label(@17, "program", $4, $17); + check_end_label(@19, "program", $4, $19); break; case K_interface: - check_end_label(@17, "interface", $4, $17); + check_end_label(@19, "interface", $4, $19); break; default: break; diff --git a/parse_misc.h b/parse_misc.h index b669a9af0..a9eb7d19b 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -83,6 +83,13 @@ extern UCDriveType uc_drive; */ extern void lex_in_package_scope(PPackage*pkg); +/* + * The parser signals when the lexor is scanning a module/interface/program + * port list so that ambiguous SystemVerilog interface formals can be + * tokenized without depending on declaration order. + */ +extern void lex_in_module_port_list(bool flag); + /* * Test if this identifier is a type identifier in the current * context. The pform code needs to help the lexor here because the From 265272a9624a269cc58007647a7ab4c854424969 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 11 May 2026 20:11:47 -0700 Subject: [PATCH 045/102] Report error for `edge` event controls on named events Using an edge control with a named event is invalid. The existing elaboration code already reports an error for `posedge` and `negedge`, but the `edge` case falls through to the default path and triggers an assert. Handle `PEEvent::EDGE` like the other edge-control cases and report the same kind of error instead. Signed-off-by: Lars-Peter Clausen --- elaborate.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/elaborate.cc b/elaborate.cc index 5216ad7b7..09c9ca2f5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4975,6 +4975,9 @@ cerr << endl; case PEEvent::NEGEDGE: cerr << "negedge"; break; + case PEEvent::EDGE: + cerr << "edge"; + break; default: cerr << "unknown edge type!"; ivl_assert(*this, 0); From ba3f46722c082a5f641a20688a330fc7f83fb220 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 11 May 2026 20:12:01 -0700 Subject: [PATCH 046/102] Add regression tests for edge controls on named event errors Check that the compiler reports an error for `posedge`, `negedge` and `edge` event controls on named events. Edge controls can not be used with named events. There is already an existing test that checks both `posedge` and `negedge`. Split it into separate tests so that each invalid event control is checked independently. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/named_event_edge_fail.v | 11 +++++++++++ ivtest/ivltests/named_event_negedge_fail.v | 11 +++++++++++ ivtest/ivltests/named_event_no_edges.v | 15 --------------- ivtest/ivltests/named_event_posedge_fail.v | 11 +++++++++++ ivtest/regress-vlg.list | 1 - ivtest/regress-vvp.list | 3 +++ ivtest/vvp_tests/named_event_edge_fail.json | 5 +++++ ivtest/vvp_tests/named_event_negedge_fail.json | 4 ++++ ivtest/vvp_tests/named_event_posedge_fail.json | 4 ++++ 9 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 ivtest/ivltests/named_event_edge_fail.v create mode 100644 ivtest/ivltests/named_event_negedge_fail.v delete mode 100644 ivtest/ivltests/named_event_no_edges.v create mode 100644 ivtest/ivltests/named_event_posedge_fail.v create mode 100644 ivtest/vvp_tests/named_event_edge_fail.json create mode 100644 ivtest/vvp_tests/named_event_negedge_fail.json create mode 100644 ivtest/vvp_tests/named_event_posedge_fail.json diff --git a/ivtest/ivltests/named_event_edge_fail.v b/ivtest/ivltests/named_event_edge_fail.v new file mode 100644 index 000000000..fbc51908c --- /dev/null +++ b/ivtest/ivltests/named_event_edge_fail.v @@ -0,0 +1,11 @@ +// Check that edge event controls can not be used with named events. + +module test; + + event e; + + initial begin + @(edge e); + end + +endmodule diff --git a/ivtest/ivltests/named_event_negedge_fail.v b/ivtest/ivltests/named_event_negedge_fail.v new file mode 100644 index 000000000..34b9c21f5 --- /dev/null +++ b/ivtest/ivltests/named_event_negedge_fail.v @@ -0,0 +1,11 @@ +// Check that negedge event controls can not be used with named events. + +module test; + + event e; + + initial begin + @(negedge e); + end + +endmodule diff --git a/ivtest/ivltests/named_event_no_edges.v b/ivtest/ivltests/named_event_no_edges.v deleted file mode 100644 index 4bbee0336..000000000 --- a/ivtest/ivltests/named_event_no_edges.v +++ /dev/null @@ -1,15 +0,0 @@ -module top; - event my_event; - - // The following two line should be an error - // You can not take the edge of a named event. - always @(posedge my_event) $display("Posedge event."); - always @(negedge my_event) $display("Negedge event."); - // This should work correctly. - always @(my_event) $display("Any event edge."); - - initial begin - #1 ->my_event; - #1 $display("FAILED"); - end -endmodule diff --git a/ivtest/ivltests/named_event_posedge_fail.v b/ivtest/ivltests/named_event_posedge_fail.v new file mode 100644 index 000000000..fd441f4b5 --- /dev/null +++ b/ivtest/ivltests/named_event_posedge_fail.v @@ -0,0 +1,11 @@ +// Check that posedge event controls can not be used with named events. + +module test; + + event e; + + initial begin + @(posedge e); + end + +endmodule diff --git a/ivtest/regress-vlg.list b/ivtest/regress-vlg.list index 9309d3afa..55fbc8cc5 100644 --- a/ivtest/regress-vlg.list +++ b/ivtest/regress-vlg.list @@ -719,7 +719,6 @@ multi_bit_strength normal ivltests gold=multi_bit_strength.gold multi_driver_delay normal ivltests multiply_large normal ivltests # Takes care of PR222 muxtest normal ivltests # Validates that X sel and inputs same, output not X -named_event_no_edges CE ivltests nb_assign normal ivltests nb_delay normal ivltests nb_ec_concat normal ivltests diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 13b3a3bf8..8424d7f55 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -156,6 +156,9 @@ module_port_array1 vvp_tests/module_port_array1.json module_port_array_fail1 vvp_tests/module_port_array_fail1.json module_port_array_init1 vvp_tests/module_port_array_init1.json monitor4 vvp_tests/monitor4.json +named_event_edge_fail vvp_tests/named_event_edge_fail.json +named_event_negedge_fail vvp_tests/named_event_negedge_fail.json +named_event_posedge_fail vvp_tests/named_event_posedge_fail.json non-polymorphic-abs vvp_tests/non-polymorphic-abs.json partsel_invalid_idx1 vvp_tests/partsel_invalid_idx1.json partsel_invalid_idx2 vvp_tests/partsel_invalid_idx2.json diff --git a/ivtest/vvp_tests/named_event_edge_fail.json b/ivtest/vvp_tests/named_event_edge_fail.json new file mode 100644 index 000000000..f572263f7 --- /dev/null +++ b/ivtest/vvp_tests/named_event_edge_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "named_event_edge_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/named_event_negedge_fail.json b/ivtest/vvp_tests/named_event_negedge_fail.json new file mode 100644 index 000000000..b0afab36a --- /dev/null +++ b/ivtest/vvp_tests/named_event_negedge_fail.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "named_event_negedge_fail.v" +} diff --git a/ivtest/vvp_tests/named_event_posedge_fail.json b/ivtest/vvp_tests/named_event_posedge_fail.json new file mode 100644 index 000000000..2ae4014d7 --- /dev/null +++ b/ivtest/vvp_tests/named_event_posedge_fail.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "named_event_posedge_fail.v" +} From 5b51ed9aa564a105f40fce5752fe9b1817cfda92 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 11 May 2026 22:14:24 -0700 Subject: [PATCH 047/102] Fix building and dependency for verion_base.h --- Makefile.in | 3 --- configure.ac | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile.in b/Makefile.in index 9779cc1d5..189c2b2d6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -239,9 +239,6 @@ ivl@EXEEXT@: $O $(CXX) $(LDFLAGS) -o ivl@EXEEXT@ $O $(dllib) endif -version_base.h: $(srcdir)/version_base.h.in config.status - ./config.status --file=$@ - %.o: %.cc config.h | dep $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep/$*.d diff --git a/configure.ac b/configure.ac index 6b8d7a4e5..6798abce8 100644 --- a/configure.ac +++ b/configure.ac @@ -16,6 +16,12 @@ AC_SUBST([VERSION], ["VER_MAJOR.VER_MINOR (VER_EXTRA)"]) AC_SUBST([PRODUCTVERSION], ["VER_MAJOR,VER_MINOR,0,0"]) AC_CONFIG_SRCDIR([netlist.h]) +# Need a stamp file like the other header files +AC_CONFIG_FILES([version_base.h],[ +_config_header=version_base.h +_stamp_name=stamp-`expr //$_config_header : '.*/\([[^./]]*\)\.[[^./]]*$'`-h +echo "timestamp for $_config_header" > `AS_DIRNAME(["$_config_header"])`/[]$_stamp_name +]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([_pli_types.h]) AC_CONFIG_HEADERS([vhdlpp/vhdlpp_config.h]) @@ -425,7 +431,6 @@ AC_CONFIG_FILES([ tgt-vhdl/Makefile tgt-vlog95/Makefile tgt-vvp/Makefile - version_base.h vhdlpp/Makefile vpi/Makefile vvp/Makefile From 46a329f16f0d1c708ae7076538c1c75e6d043b1c Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Thu, 7 May 2026 11:41:01 +0200 Subject: [PATCH 048/102] vvp: cleanup doc related rules --- vvp/Makefile.in | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/vvp/Makefile.in b/vvp/Makefile.in index c924dda85..da03dfec5 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -28,11 +28,11 @@ VPATH = $(srcdir) bindir = @bindir@ libdir = @libdir@ -mandir = @mandir@ +man1dir = @mandir@/man1 +docdir = @docdir@ # This is actually the directory where we install our own header files. # It is a little different from the generic includedir. ivl_includedir = @includedir@/iverilog$(suffix) -pdfdir = @docdir@ # For a cross compile these defines will need to be set accordingly. HOSTCC = @CC@ @@ -195,25 +195,15 @@ vvp.ps: vvp.man vvp.pdf: vvp.ps $(PS2PDF) $< $@ +INSTALL_DOC = +ifneq ($(MAN),none) +INSTALL_DOC += installman +ifneq ($(PS2PDF),none) ifeq (@MINGW32@,yes) -ifeq ($(MAN),none) -INSTALL_DOC = installman -INSTALL_PDFDIR = $(prefix) -else -ifeq ($(PS2PDF),none) -INSTALL_DOC = installman -INSTALL_PDFDIR = $(prefix) -else -INSTALL_DOC = installpdf installman -INSTALL_PDFDIR = $(pdfdir) +INSTALL_DOC += installpdf all: vvp.pdf endif endif -INSTALL_DOCDIR = $(mandir)/man1 -else -INSTALL_DOC = installman -INSTALL_DOCDIR = $(mandir)/man1 -INSTALL_PDFDIR = $(prefix) endif stamp-config-h: $(srcdir)/config.h.in ../config.status @@ -226,10 +216,10 @@ install: all installdirs installfiles F = ./vvp@EXEEXT@ $(srcdir)/libvvp.h $(INSTALL_DOC) installman: vvp.man installdirs - $(INSTALL_DATA) vvp.man "$(DESTDIR)$(mandir)/man1/vvp$(suffix).1" + $(INSTALL_DATA) vvp.man "$(DESTDIR)$(man1dir)/vvp$(suffix).1" installpdf: vvp.pdf installdirs - $(INSTALL_DATA) vvp.pdf "$(DESTDIR)$(pdfdir)/vvp$(suffix).pdf" + $(INSTALL_DATA) vvp.pdf "$(DESTDIR)$(docdir)/vvp$(suffix).pdf" installfiles: $(F) | installdirs $(INSTALL_PROGRAM) ./vvp@EXEEXT@ "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@" @@ -241,13 +231,14 @@ endif installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(libdir)" \ - "$(DESTDIR)$(INSTALL_DOCDIR)" \ - "$(DESTDIR)$(INSTALL_PDFDIR)" + "$(DESTDIR)$(docdir)" \ + "$(DESTDIR)$(man1dir)" uninstall: $(UNINSTALL32) rm -f "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@" - rm -f "$(DESTDIR)$(mandir)/man1/vvp$(suffix).1" "$(DESTDIR)$(pdfdir)/vvp$(suffix).pdf" + rm -f "$(DESTDIR)$(man1dir)/vvp$(suffix).1" \ + "$(DESTDIR)$(docdir)/vvp$(suffix).pdf" ifeq (@LIBVVP@,yes) rm -f "$(DESTDIR)$(SLDIR)/libvvp$(suffix).$(SLEXT)" rm -f "$(DESTDIR)$(ivl_includedir)/libvvp.h" From 33584ec6f1c674093648891d7139dc2146b6e11c Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Tue, 12 May 2026 10:31:44 +0200 Subject: [PATCH 049/102] tgt-fpga: cleanup doc related rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this commit, the file “iverilog-fgpa.pdf” is now also installed in the directory where all the other PDF files are located. --- tgt-fpga/Makefile.in | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index 0fa9c6738..32bf0c32c 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -23,8 +23,8 @@ suffix = @install_suffix@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ -mandir = @mandir@ -datarootdir = @datarootdir@ +man1dir = @mandir@/man1 +docdir = @docdir@ VPATH = $(srcdir) @@ -94,13 +94,15 @@ iverilog-fpga.ps: $(srcdir)/iverilog-fpga.man iverilog-fpga.pdf: iverilog-fpga.ps ps2pdf iverilog-fpga.ps iverilog-fpga.pdf -ifeq (@WIN32@,yes) -INSTALL_DOC = installpdf installman -INSTALL_DOCDIR = $(mandir)/man1 +INSTALL_DOC = +ifneq ($(MAN),none) +INSTALL_DOC += installman +ifneq ($(PS2PDF),none) +ifeq (@MINGW32@,yes) +INSTALL_DOC += installpdf all: iverilog-fpga.pdf -else -INSTALL_DOC = installman -INSTALL_DOCDIR = $(mandir)/man1 +endif +endif endif install: all installdirs installfiles @@ -111,10 +113,10 @@ F = ./fpga.tgt \ $(INSTALL_DOC) installman: $(srcdir)/iverilog-fpga.man installdirs - $(INSTALL_DATA) $(srcdir)/iverilog-fpga.man "$(DESTDIR)$(mandir)/man1/iverilog-fpga$(suffix).1" + $(INSTALL_DATA) $(srcdir)/iverilog-fpga.man "$(DESTDIR)$(man1dir)/iverilog-fpga$(suffix).1" installpdf: iverilog-fpga.pdf installdirs - $(INSTALL_DATA) iverilog-fpga.pdf "$(DESTDIR)$(prefix)/iverilog-fpga$(suffix).pdf" + $(INSTALL_DATA) iverilog-fpga.pdf "$(DESTDIR)$(docdir)/iverilog-fpga$(suffix).pdf" installfiles: $(F) | installdirs $(INSTALL_PROGRAM) ./fpga.tgt "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga.tgt" @@ -126,7 +128,7 @@ installdirs: $(srcdir)/../mkinstalldirs uninstall: rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga.tgt" - rm -f "$(DESTDIR)$(prefix)/iverilog-fpga$(suffix).pdf" "$(DESTDIR)$(mandir)/man1/iverilog-fpga$(suffix).1" + rm -f "$(DESTDIR)$(docdir)/iverilog-fpga$(suffix).pdf" "$(DESTDIR)$(man1dir)/iverilog-fpga$(suffix).1" rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga-s.conf" rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga.conf" From cdb9bc2c215efa728eafca981f1985eb84463653 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 11 May 2026 08:39:25 -0700 Subject: [PATCH 050/102] Reject `super` access without a parent class The `super` keyword refers to the parent class of the current class. If the class has no parent the lookup still returned the current class handle and left the `super` path component for l-value elaboration. This triggered the `tail_path.empty()` assert. Report an error during symbol lookup instead. Signed-off-by: Lars-Peter Clausen --- symbol_search.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/symbol_search.cc b/symbol_search.cc index 61a28d4ec..255d608c4 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -153,6 +153,15 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, if (path_tail.name == "#") { if (NetNet *net = scope->find_signal(perm_string::literal(THIS_TOKEN))) { const netclass_t *class_type = dynamic_cast(net->net_type()); + ivl_assert(*li, class_type); + if (!class_type->get_super()) { + cerr << li->get_fileline() << ": error: " + << "Class " << class_type->get_name() + << " uses `super` without a base class." + << endl; + des->errors += 1; + return false; + } path.push_back(path_tail); res->scope = scope; res->net = net; From e4afd6dc25c940a7b85d552ddd4d067568fa56ca Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 11 May 2026 08:52:09 -0700 Subject: [PATCH 051/102] Add regression test for `super` access error Check that access through `super` is rejected when the current class has no parent class. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_super_member_fail.v | 11 +++++++++++ ivtest/regress-vvp.list | 1 + ivtest/vvp_tests/sv_super_member_fail.json | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 ivtest/ivltests/sv_super_member_fail.v create mode 100644 ivtest/vvp_tests/sv_super_member_fail.json diff --git a/ivtest/ivltests/sv_super_member_fail.v b/ivtest/ivltests/sv_super_member_fail.v new file mode 100644 index 000000000..503c1131d --- /dev/null +++ b/ivtest/ivltests/sv_super_member_fail.v @@ -0,0 +1,11 @@ +// Check that `super` access in a class without a parent class is rejected. + +module test; + + class C; + function void f; + super.x = 1; + endfunction + endclass + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 8424d7f55..5671edaf5 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -288,6 +288,7 @@ sv_package_lifetime vvp_tests/sv_package_lifetime.json sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json sv_parameter_type vvp_tests/sv_parameter_type.json sv_queue_assign_op vvp_tests/sv_queue_assign_op.json +sv_super_member_fail vvp_tests/sv_super_member_fail.json sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json sdf_header vvp_tests/sdf_header.json task_return1 vvp_tests/task_return1.json diff --git a/ivtest/vvp_tests/sv_super_member_fail.json b/ivtest/vvp_tests/sv_super_member_fail.json new file mode 100644 index 000000000..14a7e7d70 --- /dev/null +++ b/ivtest/vvp_tests/sv_super_member_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_super_member_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} From 1476f36ff3349f85f5fce98c102c36ee43a4c066 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 12 May 2026 21:33:57 -0700 Subject: [PATCH 052/102] Upgrade actions/checkout to version 5 to support proper nodeJS --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3b9f2f1cf..4efc75e32 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: name: '🍏 macOS' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install dependencies run: | @@ -49,7 +49,7 @@ jobs: name: '🐧 Ubuntu ${{ matrix.os }}' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install dependencies run: | @@ -97,7 +97,7 @@ jobs: - run: git config --global core.autocrlf input shell: bash - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: msys2/setup-msys2@v2 with: From 6b1878c1b5cf5a4e1f542e26874bcb90bbe51e52 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 12 May 2026 21:53:53 -0700 Subject: [PATCH 053/102] Update to the latest actions to remove Node.js warnings --- .github/workflows/test.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4efc75e32..0af5a888d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: name: '🍏 macOS' steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install dependencies run: | @@ -49,7 +49,7 @@ jobs: name: '🐧 Ubuntu ${{ matrix.os }}' steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install dependencies run: | @@ -97,7 +97,7 @@ jobs: - run: git config --global core.autocrlf input shell: bash - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: msys2/setup-msys2@v2 with: @@ -109,7 +109,7 @@ jobs: python-pip mingw-w64-${{ matrix.env }}-perl - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: '>=3.5' @@ -128,7 +128,7 @@ jobs: run: | make check-installed - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: ${{ matrix.msystem }} path: msys2/*.zst From 214324db8c26f7094b3a8096f7dae1079e996fee Mon Sep 17 00:00:00 2001 From: Haowei Hsu Date: Wed, 13 May 2026 15:34:04 +0800 Subject: [PATCH 054/102] docs: add github url to html theme options Include the GitHub repository URL in the HTML theme options for better visibility and access to the project's source code. --- Documentation/conf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/conf.py b/Documentation/conf.py index b50c3ea7f..162fd9ae8 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -82,7 +82,9 @@ html_theme = 'shibuya' # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = { + "github_url": "https://github.com/steveicarus/iverilog", +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From 38a24e71b5c1c4949207fb99806f97f863bdfb76 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 20 Apr 2026 16:30:10 +0200 Subject: [PATCH 055/102] vpp: install missing include directory when installing from 'vvp' directory This fixes an issue unrelated to the addition of support for versioned VVP library. --- vvp/Makefile.in | 1 + 1 file changed, 1 insertion(+) diff --git a/vvp/Makefile.in b/vvp/Makefile.in index da03dfec5..c9c562c3a 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -230,6 +230,7 @@ endif installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(includedir)" \ "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(man1dir)" From 3e7135aabb96127fe67fbe1fb0d90a08f08f6a75 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Thu, 2 Apr 2026 11:13:45 +0200 Subject: [PATCH 056/102] vvp: add DLLIB to LIBS to simplify build rules --- vvp/Makefile.in | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/vvp/Makefile.in b/vvp/Makefile.in index c9c562c3a..fc49e44c8 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -61,7 +61,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -DICARUS_VPI_CONST=const CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @rdynamic@ @LDFLAGS@ -LIBS = @LIBS@ @EXTRALIBS@ +LIBS = @LIBS@ @EXTRALIBS@ @DLLIB@ ifeq (@WIN32@,yes) SLDIR=$(bindir) @@ -71,8 +71,6 @@ SLDIR=$(libdir) SLEXT=so endif -dllib=@DLLIB@ - MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"' VPI = vpi_modules.o vpi_bit.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ @@ -153,10 +151,10 @@ ifeq (@WIN32@,yes) # cocotb to build VPI modules without using our vpi_user.h and libvpi.a. # The .def file controls what is exported. vvp@EXEEXT@: main.o $O $(srcdir)/vvp.def - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ $(LDFLAGS) $(srcdir)/vvp.def main.o $O $(dllib) $(LIBS) + $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ $(LDFLAGS) $(srcdir)/vvp.def main.o $O $(LIBS) else vvp@EXEEXT@: $O main.o - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o $O $(LIBS) $(dllib) + $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o $O $(LIBS) endif endif From 4014db47e0da82ff295805b34d60a9c8a05a3d25 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Thu, 2 Apr 2026 11:37:01 +0200 Subject: [PATCH 057/102] vvp: introduce variable names for object files used by the vvp library --- vvp/Makefile.in | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/vvp/Makefile.in b/vvp/Makefile.in index fc49e44c8..f894288ad 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -73,22 +73,24 @@ endif MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"' -VPI = vpi_modules.o vpi_bit.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ - vpi_event.o vpi_iter.o vpi_mcd.o \ - vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_string.o vpi_tasks.o vpi_time.o \ - vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ - vpip_to_dec.o vpip_format.o vvp_vpi.o +CORE_OBJ = lib_main.o \ + parse.o parse_misc.o lexor.o arith.o array_common.o array.o bufif.o compile.o \ + concat.o dff.o class_type.o enum_type.o extend.o file_line.o latch.o npmos.o part.o \ + permaheap.o reduce.o resolv.o \ + sfunc.o stop.o \ + substitute.o \ + symbols.o ufunc.o codes.o vthread.o schedule.o \ + statistics.o tables.o udp.o vvp_island.o vvp_net.o vvp_net_sig.o \ + vvp_object.o vvp_cobject.o vvp_darray.o event.o logic.o delay.o \ + words.o island_tran.o -O = lib_main.o \ - parse.o parse_misc.o lexor.o arith.o array_common.o array.o bufif.o compile.o \ - concat.o dff.o class_type.o enum_type.o extend.o file_line.o latch.o npmos.o part.o \ - permaheap.o reduce.o resolv.o \ - sfunc.o stop.o \ - substitute.o \ - symbols.o ufunc.o codes.o vthread.o schedule.o \ - statistics.o tables.o udp.o vvp_island.o vvp_net.o vvp_net_sig.o \ - vvp_object.o vvp_cobject.o vvp_darray.o event.o logic.o delay.o \ - words.o island_tran.o $(VPI) +VPI_OBJ = vpi_modules.o vpi_bit.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ + vpi_event.o vpi_iter.o vpi_mcd.o \ + vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_string.o vpi_tasks.o vpi_time.o \ + vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ + vpip_to_dec.o vpip_format.o vvp_vpi.o + +LIB_OBJ = $(CORE_OBJ) $(VPI_OBJ) all: dep vvp@EXEEXT@ vvp.man @@ -115,7 +117,7 @@ distclean: clean rm -f Makefile config.log rm -f stamp-config-h config.h -cppcheck: $(O:.o=.cc) draw_tt.c +cppcheck: $(LIB_OBJ:.o=.cc) draw_tt.c cppcheck --enable=all --std=c99 --std=c++11 -f \ --check-level=exhaustive \ --suppressions-list=$(srcdir)/../cppcheck-global.sup \ @@ -143,18 +145,18 @@ CPPFLAGS+= -fpic vvp@EXEEXT@: main.o $(srcdir)/vvp.def libvvp$(suffix).$(SLEXT) $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o -L. $(LDFLAGS) -lvvp$(suffix) $(LIBS) -libvvp$(suffix).$(SLEXT): $O - $(CXX) -shared $(LDFLAGS) -o libvvp$(suffix).$(SLEXT) $O $(LIBS) $(dllib) +libvvp$(suffix).$(SLEXT): $LIB_OBJ + $(CXX) -shared $(LDFLAGS) -o libvvp$(suffix).$(SLEXT) $LIB_OBJ $(LIBS) $(dllib) else ifeq (@WIN32@,yes) # To support cocotb, we export the VPI functions directly. This allows # cocotb to build VPI modules without using our vpi_user.h and libvpi.a. # The .def file controls what is exported. -vvp@EXEEXT@: main.o $O $(srcdir)/vvp.def - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ $(LDFLAGS) $(srcdir)/vvp.def main.o $O $(LIBS) +vvp@EXEEXT@: main.o $LIB_OBJ $(srcdir)/vvp.def + $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ $(LDFLAGS) $(srcdir)/vvp.def main.o $LIB_OBJ $(LIBS) else -vvp@EXEEXT@: $O main.o - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o $O $(LIBS) +vvp@EXEEXT@: $LIB_OBJ main.o + $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o $LIB_OBJ $(LIBS) endif endif @@ -243,4 +245,4 @@ ifeq (@LIBVVP@,yes) rm -f "$(DESTDIR)$(ivl_includedir)/libvvp.h" endif --include $(patsubst %.o, dep/%.d, $O) +-include $(patsubst %.o, dep/%.d, $LIB_OBJ) From 9d3101fd193bbf271e6a29254229004d72c12432 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 27 Apr 2026 07:08:29 +0200 Subject: [PATCH 058/102] vvp: build and install libvvp as a versioned shared library It uses a dedicated LIBVVP_SOVERSION specified in onfigure.ac for the SONAME and full library version. For linking, a pkg-config file is generated, and when building on Windows, an import library is created that can be used with both GCC and MSVC compilers. On non-Windows platforms, all object files are compiled with -fPIC to ensure compatibility with shared libraries. On Windows use 'lib' prefix for library name with MinGW compiler only. Other compiler like MSVC normally are not using any library prefix. With this commit the build rules for the vpp executable has been cleaned too because the complex structure of the manually created Makefile.in made it very difficult to extract specific parts of them. --- Makefile.in | 16 +---- configure.ac | 18 ++++- vvp/Makefile.in | 173 +++++++++++++++++++++++++++++++++++------------ vvp/libvvp.pc.in | 10 +++ 4 files changed, 157 insertions(+), 60 deletions(-) create mode 100644 vvp/libvvp.pc.in diff --git a/Makefile.in b/Makefile.in index 189c2b2d6..4b01f6730 100644 --- a/Makefile.in +++ b/Makefile.in @@ -145,20 +145,8 @@ endif check: all $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true test -r check.conf || cp $(srcdir)/check.conf . - driver/iverilog -B. -BMvpi -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl -ifeq (@WIN32@,yes) -ifeq (@install_suffix@,) - vvp/vvp -M- -M./vpi ./check.vvp | grep 'Hello, World' -else - # On Windows if we have a suffix we must run the vvp part of - # the test with a suffix since it was built/linked that way. - ln vvp/vvp.exe vvp/vvp$(suffix).exe - vvp/vvp$(suffix) -M- -M./vpi ./check.vvp | grep 'Hello, World' - rm vvp/vvp$(suffix).exe -endif -else - $(ENV_VVP) vvp/vvp -M- -M./vpi ./check.vvp | grep 'Hello, World' -endif + driver/iverilog@EXEEXT@ -B. -BMvpi -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl + $(ENV_VVP) vvp/vvp$(suffix)@EXEEXT@ -M- -M./vpi ./check.vvp | grep 'Hello, World' check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py: $(MAKE) -C ivtest $@ diff --git a/configure.ac b/configure.ac index 6798abce8..9a8c74c96 100644 --- a/configure.ac +++ b/configure.ac @@ -7,6 +7,9 @@ m4_define([VER_MAJOR], [14]) m4_define([VER_MINOR], [0]) m4_define([VER_EXTRA], [devel]) +dnl define libvvp ABI version +m4_define([LIBVVP_SOVERSION], [1]) + AC_INIT([iverilog], [VER_MAJOR.VER_MINOR (VER_EXTRA)]) AC_SUBST([VERSION_MAJOR], [VER_MAJOR]) AC_SUBST([VERSION_MINOR], [VER_MINOR]) @@ -15,6 +18,11 @@ AC_SUBST([VERSION], ["VER_MAJOR.VER_MINOR (VER_EXTRA)"]) # used in res.rc AC_SUBST([PRODUCTVERSION], ["VER_MAJOR,VER_MINOR,0,0"]) +# setup libvvp soversion, which depends on abi not package version +AC_SUBST([LIBVVP_SOVERSION], [LIBVVP_SOVERSION]) +# setup libvvp version +AC_SUBST([LIBVVP_VERSION], [LIBVVP_SOVERSION.VER_MAJOR.VER_MINOR]) + AC_CONFIG_SRCDIR([netlist.h]) # Need a stamp file like the other header files AC_CONFIG_FILES([version_base.h],[ @@ -209,7 +217,14 @@ AC_FUNC_FSEEKO # Build VVP as a library and stub AC_ARG_ENABLE([libvvp], [AS_HELP_STRING([--enable-libvvp], [build VVP as a shared library])], - [AC_SUBST(LIBVVP, yes)],[]) + [enable_libvvp=yes], + [enable_libvvp=no]) + +AC_SUBST([LIBVVP], [$enable_libvvp]) + +AS_IF([test "x$enable_libvvp" = "xyes"], + [AC_MSG_NOTICE([Building with libvvp support enabled])], + [AC_MSG_NOTICE([Building with libvvp support disabled])]) AC_ARG_ENABLE([libveriuser], [AS_HELP_STRING([--enable-libveriuser], [include support for PLI 1 (deprecated)])], @@ -434,6 +449,7 @@ AC_CONFIG_FILES([ vhdlpp/Makefile vpi/Makefile vvp/Makefile + vvp/libvvp.pc vvp/vvp.man ]) AC_OUTPUT diff --git a/vvp/Makefile.in b/vvp/Makefile.in index f894288ad..9b7f0013f 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -23,6 +23,7 @@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ datarootdir = @datarootdir@ +abs_builddir = @abs_builddir@ VPATH = $(srcdir) @@ -30,6 +31,8 @@ bindir = @bindir@ libdir = @libdir@ man1dir = @mandir@/man1 docdir = @docdir@ +pkgconfigdir = @libdir@/pkgconfig + # This is actually the directory where we install our own header files. # It is a little different from the generic includedir. ivl_includedir = @includedir@/iverilog$(suffix) @@ -58,17 +61,80 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -DICARUS_VPI_CONST=const -CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ -CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ -LDFLAGS = @rdynamic@ @LDFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ @PICFLAG@ +CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ @PICFLAG@ +LDFLAGS = @rdynamic@ @LDFLAGS@ @PICFLAG@ LIBS = @LIBS@ @EXTRALIBS@ @DLLIB@ -ifeq (@WIN32@,yes) +LIBVVP_VERSION = @LIBVVP_VERSION@ +LIBVVP_SOVERSION = @LIBVVP_SOVERSION@ +LIBBASENAME=vvp$(suffix) +LDFLAGS_SHARED = @rdynamic@ @shared@ @LDFLAGS@ + +ifeq (@MINGW32@,yes) SLDIR=$(bindir) SLEXT=dll +IMPEXT=dll.a +LIBPREFIX=lib +LIBNAME=$(LIBPREFIX)$(LIBBASENAME) +LIBSONAME=$(LIBNAME).$(SLEXT).$(LIBVVP_SOVERSION) +LIBREALNAME=$(LIBNAME).$(SLEXT).$(LIBVVP_VERSION) +LIBLINKNAME=$(LIBNAME).$(SLEXT) +LIBTARGET=$(LIBNAME)-$(LIBVVP_SOVERSION).$(SLEXT) +LIBBUILD=$(LIBTARGET) +LIBLINKFLAGS=-Wl,--out-implib,$(LIBNAME).$(IMPEXT) -Wl,--no-undefined +LIBPOSTBUILD=@true +LIBINSTALL=$(LIBTARGET) +LIBDEVELINSTALL=$(LIBNAME).$(IMPEXT) +else ifeq (@WIN32@,yes) +SLDIR=$(bindir) +SLEXT=dll +IMPEXT=lib +LIBPREFIX= +LIBNAME=$(LIBPREFIX)$(LIBBASENAME) +LIBSONAME=$(LIBNAME).$(SLEXT).$(LIBVVP_SOVERSION) +LIBREALNAME=$(LIBNAME).$(SLEXT).$(LIBVVP_VERSION) +LIBLINKNAME=$(LIBNAME).$(SLEXT) +LIBTARGET=$(LIBLINKNAME) +LIBBUILD=$(LIBLINKNAME) +LIBLINKFLAGS= +LIBPOSTBUILD=@true +LIBINSTALL=$(LIBTARGET) +LIBDEVELINSTALL= +else ifneq (,$(findstring darwin,@host_os@)) +SLDIR=$(libdir) +SLEXT=dylib +LIBPREFIX=lib +LIBNAME=$(LIBPREFIX)$(LIBBASENAME) +LIBSONAME=$(LIBNAME).$(LIBVVP_SOVERSION).$(SLEXT) +LIBREALNAME=$(LIBNAME).$(LIBVVP_VERSION).$(SLEXT) +LIBLINKNAME=$(LIBNAME).$(SLEXT) +LIBTARGET=$(LIBREALNAME) +LIBBUILD=$(LIBTARGET) +LDFLAGS_SHARED=-dynamiclib +LIBLINKFLAGS= \ + -Wl,-install_name,$(libdir)/$(LIBSONAME) \ + -Wl,-compatibility_version,$(LIBVVP_SOVERSION) \ + -Wl,-current_version,$(LIBVVP_VERSION) +LIBPOSTBUILD= \ + ln -sf $(LIBREALNAME) $(LIBSONAME) && \ + ln -sf $(LIBSONAME) $(LIBLINKNAME) +LIBINSTALL=$(LIBTARGET) +LIBDEVELINSTALL= else SLDIR=$(libdir) SLEXT=so +LIBPREFIX=lib +LIBNAME=$(LIBPREFIX)$(LIBBASENAME) +LIBSONAME=$(LIBNAME).$(SLEXT).$(LIBVVP_SOVERSION) +LIBREALNAME=$(LIBNAME).$(SLEXT).$(LIBVVP_VERSION) +LIBLINKNAME=$(LIBNAME).$(SLEXT) +LIBTARGET=$(LIBREALNAME) +LIBBUILD=$(LIBLINKNAME) +LIBLINKFLAGS=-Wl,-soname,$(LIBSONAME) +LIBPOSTBUILD=ln -sf $(LIBREALNAME) $(LIBSONAME) && ln -sf $(LIBSONAME) $(LIBLINKNAME) +LIBINSTALL=$(LIBTARGET) +LIBDEVELINSTALL= endif MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"' @@ -91,27 +157,37 @@ VPI_OBJ = vpi_modules.o vpi_bit.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_d vpip_to_dec.o vpip_format.o vvp_vpi.o LIB_OBJ = $(CORE_OBJ) $(VPI_OBJ) +LIB_CLEAN = $(LIBNAME)*.$(SLEXT)* libvvp.pc + +VVP_OBJ = main.o +VVP_CLEAN = vvp@EXEEXT@ +ifeq (@WIN32@,yes) +# To support cocotb, we export the VPI functions directly. This allows +# cocotb to build VPI modules without using our vpi_user.h and libvpi.a. +# The .def file controls what is exported. +VVP_OBJ += $(srcdir)/vvp.def +endif +ifeq (@LIBVVP@,yes) +VVP_LDFLAGS = -lvvp$(suffix) +VVP_DEPS = $(LIBBUILD) +else +VVP_OBJ += $(LIB_OBJ) +endif +ifneq (@install_suffix@,) +VVP_POSTBUILD = ln -sf vvp@EXEEXT@ vvp$(suffix)@EXEEXT@ +VVP_CLEAN += vvp$(suffix)@EXEEXT@ +endif all: dep vvp@EXEEXT@ vvp.man +# ENV_VVP sets LD_LIBRARY_PATH by default to run vvp from the build tree check: all -ifeq (@WIN32@,yes) -ifeq (@install_suffix@,) - ./vvp -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.' -else - # On Windows if we have a suffix we must run the vvp test with - # a suffix since it was built/linked that way. - ln vvp.exe vvp$(suffix).exe - ./vvp$(suffix) -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.' - rm -f vvp$(suffix).exe -endif -else - $(ENV_VVP) ./vvp -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.' -endif + $(ENV_VVP) ./vvp$(suffix)@EXEEXT@ -M../vpi $(srcdir)/examples/hello.vvp | grep 'Hello, World.' clean: - rm -f *.o *~ parse.cc parse.h lexor.cc tables.cc libvvp$(suffix).$(SLEXT) - rm -rf dep vvp@EXEEXT@ parse.output vvp.man vvp.ps vvp.pdf vvp.exp + rm -f *.o *~ parse.cc parse.h lexor.cc tables.cc $(LIB_CLEAN) + rm -f $(VVP_CLEAN) parse.output vvp.man vvp.ps vvp.pdf vvp.exp + rm -rf dep distclean: clean rm -f Makefile config.log @@ -136,30 +212,15 @@ dep: mkdir dep ifeq (@LIBVVP@,yes) - -CPPFLAGS+= -fpic - -# To avoid setting LD_LIBRARY_PATH when running vvp from the build tree, -# add option -Wl,-rpath=`pwd` to the CXX command below. - -vvp@EXEEXT@: main.o $(srcdir)/vvp.def libvvp$(suffix).$(SLEXT) - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o -L. $(LDFLAGS) -lvvp$(suffix) $(LIBS) - -libvvp$(suffix).$(SLEXT): $LIB_OBJ - $(CXX) -shared $(LDFLAGS) -o libvvp$(suffix).$(SLEXT) $LIB_OBJ $(LIBS) $(dllib) -else -ifeq (@WIN32@,yes) -# To support cocotb, we export the VPI functions directly. This allows -# cocotb to build VPI modules without using our vpi_user.h and libvpi.a. -# The .def file controls what is exported. -vvp@EXEEXT@: main.o $LIB_OBJ $(srcdir)/vvp.def - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ $(LDFLAGS) $(srcdir)/vvp.def main.o $LIB_OBJ $(LIBS) -else -vvp@EXEEXT@: $LIB_OBJ main.o - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ main.o $LIB_OBJ $(LIBS) -endif +$(LIBBUILD): $(LIB_OBJ) + $(CXX) $(LDFLAGS_SHARED) $(LIBLINKFLAGS) -o $(LIBTARGET) $^ $(LIBS) + $(LIBPOSTBUILD) endif +vvp@EXEEXT@: $(VVP_OBJ) $(VVP_DEPS) + $(CXX) $(LDFLAGS) -o $@ $(VVP_OBJ) -L. $(VVP_LDFLAGS) $(LIBS) + $(VVP_POSTBUILD) + %.o: %.cc config.h | dep $(CXX) $(CPPFLAGS) -DIVL_SUFFIX='"$(suffix)"' $(MDIR1) $(MDIR2) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep/$*.d @@ -211,7 +272,7 @@ stamp-config-h: $(srcdir)/config.h.in ../config.status cd ..; ./config.status --header=vvp/config.h config.h: stamp-config-h -install: all installdirs installfiles +install: all installdirs installfiles installpkgconfig F = ./vvp@EXEEXT@ $(srcdir)/libvvp.h $(INSTALL_DOC) @@ -224,24 +285,46 @@ installpdf: vvp.pdf installdirs installfiles: $(F) | installdirs $(INSTALL_PROGRAM) ./vvp@EXEEXT@ "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@" ifeq (@LIBVVP@,yes) - $(INSTALL_PROGRAM) ./libvvp$(suffix).$(SLEXT) "$(DESTDIR)$(SLDIR)/libvvp$(suffix).$(SLEXT)" + $(INSTALL_PROGRAM) ./$(LIBINSTALL) "$(DESTDIR)$(SLDIR)/$(LIBINSTALL)" +ifeq (@WIN32@,yes) +ifneq ($(LIBDEVELINSTALL),) + $(INSTALL_PROGRAM) ./$(LIBDEVELINSTALL) "$(DESTDIR)$(libdir)/$(LIBDEVELINSTALL)" +endif +else + # Install real library + ln -sf $(LIBREALNAME) "$(DESTDIR)$(SLDIR)/$(LIBSONAME)" + ln -sf $(LIBSONAME) "$(DESTDIR)$(SLDIR)/$(LIBLINKNAME)" +endif $(INSTALL_DATA) $(srcdir)/libvvp.h "$(DESTDIR)$(ivl_includedir)/libvvp.h" endif installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" \ - "$(DESTDIR)$(includedir)" \ + "$(DESTDIR)$(ivl_includedir)" \ "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(man1dir)" +installpkgconfig: + $(INSTALL) -d "$(DESTDIR)$(pkgconfigdir)" + $(INSTALL_DATA) libvvp.pc "$(DESTDIR)$(pkgconfigdir)/libvvp$(suffix).pc" uninstall: $(UNINSTALL32) rm -f "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@" rm -f "$(DESTDIR)$(man1dir)/vvp$(suffix).1" \ "$(DESTDIR)$(docdir)/vvp$(suffix).pdf" ifeq (@LIBVVP@,yes) - rm -f "$(DESTDIR)$(SLDIR)/libvvp$(suffix).$(SLEXT)" + rm -f "$(DESTDIR)$(SLDIR)/$(LIBINSTALL)" +ifeq (@WIN32@,yes) +ifneq ($(LIBDEVELINSTALL),) + rm -f "$(DESTDIR)$(libdir)/$(LIBDEVELINSTALL)" +endif +else + rm -f "$(DESTDIR)$(SLDIR)/$(LIBLINKNAME)" + rm -f "$(DESTDIR)$(SLDIR)/$(LIBSONAME)" + rm -f "$(DESTDIR)$(SLDIR)/$(LIBREALNAME)" +endif + rm -f "$(DESTDIR)$(pkgconfigdir)/libvvp$(suffix).pc" rm -f "$(DESTDIR)$(ivl_includedir)/libvvp.h" endif diff --git a/vvp/libvvp.pc.in b/vvp/libvvp.pc.in new file mode 100644 index 000000000..2e93b2233 --- /dev/null +++ b/vvp/libvvp.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libvvp@install_suffix@ +Version: @VERSION_MAJOR@.@VERSION_MINOR@ +Description: Icarus Verilog VVP runtime library +Libs: -L${libdir} -lvvp@install_suffix@ +Cflags: -I${includedir}/iverilog@install_suffix@ From 00bb35a0ce615db12825bdfeb6a283674a5287a0 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sat, 28 Mar 2026 20:07:39 +0100 Subject: [PATCH 059/102] CI: Add support to compile on all platforms with libvvp and/or suffix enabled The specified jobs runs the build, check, install and a post install test stage. --- .github/workflows/test.yml | 49 +++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0af5a888d..5f2678d6c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,8 +14,11 @@ jobs: mac: strategy: fail-fast: false + # matrix: + # libvvp: [false, true] + # suffix: [false, true] runs-on: macos-15-intel - name: '🍏 macOS' + name: 🍏 macOS${{ matrix.libvvp && ' +libvvp' || '' }}${{ matrix.suffix && ' +suffix' || '' }} steps: - uses: actions/checkout@v6 @@ -27,8 +30,15 @@ jobs: - name: Build, check and install run: | export PATH="/usr/local/opt/bison/bin:$PATH" + CONFIG_OPTS="--enable-libveriuser" + if [ "${{ matrix.libvvp }}" = "true" ]; then + CONFIG_OPTS="$CONFIG_OPTS --enable-libvvp" + fi + if [ "${{ matrix.suffix }}" = "true" ]; then + CONFIG_OPTS="$CONFIG_OPTS --enable-suffix" + fi autoconf - ./configure --enable-libveriuser + ./configure $CONFIG_OPTS make -j$(nproc) check sudo make install @@ -41,12 +51,11 @@ jobs: strategy: fail-fast: false matrix: - os: [ - '22.04', - '24.04' - ] + os: ['22.04', '24.04'] + # libvvp: [false, true] + # suffix: [false, true] runs-on: ubuntu-${{ matrix.os }} - name: '🐧 Ubuntu ${{ matrix.os }}' + name: 🐧 Ubuntu ${{ matrix.os }}${{ matrix.libvvp && ' +libvvp' || '' }}${{ matrix.suffix && ' +suffix' || '' }} steps: - uses: actions/checkout@v6 @@ -62,8 +71,15 @@ jobs: - name: Build, check and install run: | + CONFIG_OPTS="--enable-libveriuser" + if [ "${{ matrix.libvvp }}" = "true" ]; then + CONFIG_OPTS="$CONFIG_OPTS --enable-libvvp" + fi + if [ "${{ matrix.suffix }}" = "true" ]; then + CONFIG_OPTS="$CONFIG_OPTS --enable-suffix" + fi autoconf - ./configure --enable-libveriuser + ./configure $CONFIG_OPTS make -j$(nproc) check sudo make install @@ -82,11 +98,14 @@ jobs: strategy: fail-fast: false matrix: + msystem: [MINGW64, UCRT64, CLANG64] + # libvvp: [false, true] + # suffix: [false, true] include: - { msystem: MINGW64, env: x86_64 } - { msystem: UCRT64, env: ucrt-x86_64 } - { msystem: CLANG64, env: clang-x86_64 } - name: 🟪 ${{ matrix.msystem}} + name: 🟪 ${{ matrix.msystem }}${{ matrix.libvvp && ' +libvvp' || '' }}${{ matrix.suffix && ' +suffix' || '' }} defaults: run: shell: msys2 {0} @@ -116,9 +135,17 @@ jobs: - name: Build and check run: | cd msys2 + CONFIG_OPTS="" if [ ${{ matrix.msystem }} != "CLANG64" ] ; then - export IVL_CONFIG_OPTIONS="--enable-libveriuser" + CONFIG_OPTS="$CONFIG_OPTS --enable-libveriuser" fi + if [ "${{ matrix.libvvp }}" = "true" ] ; then + CONFIG_OPTS="$CONFIG_OPTS --enable-libvvp" + fi + if [ "${{ matrix.suffix }}" = "true" ]; then + CONFIG_OPTS="$CONFIG_OPTS --enable-suffix" + fi + export IVL_CONFIG_OPTIONS="$CONFIG_OPTS" makepkg-mingw --noconfirm --noprogressbar -sCLf - name: Install @@ -130,5 +157,5 @@ jobs: - uses: actions/upload-artifact@v7 with: - name: ${{ matrix.msystem }} + name: 🟪 ${{ matrix.msystem }}${{ matrix.libvvp && ' +libvvp' || '' }} path: msys2/*.zst From a1299f7ca8625282af8929f3468953d7ad0c5043 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 13 May 2026 10:48:24 +0200 Subject: [PATCH 060/102] CI: enable building with libvvp and suffix on MacOSX Adding these build variants to the platform in question results in the smallest increase in the number of additional build jobs. --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5f2678d6c..0e9b818d0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,9 +14,9 @@ jobs: mac: strategy: fail-fast: false - # matrix: - # libvvp: [false, true] - # suffix: [false, true] + matrix: + libvvp: [true] + suffix: [true] runs-on: macos-15-intel name: 🍏 macOS${{ matrix.libvvp && ' +libvvp' || '' }}${{ matrix.suffix && ' +suffix' || '' }} steps: From a042847b387e18c78cb429462c40894ff558b1aa Mon Sep 17 00:00:00 2001 From: Haowei Hsu Date: Wed, 13 May 2026 22:12:30 +0800 Subject: [PATCH 061/102] docs: add edit this page to sidebar --- Documentation/conf.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/conf.py b/Documentation/conf.py index 162fd9ae8..619872ce1 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -73,6 +73,17 @@ highlight_language = 'none' # -- Options for HTML output ------------------------------------------------- +# A dictionary of values to pass into the template engine's context for all pages. +# +html_context = { + # Edit this page + "source_type": "github", + "source_user": "steveicarus", + "source_repo": "iverilog", + "source_version": "master", + "source_docs_path": "/Documentation/", +} + # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # From f1c71eff5c5f24be543eee799d7d4674c32da885 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 13 May 2026 15:20:42 -0700 Subject: [PATCH 062/102] parse.y: Remove unused fields from union The parser union still has a few fields that are not used by any grammar rule. They do not have matching semantic type tags and no action references them. Remove the unused fields. Signed-off-by: Lars-Peter Clausen --- parse.y | 5 ----- 1 file changed, 5 deletions(-) diff --git a/parse.y b/parse.y index 10184aeff..44d1101d9 100644 --- a/parse.y +++ b/parse.y @@ -486,8 +486,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, ivl_discipline_t discipline; - hname_t*hier; - std::list*strings; struct str_pair_t drive; @@ -540,7 +538,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, struct_type_t*struct_type; data_type_t*data_type; - class_type_t*class_type; real_type_t::type_t real_type; property_qualifier_t property_qualifier; PPackage*package; @@ -570,8 +567,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, verireal* realtime; PSpecPath* specpath; - std::list *dimensions; - PTimingCheck::event_t* timing_check_event; PTimingCheck::optional_args_t* spec_optional_args; From d84f1b9843fcdf7f9996d4b0eb1871b6923272f8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jun 2022 13:27:55 +0200 Subject: [PATCH 063/102] tgt-vvp: Use `%cmp/e` instead of `%cmp/u` for `case` comparisons `%cmp/e` and `%cmp/u` are very similar with `%cmp/e` not setting the lt flag and being a bit faster due to it. For case comparisons the flag is not needed so switch to `%cmp/e`. This speeds up simulation time designs which make use of case comparisons. Signed-off-by: Lars-Peter Clausen --- tgt-vvp/vvp_process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 2604ae656..8165abfa2 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -671,7 +671,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope) switch (ivl_statement_type(net)) { case IVL_ST_CASE: - fprintf(vvp_out, " %%cmp/u;\n"); + fprintf(vvp_out, " %%cmp/e;\n"); fprintf(vvp_out, " %%jmp/1 T_%u.%u, 6;\n", thread_count, local_base+idx); break; From 5b62f32ad69851e2aab45be4905c6e0d227b1829 Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Fri, 15 May 2026 07:47:24 -0700 Subject: [PATCH 064/102] Update copyright year in vvp_process.c --- tgt-vvp/vvp_process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 8165abfa2..8382b94ab 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2026 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 From 208078838e1a319be0d2d0bb2909ac9facf83207 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 10 May 2026 21:21:39 -0700 Subject: [PATCH 065/102] Reject unpacked l-value concatenation operands L-value concatenation operands must be packed values. Using an unpacked array, string, class object or other non-packed value as an operand can reach later assignment code with an invalid l-value representation. Check the operand type after l-value elaboration and report an elaboration error instead. Signed-off-by: Lars-Peter Clausen --- elab_lval.cc | 8 +++++--- elab_net.cc | 24 +++++++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index 4f1859c43..1068954d1 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2026 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -133,11 +133,13 @@ NetAssign_* PEConcat::elaborate_lval(Design*des, the compiler catch more errors. */ if (tmp == 0) continue; - if (tmp->expr_type() == IVL_VT_REAL) { + ivl_type_t tmp_type = tmp->net_type(); + if (tmp_type && !tmp_type->packed()) { cerr << parms_[idx]->get_fileline() << ": error: " - << "concatenation operand can not be real: " + << "concatenation operand must be packed: " << *parms_[idx] << endl; des->errors += 1; + delete tmp; continue; } diff --git a/elab_net.cc b/elab_net.cc index 6ec75d067..3cde04797 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2026 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -83,16 +83,22 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope, } if (nets[idx] == 0) { - errors += 1; - } else if (nets[idx]->data_type() == IVL_VT_REAL) { - cerr << parms_[idx]->get_fileline() << ": error: " - << "concatenation operand can no be real: " - << *parms_[idx] << endl; errors += 1; - continue; } else { - width += nets[idx]->vector_width(); - } + ivl_type_t tmp_type = nets[idx]->array_type(); + if (!tmp_type) + tmp_type = nets[idx]->net_type(); + + if (tmp_type && !tmp_type->packed()) { + cerr << parms_[idx]->get_fileline() << ": error: " + << "concatenation operand must be packed: " + << *parms_[idx] << endl; + errors += 1; + continue; + } + + width += nets[idx]->vector_width(); + } } if (errors) { From f9ab26b3d9f406105377232ab50fa5b4df3226a9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 10 May 2026 22:12:54 -0700 Subject: [PATCH 066/102] Add regression tests for unpacked l-value concat errors Check that class objects, dynamic arrays, queues, strings and static unpacked arrays can not be used as l-value concatenation operands. Check procedural and continuous assignment concatenations, including single operand concatenations. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_lval_concat_class_fail1.v | 15 ++++++++++++++ ivtest/ivltests/sv_lval_concat_class_fail2.v | 15 ++++++++++++++ ivtest/ivltests/sv_lval_concat_class_fail3.v | 14 +++++++++++++ ivtest/ivltests/sv_lval_concat_class_fail4.v | 13 ++++++++++++ ivtest/ivltests/sv_lval_concat_darray_fail1.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_darray_fail2.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_darray_fail3.v | 11 ++++++++++ ivtest/ivltests/sv_lval_concat_darray_fail4.v | 10 ++++++++++ ivtest/ivltests/sv_lval_concat_queue_fail1.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_queue_fail2.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_queue_fail3.v | 11 ++++++++++ ivtest/ivltests/sv_lval_concat_queue_fail4.v | 10 ++++++++++ ivtest/ivltests/sv_lval_concat_string_fail1.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_string_fail2.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_string_fail3.v | 11 ++++++++++ ivtest/ivltests/sv_lval_concat_string_fail4.v | 10 ++++++++++ ivtest/ivltests/sv_lval_concat_uarray_fail1.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_uarray_fail2.v | 12 +++++++++++ ivtest/ivltests/sv_lval_concat_uarray_fail3.v | 11 ++++++++++ ivtest/ivltests/sv_lval_concat_uarray_fail4.v | 10 ++++++++++ ivtest/regress-vvp.list | 20 +++++++++++++++++++ .../vvp_tests/sv_lval_concat_class_fail1.json | 5 +++++ .../vvp_tests/sv_lval_concat_class_fail2.json | 5 +++++ .../vvp_tests/sv_lval_concat_class_fail3.json | 5 +++++ .../vvp_tests/sv_lval_concat_class_fail4.json | 5 +++++ .../sv_lval_concat_darray_fail1.json | 5 +++++ .../sv_lval_concat_darray_fail2.json | 5 +++++ .../sv_lval_concat_darray_fail3.json | 5 +++++ .../sv_lval_concat_darray_fail4.json | 5 +++++ .../vvp_tests/sv_lval_concat_queue_fail1.json | 5 +++++ .../vvp_tests/sv_lval_concat_queue_fail2.json | 5 +++++ .../vvp_tests/sv_lval_concat_queue_fail3.json | 5 +++++ .../vvp_tests/sv_lval_concat_queue_fail4.json | 5 +++++ .../sv_lval_concat_string_fail1.json | 5 +++++ .../sv_lval_concat_string_fail2.json | 5 +++++ .../sv_lval_concat_string_fail3.json | 5 +++++ .../sv_lval_concat_string_fail4.json | 5 +++++ .../sv_lval_concat_uarray_fail1.json | 5 +++++ .../sv_lval_concat_uarray_fail2.json | 5 +++++ .../sv_lval_concat_uarray_fail3.json | 5 +++++ .../sv_lval_concat_uarray_fail4.json | 5 +++++ 41 files changed, 357 insertions(+) create mode 100644 ivtest/ivltests/sv_lval_concat_class_fail1.v create mode 100644 ivtest/ivltests/sv_lval_concat_class_fail2.v create mode 100644 ivtest/ivltests/sv_lval_concat_class_fail3.v create mode 100644 ivtest/ivltests/sv_lval_concat_class_fail4.v create mode 100644 ivtest/ivltests/sv_lval_concat_darray_fail1.v create mode 100644 ivtest/ivltests/sv_lval_concat_darray_fail2.v create mode 100644 ivtest/ivltests/sv_lval_concat_darray_fail3.v create mode 100644 ivtest/ivltests/sv_lval_concat_darray_fail4.v create mode 100644 ivtest/ivltests/sv_lval_concat_queue_fail1.v create mode 100644 ivtest/ivltests/sv_lval_concat_queue_fail2.v create mode 100644 ivtest/ivltests/sv_lval_concat_queue_fail3.v create mode 100644 ivtest/ivltests/sv_lval_concat_queue_fail4.v create mode 100644 ivtest/ivltests/sv_lval_concat_string_fail1.v create mode 100644 ivtest/ivltests/sv_lval_concat_string_fail2.v create mode 100644 ivtest/ivltests/sv_lval_concat_string_fail3.v create mode 100644 ivtest/ivltests/sv_lval_concat_string_fail4.v create mode 100644 ivtest/ivltests/sv_lval_concat_uarray_fail1.v create mode 100644 ivtest/ivltests/sv_lval_concat_uarray_fail2.v create mode 100644 ivtest/ivltests/sv_lval_concat_uarray_fail3.v create mode 100644 ivtest/ivltests/sv_lval_concat_uarray_fail4.v create mode 100644 ivtest/vvp_tests/sv_lval_concat_class_fail1.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_class_fail2.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_class_fail3.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_class_fail4.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_darray_fail1.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_darray_fail2.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_darray_fail3.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_darray_fail4.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_queue_fail1.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_queue_fail2.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_queue_fail3.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_queue_fail4.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_string_fail1.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_string_fail2.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_string_fail3.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_string_fail4.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_uarray_fail1.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_uarray_fail2.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_uarray_fail3.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_uarray_fail4.json diff --git a/ivtest/ivltests/sv_lval_concat_class_fail1.v b/ivtest/ivltests/sv_lval_concat_class_fail1.v new file mode 100644 index 000000000..09a0150ae --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_class_fail1.v @@ -0,0 +1,15 @@ +// Check that class objects can not be used in l-value concatenations. + +module test; + + class C; + endclass + + int x; + C c; + + initial begin + {x, c} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_class_fail2.v b/ivtest/ivltests/sv_lval_concat_class_fail2.v new file mode 100644 index 000000000..061c33898 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_class_fail2.v @@ -0,0 +1,15 @@ +// Check that class objects can not be used in single operand l-value concatenations. + +module test; + + class C; + endclass + + int x; + C c; + + initial begin + {c} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_class_fail3.v b/ivtest/ivltests/sv_lval_concat_class_fail3.v new file mode 100644 index 000000000..22e6ebcb0 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_class_fail3.v @@ -0,0 +1,14 @@ +// Check that class objects can not be used in continuous assignment l-value concatenations. + +module test; + + class C; + endclass + + int x; + C c; + int y; + + assign {x, c} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_class_fail4.v b/ivtest/ivltests/sv_lval_concat_class_fail4.v new file mode 100644 index 000000000..958c3d38d --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_class_fail4.v @@ -0,0 +1,13 @@ +// Check that class objects can not be used in single operand continuous assignment l-value concatenations. + +module test; + + class C; + endclass + + C c; + int y; + + assign {c} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_darray_fail1.v b/ivtest/ivltests/sv_lval_concat_darray_fail1.v new file mode 100644 index 000000000..66c4b93df --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_darray_fail1.v @@ -0,0 +1,12 @@ +// Check that dynamic arrays can not be used in l-value concatenations. + +module test; + + int x; + int d[]; + + initial begin + {x, d} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_darray_fail2.v b/ivtest/ivltests/sv_lval_concat_darray_fail2.v new file mode 100644 index 000000000..e0cec7842 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_darray_fail2.v @@ -0,0 +1,12 @@ +// Check that dynamic arrays can not be used in single operand l-value concatenations. + +module test; + + int x; + int d[]; + + initial begin + {d} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_darray_fail3.v b/ivtest/ivltests/sv_lval_concat_darray_fail3.v new file mode 100644 index 000000000..0617fc040 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_darray_fail3.v @@ -0,0 +1,11 @@ +// Check that dynamic arrays can not be used in continuous assignment l-value concatenations. + +module test; + + int x; + int d[]; + int y; + + assign {x, d} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_darray_fail4.v b/ivtest/ivltests/sv_lval_concat_darray_fail4.v new file mode 100644 index 000000000..c9848b0b9 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_darray_fail4.v @@ -0,0 +1,10 @@ +// Check that dynamic arrays can not be used in single operand continuous assignment l-value concatenations. + +module test; + + int d[]; + int y; + + assign {d} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_queue_fail1.v b/ivtest/ivltests/sv_lval_concat_queue_fail1.v new file mode 100644 index 000000000..5fd60aaa2 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_queue_fail1.v @@ -0,0 +1,12 @@ +// Check that queues can not be used in l-value concatenations. + +module test; + + int x; + int q[$]; + + initial begin + {x, q} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_queue_fail2.v b/ivtest/ivltests/sv_lval_concat_queue_fail2.v new file mode 100644 index 000000000..11f1474b9 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_queue_fail2.v @@ -0,0 +1,12 @@ +// Check that queues can not be used in single operand l-value concatenations. + +module test; + + int x; + int q[$]; + + initial begin + {q} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_queue_fail3.v b/ivtest/ivltests/sv_lval_concat_queue_fail3.v new file mode 100644 index 000000000..cd80fa3a3 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_queue_fail3.v @@ -0,0 +1,11 @@ +// Check that queues can not be used in continuous assignment l-value concatenations. + +module test; + + int x; + int q[$]; + int y; + + assign {x, q} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_queue_fail4.v b/ivtest/ivltests/sv_lval_concat_queue_fail4.v new file mode 100644 index 000000000..76754cb48 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_queue_fail4.v @@ -0,0 +1,10 @@ +// Check that queues can not be used in single operand continuous assignment l-value concatenations. + +module test; + + int q[$]; + int y; + + assign {q} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_string_fail1.v b/ivtest/ivltests/sv_lval_concat_string_fail1.v new file mode 100644 index 000000000..9ba22b586 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_string_fail1.v @@ -0,0 +1,12 @@ +// Check that strings can not be used in l-value concatenations. + +module test; + + int x; + string s; + + initial begin + {x, s} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_string_fail2.v b/ivtest/ivltests/sv_lval_concat_string_fail2.v new file mode 100644 index 000000000..09a3d5f41 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_string_fail2.v @@ -0,0 +1,12 @@ +// Check that strings can not be used in single operand l-value concatenations. + +module test; + + int x; + string s; + + initial begin + {s} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_string_fail3.v b/ivtest/ivltests/sv_lval_concat_string_fail3.v new file mode 100644 index 000000000..336d0e669 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_string_fail3.v @@ -0,0 +1,11 @@ +// Check that strings can not be used in continuous assignment l-value concatenations. + +module test; + + int x; + string s; + int y; + + assign {x, s} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_string_fail4.v b/ivtest/ivltests/sv_lval_concat_string_fail4.v new file mode 100644 index 000000000..404b6f0d2 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_string_fail4.v @@ -0,0 +1,10 @@ +// Check that strings can not be used in single operand continuous assignment l-value concatenations. + +module test; + + string s; + int y; + + assign {s} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_uarray_fail1.v b/ivtest/ivltests/sv_lval_concat_uarray_fail1.v new file mode 100644 index 000000000..c70b74013 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_uarray_fail1.v @@ -0,0 +1,12 @@ +// Check that static unpacked arrays can not be used in l-value concatenations. + +module test; + + int x; + int u[0:0]; + + initial begin + {x, u} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_uarray_fail2.v b/ivtest/ivltests/sv_lval_concat_uarray_fail2.v new file mode 100644 index 000000000..4d48ed593 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_uarray_fail2.v @@ -0,0 +1,12 @@ +// Check that static unpacked arrays can not be used in single operand l-value concatenations. + +module test; + + int x; + int u[0:0]; + + initial begin + {u} = x; + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_uarray_fail3.v b/ivtest/ivltests/sv_lval_concat_uarray_fail3.v new file mode 100644 index 000000000..51b778028 --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_uarray_fail3.v @@ -0,0 +1,11 @@ +// Check that static unpacked arrays can not be used in continuous assignment l-value concatenations. + +module test; + + int x; + int u[0:0]; + int y; + + assign {x, u} = y; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_uarray_fail4.v b/ivtest/ivltests/sv_lval_concat_uarray_fail4.v new file mode 100644 index 000000000..ae15eb28f --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_uarray_fail4.v @@ -0,0 +1,10 @@ +// Check that static unpacked arrays can not be used in single operand continuous assignment l-value concatenations. + +module test; + + int u[0:0]; + int y; + + assign {u} = y; + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 5671edaf5..0c806d0d1 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -274,6 +274,26 @@ sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json sv_interface vvp_tests/sv_interface.json sv_literals vvp_tests/sv_literals.json +sv_lval_concat_class_fail1 vvp_tests/sv_lval_concat_class_fail1.json +sv_lval_concat_class_fail2 vvp_tests/sv_lval_concat_class_fail2.json +sv_lval_concat_class_fail3 vvp_tests/sv_lval_concat_class_fail3.json +sv_lval_concat_class_fail4 vvp_tests/sv_lval_concat_class_fail4.json +sv_lval_concat_darray_fail1 vvp_tests/sv_lval_concat_darray_fail1.json +sv_lval_concat_darray_fail2 vvp_tests/sv_lval_concat_darray_fail2.json +sv_lval_concat_darray_fail3 vvp_tests/sv_lval_concat_darray_fail3.json +sv_lval_concat_darray_fail4 vvp_tests/sv_lval_concat_darray_fail4.json +sv_lval_concat_queue_fail1 vvp_tests/sv_lval_concat_queue_fail1.json +sv_lval_concat_queue_fail2 vvp_tests/sv_lval_concat_queue_fail2.json +sv_lval_concat_queue_fail3 vvp_tests/sv_lval_concat_queue_fail3.json +sv_lval_concat_queue_fail4 vvp_tests/sv_lval_concat_queue_fail4.json +sv_lval_concat_string_fail1 vvp_tests/sv_lval_concat_string_fail1.json +sv_lval_concat_string_fail2 vvp_tests/sv_lval_concat_string_fail2.json +sv_lval_concat_string_fail3 vvp_tests/sv_lval_concat_string_fail3.json +sv_lval_concat_string_fail4 vvp_tests/sv_lval_concat_string_fail4.json +sv_lval_concat_uarray_fail1 vvp_tests/sv_lval_concat_uarray_fail1.json +sv_lval_concat_uarray_fail2 vvp_tests/sv_lval_concat_uarray_fail2.json +sv_lval_concat_uarray_fail3 vvp_tests/sv_lval_concat_uarray_fail3.json +sv_lval_concat_uarray_fail4 vvp_tests/sv_lval_concat_uarray_fail4.json sv_mixed_assign1 vvp_tests/sv_mixed_assign1.json sv_mixed_assign2 vvp_tests/sv_mixed_assign2.json sv_mixed_assign_error1 vvp_tests/sv_mixed_assign_error1.json diff --git a/ivtest/vvp_tests/sv_lval_concat_class_fail1.json b/ivtest/vvp_tests/sv_lval_concat_class_fail1.json new file mode 100644 index 000000000..40b769246 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_class_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_class_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_class_fail2.json b/ivtest/vvp_tests/sv_lval_concat_class_fail2.json new file mode 100644 index 000000000..803e89d8d --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_class_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_class_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_class_fail3.json b/ivtest/vvp_tests/sv_lval_concat_class_fail3.json new file mode 100644 index 000000000..610d6872f --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_class_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_class_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_class_fail4.json b/ivtest/vvp_tests/sv_lval_concat_class_fail4.json new file mode 100644 index 000000000..612cc605c --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_class_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_class_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_darray_fail1.json b/ivtest/vvp_tests/sv_lval_concat_darray_fail1.json new file mode 100644 index 000000000..8442e431f --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_darray_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_darray_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_darray_fail2.json b/ivtest/vvp_tests/sv_lval_concat_darray_fail2.json new file mode 100644 index 000000000..93eb8e0ce --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_darray_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_darray_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_darray_fail3.json b/ivtest/vvp_tests/sv_lval_concat_darray_fail3.json new file mode 100644 index 000000000..cf0408a32 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_darray_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_darray_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_darray_fail4.json b/ivtest/vvp_tests/sv_lval_concat_darray_fail4.json new file mode 100644 index 000000000..0d6af611d --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_darray_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_darray_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_queue_fail1.json b/ivtest/vvp_tests/sv_lval_concat_queue_fail1.json new file mode 100644 index 000000000..94d535fef --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_queue_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_queue_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_queue_fail2.json b/ivtest/vvp_tests/sv_lval_concat_queue_fail2.json new file mode 100644 index 000000000..a53dc3713 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_queue_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_queue_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_queue_fail3.json b/ivtest/vvp_tests/sv_lval_concat_queue_fail3.json new file mode 100644 index 000000000..73844e309 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_queue_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_queue_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_queue_fail4.json b/ivtest/vvp_tests/sv_lval_concat_queue_fail4.json new file mode 100644 index 000000000..4f56bc0bc --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_queue_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_queue_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_string_fail1.json b/ivtest/vvp_tests/sv_lval_concat_string_fail1.json new file mode 100644 index 000000000..a357deb9d --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_string_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_string_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_string_fail2.json b/ivtest/vvp_tests/sv_lval_concat_string_fail2.json new file mode 100644 index 000000000..fe34900ff --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_string_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_string_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_string_fail3.json b/ivtest/vvp_tests/sv_lval_concat_string_fail3.json new file mode 100644 index 000000000..9c7409a3d --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_string_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_string_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_string_fail4.json b/ivtest/vvp_tests/sv_lval_concat_string_fail4.json new file mode 100644 index 000000000..0cd79d33d --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_string_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_string_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_uarray_fail1.json b/ivtest/vvp_tests/sv_lval_concat_uarray_fail1.json new file mode 100644 index 000000000..3b668613d --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_uarray_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_uarray_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_uarray_fail2.json b/ivtest/vvp_tests/sv_lval_concat_uarray_fail2.json new file mode 100644 index 000000000..b835f8940 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_uarray_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_uarray_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_uarray_fail3.json b/ivtest/vvp_tests/sv_lval_concat_uarray_fail3.json new file mode 100644 index 000000000..8845375aa --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_uarray_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_uarray_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_uarray_fail4.json b/ivtest/vvp_tests/sv_lval_concat_uarray_fail4.json new file mode 100644 index 000000000..15e9eb063 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_uarray_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_concat_uarray_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} From b8eac7fc191d4926e23f2b74558072cab4129daa Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 09:53:47 -0700 Subject: [PATCH 067/102] ivtest: Fix source for sv_mixed_assign2 test The sv_mixed_assign2 JSON entry accidentally references sv_mixed_assign1.v. Point it at sv_mixed_assign2.v instead. Signed-off-by: Lars-Peter Clausen --- ivtest/vvp_tests/sv_mixed_assign2.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivtest/vvp_tests/sv_mixed_assign2.json b/ivtest/vvp_tests/sv_mixed_assign2.json index 207fb7c8c..82c625110 100644 --- a/ivtest/vvp_tests/sv_mixed_assign2.json +++ b/ivtest/vvp_tests/sv_mixed_assign2.json @@ -1,5 +1,5 @@ { "type" : "NI", - "source" : "sv_mixed_assign1.v", + "source" : "sv_mixed_assign2.v", "iverilog-args" : [ "-g2009" ] } From 96cea271ba049012f995ab615ba5f5b4b232800d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 12:57:58 -0700 Subject: [PATCH 068/102] ivtest: Fix VVP regression test metadata A few JSON regression test entries reference the wrong source or gold files. There are also two regress-vvp list entries that reference each other's JSON file. Use the matching source and gold files for those entries. Signed-off-by: Lars-Peter Clausen --- ivtest/regress-vvp.list | 4 ++-- ivtest/vvp_tests/br_gh1256b.json | 2 +- ivtest/vvp_tests/sv_mixed_assign_error2.json | 4 ++-- ivtest/vvp_tests/sv_mixed_assign_error3.json | 4 ++-- ivtest/vvp_tests/sv_mixed_assign_error4.json | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 5671edaf5..28899919a 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -249,8 +249,8 @@ sv_class_prop_assign_op2 vvp_tests/sv_class_prop_assign_op2.json sv_class_prop_logic vvp_tests/sv_class_prop_logic.json sv_class_prop_nest_darray1 vvp_tests/sv_class_prop_nest_darray1.json sv_class_prop_nest_obj1 vvp_tests/sv_class_prop_nest_obj1.json -sv_class_prop_nest_real1 vvp_tests/sv_class_prop_nest_str1.json -sv_class_prop_nest_str1 vvp_tests/sv_class_prop_nest_real1.json +sv_class_prop_nest_real1 vvp_tests/sv_class_prop_nest_real1.json +sv_class_prop_nest_str1 vvp_tests/sv_class_prop_nest_str1.json sv_class_prop_nest_vec1 vvp_tests/sv_class_prop_nest_vec1.json sv_const1 vvp_tests/sv_const1.json sv_const2 vvp_tests/sv_const2.json diff --git a/ivtest/vvp_tests/br_gh1256b.json b/ivtest/vvp_tests/br_gh1256b.json index c1598a869..ae8ab6e8f 100644 --- a/ivtest/vvp_tests/br_gh1256b.json +++ b/ivtest/vvp_tests/br_gh1256b.json @@ -1,5 +1,5 @@ { "type" : "normal", - "source" : "br_gh1256a.v", + "source" : "br_gh1256b.v", "iverilog-args" : [ "-g2009" ] } diff --git a/ivtest/vvp_tests/sv_mixed_assign_error2.json b/ivtest/vvp_tests/sv_mixed_assign_error2.json index 967b059f5..8bdd1d9fc 100644 --- a/ivtest/vvp_tests/sv_mixed_assign_error2.json +++ b/ivtest/vvp_tests/sv_mixed_assign_error2.json @@ -1,6 +1,6 @@ { "type" : "CE", - "source" : "sv_mixed_assign_error1.v", - "gold" : "sv_mixed_assign_error1", + "source" : "sv_mixed_assign_error2.v", + "gold" : "sv_mixed_assign_error2", "iverilog-args" : [ "-g2009" ] } diff --git a/ivtest/vvp_tests/sv_mixed_assign_error3.json b/ivtest/vvp_tests/sv_mixed_assign_error3.json index 967b059f5..20387f916 100644 --- a/ivtest/vvp_tests/sv_mixed_assign_error3.json +++ b/ivtest/vvp_tests/sv_mixed_assign_error3.json @@ -1,6 +1,6 @@ { "type" : "CE", - "source" : "sv_mixed_assign_error1.v", - "gold" : "sv_mixed_assign_error1", + "source" : "sv_mixed_assign_error3.v", + "gold" : "sv_mixed_assign_error3", "iverilog-args" : [ "-g2009" ] } diff --git a/ivtest/vvp_tests/sv_mixed_assign_error4.json b/ivtest/vvp_tests/sv_mixed_assign_error4.json index 967b059f5..e4b2da1fd 100644 --- a/ivtest/vvp_tests/sv_mixed_assign_error4.json +++ b/ivtest/vvp_tests/sv_mixed_assign_error4.json @@ -1,6 +1,6 @@ { "type" : "CE", - "source" : "sv_mixed_assign_error1.v", - "gold" : "sv_mixed_assign_error1", + "source" : "sv_mixed_assign_error4.v", + "gold" : "sv_mixed_assign_error4", "iverilog-args" : [ "-g2009" ] } From 84dc4ec99fd6883ea4aeaf96d235ec46ca10b704 Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Sat, 16 May 2026 15:16:47 -0700 Subject: [PATCH 069/102] Update copyright year in elab_net.cc --- elab_net.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elab_net.cc b/elab_net.cc index dc9dc9782..753ab6842 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2026 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it From 9ff4a42171c246129957c9e31f252b78692135e5 Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Sat, 16 May 2026 15:17:52 -0700 Subject: [PATCH 070/102] Update copyright year in Module.cc --- Module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Module.cc b/Module.cc index 957822743..abbaf6bc8 100644 --- a/Module.cc +++ b/Module.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2022 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2026 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 From 73cee3b3e05606d050d3e7d736e1f5c55bbe98fc Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Sat, 16 May 2026 15:18:15 -0700 Subject: [PATCH 071/102] Update copyright year in Module.h --- Module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Module.h b/Module.h index 62082ab68..cd4fde766 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef IVL_Module_H #define IVL_Module_H /* - * Copyright (c) 1998-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2026 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 From 9f3f35e45111403d963a81d976fa2531cf3c96b0 Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Sat, 16 May 2026 15:19:02 -0700 Subject: [PATCH 072/102] Update copyright year in netmisc.h --- netmisc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmisc.h b/netmisc.h index ff4aa0e01..d87b5d027 100644 --- a/netmisc.h +++ b/netmisc.h @@ -1,7 +1,7 @@ #ifndef IVL_netmisc_H #define IVL_netmisc_H /* - * Copyright (c) 1999-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2026 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 From b605f42a1e9c814e57a152952e4d12ad696a8bb5 Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Sat, 16 May 2026 15:19:40 -0700 Subject: [PATCH 073/102] Update copyright year in parse_misc.h --- parse_misc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parse_misc.h b/parse_misc.h index a9eb7d19b..62adbe9e6 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -1,7 +1,7 @@ #ifndef IVL_parse_misc_H #define IVL_parse_misc_H /* - * Copyright (c) 1998-2024 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2026 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 From eadb1d24aefd20d1b9a13d03ef2f006864c9f814 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 08:38:31 -0700 Subject: [PATCH 074/102] Add 2017 and 2023 language flag support Add flags to enable IEEE1800-2017 and IEEE1800-2023 languages generations and also support them in the `begin_keywords macro. Since neither defines new keywords they'll use the same keyword mask as 2012. Update the driver, compiler, documentation and regression test harness so -g2017 and -g2023 are recognized as language generation flags. There are no specific features from these versions added yet, this is just the necessary infrastructure to allow gating new features from those generations when they are added later. Signed-off-by: Lars-Peter Clausen --- Documentation/usage/command_line_flags.rst | 10 ++++++++++ compiler.h | 2 ++ driver/iverilog.man.in | 8 ++++---- driver/main.c | 18 +++++++++++++++--- ivtest/perl-lib/RegressionList.pm | 6 ++++-- ivtest/vlog95_reg.pl | 4 +++- ivtest/vvp_reg.py | 4 ++-- lexor.lex | 4 +++- main.cc | 14 ++++++++++++++ 9 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Documentation/usage/command_line_flags.rst b/Documentation/usage/command_line_flags.rst index fb3f7c7bc..302021957 100644 --- a/Documentation/usage/command_line_flags.rst +++ b/Documentation/usage/command_line_flags.rst @@ -68,6 +68,16 @@ These flags affect the general behavior of the compiler. This flag enables the IEEE1800-2012 standard, which includes SystemVerilog. + * 2017 + + This flag enables the IEEE1800-2017 standard, which includes + SystemVerilog. + + * 2023 + + This flag enables the IEEE1800-2023 standard, which includes + SystemVerilog. + * verilog-ams This flag enables Verilog-AMS features that are supported by Icarus diff --git a/compiler.h b/compiler.h index 01893d18b..56f706c70 100644 --- a/compiler.h +++ b/compiler.h @@ -165,6 +165,8 @@ enum generation_t { GN_VER2005_SV = 5, GN_VER2009 = 6, GN_VER2012 = 7, + GN_VER2017 = 8, + GN_VER2023 = 9, GN_DEFAULT = 4 }; diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 4ff682a48..60498549b 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -6,7 +6,7 @@ iverilog - Icarus Verilog compiler .B iverilog [\-EiRSuVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] [\-Pparameter=value] [\-pflag=value] [\-dname] -[\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g] +[\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g2017\:|\-g2023\:|\-g] [\-Iincludedir] [\-Lmoduledir] [\-mmodule] [\-M[mode=]file] [\-Nfile] [\-ooutputfilename] [\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] [\-lfile] @@ -63,11 +63,11 @@ is the Verilog input, but with file inclusions and macro references expanded and removed. This is useful, for example, to preprocess Verilog source for use by other compilers. .TP 8 -.B -g1995\fI|\fP-g2001\fI|\fP-g2001-noconfig\fI|\fP-g2005\fI|\fP-g2005-sv\fI|\fP-g2009\fI|\fP-g2012 +.B -g1995\fI|\fP-g2001\fI|\fP-g2001-noconfig\fI|\fP-g2005\fI|\fP-g2005-sv\fI|\fP-g2009\fI|\fP-g2012\fI|\fP-g2017\fI|\fP-g2023 Select the Verilog language \fIgeneration\fP to support in the compiler. This selects between \fIIEEE1364\-1995\fP, \fIIEEE1364\-2001\fP, -\fIIEEE1364\-2005\fP, \fIIEEE1800\-2005\fP, \fIIEEE1800\-2009\fP, or -\fIIEEE1800\-2012\fP. +\fIIEEE1364\-2005\fP, \fIIEEE1800\-2005\fP, \fIIEEE1800\-2009\fP, +\fIIEEE1800\-2012\fP, \fIIEEE1800\-2017\fP, or \fIIEEE1800\-2023\fP. Icarus Verilog currently defaults to the \fIIEEE1364\-2005\fP generation of the language. This flag is used to restrict the language to a set of keywords/features, this allows simulation of older Verilog code that may diff --git a/driver/main.c b/driver/main.c index 0fed62ee7..865a94e4c 100644 --- a/driver/main.c +++ b/driver/main.c @@ -39,7 +39,7 @@ const char NOTICE[] = const char HELP[] = "Usage: iverilog [-EiRSuvV] [-B base] [-c cmdfile|-f cmdfile]\n" -" [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g]\n" +" [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012|-g2017|-g2023] [-g]\n" " [-D macro[=defn]] [-I includedir] [-L moduledir]\n" " [-M [mode=]depfile] [-m module]\n" " [-N file] [-o filename] [-p flag=value]\n" @@ -740,6 +740,12 @@ static int process_generation(const char*name) else if (strcmp(name,"2012") == 0) generation = "2012"; + else if (strcmp(name,"2017") == 0) + generation = "2017"; + + else if (strcmp(name,"2023") == 0) + generation = "2023"; + else if (strcmp(name,"1") == 0) { /* Deprecated: use 1995 */ generation = "1995"; gen_xtypes = "no-xtypes"; @@ -860,6 +866,8 @@ static int process_generation(const char*name) " 2005-sv -- IEEE1800-2005\n" " 2009 -- IEEE1800-2009\n" " 2012 -- IEEE1800-2012\n" + " 2017 -- IEEE1800-2017\n" + " 2023 -- IEEE1800-2023\n" "Other generation flags:\n" " assertions | supported-assertions | no-assertions\n" " specify | no-specify\n" @@ -1388,11 +1396,13 @@ int main(int argc, char **argv) fprintf(iconfig_file, "module:%s%cvhdl_sys.vpi\n", vpi_dir, sep); fprintf(iconfig_file, "module:%s%cvhdl_textio.vpi\n", vpi_dir, sep); - /* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams, + /* If verilog-2005/09/12/17/23 is enabled or icarus-misc or verilog-ams, * then include the v2005_math library. */ if (strcmp(generation, "2005") == 0 || strcmp(generation, "2009") == 0 || strcmp(generation, "2012") == 0 || + strcmp(generation, "2017") == 0 || + strcmp(generation, "2023") == 0 || strcmp(gen_icarus, "icarus-misc") == 0 || strcmp(gen_verilog_ams, "verilog-ams") == 0) { fprintf(iconfig_file, "module:%s%cv2005_math.vpi\n", vpi_dir, sep); @@ -1407,7 +1417,9 @@ int main(int argc, char **argv) v2009 module. */ if (strcmp(generation, "2005-sv") == 0 || strcmp(generation, "2009") == 0 || - strcmp(generation, "2012") == 0) { + strcmp(generation, "2012") == 0 || + strcmp(generation, "2017") == 0 || + strcmp(generation, "2023") == 0) { fprintf(iconfig_file, "module:%s%cv2009.vpi\n", vpi_dir, sep); } diff --git a/ivtest/perl-lib/RegressionList.pm b/ivtest/perl-lib/RegressionList.pm index a089b4d18..a03a1beda 100644 --- a/ivtest/perl-lib/RegressionList.pm +++ b/ivtest/perl-lib/RegressionList.pm @@ -172,13 +172,15 @@ sub read_regression_list { $nameidx{$tname} = @testlist - 1; # The generation to use is passed if it does not match - # the default. To make sure the tests are protable we + # the default. To make sure the tests are portable we # use the force SV flag to force all tests to be run # as the latest SystemVerilog generation. This assumes # the correct `begin_keywords has been added to the # various files. if ($force_sv) { - my $fsv_flags = "-g2012"; + my $fsv_flags = "-g2023"; + $args{$tname} =~ s/-g2023//; + $args{$tname} =~ s/-g2017//; $args{$tname} =~ s/-g2012//; $args{$tname} =~ s/-g2009//; $args{$tname} =~ s/-g2005-sv//; diff --git a/ivtest/vlog95_reg.pl b/ivtest/vlog95_reg.pl index 25caee834..ad2fc8174 100755 --- a/ivtest/vlog95_reg.pl +++ b/ivtest/vlog95_reg.pl @@ -4,7 +4,7 @@ # # This script is based on code with the following Copyright. # -# Copyright (c) 1999-2025 Guy Hutchison (ghutchis@pacbell.net) +# Copyright (c) 1999-2026 Guy Hutchison (ghutchis@pacbell.net) # # This source code is free software; you can redistribute it # and/or modify it in source code form under the terms of the GNU @@ -183,6 +183,8 @@ sub execute_regression { $args{$tname} =~ s/-g2005(-sv)?//g; $args{$tname} =~ s/-g2009//g; $args{$tname} =~ s/-g2012//g; + $args{$tname} =~ s/-g2017//g; + $args{$tname} =~ s/-g2023//g; $args{$tname} =~ s/-gverilog-ams//g; $cmd = "iverilog$sfx -o vsim $gen_flag $args{$tname}"; $cmd .= " -s $testmod{$tname}" if ($testmod{$tname} ne ""); diff --git a/ivtest/vvp_reg.py b/ivtest/vvp_reg.py index 601dc45bb..6cc6d5ad2 100755 --- a/ivtest/vvp_reg.py +++ b/ivtest/vvp_reg.py @@ -64,7 +64,7 @@ def process_overrides(group: str, it_dict: dict, it_opts: dict): def force_gen(it_opts: dict): '''Remove the current generation and force it to the latest.''' - generations = ['-g2012', '-g2009', '-g2005-sv', + generations = ['-g2023', '-g2017', '-g2012', '-g2009', '-g2005-sv', '-g2005', '-g2001-noconfig', '-g2001', '-g1995', '-g2', '-g1'] for gen in generations: @@ -75,7 +75,7 @@ def force_gen(it_opts: dict): idx_to_replace = it_opts['iverilog_args'].index('-g2x') it_opts[idx_to_replace] = '-gicarus-misc' - it_opts['iverilog_args'].insert(0, '-g2012') + it_opts['iverilog_args'].insert(0, '-g2023') def process_test(item: list, cfg: list) -> str: diff --git a/lexor.lex b/lexor.lex index 0e0c2646c..7c62f92eb 100644 --- a/lexor.lex +++ b/lexor.lex @@ -789,7 +789,9 @@ TU [munpf] |GN_KEYWORDS_1364_2005 |GN_KEYWORDS_1800_2005 |GN_KEYWORDS_1800_2009; - } else if (strcmp(word,"1800-2012") == 0) { + } else if (strcmp(word,"1800-2012") == 0 + || strcmp(word,"1800-2017") == 0 + || strcmp(word,"1800-2023") == 0) { lexor_keyword_mask = GN_KEYWORDS_1364_1995 |GN_KEYWORDS_1364_2001 |GN_KEYWORDS_1364_2001_CONFIG diff --git a/main.cc b/main.cc index a1f5ef1db..917e006e9 100644 --- a/main.cc +++ b/main.cc @@ -323,6 +323,12 @@ static void process_generation_flag(const char*gen) } else if (strcmp(gen,"2012") == 0) { generation_flag = GN_VER2012; + } else if (strcmp(gen,"2017") == 0) { + generation_flag = GN_VER2017; + + } else if (strcmp(gen,"2023") == 0) { + generation_flag = GN_VER2023; + } else if (strcmp(gen,"icarus-misc") == 0) { gn_icarus_misc_flag = true; @@ -1058,6 +1064,8 @@ int main(int argc, char*argv[]) lexor_keyword_mask = 0; switch (generation_flag) { + case GN_VER2023: + case GN_VER2017: case GN_VER2012: lexor_keyword_mask |= GN_KEYWORDS_1800_2012; // fallthrough @@ -1113,6 +1121,12 @@ int main(int argc, char*argv[]) case GN_VER2012: cout << "IEEE1800-2012"; break; + case GN_VER2017: + cout << "IEEE1800-2017"; + break; + case GN_VER2023: + cout << "IEEE1800-2023"; + break; } if (gn_verilog_ams_flag) From 0a6fa449deb551538b50c67f8c8a464f7d3401ee Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 14:09:00 -0700 Subject: [PATCH 075/102] Add regression tests for `begin_keywords` versions Check that each valid `begin_keywords` selector is accepted. Only check that the selector itself is accepted, in these tests there is no check if the correct keywords are actually accepted or rejected since that would get pretty exhaustive. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/begin_keywords_1364_1995.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1364_2001.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1364_2001_noconfig.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1364_2005.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1800_2005.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1800_2009.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1800_2012.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1800_2017.v | 9 +++++++++ ivtest/ivltests/begin_keywords_1800_2023.v | 9 +++++++++ ivtest/ivltests/begin_keywords_vams_2_3.v | 9 +++++++++ ivtest/regress-vvp.list | 10 ++++++++++ ivtest/vvp_tests/begin_keywords_1364_1995.json | 5 +++++ ivtest/vvp_tests/begin_keywords_1364_2001.json | 5 +++++ .../vvp_tests/begin_keywords_1364_2001_noconfig.json | 5 +++++ ivtest/vvp_tests/begin_keywords_1364_2005.json | 5 +++++ ivtest/vvp_tests/begin_keywords_1800_2005.json | 5 +++++ ivtest/vvp_tests/begin_keywords_1800_2009.json | 5 +++++ ivtest/vvp_tests/begin_keywords_1800_2012.json | 5 +++++ ivtest/vvp_tests/begin_keywords_1800_2017.json | 5 +++++ ivtest/vvp_tests/begin_keywords_1800_2023.json | 5 +++++ ivtest/vvp_tests/begin_keywords_vams_2_3.json | 5 +++++ 21 files changed, 150 insertions(+) create mode 100644 ivtest/ivltests/begin_keywords_1364_1995.v create mode 100644 ivtest/ivltests/begin_keywords_1364_2001.v create mode 100644 ivtest/ivltests/begin_keywords_1364_2001_noconfig.v create mode 100644 ivtest/ivltests/begin_keywords_1364_2005.v create mode 100644 ivtest/ivltests/begin_keywords_1800_2005.v create mode 100644 ivtest/ivltests/begin_keywords_1800_2009.v create mode 100644 ivtest/ivltests/begin_keywords_1800_2012.v create mode 100644 ivtest/ivltests/begin_keywords_1800_2017.v create mode 100644 ivtest/ivltests/begin_keywords_1800_2023.v create mode 100644 ivtest/ivltests/begin_keywords_vams_2_3.v create mode 100644 ivtest/vvp_tests/begin_keywords_1364_1995.json create mode 100644 ivtest/vvp_tests/begin_keywords_1364_2001.json create mode 100644 ivtest/vvp_tests/begin_keywords_1364_2001_noconfig.json create mode 100644 ivtest/vvp_tests/begin_keywords_1364_2005.json create mode 100644 ivtest/vvp_tests/begin_keywords_1800_2005.json create mode 100644 ivtest/vvp_tests/begin_keywords_1800_2009.json create mode 100644 ivtest/vvp_tests/begin_keywords_1800_2012.json create mode 100644 ivtest/vvp_tests/begin_keywords_1800_2017.json create mode 100644 ivtest/vvp_tests/begin_keywords_1800_2023.json create mode 100644 ivtest/vvp_tests/begin_keywords_vams_2_3.json diff --git a/ivtest/ivltests/begin_keywords_1364_1995.v b/ivtest/ivltests/begin_keywords_1364_1995.v new file mode 100644 index 000000000..ab0209665 --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1364_1995.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1364-1995 keyword set. + +`begin_keywords "1364-1995" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1364_2001.v b/ivtest/ivltests/begin_keywords_1364_2001.v new file mode 100644 index 000000000..e3873759d --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1364_2001.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1364-2001 keyword set. + +`begin_keywords "1364-2001" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1364_2001_noconfig.v b/ivtest/ivltests/begin_keywords_1364_2001_noconfig.v new file mode 100644 index 000000000..d75c4d2e0 --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1364_2001_noconfig.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1364-2001-noconfig keyword set. + +`begin_keywords "1364-2001-noconfig" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1364_2005.v b/ivtest/ivltests/begin_keywords_1364_2005.v new file mode 100644 index 000000000..4f759305a --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1364_2005.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1364-2005 keyword set. + +`begin_keywords "1364-2005" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1800_2005.v b/ivtest/ivltests/begin_keywords_1800_2005.v new file mode 100644 index 000000000..7cced42c1 --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1800_2005.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1800-2005 keyword set. + +`begin_keywords "1800-2005" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1800_2009.v b/ivtest/ivltests/begin_keywords_1800_2009.v new file mode 100644 index 000000000..a1add0a40 --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1800_2009.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1800-2009 keyword set. + +`begin_keywords "1800-2009" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1800_2012.v b/ivtest/ivltests/begin_keywords_1800_2012.v new file mode 100644 index 000000000..61e4707a3 --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1800_2012.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1800-2012 keyword set. + +`begin_keywords "1800-2012" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1800_2017.v b/ivtest/ivltests/begin_keywords_1800_2017.v new file mode 100644 index 000000000..08befd948 --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1800_2017.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1800-2017 keyword set. + +`begin_keywords "1800-2017" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_1800_2023.v b/ivtest/ivltests/begin_keywords_1800_2023.v new file mode 100644 index 000000000..f665f7504 --- /dev/null +++ b/ivtest/ivltests/begin_keywords_1800_2023.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the 1800-2023 keyword set. + +`begin_keywords "1800-2023" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/ivltests/begin_keywords_vams_2_3.v b/ivtest/ivltests/begin_keywords_vams_2_3.v new file mode 100644 index 000000000..b4bd9709e --- /dev/null +++ b/ivtest/ivltests/begin_keywords_vams_2_3.v @@ -0,0 +1,9 @@ +// Check that `begin_keywords accepts the VAMS-2.3 keyword set. + +`begin_keywords "VAMS-2.3" +module test; + initial begin + $display("PASSED"); + end +endmodule +`end_keywords diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 3f78202bb..412f724d4 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -14,6 +14,16 @@ array_slice_concat vvp_tests/array_slice_concat.json automatic_error11 vvp_tests/automatic_error11.json automatic_error12 vvp_tests/automatic_error12.json automatic_error13 vvp_tests/automatic_error13.json +begin_keywords_1364_1995 vvp_tests/begin_keywords_1364_1995.json +begin_keywords_1364_2001 vvp_tests/begin_keywords_1364_2001.json +begin_keywords_1364_2001_noconfig vvp_tests/begin_keywords_1364_2001_noconfig.json +begin_keywords_1364_2005 vvp_tests/begin_keywords_1364_2005.json +begin_keywords_1800_2005 vvp_tests/begin_keywords_1800_2005.json +begin_keywords_1800_2009 vvp_tests/begin_keywords_1800_2009.json +begin_keywords_1800_2012 vvp_tests/begin_keywords_1800_2012.json +begin_keywords_1800_2017 vvp_tests/begin_keywords_1800_2017.json +begin_keywords_1800_2023 vvp_tests/begin_keywords_1800_2023.json +begin_keywords_vams_2_3 vvp_tests/begin_keywords_vams_2_3.json bits4 vvp_tests/bits4.json bitsel11 vvp_tests/bitsel11.json br_gh13a vvp_tests/br_gh13a.json diff --git a/ivtest/vvp_tests/begin_keywords_1364_1995.json b/ivtest/vvp_tests/begin_keywords_1364_1995.json new file mode 100644 index 000000000..4714ae520 --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1364_1995.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1364_1995.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1364_2001.json b/ivtest/vvp_tests/begin_keywords_1364_2001.json new file mode 100644 index 000000000..a51d48856 --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1364_2001.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1364_2001.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1364_2001_noconfig.json b/ivtest/vvp_tests/begin_keywords_1364_2001_noconfig.json new file mode 100644 index 000000000..ac1342d7d --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1364_2001_noconfig.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1364_2001_noconfig.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1364_2005.json b/ivtest/vvp_tests/begin_keywords_1364_2005.json new file mode 100644 index 000000000..50d7b65f6 --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1364_2005.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1364_2005.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1800_2005.json b/ivtest/vvp_tests/begin_keywords_1800_2005.json new file mode 100644 index 000000000..6fadb9da6 --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1800_2005.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1800_2005.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1800_2009.json b/ivtest/vvp_tests/begin_keywords_1800_2009.json new file mode 100644 index 000000000..84460a9db --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1800_2009.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1800_2009.v", + "iverilog-args" : [ "-g2009" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1800_2012.json b/ivtest/vvp_tests/begin_keywords_1800_2012.json new file mode 100644 index 000000000..c83b42cf4 --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1800_2012.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1800_2012.v", + "iverilog-args" : [ "-g2012" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1800_2017.json b/ivtest/vvp_tests/begin_keywords_1800_2017.json new file mode 100644 index 000000000..0545c5f39 --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1800_2017.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1800_2017.v", + "iverilog-args" : [ "-g2017" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_1800_2023.json b/ivtest/vvp_tests/begin_keywords_1800_2023.json new file mode 100644 index 000000000..22a3b51e8 --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_1800_2023.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_1800_2023.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/begin_keywords_vams_2_3.json b/ivtest/vvp_tests/begin_keywords_vams_2_3.json new file mode 100644 index 000000000..fe44aca3f --- /dev/null +++ b/ivtest/vvp_tests/begin_keywords_vams_2_3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "begin_keywords_vams_2_3.v", + "iverilog-args" : [ "-g2005-sv", "-gverilog-ams" ] +} From eb45fb6eecbdcc79e0c6a0864f953aba0eb9802c Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 16 May 2026 16:22:23 -0700 Subject: [PATCH 076/102] Fix Makefile generation warning in tgt-fpga --- tgt-fpga/Makefile.in | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index 32bf0c32c..776541ad3 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -23,6 +23,7 @@ suffix = @install_suffix@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ +datarootdir = @datarootdir man1dir = @mandir@/man1 docdir = @docdir@ From fb3be420b4d62008e47ad0b7117bd402323c050f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 08:39:01 -0700 Subject: [PATCH 077/102] Support soft packed unions SystemVerilog 2023 adds soft packed unions. They are pretty much the same as regular packed unions except they remove the restriction that all elements have to have the same packed width. The packed with of the union itself is the maximum packed width of any element. The bits of each member are right-justified towards the LSBs and this representation is applied recursively to nested soft packed unions. The existing packed union member offsets already use that layout. When accessing a field that is smaller than the union itself upper bits are ignored for both reading and writing. The `soft` qualifier implies a packed union so both `union soft U { ... }` and `union soft packed U { ... }` declare a soft packed union. Signed-off-by: Lars-Peter Clausen --- elab_type.cc | 12 +++++++----- netstruct.cc | 26 +++++++++++++++++--------- netstruct.h | 15 +++++++++------ parse.y | 39 +++++++++++++++++++++++++++------------ pform_types.h | 1 + 5 files changed, 61 insertions(+), 32 deletions(-) diff --git a/elab_type.cc b/elab_type.cc index 9048e3afc..d52af2d25 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2024 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2026 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 @@ -220,11 +220,13 @@ ivl_type_t struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const res->set_line(*this); - res->packed(packed_flag); + bool is_packed = packed_flag || (union_flag && soft_flag); + res->packed(is_packed); res->set_signed(signed_flag); - if (union_flag) - res->union_flag(true); + if (union_flag) { + res->union_flag(true, soft_flag); + } for (list::iterator cur = members->begin() ; cur != members->end() ; ++ cur) { @@ -242,7 +244,7 @@ ivl_type_t struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const ; cur_name != curp->names->end() ; ++ cur_name) { decl_assignment_t*namep = *cur_name; - if (packed_flag && namep->expr) { + if (is_packed && namep->expr) { cerr << namep->expr->get_fileline() << " error: " << "Packed structs must not have default member values." << endl; diff --git a/netstruct.cc b/netstruct.cc index 3c3dc13f7..0c80bd718 100644 --- a/netstruct.cc +++ b/netstruct.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2022 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2026 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 @@ -26,22 +26,19 @@ using namespace std; -netstruct_t::netstruct_t() -: union_(false), packed_(false), signed_(false) -{ -} - netstruct_t::~netstruct_t() { } -void netstruct_t::union_flag(bool flag) +void netstruct_t::union_flag(bool flag, bool soft) { // This MUST be called before any members are pushed into the // definition. This is because the append relies on this flag // being accurate. ivl_assert(*this, members_.empty()); + ivl_assert(*this, flag || !soft); union_ = flag; + soft_union_ = soft; } void netstruct_t::packed(bool flag) @@ -64,7 +61,7 @@ void netstruct_t::append_member(Design*des, const netstruct_t::member_t&val) des->errors += 1; } } - if (union_ && packed_ && members_.size() > 1) { + if (union_ && packed_ && !soft_union_ && members_.size() > 1) { unsigned long expect_wid = members_.front().net_type->packed_width(); unsigned long got_wid = members_.back().net_type->packed_width(); if (expect_wid != got_wid) { @@ -104,9 +101,20 @@ long netstruct_t::packed_width(void) const // If this is a packed union, then all the members are the // same width, so it is sufficient to return the width of any // single member. - if (union_) + if (union_ && !soft_union_) return members_.front().net_type->packed_width(); + // A soft packed union uses the largest member width. + if (union_ && soft_union_) { + long res = 0; + for (size_t idx = 0 ; idx < members_.size() ; idx += 1) { + long wid = members_[idx].net_type->packed_width(); + if (wid > res) + res = wid; + } + return res; + } + // The width of a packed struct is the sum of member widths. long res = 0; for (size_t idx = 0 ; idx < members_.size() ; idx += 1) diff --git a/netstruct.h b/netstruct.h index 47fe09e30..a0e66fea9 100644 --- a/netstruct.h +++ b/netstruct.h @@ -1,7 +1,7 @@ #ifndef IVL_netstruct_H #define IVL_netstruct_H /* - * Copyright (c) 2011-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2026 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 @@ -39,14 +39,15 @@ class netstruct_t : public LineInfo, public ivl_type_s { }; public: - netstruct_t(); + netstruct_t() = default; ~netstruct_t() override; // If this is a union (instead of struct) then this flag is // set. We handle union and struct together because they are // so similar. - void union_flag(bool); + void union_flag(bool, bool soft = false); bool union_flag(void) const; + bool soft_union(void) const; void packed(bool flag); bool packed(void) const override; @@ -81,13 +82,15 @@ class netstruct_t : public LineInfo, public ivl_type_s { bool test_equivalence(ivl_type_t that) const override; private: - bool union_; - bool packed_; - bool signed_; + bool union_ = false; + bool soft_union_ = false; + bool packed_ = false; + bool signed_ = false; std::vectormembers_; }; inline bool netstruct_t::union_flag(void) const { return union_; } +inline bool netstruct_t::soft_union(void) const { return soft_union_; } inline bool netstruct_t::packed(void) const { return packed_; } #endif /* IVL_netstruct_H */ diff --git a/parse.y b/parse.y index 45dcadb37..69187377d 100644 --- a/parse.y +++ b/parse.y @@ -706,7 +706,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type from_exclude block_item_decls_opt %type number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt -%type import_export +%type import_export union_soft_opt %type K_genvar_opt K_static_opt K_virtual_opt K_const_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 @@ -1356,7 +1356,7 @@ packed_array_data_type /* IEEE1800-2005: A.2.2.1 */ : enum_data_type { $$ = $1; } | struct_data_type - { if (!$1->packed_flag) { + { if (!$1->packed_flag && !($1->union_flag && $1->soft_flag)) { yyerror(@1, "sorry: Unpacked structs not supported."); } $$ = $1; @@ -3013,6 +3013,13 @@ packed_signing /* IEEE 1800-2012 A.2.2.1 */ } ; +union_soft_opt + : K_soft + { $$ = true; } + | + { $$ = false; } + ; + struct_data_type /* IEEE 1800-2012 A.2.2.1 */ : K_struct packed_signing '{' struct_union_member_list '}' { struct_type_t*tmp = new struct_type_t; @@ -3020,16 +3027,20 @@ struct_data_type /* IEEE 1800-2012 A.2.2.1 */ tmp->packed_flag = $2.packed_flag; tmp->signed_flag = $2.signed_flag; tmp->union_flag = false; - tmp->members .reset($4); + tmp->soft_flag = false; + tmp->members.reset($4); $$ = tmp; } - | K_union packed_signing '{' struct_union_member_list '}' - { struct_type_t*tmp = new struct_type_t; + | K_union union_soft_opt packed_signing '{' struct_union_member_list '}' + { if ($2 && generation_flag < GN_VER2023) + yyerror(@1, "error: Soft packed unions require SystemVerilog 2023 or later."); + struct_type_t*tmp = new struct_type_t; FILE_NAME(tmp, @1); - tmp->packed_flag = $2.packed_flag; - tmp->signed_flag = $2.signed_flag; + tmp->packed_flag = $3.packed_flag; + tmp->signed_flag = $3.signed_flag; tmp->union_flag = true; - tmp->members .reset($4); + tmp->soft_flag = $2; + tmp->members.reset($5); $$ = tmp; } | K_struct packed_signing '{' error '}' @@ -3040,16 +3051,20 @@ struct_data_type /* IEEE 1800-2012 A.2.2.1 */ tmp->packed_flag = $2.packed_flag; tmp->signed_flag = $2.signed_flag; tmp->union_flag = false; + tmp->soft_flag = false; $$ = tmp; } - | K_union packed_signing '{' error '}' - { yyerror(@3, "error: Errors in union member list."); + | K_union union_soft_opt packed_signing '{' error '}' + { if ($2 && generation_flag < GN_VER2023) + yyerror(@1, "error: Soft packed unions require SystemVerilog 2023 or later."); + yyerror(@4, "error: Errors in union member list."); yyerrok; struct_type_t*tmp = new struct_type_t; FILE_NAME(tmp, @1); - tmp->packed_flag = $2.packed_flag; - tmp->signed_flag = $2.signed_flag; + tmp->packed_flag = $3.packed_flag; + tmp->signed_flag = $3.signed_flag; tmp->union_flag = true; + tmp->soft_flag = $2; $$ = tmp; } ; diff --git a/pform_types.h b/pform_types.h index 452c3e583..2ed4e7469 100644 --- a/pform_types.h +++ b/pform_types.h @@ -259,6 +259,7 @@ struct struct_type_t : public data_type_t { bool packed_flag; bool union_flag; + bool soft_flag; bool signed_flag; std::unique_ptr< std::list > members; }; From f8e9384689e5e9b04401f5337343e9efc4666d90 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 08:39:20 -0700 Subject: [PATCH 078/102] Add regression tests for soft packed unions Check that soft packed unions can have members with different widths. Check that the `soft` qualifier implies `packed` and that nested soft packed unions use the same representation recursively. Also check that member bits are right-justified and that assignments to narrower members leave the MSBs beyond the member bits unchanged. Check that soft packed unions reject default member values. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_soft_packed_union.v | 81 +++++++++++++++++++ ivtest/ivltests/sv_soft_packed_union_fail1.v | 12 +++ ivtest/regress-vvp.list | 2 + ivtest/vvp_tests/sv_soft_packed_union.json | 5 ++ .../vvp_tests/sv_soft_packed_union_fail1.json | 5 ++ 5 files changed, 105 insertions(+) create mode 100644 ivtest/ivltests/sv_soft_packed_union.v create mode 100644 ivtest/ivltests/sv_soft_packed_union_fail1.v create mode 100644 ivtest/vvp_tests/sv_soft_packed_union.json create mode 100644 ivtest/vvp_tests/sv_soft_packed_union_fail1.json diff --git a/ivtest/ivltests/sv_soft_packed_union.v b/ivtest/ivltests/sv_soft_packed_union.v new file mode 100644 index 000000000..6b0e7abc3 --- /dev/null +++ b/ivtest/ivltests/sv_soft_packed_union.v @@ -0,0 +1,81 @@ +// Check that soft packed unions can have members with different widths. + +module test; + + bit failed = 1'b0; + + typedef union soft packed { + logic [31:0] w; + logic [15:0] h; + logic [7:0] b; + } data_t; + + typedef union soft { + logic [31:0] w; + logic [7:0] b; + } implicit_packed_t; + + typedef union soft packed { + logic [15:0] w; + union soft { + logic [7:0] b; + logic [3:0] n; + } part; + } nested_t; + + data_t data; + implicit_packed_t implicit_packed; + nested_t nested; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0h, got %0h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + initial begin + data.w = 32'h12345678; + `check($bits(data), 32); + `check($bits(data_t), 32); + `check(data.w, 32'h12345678); + `check(data.h, 16'h5678); + `check(data.b, 8'h78); + + data.h = 16'habcd; + `check(data.w, 32'h1234abcd); + `check(data.h, 16'habcd); + `check(data.b, 8'hcd); + + data.b = 8'hef; + `check(data.w, 32'h1234abef); + `check(data.h, 16'habef); + `check(data.b, 8'hef); + + implicit_packed.w = 32'hf0e1d2c3; + `check($bits(implicit_packed_t), 32); + `check(implicit_packed.b, 8'hc3); + + implicit_packed.b = 8'h34; + `check(implicit_packed.w, 32'hf0e1d234); + + nested.w = 16'hbeef; + `check($bits(nested_t), 16); + `check($bits(nested.part), 8); + `check(nested.part.b, 8'hef); + `check(nested.part.n, 4'hf); + + nested.part.n = 4'ha; + `check(nested.w, 16'hbeea); + `check(nested.part.b, 8'hea); + + nested.part.b = 8'h55; + `check(nested.w, 16'hbe55); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_soft_packed_union_fail1.v b/ivtest/ivltests/sv_soft_packed_union_fail1.v new file mode 100644 index 000000000..c54b12e76 --- /dev/null +++ b/ivtest/ivltests/sv_soft_packed_union_fail1.v @@ -0,0 +1,12 @@ +// Check that soft packed unions can not have default member values. + +module test; + + typedef union soft { + logic [31:0] w = 32'h1; + logic [7:0] b; + } data_t; + + data_t data; + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 412f724d4..9ffa708db 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -339,6 +339,8 @@ sv_package_lifetime vvp_tests/sv_package_lifetime.json sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json sv_parameter_type vvp_tests/sv_parameter_type.json sv_queue_assign_op vvp_tests/sv_queue_assign_op.json +sv_soft_packed_union vvp_tests/sv_soft_packed_union.json +sv_soft_packed_union_fail1 vvp_tests/sv_soft_packed_union_fail1.json sv_super_member_fail vvp_tests/sv_super_member_fail.json sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json sdf_header vvp_tests/sdf_header.json diff --git a/ivtest/vvp_tests/sv_soft_packed_union.json b/ivtest/vvp_tests/sv_soft_packed_union.json new file mode 100644 index 000000000..073a76414 --- /dev/null +++ b/ivtest/vvp_tests/sv_soft_packed_union.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_soft_packed_union.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_soft_packed_union_fail1.json b/ivtest/vvp_tests/sv_soft_packed_union_fail1.json new file mode 100644 index 000000000..bd50b1e04 --- /dev/null +++ b/ivtest/vvp_tests/sv_soft_packed_union_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_soft_packed_union_fail1.v", + "iverilog-args" : [ "-g2023" ] +} From 46c0526dab35c177c9395bc0bf3c82b31b3a84d3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 16:13:19 -0700 Subject: [PATCH 079/102] Add support for restricted type parameters SystemVerilog 2023 allows type parameters to be restricted to a specific kind of type, e.g. `parameter type struct T = T0`. This is very similar to the type restrictions that can be applied to forward typedefs. Factor the support code from the typedefs into a standalone helper and reuse it for both. Signed-off-by: Lars-Peter Clausen --- PScope.h | 4 +++- elab_type.cc | 22 +--------------------- net_design.cc | 10 ++++++++++ net_scope.cc | 1 + netlist.h | 2 ++ parse.y | 43 ++++++++++++++++++++++++++++++------------ pform.cc | 4 +++- pform.h | 3 ++- pform_types.cc | 51 ++++++++++++++++++++++++++++++++++++++------------ pform_types.h | 36 ++++++++++++++++++++++------------- 10 files changed, 115 insertions(+), 61 deletions(-) diff --git a/PScope.h b/PScope.h index 5f8a6caf4..2d7a7b9d7 100644 --- a/PScope.h +++ b/PScope.h @@ -1,7 +1,7 @@ #ifndef IVL_PScope_H #define IVL_PScope_H /* - * Copyright (c) 2008-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2026 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 @@ -121,6 +121,8 @@ class LexicalScope { bool overridable; // Whether the parameter is a type parameter bool type_flag = false; + // Type restriction for a type parameter + type_restrict_t type_restrict; // The lexical position of the declaration unsigned lexical_pos = 0; diff --git a/elab_type.cc b/elab_type.cc index d52af2d25..c905791e1 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -452,27 +452,7 @@ ivl_type_t typedef_t::elaborate_type(Design *des, NetScope *scope) if (!elab_type) return netvector_t::integer_type(); - bool type_ok = true; - switch (basic_type) { - case ENUM: - type_ok = dynamic_cast(elab_type); - break; - case STRUCT: { - const netstruct_t *struct_type = dynamic_cast(elab_type); - type_ok = struct_type && !struct_type->union_flag(); - break; - } - case UNION: { - const netstruct_t *struct_type = dynamic_cast(elab_type); - type_ok = struct_type && struct_type->union_flag(); - break; - } - case CLASS: - type_ok = dynamic_cast(elab_type); - break; - default: - break; - } + bool type_ok = basic_type.matches(elab_type); if (!type_ok) { cerr << data_type->get_fileline() << " error: " diff --git a/net_design.cc b/net_design.cc index ab1002323..0491457b9 100644 --- a/net_design.cc +++ b/net_design.cc @@ -838,6 +838,16 @@ void NetScope::evaluate_type_parameter_(Design *des, param_ref_t cur) data_type_t *ptype = type_expr->get_type(); NetScope *type_scope = cur->second.val_scope; cur->second.ivl_type = ptype->elaborate_type(des, type_scope); + if (!cur->second.ivl_type) + return; + + if (!cur->second.type_restrict.matches(cur->second.ivl_type)) { + cerr << type_expr->get_fileline() << ": error: " + << "Type parameter `" << cur->first << "` expects a `" + << cur->second.type_restrict << "` type, got `" + << *cur->second.ivl_type << "`." << endl; + des->errors++; + } } void NetScope::evaluate_parameter_(Design*des, param_ref_t cur) diff --git a/net_scope.cc b/net_scope.cc index ec9d6f912..bd019f93d 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -281,6 +281,7 @@ void NetScope::set_parameter(perm_string key, bool is_annotatable, ref.local_flag = param.local_flag; ref.overridable = param.overridable; ref.type_flag = param.type_flag; + ref.type_restrict = param.type_restrict; ref.lexical_pos = param.lexical_pos; ivl_assert(param, !ref.range); ref.range = range_list; diff --git a/netlist.h b/netlist.h index cfaeba861..a3880604b 100644 --- a/netlist.h +++ b/netlist.h @@ -1279,6 +1279,8 @@ class NetScope : public Definitions, public Attrib { bool overridable = false; // Is it a type parameter bool type_flag = false; + // Type restriction for a type parameter + type_restrict_t type_restrict; // The lexical position of the declaration unsigned lexical_pos = 0; // range constraints diff --git a/parse.y b/parse.y index 69187377d..54a7d2be4 100644 --- a/parse.y +++ b/parse.y @@ -45,6 +45,7 @@ extern void lex_end_table(); static data_type_t* param_data_type = 0; static bool param_is_local = false; static bool param_is_type = false; +static type_restrict_t param_type_restrict; static bool in_gen_region = false; static std::list* specparam_active_range = 0; @@ -598,7 +599,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, LexicalScope::lifetime_t lifetime; - enum typedef_t::basic_type typedef_basic_type; + enum type_restrict_t::type_t type_restrict; }; %token IDENTIFIER INTERFACE_IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL @@ -858,7 +859,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type compressed_operator -%type typedef_basic_type +%type forward_type forward_type_without_enum %token K_TAND %nonassoc K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ @@ -2882,11 +2883,16 @@ block_item_decls_opt * `typedef enum ` can either be the start of a enum forward * declaration or a enum type declaration with a type identifier as its base * type. And this abmiguity can not be resolved if we reduce the K_enum to - * typedef_basic_type. */ -typedef_basic_type - : K_struct { $$ = typedef_t::STRUCT; } - | K_union { $$ = typedef_t::UNION; } - | K_class { $$ = typedef_t::CLASS; } + * forward_type_without_enum. */ +forward_type_without_enum + : K_struct { $$ = type_restrict_t::STRUCT; } + | K_union { $$ = type_restrict_t::UNION; } + | K_class { $$ = type_restrict_t::CLASS; } + ; + +forward_type + : K_enum { $$ = type_restrict_t::ENUM; } + | forward_type_without_enum ; /* Type declarations are parsed here. The rule actions call pform @@ -2902,17 +2908,17 @@ type_declaration | K_typedef identifier_name ';' { perm_string name = lex_strings.make($2); - pform_forward_typedef(@2, name, typedef_t::ANY); + pform_forward_typedef(@2, name, type_restrict_t::ANY); delete[]$2; } - | K_typedef typedef_basic_type identifier_name ';' + | K_typedef forward_type_without_enum identifier_name ';' { perm_string name = lex_strings.make($3); pform_forward_typedef(@3, name, $2); delete[]$3; } | K_typedef K_enum identifier_name ';' { perm_string name = lex_strings.make($3); - pform_forward_typedef(@3, name, typedef_t::ENUM); + pform_forward_typedef(@3, name, type_restrict_t::ENUM); delete[]$3; } | K_typedef error ';' @@ -4924,7 +4930,16 @@ module_parameter_port_list_opt ; type_param - : K_type { param_is_type = true; } + : K_type + { param_is_type = true; + param_type_restrict = {}; + } + | K_type forward_type + { if (generation_flag < GN_VER2023) + yyerror(@1, "error: Restricted type parameters require SystemVerilog 2023 or later."); + param_is_type = true; + param_type_restrict = $2; + } ; module_parameter @@ -4940,6 +4955,7 @@ module_parameter_port_list { param_data_type = $1; param_is_local = false; param_is_type = false; + param_type_restrict = {}; } parameter_assign { pform_requires_sv(@3, "Omitting initial `parameter` in parameter port " @@ -4955,6 +4971,7 @@ module_parameter_port_list "data type in parameter port list"); param_data_type = $3; param_is_type = false; + param_type_restrict = {}; } } parameter_assign @@ -5598,6 +5615,7 @@ param_type : data_type_or_implicit { param_is_type = false; param_data_type = $1; + param_type_restrict = {}; } | type_param @@ -5632,7 +5650,8 @@ parameter_assign_list parameter_assign : IDENTIFIER dimensions_opt initializer_opt parameter_value_ranges_opt { pform_set_parameter(@1, lex_strings.make($1), param_is_local, - param_is_type, param_data_type, $2, $3, $4); + param_is_type, param_type_restrict, + param_data_type, $2, $3, $4); delete[]$1; } ; diff --git a/pform.cc b/pform.cc index 0ef02563f..17a6bdbac 100644 --- a/pform.cc +++ b/pform.cc @@ -841,7 +841,7 @@ static typedef_t *pform_get_typedef(const struct vlltype&loc, perm_string name) } void pform_forward_typedef(const struct vlltype&loc, perm_string name, - enum typedef_t::basic_type basic_type) + type_restrict_t basic_type) { typedef_t *td = pform_get_typedef(loc, name); @@ -2948,6 +2948,7 @@ static void pform_set_type_parameter(const struct vlltype&loc, perm_string name, void pform_set_parameter(const struct vlltype&loc, perm_string name, bool is_local, bool is_type, + type_restrict_t type_restrict, data_type_t*data_type, const list*udims, PExpr*expr, LexicalScope::range_t*value_range) { @@ -3020,6 +3021,7 @@ void pform_set_parameter(const struct vlltype&loc, parm->local_flag = is_local; parm->overridable = overridable; parm->type_flag = is_type; + parm->type_restrict = type_restrict; parm->lexical_pos = loc.lexical_pos; scope->parameters[name] = parm; diff --git a/pform.h b/pform.h index 95d60d458..781743258 100644 --- a/pform.h +++ b/pform.h @@ -323,7 +323,7 @@ extern void pform_set_typedef(const struct vlltype&loc, perm_string name, data_type_t*data_type, std::list*unp_ranges = nullptr); extern void pform_forward_typedef(const struct vlltype&loc, perm_string name, - enum typedef_t::basic_type basic_type); + type_restrict_t basic_type); extern void pform_set_type_referenced(const struct vlltype&loc, const char*name); @@ -412,6 +412,7 @@ extern LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, extern void pform_set_parameter(const struct vlltype&loc, perm_string name, bool is_local, bool is_type, + type_restrict_t type_restrict, data_type_t*data_type, const std::list*udims, PExpr*expr, LexicalScope::range_t*value_range); extern void pform_set_specparam(const struct vlltype&loc, diff --git a/pform_types.cc b/pform_types.cc index f69c5d908..f9af4f1fe 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2026 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 @@ -19,6 +19,8 @@ # include "pform_types.h" +# include "netclass.h" +# include "netenum.h" data_type_t::~data_type_t() { @@ -55,34 +57,59 @@ bool typedef_t::set_data_type(data_type_t *t) return true; } -bool typedef_t::set_basic_type(enum basic_type bt) +bool typedef_t::set_basic_type(type_restrict_t type) { - if (bt == ANY) + return basic_type.merge(type); +} + +bool type_restrict_t::merge(type_restrict_t other) +{ + if (other.type == ANY) return true; - if (basic_type != ANY && bt != basic_type) + if (this->type != ANY && other.type != this->type) return false; - basic_type = bt; + this->type = other.type; return true; } -std::ostream& operator<< (std::ostream&out, enum typedef_t::basic_type bt) +bool type_restrict_t::matches(ivl_type_t ivl_type) const { - switch (bt) { - case typedef_t::ANY: + switch (this->type) { + case ENUM: + return dynamic_cast(ivl_type); + case STRUCT: { + const netstruct_t *struct_type = dynamic_cast(ivl_type); + return struct_type && !struct_type->union_flag(); + } + case UNION: { + const netstruct_t *struct_type = dynamic_cast(ivl_type); + return struct_type && struct_type->union_flag(); + } + case CLASS: + return dynamic_cast(ivl_type); + default: + return true; + } +} + +std::ostream& operator<< (std::ostream&out, const type_restrict_t& type) +{ + switch (type.type) { + case type_restrict_t::ANY: out << "any"; break; - case typedef_t::ENUM: + case type_restrict_t::ENUM: out << "enum"; break; - case typedef_t::STRUCT: + case type_restrict_t::STRUCT: out << "struct"; break; - case typedef_t::UNION: + case type_restrict_t::UNION: out << "union"; break; - case typedef_t::CLASS: + case type_restrict_t::CLASS: out << "class"; break; } diff --git a/pform_types.h b/pform_types.h index 2ed4e7469..29fedb693 100644 --- a/pform_types.h +++ b/pform_types.h @@ -49,6 +49,24 @@ class netclass_t; class netenum_t; typedef named named_pexpr_t; +struct type_restrict_t { + enum type_t { + ANY, + ENUM, + STRUCT, + UNION, + CLASS + }; + + type_restrict_t() = default; + type_restrict_t(type_t kind) : type(kind) { } + + bool merge(type_restrict_t other); + bool matches(ivl_type_t type) const; + + enum type_t type = ANY; +}; + /* * The pform_ident_t holds the identifier name and its lexical position * (the lexical_pos supplied by the scanner). @@ -180,26 +198,18 @@ class data_type_t : public PNamedItem { }; struct typedef_t : public PNamedItem { - explicit typedef_t(perm_string n) : basic_type(ANY), name(n) { }; + explicit typedef_t(perm_string n) : name(n) { }; ivl_type_t elaborate_type(Design*des, NetScope*scope); - enum basic_type { - ANY, - ENUM, - STRUCT, - UNION, - CLASS - }; - bool set_data_type(data_type_t *t); const data_type_t *get_data_type() const { return data_type.get(); } - bool set_basic_type(basic_type bt); - enum basic_type get_basic_type() const { return basic_type; } + bool set_basic_type(type_restrict_t type); + type_restrict_t get_basic_type() const { return basic_type; } protected: - enum basic_type basic_type; + type_restrict_t basic_type; std::unique_ptr data_type; public: perm_string name; @@ -498,6 +508,6 @@ extern std::ostream& operator<< (std::ostream&out, const pform_name_t&); extern std::ostream& operator<< (std::ostream&out, const pform_scoped_name_t&); extern std::ostream& operator<< (std::ostream&out, const name_component_t&that); extern std::ostream& operator<< (std::ostream&out, const index_component_t&that); -extern std::ostream& operator<< (std::ostream&out, enum typedef_t::basic_type bt); +extern std::ostream& operator<< (std::ostream&out, const type_restrict_t& type); #endif /* IVL_pform_types_H */ From 08479888b1880093e2fe050afa514755c4d0fe7a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 16:13:44 -0700 Subject: [PATCH 080/102] Add regression tests for restricted type parameters Check that enum, struct, union and class restricted type parameters are accepted. Check that mismatched default values and overrides are rejected. Signed-off-by: Lars-Peter Clausen --- .../ivltests/sv_type_param_restrict_class1.v | 35 ++++++++++++++++ .../ivltests/sv_type_param_restrict_class2.v | 41 +++++++++++++++++++ .../sv_type_param_restrict_class_fail1.v | 11 +++++ .../sv_type_param_restrict_class_fail2.v | 21 ++++++++++ .../ivltests/sv_type_param_restrict_enum1.v | 33 +++++++++++++++ .../ivltests/sv_type_param_restrict_enum2.v | 39 ++++++++++++++++++ .../sv_type_param_restrict_enum_fail1.v | 11 +++++ .../sv_type_param_restrict_enum_fail2.v | 22 ++++++++++ .../ivltests/sv_type_param_restrict_struct1.v | 33 +++++++++++++++ .../ivltests/sv_type_param_restrict_struct2.v | 39 ++++++++++++++++++ .../sv_type_param_restrict_struct_fail1.v | 16 ++++++++ .../sv_type_param_restrict_struct_fail2.v | 27 ++++++++++++ .../ivltests/sv_type_param_restrict_union1.v | 34 +++++++++++++++ .../ivltests/sv_type_param_restrict_union2.v | 41 +++++++++++++++++++ .../sv_type_param_restrict_union_fail1.v | 15 +++++++ .../sv_type_param_restrict_union_fail2.v | 27 ++++++++++++ ivtest/regress-vvp.list | 16 ++++++++ .../sv_type_param_restrict_class1.json | 9 ++++ .../sv_type_param_restrict_class2.json | 9 ++++ .../sv_type_param_restrict_class_fail1.json | 5 +++ .../sv_type_param_restrict_class_fail2.json | 5 +++ .../sv_type_param_restrict_enum1.json | 5 +++ .../sv_type_param_restrict_enum2.json | 5 +++ .../sv_type_param_restrict_enum_fail1.json | 5 +++ .../sv_type_param_restrict_enum_fail2.json | 5 +++ .../sv_type_param_restrict_struct1.json | 5 +++ .../sv_type_param_restrict_struct2.json | 5 +++ .../sv_type_param_restrict_struct_fail1.json | 5 +++ .../sv_type_param_restrict_struct_fail2.json | 5 +++ .../sv_type_param_restrict_union1.json | 5 +++ .../sv_type_param_restrict_union2.json | 5 +++ .../sv_type_param_restrict_union_fail1.json | 5 +++ .../sv_type_param_restrict_union_fail2.json | 5 +++ 33 files changed, 549 insertions(+) create mode 100644 ivtest/ivltests/sv_type_param_restrict_class1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_class2.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_class_fail1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_class_fail2.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_enum1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_enum2.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_enum_fail1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_enum_fail2.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_struct1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_struct2.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_struct_fail1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_struct_fail2.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_union1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_union2.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_union_fail1.v create mode 100644 ivtest/ivltests/sv_type_param_restrict_union_fail2.v create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_class1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_class2.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_class_fail1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_class_fail2.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_enum1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_enum2.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_enum_fail1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_enum_fail2.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_struct1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_struct2.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_struct_fail1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_struct_fail2.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_union1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_union2.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_union_fail1.json create mode 100644 ivtest/vvp_tests/sv_type_param_restrict_union_fail2.json diff --git a/ivtest/ivltests/sv_type_param_restrict_class1.v b/ivtest/ivltests/sv_type_param_restrict_class1.v new file mode 100644 index 000000000..9488edcc6 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_class1.v @@ -0,0 +1,35 @@ +// Check that restricted class type parameter defaults are supported. + +class C0; + bit [7:0] value; +endclass + +module M #( + parameter type class T = C0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M i_m(); + + initial begin + i_m.x = new; + + `check($bits(i_m.x.value), 8) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_class2.v b/ivtest/ivltests/sv_type_param_restrict_class2.v new file mode 100644 index 000000000..adcc6a626 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_class2.v @@ -0,0 +1,41 @@ +// Check that restricted class type parameter overrides are supported. + +class C0; + bit [7:0] value; +endclass + +class C1; + bit [15:0] value; +endclass + +module M #( + parameter type class T = C0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M #( + .T(C1) + ) i_m(); + + initial begin + i_m.x = new; + + `check($bits(i_m.x.value), 16) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_class_fail1.v b/ivtest/ivltests/sv_type_param_restrict_class_fail1.v new file mode 100644 index 000000000..d769159a9 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_class_fail1.v @@ -0,0 +1,11 @@ +// Check that a class restricted type parameter rejects non-class defaults. + +module test #( + parameter type class T = int +); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_class_fail2.v b/ivtest/ivltests/sv_type_param_restrict_class_fail2.v new file mode 100644 index 000000000..0c6781015 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_class_fail2.v @@ -0,0 +1,21 @@ +// Check that a class restricted type parameter rejects non-class overrides. + +class class_t; +endclass + +module M #( + parameter type class T = class_t +); +endmodule + +module test; + + M #( + .T(int) + ) i_m(); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_enum1.v b/ivtest/ivltests/sv_type_param_restrict_enum1.v new file mode 100644 index 000000000..60d920724 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_enum1.v @@ -0,0 +1,33 @@ +// Check that restricted enum type parameter defaults are supported. + +typedef enum bit [2:0] { + A0, B0 +} T0; + +module M #( + parameter type enum T = T0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M i_m(); + + initial begin + `check($bits(i_m.x), $bits(T0)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_enum2.v b/ivtest/ivltests/sv_type_param_restrict_enum2.v new file mode 100644 index 000000000..028e8eec6 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_enum2.v @@ -0,0 +1,39 @@ +// Check that restricted enum type parameter overrides are supported. + +typedef enum bit [2:0] { + A0, B0 +} T0; + +typedef enum bit [3:0] { + A1, B1 +} T1; + +module M #( + parameter type enum T = T0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M #( + .T(T1) + ) i_m(); + + initial begin + `check($bits(i_m.x), $bits(T1)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_enum_fail1.v b/ivtest/ivltests/sv_type_param_restrict_enum_fail1.v new file mode 100644 index 000000000..a36c1e8c7 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_enum_fail1.v @@ -0,0 +1,11 @@ +// Check that an enum restricted type parameter rejects non-enum defaults. + +module test #( + parameter type enum T = int +); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_enum_fail2.v b/ivtest/ivltests/sv_type_param_restrict_enum_fail2.v new file mode 100644 index 000000000..1e1f564ae --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_enum_fail2.v @@ -0,0 +1,22 @@ +// Check that an enum restricted type parameter rejects non-enum overrides. + +typedef enum bit { + ENUM_VALUE +} enum_t; + +module M #( + parameter type enum T = enum_t +); +endmodule + +module test; + + M #( + .T(int) + ) i_m(); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_struct1.v b/ivtest/ivltests/sv_type_param_restrict_struct1.v new file mode 100644 index 000000000..a127b117e --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_struct1.v @@ -0,0 +1,33 @@ +// Check that restricted struct type parameter defaults are supported. + +typedef struct packed { + logic [3:0] x; +} T0; + +module M #( + parameter type struct T = T0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M i_m(); + + initial begin + `check($bits(i_m.x), $bits(T0)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_struct2.v b/ivtest/ivltests/sv_type_param_restrict_struct2.v new file mode 100644 index 000000000..c3b30f58b --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_struct2.v @@ -0,0 +1,39 @@ +// Check that restricted struct type parameter overrides are supported. + +typedef struct packed { + logic [3:0] x; +} T0; + +typedef struct packed { + logic [7:0] x; +} T1; + +module M #( + parameter type struct T = T0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M #( + .T(T1) + ) i_m(); + + initial begin + `check($bits(i_m.x), $bits(T1)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_struct_fail1.v b/ivtest/ivltests/sv_type_param_restrict_struct_fail1.v new file mode 100644 index 000000000..ff707bdf7 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_struct_fail1.v @@ -0,0 +1,16 @@ +// Check that a struct restricted type parameter rejects non-struct defaults. + +typedef union packed { + logic [3:0] value; + logic [3:0] other; +} union_t; + +module test #( + parameter type struct T = union_t +); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_struct_fail2.v b/ivtest/ivltests/sv_type_param_restrict_struct_fail2.v new file mode 100644 index 000000000..bd78897a7 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_struct_fail2.v @@ -0,0 +1,27 @@ +// Check that a struct restricted type parameter rejects non-struct overrides. + +typedef struct packed { + logic [3:0] value; +} struct_t; + +typedef union packed { + logic [3:0] value; + logic [3:0] other; +} union_t; + +module M #( + parameter type struct T = struct_t +); +endmodule + +module test; + + M #( + .T(union_t) + ) i_m(); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_union1.v b/ivtest/ivltests/sv_type_param_restrict_union1.v new file mode 100644 index 000000000..df337c21e --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_union1.v @@ -0,0 +1,34 @@ +// Check that restricted union type parameter defaults are supported. + +typedef union packed { + logic [3:0] x; + logic [3:0] y; +} T0; + +module M #( + parameter type union T = T0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M i_m(); + + initial begin + `check($bits(i_m.x), $bits(T0)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_union2.v b/ivtest/ivltests/sv_type_param_restrict_union2.v new file mode 100644 index 000000000..588a245b2 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_union2.v @@ -0,0 +1,41 @@ +// Check that restricted union type parameter overrides are supported. + +typedef union packed { + logic [3:0] x; + logic [3:0] y; +} T0; + +typedef union packed { + logic [7:0] x; + logic [7:0] y; +} T1; + +module M #( + parameter type union T = T0 +); + T x; +endmodule + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + M #( + .T(T1) + ) i_m(); + + initial begin + `check($bits(i_m.x), $bits(T1)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_union_fail1.v b/ivtest/ivltests/sv_type_param_restrict_union_fail1.v new file mode 100644 index 000000000..1d581e36c --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_union_fail1.v @@ -0,0 +1,15 @@ +// Check that a union restricted type parameter rejects non-union defaults. + +typedef struct packed { + logic [3:0] value; +} struct_t; + +module test #( + parameter type union T = struct_t +); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_param_restrict_union_fail2.v b/ivtest/ivltests/sv_type_param_restrict_union_fail2.v new file mode 100644 index 000000000..b49552c17 --- /dev/null +++ b/ivtest/ivltests/sv_type_param_restrict_union_fail2.v @@ -0,0 +1,27 @@ +// Check that a union restricted type parameter rejects non-union overrides. + +typedef struct packed { + logic [3:0] value; +} struct_t; + +typedef union packed { + logic [3:0] value; + logic [3:0] other; +} union_t; + +module M #( + parameter type union T = union_t +); +endmodule + +module test; + + M #( + .T(struct_t) + ) i_m(); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 9ffa708db..7831ff27f 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -342,6 +342,22 @@ sv_queue_assign_op vvp_tests/sv_queue_assign_op.json sv_soft_packed_union vvp_tests/sv_soft_packed_union.json sv_soft_packed_union_fail1 vvp_tests/sv_soft_packed_union_fail1.json sv_super_member_fail vvp_tests/sv_super_member_fail.json +sv_type_param_restrict_class1 vvp_tests/sv_type_param_restrict_class1.json +sv_type_param_restrict_class2 vvp_tests/sv_type_param_restrict_class2.json +sv_type_param_restrict_class_fail1 vvp_tests/sv_type_param_restrict_class_fail1.json +sv_type_param_restrict_class_fail2 vvp_tests/sv_type_param_restrict_class_fail2.json +sv_type_param_restrict_enum1 vvp_tests/sv_type_param_restrict_enum1.json +sv_type_param_restrict_enum2 vvp_tests/sv_type_param_restrict_enum2.json +sv_type_param_restrict_enum_fail1 vvp_tests/sv_type_param_restrict_enum_fail1.json +sv_type_param_restrict_enum_fail2 vvp_tests/sv_type_param_restrict_enum_fail2.json +sv_type_param_restrict_struct1 vvp_tests/sv_type_param_restrict_struct1.json +sv_type_param_restrict_struct2 vvp_tests/sv_type_param_restrict_struct2.json +sv_type_param_restrict_struct_fail1 vvp_tests/sv_type_param_restrict_struct_fail1.json +sv_type_param_restrict_struct_fail2 vvp_tests/sv_type_param_restrict_struct_fail2.json +sv_type_param_restrict_union1 vvp_tests/sv_type_param_restrict_union1.json +sv_type_param_restrict_union2 vvp_tests/sv_type_param_restrict_union2.json +sv_type_param_restrict_union_fail1 vvp_tests/sv_type_param_restrict_union_fail1.json +sv_type_param_restrict_union_fail2 vvp_tests/sv_type_param_restrict_union_fail2.json sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json sdf_header vvp_tests/sdf_header.json task_return1 vvp_tests/task_return1.json diff --git a/ivtest/vvp_tests/sv_type_param_restrict_class1.json b/ivtest/vvp_tests/sv_type_param_restrict_class1.json new file mode 100644 index 000000000..333ccba29 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_class1.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_class1.v", + "iverilog-args" : [ "-g2023" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_class2.json b/ivtest/vvp_tests/sv_type_param_restrict_class2.json new file mode 100644 index 000000000..f9e01d0f3 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_class2.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_class2.v", + "iverilog-args" : [ "-g2023" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_class_fail1.json b/ivtest/vvp_tests/sv_type_param_restrict_class_fail1.json new file mode 100644 index 000000000..37ad86428 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_class_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_class_fail1.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_class_fail2.json b/ivtest/vvp_tests/sv_type_param_restrict_class_fail2.json new file mode 100644 index 000000000..3777c906f --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_class_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_class_fail2.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_enum1.json b/ivtest/vvp_tests/sv_type_param_restrict_enum1.json new file mode 100644 index 000000000..f06dd96db --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_enum1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_enum1.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_enum2.json b/ivtest/vvp_tests/sv_type_param_restrict_enum2.json new file mode 100644 index 000000000..cefdc3f87 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_enum2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_enum2.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_enum_fail1.json b/ivtest/vvp_tests/sv_type_param_restrict_enum_fail1.json new file mode 100644 index 000000000..1f65e7c27 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_enum_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_enum_fail1.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_enum_fail2.json b/ivtest/vvp_tests/sv_type_param_restrict_enum_fail2.json new file mode 100644 index 000000000..419f415d5 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_enum_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_enum_fail2.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_struct1.json b/ivtest/vvp_tests/sv_type_param_restrict_struct1.json new file mode 100644 index 000000000..fc0aa3d09 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_struct1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_struct1.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_struct2.json b/ivtest/vvp_tests/sv_type_param_restrict_struct2.json new file mode 100644 index 000000000..adb31537f --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_struct2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_struct2.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_struct_fail1.json b/ivtest/vvp_tests/sv_type_param_restrict_struct_fail1.json new file mode 100644 index 000000000..f8cd7c732 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_struct_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_struct_fail1.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_struct_fail2.json b/ivtest/vvp_tests/sv_type_param_restrict_struct_fail2.json new file mode 100644 index 000000000..4bc7cae76 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_struct_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_struct_fail2.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_union1.json b/ivtest/vvp_tests/sv_type_param_restrict_union1.json new file mode 100644 index 000000000..642b76ba5 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_union1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_union1.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_union2.json b/ivtest/vvp_tests/sv_type_param_restrict_union2.json new file mode 100644 index 000000000..b804064d0 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_union2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_param_restrict_union2.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_union_fail1.json b/ivtest/vvp_tests/sv_type_param_restrict_union_fail1.json new file mode 100644 index 000000000..bb2ea1054 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_union_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_union_fail1.v", + "iverilog-args" : [ "-g2023" ] +} diff --git a/ivtest/vvp_tests/sv_type_param_restrict_union_fail2.json b/ivtest/vvp_tests/sv_type_param_restrict_union_fail2.json new file mode 100644 index 000000000..49cc68e0b --- /dev/null +++ b/ivtest/vvp_tests/sv_type_param_restrict_union_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_type_param_restrict_union_fail2.v", + "iverilog-args" : [ "-g2023" ] +} From dea82c5a91a9d2092b10cc3c30f2c03e1a003f41 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 19:53:27 -0700 Subject: [PATCH 081/102] Handle single element static unpacked array assignments Currently single element static unpacked arrays are not always treated as unpacked arrays when elaborating assignment l-values. The net only has one pin, so checks using `pin_count() > 1` treat the array as a scalar value and skip the unpacked array path. Use `unpacked_dimensions() > 0` instead of `pin_count() > 1` when checking whether a signal is an unpacked array. This lets single element arrays follow the same l-value elaboration paths as other unpacked arrays. Signed-off-by: Lars-Peter Clausen --- elab_net.cc | 14 ++++++++------ elaborate.cc | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index 6e69f398e..9db05d56d 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -625,6 +625,9 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, // array word assignment. bool widx_flag = false; + // Whether the signal is an array + const bool sig_is_array = sig->unpacked_dimensions() > 0; + // Detect the net is a structure and there was a method path // detected. We have already broken the path_ into the path to // the net, and the path of member names. For example, if the @@ -760,7 +763,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, } } - } else if (gn_system_verilog() && sig->unpacked_dimensions() > 0 && path_tail.index.empty()) { + } else if (gn_system_verilog() && sig_is_array && path_tail.index.empty()) { // In this case, we are doing a continuous assignment to // an unpacked array. The NetNet representation is a @@ -770,15 +773,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, // This can come up from code like this: // logic [...] data [0:3]; // assign data = ...; - // In this case, "sig" is "data", and sig->pin_count() - // is 4 to account for the unpacked size. + // In this case, "sig" is "data". if (debug_elaborate) { cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " << "Net assign to unpacked array \"" << sig->name() << "\" with " << sig->pin_count() << " elements." << endl; } - } else if (sig->unpacked_dimensions() > 0) { + } else if (sig_is_array) { list unpacked_indices_const; @@ -940,7 +942,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, } } - if (sig->pin_count() > 1 && widx_flag) { + if (sig_is_array && widx_flag) { if (widx < 0 || widx >= (long) sig->pin_count()) return 0; NetNet*tmp = new NetNet(scope, scope->local_symbol(), @@ -950,7 +952,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, connect(sig->pin(widx), tmp->pin(0)); sig = tmp; - } else if (sig->pin_count() > 1) { + } else if (sig_is_array) { // If this turns out to be an l-value unpacked array, // then let the caller handle it. It will probably be diff --git a/elaborate.cc b/elaborate.cc index 3eee2f890..c78723000 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -135,7 +135,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const // If this turns out to be an assignment to an unpacked array, // then handle that special case elsewhere. - if (lval->pin_count() > 1) { + if (lval->unpacked_dimensions() > 0) { elaborate_unpacked_array_(des, scope, lval); return; } From 74491cfe9f11578c8c513d62bfd96f0bd9efaba3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 16 May 2026 19:53:36 -0700 Subject: [PATCH 082/102] Add regression tests for single element unpacked array assignments Check that continuous assignment of an assignment pattern to a single element unpacked array is accepted. Check that assigning a scalar expression to the whole unpacked array is rejected for both procedural and continuous assignments. Check that a selected element of a single element static unpacked array can be used in a continuous l-value concatenation. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_ap_uarray_single1.v | 27 +++++++++++++++++ ivtest/ivltests/sv_ap_uarray_single2.v | 28 +++++++++++++++++ .../ivltests/sv_array_assign_single_fail1.v | 13 ++++++++ ivtest/ivltests/sv_array_cassign_single.v | 30 +++++++++++++++++++ .../ivltests/sv_array_cassign_single_fail1.v | 10 +++++++ ivtest/ivltests/sv_lval_concat_uarray1.v | 29 ++++++++++++++++++ ivtest/ivltests/sv_lval_concat_uarray2.v | 30 +++++++++++++++++++ ivtest/regress-vvp.list | 7 +++++ ivtest/vvp_tests/sv_ap_uarray_single1.json | 9 ++++++ ivtest/vvp_tests/sv_ap_uarray_single2.json | 9 ++++++ .../sv_array_assign_single_fail1.json | 5 ++++ ivtest/vvp_tests/sv_array_cassign_single.json | 9 ++++++ .../sv_array_cassign_single_fail1.json | 5 ++++ ivtest/vvp_tests/sv_lval_concat_uarray1.json | 4 +++ ivtest/vvp_tests/sv_lval_concat_uarray2.json | 8 +++++ 15 files changed, 223 insertions(+) create mode 100644 ivtest/ivltests/sv_ap_uarray_single1.v create mode 100644 ivtest/ivltests/sv_ap_uarray_single2.v create mode 100644 ivtest/ivltests/sv_array_assign_single_fail1.v create mode 100644 ivtest/ivltests/sv_array_cassign_single.v create mode 100644 ivtest/ivltests/sv_array_cassign_single_fail1.v create mode 100644 ivtest/ivltests/sv_lval_concat_uarray1.v create mode 100644 ivtest/ivltests/sv_lval_concat_uarray2.v create mode 100644 ivtest/vvp_tests/sv_ap_uarray_single1.json create mode 100644 ivtest/vvp_tests/sv_ap_uarray_single2.json create mode 100644 ivtest/vvp_tests/sv_array_assign_single_fail1.json create mode 100644 ivtest/vvp_tests/sv_array_cassign_single.json create mode 100644 ivtest/vvp_tests/sv_array_cassign_single_fail1.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_uarray1.json create mode 100644 ivtest/vvp_tests/sv_lval_concat_uarray2.json diff --git a/ivtest/ivltests/sv_ap_uarray_single1.v b/ivtest/ivltests/sv_ap_uarray_single1.v new file mode 100644 index 000000000..437345724 --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray_single1.v @@ -0,0 +1,27 @@ +// Check that procedural assignment of unpacked array assignment patterns to +// single element arrays is supported. + +module test; + + reg failed; + integer a[0:0]; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + a = '{42}; + + `check(a[0], 42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_ap_uarray_single2.v b/ivtest/ivltests/sv_ap_uarray_single2.v new file mode 100644 index 000000000..42a722f01 --- /dev/null +++ b/ivtest/ivltests/sv_ap_uarray_single2.v @@ -0,0 +1,28 @@ +// Check that continuous assignment of unpacked array assignment patterns to +// single element arrays is supported. + +module test; + + reg failed; + integer a[0:0]; + + assign a = '{42}; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + #1; + `check(a[0], 42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_array_assign_single_fail1.v b/ivtest/ivltests/sv_array_assign_single_fail1.v new file mode 100644 index 000000000..e4f297663 --- /dev/null +++ b/ivtest/ivltests/sv_array_assign_single_fail1.v @@ -0,0 +1,13 @@ +// Check that scalar expressions can not be procedurally assigned to single +// element unpacked arrays. + +module test; + + integer a[0:0]; + + initial begin + a = 1; + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_array_cassign_single.v b/ivtest/ivltests/sv_array_cassign_single.v new file mode 100644 index 000000000..1a54abf1a --- /dev/null +++ b/ivtest/ivltests/sv_array_cassign_single.v @@ -0,0 +1,30 @@ +// Check that continuous array assignment to single element unpacked arrays is +// supported. + +module test; + + reg failed; + wire [31:0] a[0:0]; + reg [31:0] b[0:0]; + + assign a = b; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + b[0] = 32'd42; + #1; + `check(a[0], 32'd42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_array_cassign_single_fail1.v b/ivtest/ivltests/sv_array_cassign_single_fail1.v new file mode 100644 index 000000000..2ce3f7fda --- /dev/null +++ b/ivtest/ivltests/sv_array_cassign_single_fail1.v @@ -0,0 +1,10 @@ +// Check that scalar expressions can not be continuously assigned to single +// element unpacked arrays. + +module test; + + wire [31:0] a[0:0]; + + assign a = 1; + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_uarray1.v b/ivtest/ivltests/sv_lval_concat_uarray1.v new file mode 100644 index 000000000..1d88e907b --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_uarray1.v @@ -0,0 +1,29 @@ +// Check that single element static unpacked array elements can be used in +// procedural l-value concatenations. + +module test; + + reg failed; + reg [7:0] a[0:0]; + reg [7:0] y; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + y = 8'h78; + {a[0]} = y; + + `check(a[0], 8'h78); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_concat_uarray2.v b/ivtest/ivltests/sv_lval_concat_uarray2.v new file mode 100644 index 000000000..cfa60262c --- /dev/null +++ b/ivtest/ivltests/sv_lval_concat_uarray2.v @@ -0,0 +1,30 @@ +// Check that single element static unpacked array elements can be used in +// continuous l-value concatenations. + +module test; + + reg failed; + wire [7:0] a[0:0]; + reg [7:0] y; + + assign {a[0]} = y; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + y = 8'h78; + #1; + `check(a[0], 8'h78); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 7831ff27f..33ab7bda9 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -233,12 +233,17 @@ sv_ap_uarray5 vvp_tests/sv_ap_uarray5.json sv_ap_uarray6 vvp_tests/sv_ap_uarray6.json sv_ap_uarray_fail1 vvp_tests/sv_ap_uarray_fail1.json sv_ap_uarray_fail2 vvp_tests/sv_ap_uarray_fail2.json +sv_ap_uarray_single1 vvp_tests/sv_ap_uarray_single1.json +sv_ap_uarray_single2 vvp_tests/sv_ap_uarray_single2.json sv_argumentless_func vvp_tests/sv_argumentless_func.json sv_array_assign_fail1 vvp_tests/sv_array_assign_fail1.json sv_array_assign_fail2 vvp_tests/sv_array_assign_fail2.json +sv_array_assign_single_fail1 vvp_tests/sv_array_assign_single_fail1.json sv_array_cassign6 vvp_tests/sv_array_cassign6.json sv_array_cassign7 vvp_tests/sv_array_cassign7.json sv_array_cassign8 vvp_tests/sv_array_cassign8.json +sv_array_cassign_single vvp_tests/sv_array_cassign_single.json +sv_array_cassign_single_fail1 vvp_tests/sv_array_cassign_single_fail1.json sv_automatic_2state vvp_tests/sv_automatic_2state.json sv_byte_array_string1 vvp_tests/sv_byte_array_string1.json sv_byte_array_string2 vvp_tests/sv_byte_array_string2.json @@ -321,6 +326,8 @@ sv_lval_concat_string_fail1 vvp_tests/sv_lval_concat_string_fail1.json sv_lval_concat_string_fail2 vvp_tests/sv_lval_concat_string_fail2.json sv_lval_concat_string_fail3 vvp_tests/sv_lval_concat_string_fail3.json sv_lval_concat_string_fail4 vvp_tests/sv_lval_concat_string_fail4.json +sv_lval_concat_uarray1 vvp_tests/sv_lval_concat_uarray1.json +sv_lval_concat_uarray2 vvp_tests/sv_lval_concat_uarray2.json sv_lval_concat_uarray_fail1 vvp_tests/sv_lval_concat_uarray_fail1.json sv_lval_concat_uarray_fail2 vvp_tests/sv_lval_concat_uarray_fail2.json sv_lval_concat_uarray_fail3 vvp_tests/sv_lval_concat_uarray_fail3.json diff --git a/ivtest/vvp_tests/sv_ap_uarray_single1.json b/ivtest/vvp_tests/sv_ap_uarray_single1.json new file mode 100644 index 000000000..792665cb9 --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray_single1.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray_single1.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_ap_uarray_single2.json b/ivtest/vvp_tests/sv_ap_uarray_single2.json new file mode 100644 index 000000000..e372d0a0b --- /dev/null +++ b/ivtest/vvp_tests/sv_ap_uarray_single2.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_ap_uarray_single2.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_array_assign_single_fail1.json b/ivtest/vvp_tests/sv_array_assign_single_fail1.json new file mode 100644 index 000000000..54c147114 --- /dev/null +++ b/ivtest/vvp_tests/sv_array_assign_single_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_array_assign_single_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_array_cassign_single.json b/ivtest/vvp_tests/sv_array_cassign_single.json new file mode 100644 index 000000000..23848684d --- /dev/null +++ b/ivtest/vvp_tests/sv_array_cassign_single.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_array_cassign_single.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_array_cassign_single_fail1.json b/ivtest/vvp_tests/sv_array_cassign_single_fail1.json new file mode 100644 index 000000000..03252cf4e --- /dev/null +++ b/ivtest/vvp_tests/sv_array_cassign_single_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_array_cassign_single_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_lval_concat_uarray1.json b/ivtest/vvp_tests/sv_lval_concat_uarray1.json new file mode 100644 index 000000000..96d4aced9 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_uarray1.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "sv_lval_concat_uarray1.v" +} diff --git a/ivtest/vvp_tests/sv_lval_concat_uarray2.json b/ivtest/vvp_tests/sv_lval_concat_uarray2.json new file mode 100644 index 000000000..c678866fb --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_concat_uarray2.json @@ -0,0 +1,8 @@ +{ + "type" : "normal", + "source" : "sv_lval_concat_uarray2.v", + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} From ca3a00a51a79ab9c4d7b35d0e52499e0aad01e4c Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 16 May 2026 22:56:23 -0700 Subject: [PATCH 083/102] Update some vlog95 interface configurations --- ivtest/vvp_tests/sv_interface_port_array_basic.json | 6 +++++- ivtest/vvp_tests/sv_interface_port_basic.json | 6 +++++- ivtest/vvp_tests/sv_interface_port_forwarding.json | 6 +++++- ivtest/vvp_tests/sv_interface_port_indexed_actual.json | 6 +++++- .../sv_interface_port_indexed_actual_generate.json | 6 +++++- ivtest/vvp_tests/sv_interface_port_positional.json | 6 +++++- ivtest/vvp_tests/sv_interface_port_unmodported_basic.json | 6 +++++- ivtest/vvp_tests/sv_interface_port_wildcard.json | 6 +++++- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/ivtest/vvp_tests/sv_interface_port_array_basic.json b/ivtest/vvp_tests/sv_interface_port_array_basic.json index e6cc98c0c..795be443a 100644 --- a/ivtest/vvp_tests/sv_interface_port_array_basic.json +++ b/ivtest/vvp_tests/sv_interface_port_array_basic.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_array_basic.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Interfaces are not supported", + "type" : "TE" + } } diff --git a/ivtest/vvp_tests/sv_interface_port_basic.json b/ivtest/vvp_tests/sv_interface_port_basic.json index 2c45baa13..90c5f7477 100644 --- a/ivtest/vvp_tests/sv_interface_port_basic.json +++ b/ivtest/vvp_tests/sv_interface_port_basic.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_basic.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Interfaces are not supported", + "type" : "TE" + } } diff --git a/ivtest/vvp_tests/sv_interface_port_forwarding.json b/ivtest/vvp_tests/sv_interface_port_forwarding.json index 5642f3d7e..d9b785c3f 100644 --- a/ivtest/vvp_tests/sv_interface_port_forwarding.json +++ b/ivtest/vvp_tests/sv_interface_port_forwarding.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_forwarding.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Interfaces are not supported", + "type" : "TE" + } } diff --git a/ivtest/vvp_tests/sv_interface_port_indexed_actual.json b/ivtest/vvp_tests/sv_interface_port_indexed_actual.json index 8ea7b2d4f..7b6538549 100644 --- a/ivtest/vvp_tests/sv_interface_port_indexed_actual.json +++ b/ivtest/vvp_tests/sv_interface_port_indexed_actual.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_indexed_actual.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Interfaces are not supported", + "type" : "TE" + } } diff --git a/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json b/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json index 7fb5875fa..78951ccc0 100644 --- a/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json +++ b/ivtest/vvp_tests/sv_interface_port_indexed_actual_generate.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_indexed_actual_generate.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Generate and net arrays are not supported", + "type" : "CE" + } } diff --git a/ivtest/vvp_tests/sv_interface_port_positional.json b/ivtest/vvp_tests/sv_interface_port_positional.json index bd2e7ad3a..ec9124164 100644 --- a/ivtest/vvp_tests/sv_interface_port_positional.json +++ b/ivtest/vvp_tests/sv_interface_port_positional.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_positional.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Interfaces are not supported", + "type" : "TE" + } } diff --git a/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json index 97611b589..d52a51216 100644 --- a/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json +++ b/ivtest/vvp_tests/sv_interface_port_unmodported_basic.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_unmodported_basic.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Interfaces are not supported", + "type" : "TE" + } } diff --git a/ivtest/vvp_tests/sv_interface_port_wildcard.json b/ivtest/vvp_tests/sv_interface_port_wildcard.json index 11daa24f7..d6f8863fe 100644 --- a/ivtest/vvp_tests/sv_interface_port_wildcard.json +++ b/ivtest/vvp_tests/sv_interface_port_wildcard.json @@ -1,5 +1,9 @@ { "type" : "normal", "source" : "sv_interface_port_wildcard.v", - "iverilog-args" : [ "-g2005-sv" ] + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Interfaces are not supported", + "type" : "EF" + } } From 86546b5960318c7d891a5d3747ec85386cb1611f Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 16 May 2026 23:15:56 -0700 Subject: [PATCH 084/102] Set LD_LIBRARY for BSD so make check works --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index 9a8c74c96..c3e1a5bfb 100644 --- a/configure.ac +++ b/configure.ac @@ -315,6 +315,9 @@ case "$host_os" in linux*) ENV_VVP="LD_LIBRARY_PATH=$VVP_BUILDDIR" ;; + *bsd*) + ENV_VVP="LD_LIBRARY_PATH=$VVP_BUILDDIR" + ;; darwin*) ENV_VVP="DYLD_LIBRARY_PATH=$VVP_BUILDDIR" ;; From e7934d5e66e7fe2e5959285fc8a33288b53270f0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 May 2026 11:05:02 -0700 Subject: [PATCH 085/102] pform_makewire(): Fix indentation The assignment handling block uses space-based indentation that does not match the surrounding code. Fix the indentation before changing the block. Signed-off-by: Lars-Peter Clausen --- pform.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pform.cc b/pform.cc index 17a6bdbac..21d386d73 100644 --- a/pform.cc +++ b/pform.cc @@ -2714,17 +2714,17 @@ void pform_makewire(const struct vlltype&li, while (! assign_list->empty()) { decl_assignment_t*first = assign_list->front(); assign_list->pop_front(); - if (PExpr*expr = first->expr.release()) { - if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { - pform_make_var_init(li, first->name, expr); - } else { - PEIdent*lval = new PEIdent(first->name.first, + if (PExpr*expr = first->expr.release()) { + if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { + pform_make_var_init(li, first->name, expr); + } else { + PEIdent*lval = new PEIdent(first->name.first, first->name.second); - FILE_NAME(lval, li); - PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); - FILE_NAME(ass, li); - } - } + FILE_NAME(lval, li); + PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); + FILE_NAME(ass, li); + } + } delete first; } } From 3495889112cc41d9e69ce1241b539c2983a21146 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Jan 2022 17:14:20 +0100 Subject: [PATCH 086/102] Support SystemVerilog net declaration assignments SystemVerilog allows initialized and uninitialized net declaration entries to be mixed in the same declaration, e.g. `wire x, y = 1'b1`. In Verilog, either all nets need to have an initializer or non can have one. In addition SystemVerilog also allows assignments to arrays of wires during declaration. E.g. `wire a[3:0] = b;` Currently there are two different rules for net declarations, one for each of the Verilog variants. Combine these into a single rule to support SystemVerilog mixed declarations as well as the assignment to array nets. When running in Verilog mode still reject mixed initialized and uninitialized with a check after the parsing. Signed-off-by: Lars-Peter Clausen --- parse.y | 128 +++++++++++++++++++++---------------------------------- pform.cc | 12 ++++-- pform.h | 7 --- 3 files changed, 57 insertions(+), 90 deletions(-) diff --git a/parse.y b/parse.y index 54a7d2be4..8c94dd4b5 100644 --- a/parse.y +++ b/parse.y @@ -101,6 +101,29 @@ static pform_name_t* pform_create_super(void) return res; } +static void check_net_decl_assigns(const struct vlltype&loc, + const std::list*assign_list) +{ + if (gn_system_verilog()) + return; + + bool has_initializer = false; + bool has_no_initializer = false; + + for (const auto*cur : *assign_list) { + if (cur->expr) + has_initializer = true; + else + has_no_initializer = true; + + if (has_initializer && has_no_initializer) { + pform_requires_sv(loc, "Mixing initialized and uninitialized " + "net declaration entries"); + return; + } + } +} + /* The rules sometimes push attributes into a global context where sub-rules may grab them. This makes parser rules a little easier to write in some cases. */ @@ -720,9 +743,6 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type udp_port_decl udp_port_decls %type udp_initial udp_init_opt -%type net_variable -%type net_variable_list - %type event_variable label_opt class_declaration_endlabel_opt %type block_identifier_opt %type identifier_name @@ -731,9 +751,6 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type loop_variables %type list_of_port_identifiers list_of_variable_port_identifiers -%type net_decl_assigns -%type net_decl_assign - %type port port_opt port_reference port_reference_list %type port_declaration %type list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign @@ -780,7 +797,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type assignment_pattern expression expression_opt expr_mintypmax %type expr_primary_or_typename expr_primary %type class_new dynamic_array_new -%type var_decl_initializer_opt initializer_opt +%type net_decl_initializer_opt var_decl_initializer_opt initializer_opt %type inc_or_dec_expression inside_expression lpvalue %type branch_probe_expression streaming_concatenation %type delay_value delay_value_simple @@ -788,8 +805,8 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type expression_list_with_nuls expression_list_proper %type cont_assign cont_assign_list -%type variable_decl_assignment -%type list_of_variable_decl_assignments +%type net_decl_assign variable_decl_assignment +%type net_decl_assigns list_of_variable_decl_assignments %type data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void %type data_type_or_implicit_no_opt @@ -4983,70 +5000,30 @@ module_item /* Modules can contain further sub-module definitions. */ : module - | attribute_list_opt net_type data_type_or_implicit delay3_opt net_variable_list ';' - - { data_type_t*data_type = $3; - pform_check_net_data_type(@2, $2, $3); - if (data_type == 0) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); - } - pform_set_data_type(@2, data_type, $5, $2, $1); - if ($4 != 0) { - yyerror(@2, "sorry: Net delays not supported."); - delete $4; - } - delete $1; - } - - | attribute_list_opt K_wreal delay3 net_variable_list ';' - { real_type_t*tmpt = new real_type_t(real_type_t::REAL); - pform_set_data_type(@2, tmpt, $4, NetNet::WIRE, $1); - if ($3 != 0) { - yyerror(@3, "sorry: Net delays not supported."); - delete $3; - } - delete $1; - } - - | attribute_list_opt K_wreal net_variable_list ';' - { real_type_t*tmpt = new real_type_t(real_type_t::REAL); - pform_set_data_type(@2, tmpt, $3, NetNet::WIRE, $1); - delete $1; - } - /* Very similar to the rule above, but this takes a list of net_decl_assigns, which are = assignment declarations. */ - | attribute_list_opt net_type data_type_or_implicit delay3_opt net_decl_assigns ';' - { data_type_t*data_type = $3; - pform_check_net_data_type(@2, $2, $3); - if (data_type == 0) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); - } - pform_makewire(@2, $4, str_strength, $5, $2, data_type, $1); - delete $1; - } - - /* This form doesn't have the range, but does have strengths. This - gives strength to the assignment drivers. */ - - | attribute_list_opt net_type drive_strength data_type_or_implicit net_decl_assigns ';' + | attribute_list_opt net_type drive_strength_opt data_type_or_implicit delay3_opt net_decl_assigns ';' { data_type_t*data_type = $4; pform_check_net_data_type(@2, $2, $4); + check_net_decl_assigns(@6, $6); if (data_type == 0) { data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); FILE_NAME(data_type, @2); } - pform_makewire(@2, 0, $3, $5, $2, data_type, $1); + pform_makewire(@2, $5, $3, $6, $2, data_type, $1); delete $1; } - | attribute_list_opt K_wreal net_decl_assigns ';' + | attribute_list_opt K_wreal delay3_opt net_decl_assigns ';' { real_type_t*data_type = new real_type_t(real_type_t::REAL); - pform_makewire(@2, 0, str_strength, $3, NetNet::WIRE, data_type, $1); + check_net_decl_assigns(@4, $4); + if ($3) { + yyerror(@2, "error: wreal net does not support delay."); + delete $3; + } + pform_makewire(@2, 0, str_strength, $4, NetNet::WIRE, data_type, $1); delete $1; } @@ -5550,10 +5527,21 @@ generate_block Note that the continuous assignment statement is generated as a side effect, and all I pass up is the name of the l-value. */ +net_decl_initializer_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; + net_decl_assign - : IDENTIFIER '=' expression + : IDENTIFIER dimensions_opt net_decl_initializer_opt { decl_assignment_t*tmp = new decl_assignment_t; tmp->name = { lex_strings.make($1), @1.lexical_pos }; + if ($2) { + tmp->index = *$2; + if ($3) + pform_requires_sv(@$, "Assignment of net array during declaration"); + delete $2; + } tmp->expr.reset($3); delete[]$1; $$ = tmp; @@ -6026,26 +6014,6 @@ dimensions } ; -net_variable - : IDENTIFIER dimensions_opt - { pform_ident_t name = { lex_strings.make($1), @1.lexical_pos }; - $$ = pform_makewire(@1, name, NetNet::IMPLICIT, $2); - delete [] $1; - } - ; - -net_variable_list - : net_variable - { std::vector *tmp = new std::vector; - tmp->push_back($1); - $$ = tmp; - } - | net_variable_list ',' net_variable - { $1->push_back($3); - $$ = $1; - } - ; - event_variable : IDENTIFIER dimensions_opt { if ($2) { diff --git a/pform.cc b/pform.cc index 21d386d73..d5de24d02 100644 --- a/pform.cc +++ b/pform.cc @@ -49,6 +49,10 @@ using namespace std; +static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, + std::vector *wires, NetNet::Type net_type, + list*attr, bool is_const = false); + /* * The "// synthesis translate_on/off" meta-comments cause this flag * to be turned off or on. The pform_make_behavior and similar @@ -2724,6 +2728,8 @@ void pform_makewire(const struct vlltype&li, PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); FILE_NAME(ass, li); } + } else if (delay) { + VLerror(li, "sorry: net delays not supported."); } delete first; } @@ -3272,9 +3278,9 @@ void pform_set_port_type(const struct vlltype&li, * This function detects the derived class for the given type and * dispatches the type to the proper subtype function. */ -void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, - std::vector *wires, NetNet::Type net_type, - list*attr, bool is_const) +static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, + std::vector *wires, NetNet::Type net_type, + list*attr, bool is_const) { if (data_type == 0) { VLerror(li, "internal error: data_type==0."); diff --git a/pform.h b/pform.h index 781743258..5fb7e5035 100644 --- a/pform.h +++ b/pform.h @@ -384,13 +384,6 @@ extern void pform_set_port_type(const struct vlltype&li, data_type_t*dt, std::list*attr); -extern void pform_set_data_type(const struct vlltype&li, - data_type_t *data_type, - std::vector *wires, - NetNet::Type net_type, - std::list*attr, - bool is_const = false); - extern void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, std::list*names, NetNet::Type net_type, std::list*attr); extern void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, std::list*names, NetNet::Type net_type, std::list*addr); From 02fa1a99784c4725f16cf092c66c9dd294301d70 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Apr 2022 20:43:05 +0200 Subject: [PATCH 087/102] pform_set_data_type(): Remove `net_type` parameter `pform_set_data_type()` is now only called on wires that already have the correct wire type set. There is no need to pass the same type to `pform_set_data_type()` and set it again. Signed-off-by: Lars-Peter Clausen --- pform.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pform.cc b/pform.cc index d5de24d02..d7c476532 100644 --- a/pform.cc +++ b/pform.cc @@ -50,7 +50,7 @@ using namespace std; static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, - std::vector *wires, NetNet::Type net_type, + std::vector *wires, list*attr, bool is_const = false); /* @@ -2713,7 +2713,7 @@ void pform_makewire(const struct vlltype&li, wires->push_back(wire); } - pform_set_data_type(li, data_type, wires, type, attr, is_const); + pform_set_data_type(li, data_type, wires, attr, is_const); while (! assign_list->empty()) { decl_assignment_t*first = assign_list->front(); @@ -3279,7 +3279,7 @@ void pform_set_port_type(const struct vlltype&li, * dispatches the type to the proper subtype function. */ static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, - std::vector *wires, NetNet::Type net_type, + std::vector *wires, list*attr, bool is_const) { if (data_type == 0) { @@ -3295,11 +3295,6 @@ static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, pform_set_net_range(wire, vec_type); - // If these fail there is a bug somewhere else. pform_set_data_type() - // is only ever called on a fresh wire that already exists. - bool rc = wire->set_wire_type(net_type); - ivl_assert(li, rc); - wire->set_data_type(data_type); wire->set_const(is_const); From 28e121c040830d9bfaeb7919cc7917fd11f0d38e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 6 May 2026 23:01:47 -0700 Subject: [PATCH 088/102] Add regression tests for net declaration assignments Check that SystemVerilog net declarations can mix entries with and without initialization. Check that in SystemVerilog it is possible to do assignments within net array declarations. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_net_array_decl_assign.v | 27 +++++++++++++++ ivtest/ivltests/sv_net_decl_assign.v | 33 +++++++++++++++++++ ivtest/regress-vvp.list | 2 ++ .../vvp_tests/sv_net_array_decl_assign.json | 9 +++++ ivtest/vvp_tests/sv_net_decl_assign.json | 5 +++ 5 files changed, 76 insertions(+) create mode 100644 ivtest/ivltests/sv_net_array_decl_assign.v create mode 100644 ivtest/ivltests/sv_net_decl_assign.v create mode 100644 ivtest/vvp_tests/sv_net_array_decl_assign.json create mode 100644 ivtest/vvp_tests/sv_net_decl_assign.json diff --git a/ivtest/ivltests/sv_net_array_decl_assign.v b/ivtest/ivltests/sv_net_array_decl_assign.v new file mode 100644 index 000000000..48658d317 --- /dev/null +++ b/ivtest/ivltests/sv_net_array_decl_assign.v @@ -0,0 +1,27 @@ +// Check that net arrays can be initialized during declaration. + +module test; + + reg failed; + + wire [3:0] a[0:1] = '{4'h1, 4'h2}; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(a[0], 4'h1) + `check(a[1], 4'h2) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_net_decl_assign.v b/ivtest/ivltests/sv_net_decl_assign.v new file mode 100644 index 000000000..31ec9b22b --- /dev/null +++ b/ivtest/ivltests/sv_net_decl_assign.v @@ -0,0 +1,33 @@ +// Check that net declarations can mix initialized and uninitialized entries. + +module test; + + reg failed; + + wire [3:0] a, b = 4'h5; + wire [3:0] c = 4'ha, d; + + assign a = b; + assign d = c; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(a, 4'h5) + `check(b, 4'h5) + `check(c, 4'ha) + `check(d, 4'ha) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 33ab7bda9..36d22f512 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -342,6 +342,8 @@ sv_module_port1 vvp_tests/sv_module_port1.json sv_module_port2 vvp_tests/sv_module_port2.json sv_module_port3 vvp_tests/sv_module_port3.json sv_module_port4 vvp_tests/sv_module_port4.json +sv_net_array_decl_assign vvp_tests/sv_net_array_decl_assign.json +sv_net_decl_assign vvp_tests/sv_net_decl_assign.json sv_package_lifetime vvp_tests/sv_package_lifetime.json sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json sv_parameter_type vvp_tests/sv_parameter_type.json diff --git a/ivtest/vvp_tests/sv_net_array_decl_assign.json b/ivtest/vvp_tests/sv_net_array_decl_assign.json new file mode 100644 index 000000000..7e4cdb535 --- /dev/null +++ b/ivtest/vvp_tests/sv_net_array_decl_assign.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_net_array_decl_assign.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_net_decl_assign.json b/ivtest/vvp_tests/sv_net_decl_assign.json new file mode 100644 index 000000000..ded9a2672 --- /dev/null +++ b/ivtest/vvp_tests/sv_net_decl_assign.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_net_decl_assign.v", + "iverilog-args" : [ "-g2005-sv" ] +} From 85c58d0a7a86363a7be28421c3d5262a29a8ddd4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 May 2026 12:55:30 -0700 Subject: [PATCH 089/102] Use helper types for drive strengths and delays Drive strengths and delays are often handled as a pair of drive values and a rise/fall/decay triple. Add small helper types to carry these groups and use them in the continuous assignment and gate/UDP elaboration paths. Use the same helper types when propagating drive and delay values through netlist links. Also add helpers for dumping the values in debug output. This keeps the behavior consistent and fixes one small bug where some of the debug dumps printed the pointer value for the delays, rather than the actual delay values. Signed-off-by: Lars-Peter Clausen --- PDelays.cc | 44 ++++++++++---------- PDelays.h | 8 ++-- PGate.cc | 41 +++++-------------- PGate.h | 14 +++---- cprop.cc | 4 +- design_dump.cc | 107 ++++++++++++++++++++++--------------------------- elab_sig.cc | 4 +- elaborate.cc | 43 ++++++++------------ net_func.cc | 8 ++-- net_link.cc | 28 ++++++------- netlist.cc | 9 ++++- netlist.h | 66 +++++++++++++++++++++++------- pform.cc | 6 +-- pform_dump.cc | 6 +-- 14 files changed, 187 insertions(+), 201 deletions(-) diff --git a/PDelays.cc b/PDelays.cc index 20645434a..97e1d577b 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2026 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 @@ -130,10 +130,11 @@ static NetExpr* make_delay_nets(Design*des, NetScope*scope, NetExpr*expr) return expr; } -static NetExpr* calc_decay_time(NetExpr *rise, NetExpr *fall) +static const NetExpr *calc_decay_time(const NetExpr *rise, + const NetExpr *fall) { - const NetEConst *c_rise = dynamic_cast(rise); - const NetEConst *c_fall = dynamic_cast(fall); + const NetEConst *c_rise = dynamic_cast(rise); + const NetEConst *c_fall = dynamic_cast(fall); if (c_rise && c_fall) { if (c_rise->value() < c_fall->value()) return rise; else return fall; @@ -142,44 +143,43 @@ static NetExpr* calc_decay_time(NetExpr *rise, NetExpr *fall) return 0; } -void PDelays::eval_delays(Design*des, NetScope*scope, - NetExpr*&rise_time, - NetExpr*&fall_time, - NetExpr*&decay_time, +void PDelays::eval_delays(Design*des, NetScope*scope, delay_exprs_t &delays, bool as_nets_flag) const { assert(scope); - if (delay_[0]) { - rise_time = calculate_val(des, scope, delay_[0]); + NetExpr *rise = calculate_val(des, scope, delay_[0]); if (as_nets_flag) - rise_time = make_delay_nets(des, scope, rise_time); + rise = make_delay_nets(des, scope, rise); + delays.rise = rise; if (delay_[1]) { - fall_time = calculate_val(des, scope, delay_[1]); + NetExpr *fall = calculate_val(des, scope, delay_[1]); if (as_nets_flag) - fall_time = make_delay_nets(des, scope, fall_time); + fall = make_delay_nets(des, scope, fall); + delays.fall = fall; if (delay_[2]) { - decay_time = calculate_val(des, scope, delay_[2]); + NetExpr *decay = calculate_val(des, scope, delay_[2]); if (as_nets_flag) - decay_time = make_delay_nets(des, scope, - decay_time); + decay = make_delay_nets(des, scope, decay); + delays.decay = decay; } else { // If this is zero then we need to do the min() // at run time. - decay_time = calc_decay_time(rise_time, fall_time); + delays.decay = calc_decay_time(delays.rise, + delays.fall); } } else { assert(delay_[2] == 0); - fall_time = rise_time; - decay_time = rise_time; + delays.fall = delays.rise; + delays.decay = delays.rise; } } else { - rise_time = 0; - fall_time = 0; - decay_time = 0; + delays.rise = nullptr; + delays.fall = nullptr; + delays.decay = nullptr; } } diff --git a/PDelays.h b/PDelays.h index 30709070d..87a727e57 100644 --- a/PDelays.h +++ b/PDelays.h @@ -1,7 +1,7 @@ #ifndef IVL_PDelays_H #define IVL_PDelays_H /* - * Copyright (c) 1999-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2026 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,7 @@ class Design; class NetScope; class NetExpr; class PExpr; +struct delay_exprs_t; /* * Various PForm objects can carry delays. These delays include rise, @@ -46,10 +47,7 @@ class PDelays { unsigned delay_count() const; - void eval_delays(Design*des, NetScope*scope, - NetExpr*&rise_time, - NetExpr*&fall_time, - NetExpr*&decay_time, + void eval_delays(Design*des, NetScope*scope, delay_exprs_t &delays, bool as_nets_flag =false) const; void dump_delays(std::ostream&out) const; diff --git a/PGate.cc b/PGate.cc index 6da02060e..944d4e2dd 100644 --- a/PGate.cc +++ b/PGate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2026 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 @@ -41,29 +41,23 @@ void PGate::set_pins_(list*pins) } PGate::PGate(perm_string name, list*pins, const list*del) -: name_(name), pins_(pins? pins->size() : 0), ranges_(0) +: name_(name), pins_(pins? pins->size() : 0), ranges_(nullptr) { if (pins) set_pins_(pins); if (del) delay_.set_delays(del); - str0_ = IVL_DR_STRONG; - str1_ = IVL_DR_STRONG; } PGate::PGate(perm_string name, list*pins, PExpr*del) -: name_(name), pins_(pins? pins->size() : 0), ranges_(0) +: name_(name), pins_(pins? pins->size() : 0), ranges_(nullptr) { if (pins) set_pins_(pins); if (del) delay_.set_delay(del); - str0_ = IVL_DR_STRONG; - str1_ = IVL_DR_STRONG; } PGate::PGate(perm_string name, list*pins) -: name_(name), pins_(pins? pins->size() : 0), ranges_(0) +: name_(name), pins_(pins? pins->size() : 0), ranges_(nullptr) { if (pins) set_pins_(pins); - str0_ = IVL_DR_STRONG; - str1_ = IVL_DR_STRONG; } PGate::~PGate() @@ -76,24 +70,14 @@ void PGate::set_ranges(list*ranges) ranges_ = ranges; } -ivl_drive_t PGate::strength0() const +drive_strength_t PGate::strength() const { - return str0_; + return strength_; } -void PGate::strength0(ivl_drive_t s) +void PGate::strength(const drive_strength_t &str) { - str0_ = s; -} - -ivl_drive_t PGate::strength1() const -{ - return str1_; -} - -void PGate::strength1(ivl_drive_t s) -{ - str1_ = s; + strength_ = str; } void PGate::elaborate_scope(Design*, NetScope*) const @@ -109,15 +93,10 @@ void PGate::elaborate_scope(Design*, NetScope*) const * numbers of expressions. */ -void PGate::eval_delays(Design*des, NetScope*scope, - NetExpr*&rise_expr, - NetExpr*&fall_expr, - NetExpr*&decay_expr, +void PGate::eval_delays(Design*des, NetScope*scope, delay_exprs_t &delays, bool as_net_flag) const { - delay_.eval_delays(des, scope, - rise_expr, fall_expr, decay_expr, - as_net_flag); + delay_.eval_delays(des, scope, delays, as_net_flag); } unsigned PGate::delay_count() const diff --git a/PGate.h b/PGate.h index 88e0d8c57..0c832ddd1 100644 --- a/PGate.h +++ b/PGate.h @@ -31,6 +31,7 @@ class PExpr; class PUdp; class Module; +struct delay_exprs_t; /* * A PGate represents a Verilog gate. The gate has a name and other @@ -66,10 +67,7 @@ class PGate : public PNamedItem { // This evaluates the delays as far as possible, but returns // an expression, and do not signal errors. - void eval_delays(Design*des, NetScope*scope, - NetExpr*&rise_time, - NetExpr*&fall_time, - NetExpr*&decay_time, + void eval_delays(Design*des, NetScope*scope, delay_exprs_t &delays, bool as_net_flag =false) const; unsigned delay_count() const; @@ -77,11 +75,9 @@ class PGate : public PNamedItem { unsigned pin_count() const { return pins_.size(); } PExpr*pin(unsigned idx) const { return pins_[idx]; } - ivl_drive_t strength0() const; - ivl_drive_t strength1() const; + drive_strength_t strength() const; - void strength0(ivl_drive_t); - void strength1(ivl_drive_t); + void strength(const drive_strength_t &str); std::map attributes; @@ -109,7 +105,7 @@ class PGate : public PNamedItem { std::list*ranges_; - ivl_drive_t str0_, str1_; + drive_strength_t strength_; void set_pins_(std::list*pins); diff --git a/cprop.cc b/cprop.cc index 9e7864b09..804fa4e91 100644 --- a/cprop.cc +++ b/cprop.cc @@ -180,9 +180,7 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj) << "Replace binary MUX with constant select=" << sel_val << " with a BUFZ to the selected input." << endl; - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); + tmp->delay_times(obj->delay_times()); connect(tmp->pin(0), obj->pin_Result()); if (sel_val == verinum::V1) diff --git a/design_dump.cc b/design_dump.cc index c1e74325d..fe5d9edf3 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2026 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 @@ -90,6 +90,30 @@ ostream& operator << (ostream&o, ivl_drive_t str) return o; } +ostream &operator << (ostream &o, const drive_strength_t &strength) +{ + o << strength.drive0 << "0 " << strength.drive1 << "1"; + return o; +} + +static void dump_delay_expr(ostream &o, const NetExpr *expr) +{ + if (expr) + o << *expr; + else + o << "0"; +} + +ostream &operator << (ostream &o, const delay_exprs_t &delays) +{ + dump_delay_expr(o, delays.rise); + o << ","; + dump_delay_expr(o, delays.fall); + o << ","; + dump_delay_expr(o, delays.decay); + return o; +} + ostream& operator << (ostream&o, ivl_variable_type_t val) { switch (val) { @@ -454,8 +478,7 @@ void NetNet::dump_net(ostream&o, unsigned ind) const o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) o << " scope=" << scope_path(scope()); - o << " #(" << rise_time() << "," << fall_time() << "," - << decay_time() << ") vector_width=" << vector_width() + o << " #(" << delay_times() << ") vector_width=" << vector_width() << " pin_count=" << pin_count(); if (pins_are_virtual()) { o << " pins_are_virtual" << endl; @@ -486,8 +509,7 @@ void NetNet::dump_net(ostream&o, unsigned ind) const void NetNode::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "node: "; - o << typeid(*this).name() << " #(" << rise_time() - << "," << fall_time() << "," << decay_time() << ") " << name() + o << typeid(*this).name() << " #(" << delay_times() << ") " << name() << endl; dump_node_pins(o, ind+4); @@ -518,8 +540,7 @@ void NetPins::dump_node_pins(ostream&o, unsigned ind, const char**pin_names) con break; } - o << " (" << pin(idx).drive0() << "0 " - << pin(idx).drive1() << "1): "; + o << " (" << pin(idx).drive() << "): "; if (pin(idx).is_linked()) { const Nexus*nex = pin(idx).nexus(); @@ -622,11 +643,7 @@ void NetConcat::dump_node(ostream&o, unsigned ind) const o << setw(ind) << "" << "NetConcat: "; o << name(); - if (rise_time()) - o << " #(" << *rise_time() - << "," << *fall_time() << "," << *decay_time() << ")"; - else - o << " #(0,0,0)"; + o << " #(" << delay_times() << ")"; o << " scope=" << scope_path(scope()) << " width=" << width_ << endl; dump_node_pins(o, ind+4); @@ -651,14 +668,7 @@ void NetPow::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "LPM_POW (NetPow): " << name() << " scope=" << scope_path(scope()) - << " delay=("; - if (rise_time()) - o << *rise_time() << "," << *fall_time() << "," - << *decay_time(); - else - o << "0,0,0"; - - o << ")" << endl; + << " delay=(" << delay_times() << ")" << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } @@ -676,8 +686,7 @@ void NetBUFZ::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "NetBUFZ: " << name() << " scope=" << scope_path(scope()) - << " delay=(" << rise_time() << "," << fall_time() << "," << - decay_time() << ") width=" << width() + << " delay=(" << delay_times() << ") width=" << width() << (transparent()? " " : " non-") << "transparent" << endl; dump_node_pins(o, ind+4); } @@ -693,10 +702,8 @@ void NetConst::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "constant " << value_; o << ": " << name(); - if (rise_time()) - o << " #(" << *rise_time() - << "," << *fall_time() - << "," << *decay_time() << ")"; + if (delay_times().has_delay()) + o << " #(" << delay_times() << ")"; else o << " #(.,.,.)"; o << endl; @@ -729,10 +736,8 @@ void NetLiteral::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "constant real " << real_ << ": " << name(); - if (rise_time()) - o << " #(" << *rise_time() - << "," << *fall_time() - << "," << *decay_time() << ")"; + if (delay_times().has_delay()) + o << " #(" << delay_times() << ")"; else o << " #(.,.,.)"; o << endl; @@ -810,8 +815,7 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const o << "xor"; break; } - o << " #(" << rise_time() - << "," << fall_time() << "," << decay_time() << ") " << name() + o << " #(" << delay_times() << ") " << name() << " scope=" << scope_path(scope()) << endl; @@ -839,10 +843,8 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const } o << setw(ind) << "" << "NetPartSelect(" << pt << "): " << name(); - if (rise_time()) - o << " #(" << *rise_time() - << "," << *fall_time() - << "," << *decay_time() << ")"; + if (delay_times().has_delay()) + o << " #(" << delay_times() << ")"; else o << " #(.,.,.)"; o << " off=" << off_ << " wid=" << wid_ <local_symbol(), 1, pull_type, wid); pull->set_line(*this); - pull->pin(0).drive0(IVL_DR_SUPPLY); - pull->pin(0).drive1(IVL_DR_SUPPLY); + pull->pin(0).drive(drive_strength_t(IVL_DR_SUPPLY, + IVL_DR_SUPPLY)); des->add_node(pull); wtype = NetNet::WIRE; } diff --git a/elaborate.cc b/elaborate.cc index c78723000..ff448cc95 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -115,19 +115,16 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const { ivl_assert(*this, scope); - NetExpr* rise_time, *fall_time, *decay_time; - eval_delays(des, scope, rise_time, fall_time, decay_time, true); - - ivl_drive_t drive0 = strength0(); - ivl_drive_t drive1 = strength1(); + drive_strength_t drive = strength(); + delay_exprs_t delays; + eval_delays(des, scope, delays, true); ivl_assert(*this, pin(0)); ivl_assert(*this, pin(1)); /* Elaborate the l-value. */ // A continuous assignment can drive a variable if the default strength is used. - bool var_allowed_in_sv = (drive0 == IVL_DR_STRONG && - drive1 == IVL_DR_STRONG) ? true : false; + bool var_allowed_in_sv = !drive.has_drive(); NetNet*lval = pin(0)->elaborate_lnet(des, scope, var_allowed_in_sv); if (lval == 0) { return; @@ -214,7 +211,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const /* When we are given a non-default strength value and if the drive * source is a bit, part, indexed select or a concatenation we need * to add a driver (BUFZ) to convey the strength information. */ - if ((drive0 != IVL_DR_STRONG || drive1 != IVL_DR_STRONG) && + if (drive.has_drive() && ((dynamic_cast(rval_expr)) || (dynamic_cast(rval_expr)))) { need_driver_flag = true; @@ -242,11 +239,11 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const /* Set the drive and delays for the r-val. */ - if (drive0 != IVL_DR_STRONG || drive1 != IVL_DR_STRONG) - rval->pin(0).drivers_drive(drive0, drive1); + if (drive.has_drive()) + rval->pin(0).drivers_drive(drive); - if (rise_time || fall_time || decay_time) - rval->pin(0).drivers_delays(rise_time, fall_time, decay_time); + if (delays.has_delay()) + rval->pin(0).drivers_delays(delays); connect(lval->pin(0), rval->pin(0)); @@ -826,8 +823,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const values are given, they are taken as specified. */ if (check_delay_count(des)) return; - NetExpr* rise_time, *fall_time, *decay_time; - eval_delays(des, scope, rise_time, fall_time, decay_time, true); + delay_exprs_t delays; + eval_delays(des, scope, delays, true); + drive_strength_t drive = strength(); struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; @@ -859,12 +857,8 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const attrib_list[adx].val); /* Set the delays and drive strength for all built in gates. */ - cur[idx]->rise_time(rise_time); - cur[idx]->fall_time(fall_time); - cur[idx]->decay_time(decay_time); - - cur[idx]->pin(0).drive0(strength0()); - cur[idx]->pin(0).drive1(strength1()); + cur[idx]->delay_times(delays); + cur[idx]->pin(0).drive(drive); cur[idx]->set_line(*this); des->add_node(cur[idx]); @@ -2457,7 +2451,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const { - NetExpr*rise_expr =0, *fall_expr =0, *decay_expr =0; + delay_exprs_t delays; perm_string my_name = get_name(); if (my_name == 0) @@ -2474,8 +2468,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const } else { PDelays tmp_del; tmp_del.set_delays(overrides_, false); - tmp_del.eval_delays(des, scope, rise_expr, fall_expr, - decay_expr, true); + tmp_del.eval_delays(des, scope, delays, true); } } @@ -2494,9 +2487,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const ivl_assert(*this, udp); NetUDP*net = new NetUDP(scope, my_name, udp->ports.size(), udp); net->set_line(*this); - net->rise_time(rise_expr); - net->fall_time(fall_expr); - net->decay_time(decay_expr); + net->delay_times(delays); struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; diff --git a/net_func.cc b/net_func.cc index 1bd714aa4..755be3ec8 100644 --- a/net_func.cc +++ b/net_func.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2026 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 @@ -41,8 +41,7 @@ NetUserFunc::NetUserFunc(NetScope*s, perm_string n, NetScope*d, for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).drive0(IVL_DR_HiZ); - pin(idx).drive1(IVL_DR_HiZ); + pin(idx).drive(drive_strength_t::hiz); } } @@ -103,8 +102,7 @@ NetSysFunc::NetSysFunc(NetScope*s, perm_string n, for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).drive0(IVL_DR_HiZ); - pin(idx).drive1(IVL_DR_HiZ); + pin(idx).drive(drive_strength_t::hiz); } } diff --git a/net_link.cc b/net_link.cc index 039428ae9..4ef426e48 100644 --- a/net_link.cc +++ b/net_link.cc @@ -164,25 +164,26 @@ Link::DIR Link::get_dir() const return dir_; } -void Link::drivers_delays(const NetExpr*rise, const NetExpr*fall, const NetExpr*decay) +void Link::drivers_delays(const delay_exprs_t &delays) { - find_nexus_()->drivers_delays(rise, fall, decay); + find_nexus_()->drivers_delays(delays); } -void Link::drivers_drive(ivl_drive_t drive0__, ivl_drive_t drive1__) +void Link::drivers_drive(const drive_strength_t &drive) { - find_nexus_()->drivers_drive(drive0__, drive1__); + find_nexus_()->drivers_drive(drive); } -void Link::drive0(ivl_drive_t str) +void Link::drive(const drive_strength_t &drive) { - drive0_ = str; + drive0_ = drive.drive0; + drive1_ = drive.drive1; } -void Link::drive1(ivl_drive_t str) +drive_strength_t Link::drive() const { - drive1_ = str; + return drive_strength_t(drive0_, drive1_); } ivl_drive_t Link::drive0() const @@ -358,7 +359,7 @@ bool Nexus::drivers_present() const return false; } -void Nexus::drivers_delays(const NetExpr*rise, const NetExpr*fall, const NetExpr*decay) +void Nexus::drivers_delays(const delay_exprs_t &delays) { for (Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { if (cur->get_dir() != Link::OUTPUT) @@ -368,20 +369,17 @@ void Nexus::drivers_delays(const NetExpr*rise, const NetExpr*fall, const NetExpr if (obj == 0) continue; - obj->rise_time(rise); - obj->fall_time(fall); - obj->decay_time(decay); + obj->delay_times(delays); } } -void Nexus::drivers_drive(ivl_drive_t drive0, ivl_drive_t drive1) +void Nexus::drivers_drive(const drive_strength_t &drive) { for (Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { if (cur->get_dir() != Link::OUTPUT) continue; - cur->drive0(drive0); - cur->drive1(drive1); + cur->drive(drive); } } diff --git a/netlist.cc b/netlist.cc index b26c508ec..79b5f6cfb 100644 --- a/netlist.cc +++ b/netlist.cc @@ -40,6 +40,8 @@ using namespace std; +const drive_strength_t drive_strength_t::hiz(IVL_DR_HiZ, IVL_DR_HiZ); + ostream& operator<< (ostream&o, NetNet::Type t) { switch (t) { @@ -237,7 +239,7 @@ bool NetPins::is_linked(void) const } NetObj::NetObj(NetScope*s, perm_string n, unsigned np) -: NetPins(np), scope_(s), name_(n), delay1_(0), delay2_(0), delay3_(0) +: NetPins(np), scope_(s), name_(n), delays_() { /* Don't ivl_assert(*this, np > 0); @@ -260,6 +262,11 @@ const NetScope* NetObj::scope() const return scope_; } +void NetObj::delay_times(const delay_exprs_t &delays) +{ + delays_ = delays; +} + NetNode::NetNode(NetScope*s, perm_string n, unsigned npins) : NetObj(s, n, npins), node_next_(0), node_prev_(0), design_(0) { diff --git a/netlist.h b/netlist.h index a3880604b..812372ff5 100644 --- a/netlist.h +++ b/netlist.h @@ -103,6 +103,42 @@ struct functor_t; # define ENUM_UNSIGNED_INT #endif +struct drive_strength_t { + static const drive_strength_t hiz; + + explicit drive_strength_t(ivl_drive_t d0 = IVL_DR_STRONG, + ivl_drive_t d1 = IVL_DR_STRONG) + : drive0(d0), drive1(d1) + { } + + bool has_drive() const + { + return drive0 != IVL_DR_STRONG || drive1 != IVL_DR_STRONG; + } + + ivl_drive_t drive0; + ivl_drive_t drive1; +}; + +struct delay_exprs_t { + explicit delay_exprs_t(const NetExpr *r = nullptr, + const NetExpr *f = nullptr, + const NetExpr *d = nullptr) + : rise(r), fall(f), decay(d) + { } + + bool has_delay() const + { + return rise || fall || decay; + } + + const NetExpr *rise; + const NetExpr *fall; + const NetExpr *decay; +}; + +std::ostream &operator << (std::ostream &o, const drive_strength_t &strength); +std::ostream &operator << (std::ostream &o, const delay_exprs_t &delays); std::ostream& operator << (std::ostream&o, ivl_variable_type_t val); extern void join_island(NetPins*obj); @@ -126,17 +162,17 @@ class Link { DIR get_dir() const; // Set the delay for all the drivers to this nexus. - void drivers_delays(const NetExpr*rise, const NetExpr*fall, const NetExpr*decay); + void drivers_delays(const delay_exprs_t &delays); // A link has a drive strength for 0 and 1 values. The drive0 // strength is for when the link has the value 0, and drive1 // strength is for when the link has a value 1. - void drive0(ivl_drive_t); - void drive1(ivl_drive_t); + void drive(const drive_strength_t &drive); + drive_strength_t drive() const; // This sets the drives for all drivers of this link, and not // just the current link. - void drivers_drive(ivl_drive_t d0, ivl_drive_t d1); + void drivers_drive(const drive_strength_t &drive); ivl_drive_t drive0() const; ivl_drive_t drive1() const; @@ -269,13 +305,15 @@ class NetObj : public NetPins, public Attrib { perm_string name() const { return name_; } void rename(perm_string n) { name_ = n; } - const NetExpr* rise_time() const { return delay1_; } - const NetExpr* fall_time() const { return delay2_; } - const NetExpr* decay_time() const { return delay3_; } + const NetExpr *rise_time() const { return delays_.rise; } + const NetExpr *fall_time() const { return delays_.fall; } + const NetExpr *decay_time() const { return delays_.decay; } + delay_exprs_t delay_times() const + { + return delays_; + } - void rise_time(const NetExpr* d) { delay1_ = d; } - void fall_time(const NetExpr* d) { delay2_ = d; } - void decay_time(const NetExpr* d) { delay3_ = d; } + void delay_times(const delay_exprs_t &delays); void dump_obj_attr(std::ostream&, unsigned) const; @@ -284,9 +322,7 @@ class NetObj : public NetPins, public Attrib { private: NetScope*scope_; perm_string name_; - const NetExpr* delay1_; - const NetExpr* delay2_; - const NetExpr* delay3_; + delay_exprs_t delays_; }; /* @@ -374,8 +410,8 @@ class Nexus { const char* name() const; - void drivers_delays(const NetExpr*rise, const NetExpr*fall, const NetExpr*decay); - void drivers_drive(ivl_drive_t d0, ivl_drive_t d1); + void drivers_delays(const delay_exprs_t &delays); + void drivers_drive(const drive_strength_t &drive); Link*first_nlink(); const Link* first_nlink()const; diff --git a/pform.cc b/pform.cc index d7c476532..e66d5dce8 100644 --- a/pform.cc +++ b/pform.cc @@ -2260,8 +2260,7 @@ static void pform_makegate(PGBuiltin::Type type, // pform_bind_attributes function to keep the attr object. pform_bind_attributes(cur->attributes, attr, true); - cur->strength0(str.str0); - cur->strength1(str.str1); + cur->strength(drive_strength_t(str.str0, str.str1)); cur->set_line(info); if (pform_cur_generate) { @@ -2483,8 +2482,7 @@ static PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval, else cur = new PGAssign(wires, del); - cur->strength0(str.str0); - cur->strength1(str.str1); + cur->strength(drive_strength_t(str.str0, str.str1)); if (pform_cur_generate) pform_cur_generate->add_gate(cur); diff --git a/pform_dump.cc b/pform_dump.cc index 6dc130687..94913eca6 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2026 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 @@ -741,7 +741,7 @@ void PGate::dump(ostream&out, unsigned ind) const void PGAssign::dump(ostream&out, unsigned ind) const { out << setw(ind) << ""; - out << "assign (" << strength0() << "0 " << strength1() << "1) "; + out << "assign (" << strength() << ") "; dump_delays(out); out << " " << *pin(0) << " = " << *pin(1) << ";" << endl; } @@ -787,7 +787,7 @@ void PGBuiltin::dump(ostream&out, unsigned ind) const out << "builtin gate "; } - out << "(" << strength0() << "0 " << strength1() << "1) "; + out << "(" << strength() << ") "; dump_delays(out); out << " " << get_name(); dump_ranges(out); From ab6a0e0799e17f6e737655dccad55ec496927609 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 May 2026 12:56:09 -0700 Subject: [PATCH 090/102] Preserve delay and strength in unpacked array continuous assignments Continuous assignments to unpacked arrays are expanded into per-element BUFZ drivers. Currently this path drops the delay and drive strength from the original continuous assignment, so `assign #5 a = b` updates the array immediately and `assign (weak1, weak0) a = b` drives with the default strength. Pass the evaluated delay and strength values through the unpacked array assignment helper and apply them to each generated element driver. Signed-off-by: Lars-Peter Clausen --- PGate.h | 5 ++++- elaborate.cc | 9 ++++++--- netmisc.cc | 21 +++++++++++++++++---- netmisc.h | 6 +++++- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/PGate.h b/PGate.h index 0c832ddd1..84e172377 100644 --- a/PGate.h +++ b/PGate.h @@ -32,6 +32,7 @@ class PExpr; class PUdp; class Module; struct delay_exprs_t; +struct drive_strength_t; /* * A PGate represents a Verilog gate. The gate has a name and other @@ -129,7 +130,9 @@ class PGAssign : public PGate { virtual void elaborate(Design*des, NetScope*scope) const override; private: - void elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const; + void elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval, + const drive_strength_t &drive, + const delay_exprs_t &delays) const; }; diff --git a/elaborate.cc b/elaborate.cc index ff448cc95..67320db99 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -133,7 +133,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const // If this turns out to be an assignment to an unpacked array, // then handle that special case elsewhere. if (lval->unpacked_dimensions() > 0) { - elaborate_unpacked_array_(des, scope, lval); + elaborate_unpacked_array_(des, scope, lval, drive, delays); return; } @@ -311,11 +311,14 @@ NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &l return expr_net; } -void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const +void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval, + const drive_strength_t &drive, + const delay_exprs_t &delays) const { NetNet *rval_net = elaborate_unpacked_array(des, scope, *this, lval, pin(1)); if (rval_net) - assign_unpacked_with_bufz(des, scope, lval, lval, rval_net); + assign_unpacked_with_bufz(des, scope, lval, lval, rval_net, drive, + delays); } void PGBuiltin::calculate_gate_and_lval_count_(unsigned&gate_count, diff --git a/netmisc.cc b/netmisc.cc index 66e852820..a5af12d76 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1619,6 +1619,8 @@ NetExpr*collapse_array_indices(Design*des, NetScope*scope, const NetNet*net, static void assign_unpacked_with_bufz_dim(Design *des, NetScope *scope, const LineInfo *loc, NetNet *lval, NetNet *rval, + const drive_strength_t &drive, + const delay_exprs_t &delays, const std::vector &stride, unsigned int dim = 0, unsigned int idx_l = 0, @@ -1661,11 +1663,19 @@ static void assign_unpacked_with_bufz_dim(Design *des, NetScope *scope, driver->set_line(*loc); des->add_node(driver); - connect(lval->pin(idx_l), driver->pin(0)); connect(driver->pin(1), rval->pin(idx_r)); + + if (drive.has_drive()) + driver->pin(0).drive(drive); + + if (delays.has_delay()) + driver->delay_times(delays); + + connect(lval->pin(idx_l), driver->pin(0)); } else { assign_unpacked_with_bufz_dim(des, scope, loc, lval, rval, - stride, dim + 1, idx_l, idx_r); + drive, delays, stride, + dim + 1, idx_l, idx_r); } idx_l += inc_l; @@ -1675,7 +1685,9 @@ static void assign_unpacked_with_bufz_dim(Design *des, NetScope *scope, void assign_unpacked_with_bufz(Design*des, NetScope*scope, const LineInfo*loc, - NetNet*lval, NetNet*rval) + NetNet*lval, NetNet*rval, + const drive_strength_t &drive, + const delay_exprs_t &delays) { ivl_assert(*loc, lval->pin_count()==rval->pin_count()); @@ -1683,7 +1695,8 @@ void assign_unpacked_with_bufz(Design*des, NetScope*scope, vector stride(dims.size()); make_strides(dims, stride); - assign_unpacked_with_bufz_dim(des, scope, loc, lval, rval, stride); + assign_unpacked_with_bufz_dim(des, scope, loc, lval, rval, drive, + delays, stride); } /* diff --git a/netmisc.h b/netmisc.h index d87b5d027..ff9edc1ec 100644 --- a/netmisc.h +++ b/netmisc.h @@ -492,7 +492,11 @@ extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope, extern void assign_unpacked_with_bufz(Design*des, NetScope*scope, const LineInfo*loc, - NetNet*lval, NetNet*rval); + NetNet*lval, NetNet*rval, + const drive_strength_t &drive = + drive_strength_t(), + const delay_exprs_t &delays = + delay_exprs_t()); extern NetPartSelect* detect_partselect_lval(Link&pin); From 635bdd8eb8325de8bd9d7d3133bd4938c9b2aaa4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 May 2026 12:06:44 -0700 Subject: [PATCH 091/102] Add regression tests for unpacked array continuous assignment strength and delay Check that continuous assignments to unpacked net arrays preserve delay and drive strength on the generated element drivers. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_array_cassign10.v | 39 +++++++++++++++++++++ ivtest/ivltests/sv_array_cassign9.v | 44 ++++++++++++++++++++++++ ivtest/regress-vvp.list | 2 ++ ivtest/vvp_tests/sv_array_cassign10.json | 9 +++++ ivtest/vvp_tests/sv_array_cassign9.json | 9 +++++ 5 files changed, 103 insertions(+) create mode 100644 ivtest/ivltests/sv_array_cassign10.v create mode 100644 ivtest/ivltests/sv_array_cassign9.v create mode 100644 ivtest/vvp_tests/sv_array_cassign10.json create mode 100644 ivtest/vvp_tests/sv_array_cassign9.json diff --git a/ivtest/ivltests/sv_array_cassign10.v b/ivtest/ivltests/sv_array_cassign10.v new file mode 100644 index 000000000..5a5fa6856 --- /dev/null +++ b/ivtest/ivltests/sv_array_cassign10.v @@ -0,0 +1,39 @@ +// Check that continuous assignments to unpacked arrays preserve drive strength. + +module test; + + reg failed; + reg [8*3-1:0] s; + + wire driven[0:1]; + wire resolved[0:1]; + + assign (weak1, weak0) driven = '{1'b1, 1'b0}; + assign resolved[0] = 1'b0; + assign resolved[1] = 1'b1; + assign (weak1, weak0) resolved = '{1'b1, 1'b0}; + + `define check_str(val, exp) begin \ + $swrite(s, "%v", val); \ + if (s != exp) begin \ + $display("FAILED(%0d). '%s' expected %s, got %s", `__LINE__, \ + `"val`", exp, s); \ + failed = 1'b1; \ + end \ + end + + initial begin + failed = 1'b0; + + #0; + `check_str(driven[0], "We1"); + `check_str(driven[1], "We0"); + `check_str(resolved[0], "St0"); + `check_str(resolved[1], "St1"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_array_cassign9.v b/ivtest/ivltests/sv_array_cassign9.v new file mode 100644 index 000000000..4db9f0d05 --- /dev/null +++ b/ivtest/ivltests/sv_array_cassign9.v @@ -0,0 +1,44 @@ +// Check that continuous assignments to unpacked arrays preserve delay. + +module test; + + reg failed; + + wire delayed[0:1]; + reg value[0:1]; + + assign #5 delayed = value; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + value[0] = 1'b1; + value[1] = 1'b0; + + #5; + `check(delayed[0], 1'b1) + `check(delayed[1], 1'b0) + + value[0] = 1'b0; + value[1] = 1'b1; + + #4; + `check(delayed[0], 1'b1) + `check(delayed[1], 1'b0) + + #1; + `check(delayed[0], 1'b0) + `check(delayed[1], 1'b1) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 36d22f512..09f0498cf 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -242,6 +242,8 @@ sv_array_assign_single_fail1 vvp_tests/sv_array_assign_single_fail1.json sv_array_cassign6 vvp_tests/sv_array_cassign6.json sv_array_cassign7 vvp_tests/sv_array_cassign7.json sv_array_cassign8 vvp_tests/sv_array_cassign8.json +sv_array_cassign9 vvp_tests/sv_array_cassign9.json +sv_array_cassign10 vvp_tests/sv_array_cassign10.json sv_array_cassign_single vvp_tests/sv_array_cassign_single.json sv_array_cassign_single_fail1 vvp_tests/sv_array_cassign_single_fail1.json sv_automatic_2state vvp_tests/sv_automatic_2state.json diff --git a/ivtest/vvp_tests/sv_array_cassign10.json b/ivtest/vvp_tests/sv_array_cassign10.json new file mode 100644 index 000000000..0c3331289 --- /dev/null +++ b/ivtest/vvp_tests/sv_array_cassign10.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_array_cassign10.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_array_cassign9.json b/ivtest/vvp_tests/sv_array_cassign9.json new file mode 100644 index 000000000..1b8bd91eb --- /dev/null +++ b/ivtest/vvp_tests/sv_array_cassign9.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_array_cassign9.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} From ecb8a70bed97b6300e4d775788dbd7fc99044aef Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 18 May 2026 07:49:42 +0200 Subject: [PATCH 092/102] iverilog: add missing -B options to man page and app usage --- driver/iverilog.man.in | 29 ++++++++++++++++++++++------- driver/main.c | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 60498549b..7ccc93ee9 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -4,7 +4,7 @@ iverilog - Icarus Verilog compiler .SH SYNOPSIS .B iverilog -[\-EiRSuVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] +[\-EiRSuVv] [\-B[MPV]path] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] [\-Pparameter=value] [\-pflag=value] [\-dname] [\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g2017\:|\-g2023\:|\-g] [\-Iincludedir] [\-Lmoduledir] [\-mmodule] [\-M[mode=]file] [\-Nfile] @@ -21,13 +21,28 @@ further processing. The main target is \fIvvp\fP for simulation. .SH OPTIONS \fIiverilog\fP accepts the following options: .TP 8 -.B -B\fIbase\fP +.BI \-B path The \fIiverilog\fP program uses external programs and configuration -files to preprocess and compile the Verilog source. Normally, the path -used to locate these tools is built into the \fIiverilog\fP -program. However, the \fB\-B\fP switch allows the user to select a -different set of programs. The path given is used to locate -\fIivlpp\fP, \fIivl\fP, code generators and the VPI modules. +files to preprocess and compile Verilog source files. Normally, the +paths used to locate these tools are built into the +\fIiverilog\fP executable. The \fB\-B\fP option allows the user to +override these paths. +The specified path is used as the default base directory for locating +\fIivlpp\fP, \fIivl\fP, code generators, configuration files, and +VPI modules. +Specialized forms of this option may be used to override individual +tool paths: +.RS +.TP +.BI \-BM path +Directory for VPI modules. +.TP +.BI \-BP path +Directory for the \fIivlpp\fP preprocessor. +.TP +.BI \-BV path +Directory for the \fIvhdlpp\fP VHDL preprocessor. +.RE .TP 8 .B -c\fIfile\fP -f\fIfile\fP These flags specify an input file that contains a list of Verilog diff --git a/driver/main.c b/driver/main.c index 865a94e4c..fd1e563f8 100644 --- a/driver/main.c +++ b/driver/main.c @@ -38,7 +38,7 @@ const char NOTICE[] = ; const char HELP[] = -"Usage: iverilog [-EiRSuvV] [-B base] [-c cmdfile|-f cmdfile]\n" +"Usage: iverilog [-EiRSuvV] [-B[MPV] base] [-c cmdfile|-f cmdfile]\n" " [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012|-g2017|-g2023] [-g]\n" " [-D macro[=defn]] [-I includedir] [-L moduledir]\n" " [-M [mode=]depfile] [-m module]\n" From 8b861b417132dd6ae197c4151667301c0c282ef6 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 18 May 2026 07:50:07 +0200 Subject: [PATCH 093/102] iverilog: add -BI option to support custom location for the ivl parser --- driver/iverilog.man.in | 5 ++++- driver/main.c | 12 +++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 7ccc93ee9..3c38f1abd 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -4,7 +4,7 @@ iverilog - Icarus Verilog compiler .SH SYNOPSIS .B iverilog -[\-EiRSuVv] [\-B[MPV]path] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] +[\-EiRSuVv] [\-B[IMPV]path] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] [\-Pparameter=value] [\-pflag=value] [\-dname] [\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g2017\:|\-g2023\:|\-g] [\-Iincludedir] [\-Lmoduledir] [\-mmodule] [\-M[mode=]file] [\-Nfile] @@ -34,6 +34,9 @@ Specialized forms of this option may be used to override individual tool paths: .RS .TP +.BI \-BI path +Directory for the \fIivl\fP parser. +.TP .BI \-BM path Directory for VPI modules. .TP diff --git a/driver/main.c b/driver/main.c index fd1e563f8..56aa62cdf 100644 --- a/driver/main.c +++ b/driver/main.c @@ -38,7 +38,7 @@ const char NOTICE[] = ; const char HELP[] = -"Usage: iverilog [-EiRSuvV] [-B[MPV] base] [-c cmdfile|-f cmdfile]\n" +"Usage: iverilog [-EiRSuvV] [-B[IMPV] base] [-c cmdfile|-f cmdfile]\n" " [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012|-g2017|-g2023] [-g]\n" " [-D macro[=defn]] [-I includedir] [-L moduledir]\n" " [-M [mode=]depfile] [-m module]\n" @@ -112,6 +112,7 @@ extern void cfreset(FILE*fd, const char*path); const char*base = 0; const char*vpi_dir = 0; +const char*ivl_dir = 0; const char*ivlpp_dir = 0; const char*vhdlpp_dir= 0; const char*vhdlpp_work = 0; @@ -340,7 +341,7 @@ static int t_version_only(void) } fflush(0); - snprintf(tmp, sizeof tmp, "%s%civl -V -C\"%s\" -C\"%s\"", base, sep, + snprintf(tmp, sizeof tmp, "%s%civl -V -C\"%s\" -C\"%s\"", ivl_dir, sep, iconfig_path, iconfig_common_path); rc = system(tmp); if (rc != 0) { @@ -447,7 +448,7 @@ static int t_compile(void) #endif /* Build the ivl command. */ - snprintf(tmp, sizeof tmp, "%s%civl", base, sep); + snprintf(tmp, sizeof tmp, "%s%civl", ivl_dir, sep); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); @@ -1224,6 +1225,9 @@ int main(int argc, char **argv) character of the path indicates which path the user is specifying. */ switch (optarg[0]) { + case 'I': /* Path for the ivl parser */ + ivl_dir = optarg+1; + break; case 'M': /* Path for the VPI modules */ vpi_dir = optarg+1; break; @@ -1375,6 +1379,8 @@ int main(int argc, char **argv) vpi_dir = base; if (ivlpp_dir == 0) ivlpp_dir = base; + if (ivl_dir == 0) + ivl_dir = base; if (vhdlpp_dir == 0) vhdlpp_dir = base; From 2e50fb2f0632ad47e1ad5ad6ff3a907df01b8e23 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Fri, 8 May 2026 19:13:19 +0200 Subject: [PATCH 094/102] iverilog: add -Bt option to find .conf when using -t in custom install or build dir --- driver/iverilog.man.in | 7 ++++++- driver/main.c | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 3c38f1abd..b5f4d1360 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -4,7 +4,7 @@ iverilog - Icarus Verilog compiler .SH SYNOPSIS .B iverilog -[\-EiRSuVv] [\-B[IMPV]path] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] +[\-EiRSuVv] [\-B[IMPVt]path] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] [\-Pparameter=value] [\-pflag=value] [\-dname] [\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g2017\:|\-g2023\:|\-g] [\-Iincludedir] [\-Lmoduledir] [\-mmodule] [\-M[mode=]file] [\-Nfile] @@ -45,6 +45,11 @@ Directory for the \fIivlpp\fP preprocessor. .TP .BI \-BV path Directory for the \fIvhdlpp\fP VHDL preprocessor. +.TP +.BI \-Bt path +Directory used to locate target configuration files for the +\fB\-t\fP\fItarget\fP option. The configuration file name is +\fItarget\fP.conf. .RE .TP 8 .B -c\fIfile\fP -f\fIfile\fP diff --git a/driver/main.c b/driver/main.c index 56aa62cdf..95d02e91b 100644 --- a/driver/main.c +++ b/driver/main.c @@ -38,7 +38,7 @@ const char NOTICE[] = ; const char HELP[] = -"Usage: iverilog [-EiRSuvV] [-B[IMPV] base] [-c cmdfile|-f cmdfile]\n" +"Usage: iverilog [-EiRSuvV] [-B[IMPVt] base] [-c cmdfile|-f cmdfile]\n" " [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012|-g2017|-g2023] [-g]\n" " [-D macro[=defn]] [-I includedir] [-L moduledir]\n" " [-M [mode=]depfile] [-m module]\n" @@ -112,6 +112,7 @@ extern void cfreset(FILE*fd, const char*path); const char*base = 0; const char*vpi_dir = 0; +const char*tconfig_dir = 0; const char*ivl_dir = 0; const char*ivlpp_dir = 0; const char*vhdlpp_dir= 0; @@ -1237,6 +1238,9 @@ int main(int argc, char **argv) case 'V': /* Path for the vhdlpp VHDL processor */ vhdlpp_dir = optarg+1; break; + case 't': /* Path to target.conf for the -ttarget option */ + tconfig_dir = optarg+1; + break; default: /* Otherwise, this is a default base. */ base=optarg; break; @@ -1383,6 +1387,8 @@ int main(int argc, char **argv) ivl_dir = base; if (vhdlpp_dir == 0) vhdlpp_dir = base; + if (tconfig_dir == 0) + tconfig_dir = base; if (version_flag || verbose_flag) { printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n"); @@ -1392,7 +1398,7 @@ int main(int argc, char **argv) /* Make a common conf file path to reflect the target. */ snprintf(iconfig_common_path, sizeof iconfig_common_path, "%s%c%s%s.conf", - base, sep, targ, synth_flag? "-s" : ""); + tconfig_dir, sep, targ, synth_flag? "-s" : ""); /* Write values to the iconfig file. */ fprintf(iconfig_file, "basedir:%s\n", base); From 0d74d5b211746f2aae8ccf4c8af9621fd7faf06d Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Tue, 12 May 2026 11:45:41 +0200 Subject: [PATCH 095/102] iverilog: add test for the vvp example mentioned in the documentation This test was added to verify the new options in the `iverilog` program, which allow it to be run from a build directory. Since `iverilog` is not compatible with the MSYS2 runtime environment used in CI, the added test is excluded on this platform. --- configure.ac | 16 ++++++++++++++++ driver/Makefile.in | 20 ++++++++++++++++++++ driver/hello_world.v | 3 +++ 3 files changed, 39 insertions(+) create mode 100644 driver/hello_world.v diff --git a/configure.ac b/configure.ac index c3e1a5bfb..5560dc981 100644 --- a/configure.ac +++ b/configure.ac @@ -98,6 +98,22 @@ AC_SUBST(EXEEXT) # Combined check for Microsoft-related bogosities; sets WIN32 if found AX_WIN32 +# detect msys shell +AC_MSG_CHECKING([whether the shell is an MSYS2 runtime shell]) + +AS_CASE([$host_os:$MSYSTEM], + [*mingw*:UCRT64|*mingw*:MINGW64|*mingw*:MINGW32|*mingw*:CLANG64], [ + MSYS_SHELL=true + msys_shell_result=yes + ], + [ + MSYS_SHELL=false + msys_shell_result=no + ] +) +AC_MSG_RESULT([$msys_shell_result]) +AC_SUBST([MSYS_SHELL]) + # Check to see if we are using the Sun compiler. If so then configure # some of the flags to match the Sun compiler syntax. This is also used # in the aclocal.m4 file to configure the flags used to build and link diff --git a/driver/Makefile.in b/driver/Makefile.in index f0c6831ce..36b9abcd2 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -17,12 +17,18 @@ # SHELL = /bin/sh +EXEEXT = @EXEEXT@ +ENV_VVP=@ENV_VVP@ +MSYS_SHELL=@MSYS_SHELL@ + suffix = @install_suffix@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ datarootdir = @datarootdir@ +builddir=@builddir@ +top_builddir=@top_builddir@ VPATH = $(srcdir) @@ -58,11 +64,25 @@ O = main.o substit.o cflexor.o cfparse.o all: dep iverilog@EXEEXT@ iverilog.man check: all + @if $(MSYS_SHELL); then \ + echo "iverilog: execution from a build directory not suppported for this runtime"; \ + else \ + echo "iverilog: create .vpp from .v file and run it"; \ + $(builddir)/iverilog@EXEEXT@ \ + -B$(top_builddir)/tgt-vvp \ + -BI$(top_builddir) \ + -BM$(top_builddir)/vpi \ + -BP$(top_builddir)/ivlpp \ + -Bt$(top_builddir)/tgt-vvp \ + $(verbose) -o top.vvp -s top $(srcdir)/hello_world.v; \ + $(ENV_VVP) $(top_builddir)/vvp/vvp$(suffix)@EXEEXT@ top.vvp; \ + fi clean: rm -f *.o cflexor.c cfparse.c cfparse.h cfparse.output rm -f iverilog@EXEEXT@ iverilog.man iverilog.pdf iverilog.ps rm -rf dep + rm -f test.conf top.vvp distclean: clean rm -f Makefile config.log diff --git a/driver/hello_world.v b/driver/hello_world.v new file mode 100644 index 000000000..33ca7ea79 --- /dev/null +++ b/driver/hello_world.v @@ -0,0 +1,3 @@ +module top; + initial $display("Hello World!"); +endmodule From 7e7d0ae94b8ee8450c8a136090c958dc9fec9e6c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 4 Jun 2022 00:15:35 +0200 Subject: [PATCH 096/102] NetEvWait: Don't delete event in destructor `NetEvWait` deletes the event that is assigned to it when itself is deleted. But the event is not owned by the `NetEvWait`, it is shared among all consumers of the event. Deleting it when the `NetEvWait` is deleted can result in undefined behavior. This is mainly a problem for non-blocking event control assignments with a zero or negative immediate valued repeat. In this case the `NetEvWait` will be deleted as it is not needed. ``` reg x; event e; x <= repeat(1) @e 1'b0; x <= repeat(0) @e 1'b1; // Assert triggered since in-use event is freed ``` Remove the delete to fix this. Events that end up being unused will be freed by the nodangle functor. Signed-off-by: Lars-Peter Clausen --- net_event.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/net_event.cc b/net_event.cc index 2808b7c66..1f5984387 100644 --- a/net_event.cc +++ b/net_event.cc @@ -407,7 +407,6 @@ NetEvWait::~NetEvWait() tmp->next = tmp->next->next; delete tmp; } - delete tgt; } events_.clear(); } From e35c857a249e9342b70bf03b051f056c4f8412f7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jun 2022 17:18:35 +0200 Subject: [PATCH 097/102] Extend non-blocking event control with <= 0 repeat test Extend the non-blocking event control assignment tests to check that a 0 or negative repeat value is handled correctly. In this case the assignment should be executed like a regular non-blocking assignment and the event control should be ignored. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/nb_ec_array.v | 17 ++++++++++++++ ivtest/ivltests/nb_ec_array_pv.v | 10 +++++++++ ivtest/ivltests/nb_ec_array_pv2.v | 10 +++++++++ ivtest/ivltests/nb_ec_pv.v | 10 +++++++++ ivtest/ivltests/nb_ec_pv2.v | 37 +++++++++++++++++++++++++++++++ ivtest/ivltests/nb_ec_real.v | 17 ++++++++++++++ ivtest/ivltests/nb_ec_vector.v | 17 ++++++++++++++ 7 files changed, 118 insertions(+) diff --git a/ivtest/ivltests/nb_ec_array.v b/ivtest/ivltests/nb_ec_array.v index eca60ee65..674509e4f 100644 --- a/ivtest/ivltests/nb_ec_array.v +++ b/ivtest/ivltests/nb_ec_array.v @@ -78,6 +78,23 @@ module top; pass = 1'b0; end + // These should execute as if there was no event control + result[0] <= repeat(0) @(posedge clk) 4'h4; + #1 + if ($simtime != 171 || result[0] !== 4'h4) begin + $display("Failed @ at %0t, expected 4'h4, got %h", + $simtime, result[0]); + pass = 1'b0; + end + + result[0] <= repeat(-1) @(posedge clk) 4'h5; + #1 + if ($simtime != 172 || result[0] !== 4'h5) begin + $display("Failed @ at %0t, expected 4'h5, got %h", + $simtime, result[0]); + pass = 1'b0; + end + if (pass) $display("PASSED"); $finish; end diff --git a/ivtest/ivltests/nb_ec_array_pv.v b/ivtest/ivltests/nb_ec_array_pv.v index a23ce06bc..357d96c0f 100644 --- a/ivtest/ivltests/nb_ec_array_pv.v +++ b/ivtest/ivltests/nb_ec_array_pv.v @@ -81,6 +81,16 @@ module top; pass = 1'b0; end + // These should execute as if there was no event control + result[0][3:0] <= repeat(0) @(posedge clk) 4'h3; + result[0][7:4] <= repeat(-1) @(posedge clk) 4'h4; + #1 + if ($simtime != 171 || result[0] !== 8'h43) begin + $display("Failed @ at %0t, expected 8'h43, got %h", + $simtime, result[0]); + pass = 1'b0; + end + if (pass) $display("PASSED"); $finish; end diff --git a/ivtest/ivltests/nb_ec_array_pv2.v b/ivtest/ivltests/nb_ec_array_pv2.v index b8434b5cb..bdb2c930e 100644 --- a/ivtest/ivltests/nb_ec_array_pv2.v +++ b/ivtest/ivltests/nb_ec_array_pv2.v @@ -84,6 +84,16 @@ module top; pass = 1'b0; end + // These should execute as if there was no event control + result[j][i+:4] <= repeat(0) @(posedge clk) 4'h3; + result[j][i+4+:4] <= repeat(-1) @(posedge clk) 4'h4; + #1 + if ($simtime != 171 || result[j] !== 8'h43) begin + $display("Failed @ at %0t, expected 8'h43, got %h", + $simtime, result[j]); + pass = 1'b0; + end + if (pass) $display("PASSED"); $finish; end diff --git a/ivtest/ivltests/nb_ec_pv.v b/ivtest/ivltests/nb_ec_pv.v index 4d65f5fc0..c44cdc3a2 100644 --- a/ivtest/ivltests/nb_ec_pv.v +++ b/ivtest/ivltests/nb_ec_pv.v @@ -78,6 +78,16 @@ module top; pass = 1'b0; end + // These should execute as if there was no event control + result[3:0] <= repeat(0) @(posedge clk) 4'h3; + result[7:4] <= repeat(-1) @(posedge clk) 4'h4; + #1 + if ($simtime != 171 || result !== 8'h43) begin + $display("Failed @ at %0t, expected 8'h43, got %h", + $simtime, result); + pass = 1'b0; + end + if (pass) $display("PASSED"); $finish; end diff --git a/ivtest/ivltests/nb_ec_pv2.v b/ivtest/ivltests/nb_ec_pv2.v index 80260b4a7..112ff0d21 100644 --- a/ivtest/ivltests/nb_ec_pv2.v +++ b/ivtest/ivltests/nb_ec_pv2.v @@ -5,6 +5,7 @@ module top; reg clk = 0; reg [7:0] result; reg [3:0] bit; + integer count; always #10 clk = ~clk; @@ -12,6 +13,7 @@ module top; // Since the bit is not defined this assignment will not happen. // We will check to verify this fact 1 time step after it should // happen (50). + #0; result[bit] <= repeat(3) @(posedge clk) 1'b0; if ($simtime != 0 || result !== 8'bx) begin $display("Failed repeat(3) blocked at %0t, expected 8'hxx, got %h", @@ -34,6 +36,41 @@ module top; pass = 1'b0; end + // These should execute as if there was no event control + count = 0; + result[bit] <= repeat(count) @(posedge clk) 1'b1; + #1 + if ($simtime != 71 || result !== 8'bxxxxxxx1) begin + $display("Failed @ at %0t, expected 8'bxxxxxxx1, got %h", + $simtime, result); + pass = 1'b0; + end + + count = -1; + result[bit+1] <= repeat(count) @(posedge clk) 1'b0; + #1 + if ($simtime != 72 || result !== 8'bxxxxxx01) begin + $display("Failed @ at %0t, expected 8'bxxxxxx01, got %h", + $simtime, result); + pass = 1'b0; + end + + result[bit+2] <= repeat(0) @(posedge clk) 1'b1; + #1 + if ($simtime != 73 || result !== 8'bxxxxx101) begin + $display("Failed @ at %0t, expected 8'bxxxxx101, got %h", + $simtime, result); + pass = 1'b0; + end + + result[bit+3] <= repeat(-1) @(posedge clk) 1'b0; + #1 + if ($simtime != 74 || result !== 8'bxxxx0101) begin + $display("Failed @ at %0t, expected 8'bxxxx0101, got %h", + $simtime, result); + pass = 1'b0; + end + if (pass) $display("PASSED"); $finish; end diff --git a/ivtest/ivltests/nb_ec_real.v b/ivtest/ivltests/nb_ec_real.v index 2ceba1a21..3334d247d 100644 --- a/ivtest/ivltests/nb_ec_real.v +++ b/ivtest/ivltests/nb_ec_real.v @@ -78,6 +78,23 @@ module top; pass = 1'b0; end + // These should execute as if there was no event control + result <= repeat(0) @(posedge clk) 4.0; + #1 + if ($simtime != 171 || result != 4.0) begin + $display("Failed @ at %0t, expected 4.0, got %f", + $simtime, result); + pass = 1'b0; + end + + result <= repeat(-1) @(posedge clk) 5.0; + #1 + if ($simtime != 172 || result != 5.0) begin + $display("Failed @ at %0t, expected 5.0, got %f", + $simtime, result); + pass = 1'b0; + end + if (pass) $display("PASSED"); $finish; end diff --git a/ivtest/ivltests/nb_ec_vector.v b/ivtest/ivltests/nb_ec_vector.v index 0c6238a37..5c3dd8b26 100644 --- a/ivtest/ivltests/nb_ec_vector.v +++ b/ivtest/ivltests/nb_ec_vector.v @@ -78,6 +78,23 @@ module top; pass = 1'b0; end + // These should execute as if there was no event control + result <= repeat(0) @(posedge clk) 4'h4; + #1 + if ($simtime != 171 || result !== 4'h4) begin + $display("Failed @ at %0t, expected 4'h4, got %h", + $simtime, result); + pass = 1'b0; + end + + result <= repeat(-1) @(posedge clk) 4'h5; + #1 + if ($simtime != 172 || result !== 4'h5) begin + $display("Failed @ at %0t, expected 4'h5, got %h", + $simtime, result); + pass = 1'b0; + end + if (pass) $display("PASSED"); $finish; end From aafda65b99aaff7d930347d9b36b62fe4655f45f Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 21 May 2026 05:19:53 -0700 Subject: [PATCH 098/102] Cppcheck cleanup --- PGate.h | 2 +- cppcheck.sup | 50 +++++++++++++------------- driver/cppcheck.sup | 2 ++ elaborate.cc | 2 +- net_link.cc | 10 +++--- net_scope.cc | 10 +++--- netlist.h | 8 ++--- parse.y | 8 ++--- pform.cc | 2 +- pform.h | 2 +- pform_types.h | 2 +- t-dll.cc | 8 ++--- t-dll.h | 2 +- tgt-fpga/device.h | 4 +-- tgt-fpga/tables.c | 8 ++--- tgt-fpga/xilinx.c | 78 ++++++++++++++++++++--------------------- tgt-fpga/xilinx.h | 44 +++++++++++------------ tgt-pcb/cppcheck.sup | 2 ++ tgt-vhdl/vhdl_syntax.cc | 4 +-- tgt-vhdl/vhdl_syntax.hh | 2 +- vhdlpp/architec_emit.cc | 4 +-- vhdlpp/cppcheck.sup | 3 ++ vhdlpp/library.cc | 2 +- vpi/cppcheck.sup | 4 +++ vvp/compile.cc | 18 +++++----- vvp/compile.h | 4 +-- vvp/delay.cc | 2 +- vvp/vpip_to_dec.cc | 16 ++++----- vvp/vvp_island.h | 2 +- 29 files changed, 159 insertions(+), 146 deletions(-) diff --git a/PGate.h b/PGate.h index 84e172377..ca67bd4e6 100644 --- a/PGate.h +++ b/PGate.h @@ -235,7 +235,7 @@ class PGModule : public PGate { unsigned nparms_; friend class delayed_elaborate_scope_mod_instances; - void elaborate_mod_(Design*, Module*mod, NetScope*scope) const; + void elaborate_mod_(Design*, const Module*mod, NetScope*scope) const; void elaborate_udp_(Design*, PUdp *udp, NetScope*scope) const; void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const; void elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const; diff --git a/cppcheck.sup b/cppcheck.sup index 1147d347e..f4e70d72d 100644 --- a/cppcheck.sup +++ b/cppcheck.sup @@ -10,9 +10,9 @@ nullPointerOutOfMemory ctuuninitvar:parse_misc.cc:61 // Skip strdup() not constant. -constVariablePointer:main.cc:415 -constVariablePointer:main.cc:419 -constVariablePointer:main.cc:669 +constVariablePointer:main.cc:421 +constVariablePointer:main.cc:425 +constVariablePointer:main.cc:675 // const auto should be const constVariablePointer:elab_expr.cc:344 @@ -24,9 +24,9 @@ constParameterReference:net_udp.cc:37 // These cannot be static since they access object data functionStatic:net_link.cc:178 -functionStatic:net_link.cc:183 -functionStatic:net_link.cc:188 -functionStatic:net_link.cc:193 +functionStatic:net_link.cc:184 +functionStatic:net_link.cc:189 +functionStatic:net_link.cc:194 // This cannot be static when checking with valgrind functionStatic:libmisc/StringHeap.cc @@ -36,23 +36,23 @@ uninitMemberVar:t-dll.cc:41 uninitMemberVar:t-dll.cc:109 // By convention we put statics at the top scope. -variableScope:pform.cc:3461 +variableScope:pform.cc:3499 // These are correct and are used to find the base (zero) pin. -thisSubtraction:netlist.h:5310 -thisSubtraction:netlist.h:5319 +thisSubtraction:netlist.h:5376 +thisSubtraction:netlist.h:5385 // This is used when running a debugger // debugger_release -knownConditionTrueFalse:main.cc:949 +knownConditionTrueFalse:main.cc:955 // These should be checked, but are not real issues -knownConditionTrueFalse:elaborate.cc:7633 -knownConditionTrueFalse:elab_sig.cc:271 -knownConditionTrueFalse:elab_sig.cc:338 +knownConditionTrueFalse:elaborate.cc:7970 +knownConditionTrueFalse:elab_sig.cc:272 +knownConditionTrueFalse:elab_sig.cc:345 // Yes, it's a duplicate -duplicateCondition:elaborate.cc:7684 +duplicateCondition:elaborate.cc:8021 // To complicated to use std::find_if() useStlAlgorithm:map_named_args.cc:38 @@ -722,31 +722,33 @@ unusedFunction:Statement.h:192 // chain_args() unusedFunction:Statement.h:341 // gn_modules_nest() -unusedFunction:compiler.h:245 +unusedFunction:compiler.h:247 // driven_mask() unusedFunction:link_const.cc:275 // find_root_scope() unusedFunction:net_design.cc:121 // assign_lval() -unusedFunction:net_link.cc:282 +unusedFunction:net_link.cc:283 // intersect() -unusedFunction:net_link.cc:689 +unusedFunction:net_link.cc:687 // get_def_fileline() unusedFunction:net_scope.cc:201 // get_module_port_info() -unusedFunction:net_scope.cc:599 +unusedFunction:net_scope.cc:600 // find_link_signal() -unusedFunction:netlist.cc:111 +unusedFunction:netlist.cc:113 // find_link() -unusedFunction:netlist.cc:297 +unusedFunction:netlist.cc:304 // set_module_port_index() -unusedFunction:netlist.cc:651 +unusedFunction:netlist.cc:658 // width_a() -unusedFunction:netlist.cc:1678 +unusedFunction:netlist.cc:1685 // width_b() -unusedFunction:netlist.cc:1683 +unusedFunction:netlist.cc:1690 // result_sig() -unusedFunction:netlist.cc:2184 +unusedFunction:netlist.cc:2191 +// soft_union() +unusedFunction:netstruct.h:93 // test_protected() unusedFunction:property_qual.h:50 // test_rand() diff --git a/driver/cppcheck.sup b/driver/cppcheck.sup index 70838cc38..82ce9a74e 100644 --- a/driver/cppcheck.sup +++ b/driver/cppcheck.sup @@ -18,8 +18,10 @@ memleakOnRealloc:cfparse.y allocaCalled:cfparse.c constParameterPointer:cfparse.c constVariablePointer:cfparse.c +invalidPrintfArgType_sint:cfparse.c knownConditionTrueFalse:cfparse.c sizeofwithnumericparameter:cfparse.c +unsignedPositive:cfparse.c constVariablePointer: duplicateBreak: nullPointer: diff --git a/elaborate.cc b/elaborate.cc index 67320db99..988110c7f 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1679,7 +1679,7 @@ bool PGModule::bind_interface_ports_(Design*des, const Module*rmod, * the parameters. This is done with BUFZ gates so that they look just * like continuous assignment connections. */ -void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const +void PGModule::elaborate_mod_(Design*des, const Module*rmod, NetScope*scope) const { ivl_assert(*this, scope); diff --git a/net_link.cc b/net_link.cc index 4ef426e48..df28aaef9 100644 --- a/net_link.cc +++ b/net_link.cc @@ -169,16 +169,16 @@ void Link::drivers_delays(const delay_exprs_t &delays) find_nexus_()->drivers_delays(delays); } -void Link::drivers_drive(const drive_strength_t &drive) +void Link::drivers_drive(const drive_strength_t &drive_i) { - find_nexus_()->drivers_drive(drive); + find_nexus_()->drivers_drive(drive_i); } -void Link::drive(const drive_strength_t &drive) +void Link::drive(const drive_strength_t &drive_i) { - drive0_ = drive.drive0; - drive1_ = drive.drive1; + drive0_ = drive_i.drive0; + drive1_ = drive_i.drive1; } drive_strength_t Link::drive() const diff --git a/net_scope.cc b/net_scope.cc index bd019f93d..cd9e923d0 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -239,16 +239,16 @@ void NetScope::add_typedefs(const map*typedefs) typedefs_ = *typedefs; } -NetScope*NetScope::find_typedef_scope(const Design*des, const typedef_t*type) +NetScope*NetScope::find_typedef_scope(const Design*des, const typedef_t*type_i) { - ivl_assert(*this, type); + ivl_assert(*this, type_i); NetScope *cur_scope = this; while (cur_scope) { - auto it = cur_scope->typedefs_.find(type->name); - if (it != cur_scope->typedefs_.end() && it->second == type) + auto it = cur_scope->typedefs_.find(type_i->name); + if (it != cur_scope->typedefs_.end() && it->second == type_i) return cur_scope; - NetScope*import_scope = cur_scope->find_import(des, type->name); + NetScope*import_scope = cur_scope->find_import(des, type_i->name); if (import_scope) cur_scope = import_scope; else if (cur_scope == unit_) diff --git a/netlist.h b/netlist.h index 812372ff5..86bfb9b73 100644 --- a/netlist.h +++ b/netlist.h @@ -167,12 +167,12 @@ class Link { // A link has a drive strength for 0 and 1 values. The drive0 // strength is for when the link has the value 0, and drive1 // strength is for when the link has a value 1. - void drive(const drive_strength_t &drive); + void drive(const drive_strength_t &drive_i); drive_strength_t drive() const; // This sets the drives for all drivers of this link, and not // just the current link. - void drivers_drive(const drive_strength_t &drive); + void drivers_drive(const drive_strength_t &drive_i); ivl_drive_t drive0() const; ivl_drive_t drive1() const; @@ -308,7 +308,7 @@ class NetObj : public NetPins, public Attrib { const NetExpr *rise_time() const { return delays_.rise; } const NetExpr *fall_time() const { return delays_.fall; } const NetExpr *decay_time() const { return delays_.decay; } - delay_exprs_t delay_times() const + const delay_exprs_t &delay_times() const { return delays_; } @@ -1007,7 +1007,7 @@ class NetScope : public Definitions, public Attrib { void add_typedefs(const std::map*typedefs); /* Search the scope hierarchy for the scope where 'type' was defined. */ - NetScope*find_typedef_scope(const Design*des, const typedef_t*type); + NetScope*find_typedef_scope(const Design*des, const typedef_t*type_i); /* Parameters exist within a scope, and these methods allow one to manipulate the set. In these cases, the name is the diff --git a/parse.y b/parse.y index 8c94dd4b5..985afe40a 100644 --- a/parse.y +++ b/parse.y @@ -2925,17 +2925,17 @@ type_declaration | K_typedef identifier_name ';' { perm_string name = lex_strings.make($2); - pform_forward_typedef(@2, name, type_restrict_t::ANY); + pform_forward_typedef(@2, name, type_restrict_t(type_restrict_t::ANY)); delete[]$2; } | K_typedef forward_type_without_enum identifier_name ';' { perm_string name = lex_strings.make($3); - pform_forward_typedef(@3, name, $2); + pform_forward_typedef(@3, name, type_restrict_t($2)); delete[]$3; } | K_typedef K_enum identifier_name ';' { perm_string name = lex_strings.make($3); - pform_forward_typedef(@3, name, type_restrict_t::ENUM); + pform_forward_typedef(@3, name, type_restrict_t(type_restrict_t::ENUM)); delete[]$3; } | K_typedef error ';' @@ -4955,7 +4955,7 @@ type_param { if (generation_flag < GN_VER2023) yyerror(@1, "error: Restricted type parameters require SystemVerilog 2023 or later."); param_is_type = true; - param_type_restrict = $2; + param_type_restrict = type_restrict_t($2); } ; diff --git a/pform.cc b/pform.cc index e66d5dce8..0a62724e8 100644 --- a/pform.cc +++ b/pform.cc @@ -1418,7 +1418,7 @@ Module::port_t* pform_module_interface_port_reference( } void pform_module_define_interface_port(const struct vlltype&loc, - Module::port_t*port, + const Module::port_t*port, list*attr) { ivl_assert(loc, port); diff --git a/pform.h b/pform.h index 5fb7e5035..610dd8390 100644 --- a/pform.h +++ b/pform.h @@ -174,7 +174,7 @@ extern Module::port_t* pform_module_interface_port_reference( perm_string name, std::list*udims = 0); extern void pform_module_define_interface_port(const struct vlltype&loc, - Module::port_t*port, + const Module::port_t*port, std::list*attr); extern void pform_endmodule(const char*, bool inside_celldefine, Module::UCDriveType uc_drive_def); diff --git a/pform_types.h b/pform_types.h index 29fedb693..e16273cf6 100644 --- a/pform_types.h +++ b/pform_types.h @@ -59,7 +59,7 @@ struct type_restrict_t { }; type_restrict_t() = default; - type_restrict_t(type_t kind) : type(kind) { } + explicit type_restrict_t(type_t kind) : type(kind) { } bool merge(type_restrict_t other); bool matches(ivl_type_t type) const; diff --git a/t-dll.cc b/t-dll.cc index 6a99ec8d6..1d130dbca 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -401,13 +401,13 @@ static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net) scope->switches.push_back(net); } -ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope, +ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope_i, const char*name) { unsigned idx = 0; - while (idx < scope->param.size()) { - if (strcmp(name, scope->param[idx].basename) == 0) - return &scope->param[idx]; + while (idx < scope_i->param.size()) { + if (strcmp(name, scope_i->param[idx].basename) == 0) + return &scope_i->param[idx]; idx += 1; } diff --git a/t-dll.h b/t-dll.h index 4dc074247..44d5c3724 100644 --- a/t-dll.h +++ b/t-dll.h @@ -162,7 +162,7 @@ struct dll_target : public target_t, public expr_scan_t { static ivl_scope_t find_scope(ivl_design_s &des, const NetScope*cur); static ivl_signal_t find_signal(ivl_design_s &des, const NetNet*net); - static ivl_parameter_t scope_find_param(ivl_scope_t scope, + static ivl_parameter_t scope_find_param(ivl_scope_t scope_i, const char*name); void add_root(const NetScope *s); diff --git a/tgt-fpga/device.h b/tgt-fpga/device.h index 03cb08b1b..0c001215d 100644 --- a/tgt-fpga/device.h +++ b/tgt-fpga/device.h @@ -1,7 +1,7 @@ #ifndef IVL_device_H #define IVL_device_H /* - * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2026 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 @@ -72,6 +72,6 @@ struct device_s { * This function is used if the user specifies the architecture * explicitly, with the -parch=name flag. */ -extern device_t device_from_arch(const char*arch); +extern device_t device_from_arch(const char*arch_i); #endif /* IVL_device_H */ diff --git a/tgt-fpga/tables.c b/tgt-fpga/tables.c index 1aa44f16f..73fa608c8 100644 --- a/tgt-fpga/tables.c +++ b/tgt-fpga/tables.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2026 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 @@ -40,14 +40,14 @@ const struct device_table_s { { 0, 0 } }; -device_t device_from_arch(const char*arch) +device_t device_from_arch(const char*arch_i) { unsigned idx; - assert(arch); + assert(arch_i); for (idx = 0 ; device_table[idx].name ; idx += 1) { - if (strcmp(arch, device_table[idx].name) == 0) + if (strcmp(arch_i, device_table[idx].name) == 0) return device_table[idx].driver; } diff --git a/tgt-fpga/xilinx.c b/tgt-fpga/xilinx.c index eb1ad7738..233d58bd1 100644 --- a/tgt-fpga/xilinx.c +++ b/tgt-fpga/xilinx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2014 Stephen Williams (steve at icarus.com) + * Copyright (c) 2003-2026 Stephen Williams (steve at 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 @@ -26,80 +26,80 @@ # include # include "ivl_alloc.h" -edif_cell_t xilinx_cell_buf(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_buf(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "BUF", 2); + cell = edif_xcell_create(xlib_i, "BUF", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "BUFE", 3); + cell = edif_xcell_create(xlib_i, "BUFE", 3); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); edif_cell_portconfig(cell, BUF_T, "E", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "BUFG", 2); + cell = edif_xcell_create(xlib_i, "BUFG", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "BUFT", 3); + cell = edif_xcell_create(xlib_i, "BUFT", 3); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); edif_cell_portconfig(cell, BUF_T, "T", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "IBUF", 2); + cell = edif_xcell_create(xlib_i, "IBUF", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_inv(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_inv(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "INV", 2); + cell = edif_xcell_create(xlib_i, "INV", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "MUXF5", 4); + cell = edif_xcell_create(xlib_i, "MUXF5", 4); edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT); @@ -107,12 +107,12 @@ edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib) return cell; } -edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "MUXF6", 4); + cell = edif_xcell_create(xlib_i, "MUXF6", 4); edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT); @@ -120,36 +120,36 @@ edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib) return cell; } -edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell) return cell; - cell = edif_xcell_create(xlib, "OBUF", 2); + cell = edif_xcell_create(xlib_i, "OBUF", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "LUT2", 3); + cell = edif_xcell_create(xlib_i, "LUT2", 3); edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "LUT3", 4); + cell = edif_xcell_create(xlib_i, "LUT3", 4); edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT); @@ -157,12 +157,12 @@ edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib) return cell; } -edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "LUT4", 5); + cell = edif_xcell_create(xlib_i, "LUT4", 5); edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT); @@ -172,12 +172,12 @@ edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib) } -edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "FDCE", 5); + cell = edif_xcell_create(xlib_i, "FDCE", 5); edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT); @@ -186,12 +186,12 @@ edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib) return cell; } -edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "FDCPE", 6); + cell = edif_xcell_create(xlib_i, "FDCPE", 6); edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT); @@ -201,12 +201,12 @@ edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib) return cell; } -edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "FDRE", 5); + cell = edif_xcell_create(xlib_i, "FDRE", 5); edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT); @@ -216,24 +216,24 @@ edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib) } -edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "MULT_AND", 3); + cell = edif_xcell_create(xlib_i, "MULT_AND", 3); edif_cell_portconfig(cell, MULT_AND_LO, "LO", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MULT_AND_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, MULT_AND_I1, "I1", IVL_SIP_INPUT); return cell; } -edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "MUXCY", 4); + cell = edif_xcell_create(xlib_i, "MUXCY", 4); edif_cell_portconfig(cell, MUXCY_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT); @@ -241,12 +241,12 @@ edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib) return cell; } -edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "MUXCY_L", 4); + cell = edif_xcell_create(xlib_i, "MUXCY_L", 4); edif_cell_portconfig(cell, MUXCY_O, "LO", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT); @@ -254,12 +254,12 @@ edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib) return cell; } -edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib) +edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib_i) { static edif_cell_t cell = 0; if (cell != 0) return cell; - cell = edif_xcell_create(xlib, "XORCY", 3); + cell = edif_xcell_create(xlib_i, "XORCY", 3); edif_cell_portconfig(cell, XORCY_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, XORCY_CI, "CI", IVL_SIP_INPUT); edif_cell_portconfig(cell, XORCY_LI, "LI", IVL_SIP_INPUT); diff --git a/tgt-fpga/xilinx.h b/tgt-fpga/xilinx.h index b3b0ae7ac..70f241614 100644 --- a/tgt-fpga/xilinx.h +++ b/tgt-fpga/xilinx.h @@ -1,7 +1,7 @@ #ifndef IVL_xilinx_H #define IVL_xilinx_H /* - * Copyright (c) 2003-2014 Stephen Williams (steve at icarus.com) + * Copyright (c) 2003-2026 Stephen Williams (steve at 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 @@ -34,13 +34,13 @@ /* Buffer types of devices have the BUF_O and BUF_I pin assignments. The BUF, INV, and certain specialized devices fit in this category. */ -extern edif_cell_t xilinx_cell_buf (edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_inv (edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib); +extern edif_cell_t xilinx_cell_buf (edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_inv (edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib_i); #define BUF_O 0 #define BUF_I 1 /* Only bufe and buft buffers have this input. */ @@ -52,9 +52,9 @@ extern edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib); 2, 3 or 4 inputs. All forms have a single bit output. Also, the real behavior of the device will need to be specified by an INIT parameter string. */ -extern edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib); +extern edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib_i); #define LUT_O 0 #define LUT_I0 1 #define LUT_I1 2 @@ -67,9 +67,9 @@ extern edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib); /* * These are flip-flops of various sort, but similar pinouts. */ -extern edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib); +extern edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib_i); #define FDCE_Q 0 #define FDCE_C 1 #define FDCE_D 2 @@ -80,28 +80,28 @@ extern edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib); /* === Virtex/Virtex2 Carry Chain Logic === */ -extern edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib); +extern edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib_i); #define MULT_AND_LO 0 #define MULT_AND_I0 1 #define MULT_AND_I1 2 -extern edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib); +extern edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib_i); #define MUXCY_O 0 #define MUXCY_DI 1 #define MUXCY_CI 2 #define MUXCY_S 3 -extern edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib); +extern edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib_i); #define XORCY_O 0 #define XORCY_CI 1 #define XORCY_LI 2 /* === Virtex/Virtex2 MUX devices */ -extern edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_muxf7(edif_xlibrary_t xlib); -extern edif_cell_t xilinx_cell_muxf8(edif_xlibrary_t xlib); +extern edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_muxf7(edif_xlibrary_t xlib_i); +extern edif_cell_t xilinx_cell_muxf8(edif_xlibrary_t xlib_i); #define MUXF_O 0 #define MUXF_I0 1 #define MUXF_I1 2 diff --git a/tgt-pcb/cppcheck.sup b/tgt-pcb/cppcheck.sup index b79920b11..0599400b1 100644 --- a/tgt-pcb/cppcheck.sup +++ b/tgt-pcb/cppcheck.sup @@ -10,7 +10,9 @@ unusedFunction:pcb.cc:84 // Errors/limitations in the generated yacc and lex files duplicateBreak:fp.lex constParameterPointer:fp.cc +invalidPrintfArgType_sint:fp.cc knownConditionTrueFalse:fp.cc +unsignedPositive:fp.cc constVariablePointer:fp_lex.cc cstyleCast:fp_lex.cc duplicateBreak:fp_lex.cc diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index d62daefa5..763a31e07 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -286,9 +286,9 @@ void stmt_container::find_vars(vhdl_var_set_t& read, (*it)->find_vars(read, write); } -void stmt_container::emit(std::ostream &of, int level, bool newline) const +void stmt_container::emit(std::ostream &of, int level, bool trailing_newln) const { - emit_children(of, stmts_, level, "", newline); + emit_children(of, stmts_, level, "", trailing_newln); } vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index e74d564af..66b2e8903 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -360,7 +360,7 @@ public: void add_stmt(vhdl_seq_stmt *stmt); void move_stmts_from(stmt_container *other); - void emit(std::ostream &of, int level, bool newline=true) const; + void emit(std::ostream &of, int level, bool trailing_newln=true) const; bool empty() const { return stmts_.empty(); } void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write); diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 900dfe8c0..012c8684c 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2026 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 @@ -203,7 +203,7 @@ int CondSignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc) int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc) { - const char*comma = ""; + const char*comma; int errors = 0; arc->set_cur_component(this); diff --git a/vhdlpp/cppcheck.sup b/vhdlpp/cppcheck.sup index 5613c1c10..53b54a207 100644 --- a/vhdlpp/cppcheck.sup +++ b/vhdlpp/cppcheck.sup @@ -24,6 +24,7 @@ useStlAlgorithm // Errors/limitations in the generated yacc and lex files cstyleCast:lexor.cc constVariablePointer:lexor.cc +duplicateBreak:lexor.cc redundantInitialization:lexor.cc unusedFunction:lexor.cc unusedStructMember:lexor.cc @@ -32,7 +33,9 @@ duplicateBreak:lexor.lex redundantInitialization:lexor.lex uselessAssignmentPtrArg:lexor.lex constParameterPointer:parse.cc +invalidPrintfArgType_sint:parse.cc knownConditionTrueFalse:parse.cc +unsignedPositive:parse.cc // Unused functions unusedFunction:LineInfo.h diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index b59bc7990..b72a7d896 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -78,7 +78,6 @@ void library_add_directory(const char*directory) SubprogramHeader*library_match_subprogram(perm_string name, const list*params) { - SubprogramHeader*subp; map::const_iterator lib_it; for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) { @@ -86,6 +85,7 @@ SubprogramHeader*library_match_subprogram(perm_string name, const list::const_iterator pack_it; for(pack_it = lib.packages.begin(); pack_it != lib.packages.end(); ++pack_it) { + SubprogramHeader*subp; if((subp = pack_it->second->match_subprogram(name, params))) return subp; } diff --git a/vpi/cppcheck.sup b/vpi/cppcheck.sup index 078495990..c69de0859 100644 --- a/vpi/cppcheck.sup +++ b/vpi/cppcheck.sup @@ -280,6 +280,8 @@ unusedFunction:fastlz.c:418 // lz4.c from GTKWave bitwiseOnBoolean:lz4.c constVariablePointer:lz4.c +invalidPrintfArgType_sint:lz4.c +invalidPrintfArgType_uint:lz4.c staticFunction:lz4.c syntaxError:lz4.c unusedStructMember:lz4.c @@ -359,6 +361,8 @@ variableScope:sys_random.c:47 variableScope:sys_random.c:70 variableScope:sys_random.c:93 variableScope:sys_random.c:148 +// Also a comparison warning. +compareValueOutOfTypeRangeError:sys_random.c:195 // Issues in Lex/Yacc files allocaCalled:sdf_parse.c diff --git a/vvp/compile.cc b/vvp/compile.cc index 5c0460086..7cfa13005 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1573,7 +1573,7 @@ struct __vpiModPath* compile_modpath(char*label, unsigned width, } static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path, - char edge, + char edge_c, const struct symb_s&src, struct numbv_s&vals, bool ifnone) @@ -1591,12 +1591,12 @@ static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path, vvp_fun_modpath_src*obj = 0; int vpi_edge = vpiNoEdge; - if (edge == 0) { + if (edge_c == 0) { obj = new vvp_fun_modpath_src(use_delay); } else { bool posedge, negedge; - switch (edge) { + switch (edge_c) { case '+': vpi_edge = vpiPosedge; posedge = true; @@ -1616,8 +1616,8 @@ static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path, default: posedge = false; negedge = false; - fprintf(stderr, "Unknown edge identifier %c(%d).\n", edge, - edge); + fprintf(stderr, "Unknown edge identifier %c(%d).\n", edge_c, + edge_c); assert(0); } obj = new vvp_fun_modpath_edge(use_delay, posedge, negedge); @@ -1636,19 +1636,19 @@ static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path, return srcobj; } -void compile_modpath_src(struct __vpiModPath*dst, char edge, +void compile_modpath_src(struct __vpiModPath*dst, char edge_c, const struct symb_s&src, struct numbv_s&vals, const struct symb_s&condit_src, const struct symb_s&path_term_in) { struct __vpiModPathSrc*obj = - make_modpath_src(dst, edge, src, vals, false); + make_modpath_src(dst, edge_c, src, vals, false); input_connect(obj->net, 1, condit_src.text); compile_vpi_lookup(&obj->path_term_in.expr, path_term_in.text); } -void compile_modpath_src(struct __vpiModPath*dst, char edge, +void compile_modpath_src(struct __vpiModPath*dst, char edge_c, const struct symb_s&src, struct numbv_s&vals, int condit_src, @@ -1657,7 +1657,7 @@ void compile_modpath_src(struct __vpiModPath*dst, char edge, { assert(condit_src == 0); struct __vpiModPathSrc*obj = - make_modpath_src(dst, edge, src, vals, ifnone); + make_modpath_src(dst, edge_c, src, vals, ifnone); compile_vpi_lookup(&obj->path_term_in.expr, path_term_in.text); } diff --git a/vvp/compile.h b/vvp/compile.h index d19263ae5..cccc2391a 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -242,13 +242,13 @@ extern __vpiModPath* compile_modpath(char*label, struct symb_s drv, struct symb_s dest); extern void compile_modpath_src(__vpiModPath*dst, - char edge, + char edge_c, const struct symb_s&src, struct numbv_s&vals, const struct symb_s&condit_src, const struct symb_s&path_term_in); extern void compile_modpath_src(__vpiModPath*dst, - char edge, + char edge_c, const struct symb_s&src, struct numbv_s&vals, int condit_src, /* match with '0' */ diff --git a/vvp/delay.cc b/vvp/delay.cc index 49954b13d..af5224580 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -626,7 +626,7 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, typedef list::const_iterator iter_t; iter_t cur = candidate_list.begin(); - vvp_fun_modpath_src*src = *cur; + const vvp_fun_modpath_src*src = *cur; for (unsigned idx = 0 ; idx < 12 ; idx += 1) { out_at[idx] = src->wake_time_ + src->delay_[idx]; diff --git a/vvp/vpip_to_dec.cc b/vvp/vpip_to_dec.cc index 5bb686d62..96c928c7e 100644 --- a/vvp/vpip_to_dec.cc +++ b/vvp/vpip_to_dec.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2025 Stephen Williams + * Copyright (c) 2008-2026 Stephen Williams * Copyright (c) 2002 Larry Doolittle (larry@doolittle.boa.org) * * This source code is free software; you can redistribute it @@ -58,6 +58,11 @@ #define B_ISX(x) ((x) == 2) #define B_ISZ(x) ((x) == 3) +/* Jump through some hoops so we don't have to malloc/free valv + * on every call, and implement an optional malloc-less version. */ +static unsigned long *valv=NULL; +static unsigned int vlen_alloc=0; + /* The program works by building a base BASE representation of the number * in the valv array. BBITS bits of the number can be put in at a time. * Previous values of each valv element are always less than BASE, the @@ -68,7 +73,7 @@ * less than or equal to 2^BBITS. BBITS and BASE are configured above * to depend on the "unsigned long" length of the host, for efficiency. */ -static inline void shift_in(unsigned long *valv, unsigned int vlen, unsigned long val) +static inline void shift_in(unsigned int vlen, unsigned long val) { unsigned int i; /* printf("shift in %u\n",val); */ @@ -103,11 +108,6 @@ static inline int write_digits(unsigned long v, char **buf, return zero_suppress; } -/* Jump through some hoops so we don't have to malloc/free valv - * on every call, and implement an optional malloc-less version. */ -static unsigned long *valv=NULL; -static unsigned int vlen_alloc=0; - #ifdef CHECK_WITH_VALGRIND void dec_str_delete(void) { @@ -179,7 +179,7 @@ unsigned vpip_vec4_to_dec_str(const vvp_vector4_t&vec4, if ((mbits-idx-1)%BBITS==0) { /* make negative 2's complement, not 1's complement */ if (comp && idx==mbits-1) ++val; - shift_in(valv,vlen,val); + shift_in(vlen,val); val=0; } else { val=val+val; diff --git a/vvp/vvp_island.h b/vvp/vvp_island.h index 9841f6bbe..68c31373e 100644 --- a/vvp/vvp_island.h +++ b/vvp/vvp_island.h @@ -218,7 +218,7 @@ struct vvp_island_branch { static inline vvp_branch_ptr_t next(vvp_branch_ptr_t cur) { - vvp_island_branch*ptr = cur.ptr(); + const vvp_island_branch*ptr = cur.ptr(); unsigned ab = cur.port(); return ptr->link[ab]; } From 6a6ff90197318550d1439c2d64e14cbeaeb2d0db Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Thu, 21 May 2026 09:27:48 -0700 Subject: [PATCH 099/102] Update clean target in Makefile to remove test.conf Remove test.conf from the clean target in Makefile. --- driver/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/Makefile.in b/driver/Makefile.in index 36b9abcd2..910d50599 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -82,7 +82,7 @@ clean: rm -f *.o cflexor.c cfparse.c cfparse.h cfparse.output rm -f iverilog@EXEEXT@ iverilog.man iverilog.pdf iverilog.ps rm -rf dep - rm -f test.conf top.vvp + rm -f top.vvp distclean: clean rm -f Makefile config.log From 297dbe94c28f17c1e4133da893d81f83eaa5654c Mon Sep 17 00:00:00 2001 From: Cookie Date: Fri, 22 May 2026 14:42:26 +0800 Subject: [PATCH 100/102] Ignore configure generated files --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4547e8487..1abf677d2 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ config.h stamp-*-h /version.h /version_tag.h +/version_base.h # Directories autom4te.cache @@ -94,6 +95,7 @@ dep /vvp/dump.* /vvp/lexor.cc +/vvp/libvvp.pc /vvp/parse.cc /vvp/parse.h /vvp/parse.output @@ -103,6 +105,7 @@ dep /iverilog-vpi.man /driver-vpi/res.rc +/driver-vpi/iverilog-vpi.man /driver/iverilog.man /vvp/vvp.man @@ -118,4 +121,4 @@ dep /vvp/vvp.exp # Check output -/check.vvp +/check.vvp \ No newline at end of file From e54b404700d46c38d0ad8e0737437ba49b4fd09c Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 22 May 2026 00:27:29 -0700 Subject: [PATCH 101/102] Update driver make check to work with all systems --- Makefile.in | 7 ++++--- configure.ac | 16 +++++++--------- driver/Makefile.in | 25 +++++++++++-------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Makefile.in b/Makefile.in index 4b01f6730..2503db9c7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -140,12 +140,13 @@ dosify$(BUILDEXT): $(srcdir)/dosify.c $(BUILDCC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o dosify$(BUILDEXT) $(srcdir)/dosify.c endif -# This rule rules the compiler in the trivial hello.vl program to make -# sure the basics were compiled properly. +# This rule runs the compiler using the trivial hello.vl program to make sure +# the base programs are compiled properly. check: all $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true + rm -f check.vvp test -r check.conf || cp $(srcdir)/check.conf . - driver/iverilog@EXEEXT@ -B. -BMvpi -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl + driver/iverilog@EXEEXT@ -B. -BMvpi -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl && \ $(ENV_VVP) vvp/vvp$(suffix)@EXEEXT@ -M- -M./vpi ./check.vvp | grep 'Hello, World' check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py: diff --git a/configure.ac b/configure.ac index 5560dc981..9ad90e571 100644 --- a/configure.ac +++ b/configure.ac @@ -98,21 +98,19 @@ AC_SUBST(EXEEXT) # Combined check for Microsoft-related bogosities; sets WIN32 if found AX_WIN32 -# detect msys shell -AC_MSG_CHECKING([whether the shell is an MSYS2 runtime shell]) +# Detect which directory/file separator to use +AC_MSG_CHECKING([for directory/file separator]) AS_CASE([$host_os:$MSYSTEM], - [*mingw*:UCRT64|*mingw*:MINGW64|*mingw*:MINGW32|*mingw*:CLANG64], [ - MSYS_SHELL=true - msys_shell_result=yes + [*mingw*:UCRT64|*mingw*:MINGW64|*mingw*:MINGW32|*mingw*:CLANG64|*mingw*:CLANGARM64], [ + PATH_SEP=\\\\ ], [ - MSYS_SHELL=false - msys_shell_result=no + PATH_SEP=/ ] ) -AC_MSG_RESULT([$msys_shell_result]) -AC_SUBST([MSYS_SHELL]) +AC_MSG_RESULT([$PATH_SEP]) +AC_SUBST([PATH_SEP]) # Check to see if we are using the Sun compiler. If so then configure # some of the flags to match the Sun compiler syntax. This is also used diff --git a/driver/Makefile.in b/driver/Makefile.in index 910d50599..91e472816 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -19,7 +19,7 @@ SHELL = /bin/sh EXEEXT = @EXEEXT@ ENV_VVP=@ENV_VVP@ -MSYS_SHELL=@MSYS_SHELL@ +PATH_SEP=@PATH_SEP@ suffix = @install_suffix@ @@ -64,19 +64,16 @@ O = main.o substit.o cflexor.o cfparse.o all: dep iverilog@EXEEXT@ iverilog.man check: all - @if $(MSYS_SHELL); then \ - echo "iverilog: execution from a build directory not suppported for this runtime"; \ - else \ - echo "iverilog: create .vpp from .v file and run it"; \ - $(builddir)/iverilog@EXEEXT@ \ - -B$(top_builddir)/tgt-vvp \ - -BI$(top_builddir) \ - -BM$(top_builddir)/vpi \ - -BP$(top_builddir)/ivlpp \ - -Bt$(top_builddir)/tgt-vvp \ - $(verbose) -o top.vvp -s top $(srcdir)/hello_world.v; \ - $(ENV_VVP) $(top_builddir)/vvp/vvp$(suffix)@EXEEXT@ top.vvp; \ - fi + @echo "driver/iverilog: create a vvp file and then run it." + @rm -f top.vvp + @$(builddir)/iverilog@EXEEXT@ \ + -B$(top_builddir)$(PATH_SEP)tgt-vvp \ + -BI$(top_builddir) \ + -BM$(top_builddir)$(PATH_SEP)vpi \ + -BP$(top_builddir)$(PATH_SEP)ivlpp \ + -Bt$(top_builddir)$(PATH_SEP)tgt-vvp \ + $(verbose) -o top.vvp -s top $(srcdir)/hello_world.v && \ + $(ENV_VVP) $(top_builddir)/vvp/vvp$(suffix)@EXEEXT@ top.vvp clean: rm -f *.o cflexor.c cfparse.c cfparse.h cfparse.output From 2d3502f4b70b6ac32710266009c290288cf3a06f Mon Sep 17 00:00:00 2001 From: "Cary R." Date: Fri, 22 May 2026 10:14:31 -0700 Subject: [PATCH 102/102] Cleanup .gitignore organization and files --- .gitignore | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 1abf677d2..dafd965e3 100644 --- a/.gitignore +++ b/.gitignore @@ -35,18 +35,20 @@ Makefile /_pli_types.h config.h /tgt-pcb/pcb_config.h -/tgt-pcb/fp.cc -/tgt-pcb/fp.h -/tgt-pcb/fp.output -/tgt-pcb/fp_lex.cc /tgt-vvp/vvp_config.h /tgt-vhdl/vhdl_config.h +/vhdlpp/vhdlpp_config.h /vpi/vpi_config.h stamp-*-h -/version.h /version_tag.h /version_base.h +/driver-vpi/iverilog-vpi.man +/driver-vpi/res.rc +/driver/iverilog.man +/vvp/libvvp.pc +/vvp/vvp.man + # Directories autom4te.cache dep @@ -57,8 +59,6 @@ dep *.vpi /cadpli/cadpli.vpl -/tgt-blif/Makefile - # lex, yacc and gperf output /driver/cflexor.c /driver/cfparse.c @@ -67,14 +67,6 @@ dep /ivlpp/lexor.c -/vhdlpp/lexor.cc -/vhdlpp/lexor_keyword.cc -/vhdlpp/parse.cc -/vhdlpp/parse.h -/vhdlpp/parse.output -/vhdlpp/vhdlpp_config.h -/vhdlpp/vhdlpp - /lexor.cc /lexor_keyword.cc /parse.cc @@ -83,6 +75,17 @@ dep /syn-rules.cc /syn-rules.output +/tgt-pcb/fp.cc +/tgt-pcb/fp.h +/tgt-pcb/fp.output +/tgt-pcb/fp_lex.cc + +/vhdlpp/lexor.cc +/vhdlpp/lexor_keyword.cc +/vhdlpp/parse.cc +/vhdlpp/parse.h +/vhdlpp/parse.output + /vpi/sdf_lexor.c /vpi/sdf_parse.c /vpi/sdf_parse.h @@ -95,7 +98,6 @@ dep /vvp/dump.* /vvp/lexor.cc -/vvp/libvvp.pc /vvp/parse.cc /vvp/parse.h /vvp/parse.output @@ -103,22 +105,18 @@ dep # Program created files /vvp/tables.cc -/iverilog-vpi.man -/driver-vpi/res.rc -/driver-vpi/iverilog-vpi.man -/driver/iverilog.man -/vvp/vvp.man - # The executables. *.exe /driver/iverilog -/iverilog-vpi +/driver-vpi/iverilog-vpi /ivl /ivlpp/ivlpp +/vhdlpp/vhdlpp /vvp/vvp /ivl.exp /vvp/vvp.exp # Check output -/check.vvp \ No newline at end of file +/check.vvp +/driver/top.vvp