Merge branch 'master' into master

This commit is contained in:
Cary R. 2026-05-22 18:15:37 -07:00 committed by GitHub
commit 8cf4507fcb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
330 changed files with 5702 additions and 1445 deletions

20
.github/test.sh vendored
View File

@ -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

View File

@ -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

View File

@ -14,60 +14,82 @@ jobs:
mac:
strategy:
fail-fast: false
matrix:
libvvp: [true]
suffix: [true]
runs-on: macos-15-intel
name: '🍏 macOS'
name: 🍏 macOS${{ matrix.libvvp && ' +libvvp' || '' }}${{ matrix.suffix && ' +suffix' || '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install dependencies
run: |
brew install bison
pip3 install --break-system-packages docopt
- 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
- name: Test
run: ./.github/test.sh
run: |
make check-installed
lin:
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@v4
- uses: actions/checkout@v6
- 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-venv
python3 -m venv .venv
. .venv/bin/activate
pip install --upgrade pip
pip install -r Documentation/requirements.txt
- 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
- name: Test
run: ./.github/test.sh
run:
make check-installed
- name: Documentation
run: |
. .venv/bin/activate
cd Documentation
make html
@ -76,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}
@ -91,7 +116,7 @@ jobs:
- run: git config --global core.autocrlf input
shell: bash
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: msys2/setup-msys2@v2
with:
@ -103,16 +128,24 @@ jobs:
python-pip
mingw-w64-${{ matrix.env }}-perl
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: '>=3.5'
- 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
@ -120,13 +153,9 @@ 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
- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.msystem }}
name: 🟪 ${{ matrix.msystem }}${{ matrix.libvvp && ' +libvvp' || '' }}
path: msys2/*.zst

47
.gitignore vendored
View File

@ -8,6 +8,10 @@
*.swp
*~
# Virtual environments
.conda/
.venv/
# Top level generic files
tags
TAGS
@ -31,16 +35,19 @@ 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
/devel/
@ -53,8 +60,6 @@ dep
*.vpi
/cadpli/cadpli.vpl
/tgt-blif/Makefile
# lex, yacc and gperf output
/driver/cflexor.c
/driver/cfparse.c
@ -63,14 +68,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
@ -79,6 +76,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
@ -98,17 +106,13 @@ dep
# Program created files
/vvp/tables.cc
/iverilog-vpi.man
/driver-vpi/res.rc
/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
@ -116,3 +120,4 @@ dep
# Check output
/check.vvp
/driver/top.vvp

View File

@ -73,16 +73,29 @@ 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.
#
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
# 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,

View File

@ -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

View File

@ -0,0 +1,2 @@
sphinx==8.1.3
shibuya==2026.1.9

View File

@ -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

View File

@ -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.

View File

@ -36,9 +36,12 @@ 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
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
@ -48,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
@ -67,9 +66,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)
mandir = @mandir@
pdfdir = @docdir@
ivl_includedir = @includedir@/iverilog$(suffix)
dllib=@DLLIB@
@ -132,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 ivl@EXEEXT@ version.exe 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
@ -143,35 +140,26 @@ 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 -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 $@
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 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
rm -f lexor_keyword.cc libivl.a libvpi.a syn-rules.cc
rm -rf dep
rm -f version.exe
distclean: clean
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
@ -179,13 +167,14 @@ 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)
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 \
@ -216,6 +205,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
@ -234,26 +228,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@;$(includedir);' \
-e 's;@LIBDIR@;@libdir@;' $< > $@
chmod +x $@
endif
version.exe: $(srcdir)/version.c $(srcdir)/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
@ -280,22 +254,12 @@ 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.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 version.exe
iverilog_man.pdf: iverilog_man.ps
$(PS2PDF) $< $@
cp $@ iverilog_man_`./version.exe %M_%n`.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),
@ -321,33 +285,6 @@ version_tag.h version:
echo '#define VERSION_TAG ""' > version_tag.h; \
fi
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
endif
endif
INSTALL_DOCDIR = $(mandir)/man1
else
INSTALL_DOC = installman
INSTALL_DOCDIR = $(mandir)/man1
INSTALL_PDFDIR = $(prefix)
endif
ifeq (@MINGW32@,yes)
WIN32_INSTALL =
else
WIN32_INSTALL = installwin32
endif
install: all installdirs installfiles
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
@ -359,37 +296,24 @@ 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@"
$(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)$(INSTALL_DOCDIR)" \
"$(DESTDIR)$(INSTALL_PDFDIR)"
"$(DESTDIR)$(libdir)/ivl$(suffix)/include"
uninstall:
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
@ -397,13 +321,13 @@ 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)$(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"
do rm -f "$(DESTDIR)$(ivl_includedir)/$$f"; done
-test X$(suffix) = X || rmdir "$(DESTDIR)$(ivl_includedir)"
-include $(patsubst %.o, dep/%.d, $O)
.PHONY: check-installed check-installed-vpi check-installed-vvp check-installed-vvp-py

View File

@ -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
@ -21,13 +21,65 @@
# include "Module.h"
# include "PGate.h"
# include "PModport.h"
# include "PWire.h"
# include "parse_api.h"
# include "ivl_assert.h"
# include <iostream>
using namespace std;
list<Module::named_expr_t> Module::user_defparms;
Module::port_t::port_t()
: port_kind(P_SIGNAL), default_value(0), interface_unpacked_dimensions(0), lexical_pos(0)
{
}
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<perm_string,Module*>::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<perm_string,PModport*>::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)
@ -63,12 +115,18 @@ const vector<PEIdent*>& Module::get_port(unsigned idx) const
ivl_assert(*this, idx < ports.size());
static const vector<PEIdent*> 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);

View File

@ -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
@ -43,6 +43,7 @@ class PFunction;
class PWire;
class PProcess;
class Design;
class LineInfo;
class NetScope;
/*
@ -65,9 +66,25 @@ 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<PEIdent*> 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;
std::list<pform_range_t>*interface_unpacked_dimensions;
unsigned lexical_pos;
bool is_interface_port() const { return port_kind == P_INTERFACE; }
};
public:
@ -148,6 +165,7 @@ class Module : public PScopeExtra, public PNamedItem {
unsigned port_count() const;
const std::vector<PEIdent*>& 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)
@ -181,4 +199,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 */

View File

@ -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<NetEConst*>(rise);
const NetEConst *c_fall = dynamic_cast<NetEConst*>(fall);
const NetEConst *c_rise = dynamic_cast<const NetEConst*>(rise);
const NetEConst *c_fall = dynamic_cast<const NetEConst*>(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;
}
}

View File

@ -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;

View File

@ -1,7 +1,7 @@
#ifndef IVL_PExpr_H
#define IVL_PExpr_H
/*
* 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
@ -691,12 +691,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<netrange_t> &dims,
unsigned int cur_dim) const;
private:
char*text_;
};

View File

@ -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<PExpr*>*pins)
}
PGate::PGate(perm_string name, list<PExpr*>*pins, const list<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_delays(del);
str0_ = IVL_DR_STRONG;
str1_ = IVL_DR_STRONG;
}
PGate::PGate(perm_string name, list<PExpr*>*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<PExpr*>*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<pform_range_t>*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

30
PGate.h
View File

@ -31,6 +31,8 @@
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
@ -66,10 +68,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 +76,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<perm_string,PExpr*> attributes;
@ -109,7 +106,7 @@ class PGate : public PNamedItem {
std::list<pform_range_t>*ranges_;
ivl_drive_t str0_, str1_;
drive_strength_t strength_;
void set_pins_(std::list<PExpr*>*pins);
@ -133,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;
};
@ -236,11 +235,20 @@ 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;
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<PExpr*>&pins,
const std::vector<bool>&pins_fromwc) const;
bool match_module_ports_(Design*des, const Module*mod,
NetScope*scope,
std::vector<PExpr*>&pins,
std::vector<bool>&pins_fromwc,
std::vector<bool>&pins_is_explicitly_not_connected) const;
// Not currently used.
#if 0
bool elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const;

View File

@ -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;

1
aclocal.m4 vendored
View File

@ -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])

View File

@ -4,4 +4,4 @@ nullPointerOutOfMemory:cadpli.c:53
nullPointerOutOfMemory:cadpli.c:54
// Unused function
unusedFunction:ivl_dlfcn.h:73
unusedFunction:ivl_dlfcn.h:87

View File

@ -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
};

View File

@ -1,8 +1,35 @@
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])
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])
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"])
# 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],[
_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])
@ -71,6 +98,20 @@ AC_SUBST(EXEEXT)
# Combined check for Microsoft-related bogosities; sets WIN32 if found
AX_WIN32
# 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|*mingw*:CLANGARM64], [
PATH_SEP=\\\\
],
[
PATH_SEP=/
]
)
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
# in the aclocal.m4 file to configure the flags used to build and link
@ -190,7 +231,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)])],
@ -281,6 +329,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"
;;
@ -390,5 +441,32 @@ 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-vpi/iverilog-vpi.man
driver-vpi/res.rc
driver/Makefile
driver/iverilog.man
ivlpp/Makefile
ivtest/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
vvp/libvvp.pc
vvp/vvp.man
])
AC_OUTPUT

View File

@ -10,47 +10,49 @@ 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:421
constVariablePointer:main.cc:425
constVariablePointer:main.cc:675
// 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
// 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
// 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
variableScope:pform.cc:3499
// These are correct and are used to find the base (zero) pin.
thisSubtraction:netlist.h:5309
thisSubtraction:netlist.h:5318
thisSubtraction:netlist.h:5376
thisSubtraction:netlist.h:5385
// This is used when running a debugger
// debugger_release
knownConditionTrueFalse:main.cc:931
knownConditionTrueFalse:main.cc:955
// These should be checked, but are not real issues
knownConditionTrueFalse:elaborate.cc:7621
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:7672
duplicateCondition:elaborate.cc:8021
// 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,31 +722,33 @@ unusedFunction:Statement.h:192
// chain_args()
unusedFunction:Statement.h:341
// gn_modules_nest()
unusedFunction:compiler.h:228
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:591
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()
@ -756,13 +760,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:<stdout>
cstyleCast:<stdout>
duplicateBreak:<stdout>
nullPointer:<stdout>
redundantInitialization:<stdout>
syntaxError:<stdout>

View File

@ -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)

View File

@ -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_ <<endl;
@ -854,10 +856,8 @@ void NetSubstitute::dump_node(ostream&fd, unsigned ind) const
{
fd << setw(ind) << "" << "NetSubstitute: "
<< name();
if (rise_time())
fd << " #(" << *rise_time()
<< "," << *fall_time()
<< "," << *decay_time() << ")";
if (delay_times().has_delay())
fd << " #(" << delay_times() << ")";
else
fd << " #(.,.,.)";
fd << " width=" << wid_ << " base=" << off_ <<endl;
@ -877,10 +877,8 @@ void NetReplicate::dump_node(ostream&o, unsigned ind) const
void NetSignExtend::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NetSignExtend: " << name();
if (rise_time())
o << " #(" << *rise_time()
<< "," << *fall_time()
<< "," << *decay_time() << ")";
if (delay_times().has_delay())
o << " #(" << delay_times() << ")";
else
o << " #(.,.,.)";
o << " output width=" << width_ << endl;
@ -914,8 +912,7 @@ void NetUReduce::dump_node(ostream&o, unsigned ind) const
o << "xnor";
break;
}
o << " #(" << rise_time()
<< "," << fall_time() << "," << decay_time() << ") " << name()
o << " #(" << delay_times() << ") " << name()
<< " scope=" << scope_path(scope())
<< endl;
@ -935,10 +932,8 @@ void NetUserFunc::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "USER FUNC: "
<< scope_path(def_);
if (rise_time())
o << " #(" <<*rise_time()
<<","<<*fall_time()
<< "," <<*decay_time() << ")";
if (delay_times().has_delay())
o << " #(" << delay_times() << ")";
o << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
@ -986,14 +981,7 @@ void NetTran::dump_node(ostream&o, unsigned ind) const
<< " part=" << part_width()
<< " offset=" << part_offset();
}
o << " delay=(";
if (rise_time())
o << *rise_time() << "," << *fall_time() << ","
<< *decay_time();
else
o << "0,0,0";
o << ")" << endl;
o << " delay=(" << delay_times() << ")" << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
@ -1001,8 +989,7 @@ void NetTran::dump_node(ostream&o, unsigned ind) const
void NetUDP::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "UDP (" << udp_name() << "): ";
o << " #(" << rise_time() << "," << fall_time() << "," << decay_time() <<
") " << name() << endl;
o << " #(" << delay_times() << ") " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);

View File

@ -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
@ -95,20 +135,39 @@ 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
#
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)"
@ -117,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"

View File

@ -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

View File

@ -17,20 +17,26 @@
#
SHELL = /bin/sh
EXEEXT = @EXEEXT@
ENV_VVP=@ENV_VVP@
PATH_SEP=@PATH_SEP@
suffix = @install_suffix@
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
datarootdir = @datarootdir@
builddir=@builddir@
top_builddir=@top_builddir@
VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
includedir = $(prefix)/include
mandir = @mandir@
pdfdir = @docdir@
man1dir = @mandir@/man1
docdir = @docdir@
dllib=@DLLIB@
@ -58,11 +64,22 @@ O = main.o substit.o cflexor.o cfparse.o
all: dep iverilog@EXEEXT@ iverilog.man
check: all
@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
rm -f iverilog@EXEEXT@ iverilog.man iverilog.pdf iverilog.ps
rm -rf dep
rm -f top.vvp
distclean: clean
rm -f Makefile config.log
@ -96,15 +113,14 @@ 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
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 ./$< > $@
@ -112,25 +128,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
@ -139,21 +145,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)

View File

@ -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
@ -18,9 +18,12 @@ 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:<stdout>
duplicateBreak:<stdout>
nullPointer:<stdout>
redundantInitialization:<stdout>
staticFunction:<stdout>

3
driver/hello_world.v Normal file
View File

@ -0,0 +1,3 @@
module top;
initial $display("Hello World!");
endmodule

View File

@ -1,12 +1,12 @@
.TH iverilog 1 "Jan 13th, 2026" "" "Version %M.%n%E"
.TH iverilog 1 "Jan 13th, 2026" "" "Version @VERSION@"
.SH NAME
iverilog - Icarus Verilog compiler
.SH SYNOPSIS
.B iverilog
[\-EiRSuVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]]
[\-EiRSuVv] [\-B[IMPVt]path] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]]
[\-Pparameter=value] [\-pflag=value] [\-dname]
[\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g<feature>]
[\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g2017\:|\-g2023\:|\-g<feature>]
[\-Iincludedir] [\-Lmoduledir] [\-mmodule] [\-M[mode=]file] [\-Nfile]
[\-ooutputfilename] [\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass]
[\-ypath] [\-lfile]
@ -21,13 +21,36 @@ 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 \-BI path
Directory for the \fIivl\fP parser.
.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.
.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
These flags specify an input file that contains a list of Verilog
@ -63,11 +86,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

View File

@ -38,8 +38,8 @@ const char NOTICE[] =
;
const char HELP[] =
"Usage: iverilog [-EiRSuvV] [-B base] [-c cmdfile|-f cmdfile]\n"
" [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g<feature>]\n"
"Usage: iverilog [-EiRSuvV] [-B[IMPVt] base] [-c cmdfile|-f cmdfile]\n"
" [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012|-g2017|-g2023] [-g<feature>]\n"
" [-D macro[=defn]] [-I includedir] [-L moduledir]\n"
" [-M [mode=]depfile] [-m module]\n"
" [-N file] [-o filename] [-p flag=value]\n"
@ -112,6 +112,8 @@ 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;
const char*vhdlpp_work = 0;
@ -340,7 +342,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 +449,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);
@ -740,6 +742,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 +868,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"
@ -1216,6 +1226,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;
@ -1225,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;
@ -1367,8 +1383,12 @@ 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;
if (tconfig_dir == 0)
tconfig_dir = base;
if (version_flag || verbose_flag) {
printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n");
@ -1378,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);
@ -1388,11 +1408,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 +1429,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);
}

View File

@ -499,6 +499,9 @@ NetExpr* PEAssignPattern::elaborate_expr_uarray_(Design *des, NetScope *scope,
if (const auto ap = dynamic_cast<PEAssignPattern*>(parms_[idx])) {
expr = ap->elaborate_expr_uarray_(des, scope, uarray_type,
dims, cur_dim, need_const);
} else if (const auto s = dynamic_cast<PEString*>(parms_[idx])) {
expr = s->elaborate_expr_uarray_(des, scope, uarray_type,
dims, cur_dim);
} else if (dynamic_cast<PEConcat*>(parms_[idx])) {
cerr << get_fileline() << ": sorry: "
<< "Array concatenation is not yet supported."
@ -6186,20 +6189,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<const NetEConstEnum*> (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_;
@ -6827,6 +6816,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 "
@ -8816,19 +8808,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<PEAssignPattern*> (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<const netarray_t*> (ntype);
init_val = init_->elaborate_expr(des, scope, array_type, flags);
}
NetENew*tmp = new NetENew(ntype, size, init_val);
@ -9151,13 +9132,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<netrange_t> &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<NetExpr*> 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<const netuarray_t*>(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;
}
/*

View File

@ -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;
}

View File

@ -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) {
@ -557,6 +563,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_
@ -616,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
@ -751,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
@ -761,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<long> unpacked_indices_const;
@ -931,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(),
@ -941,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

View File

@ -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,12 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
if (pp == 0)
continue;
if (pp->is_interface_port()) {
interface_formal_port_t formal;
resolve_interface_formal_port(this, des, pp, formal, true);
continue;
}
// The port has a name and an array of expressions. The
// expression are all identifiers that should reference
// wires within the scope.
@ -451,6 +458,12 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
NetScope::scope_vec_t instance = scope->instance_arrays[get_name()];
vector<PExpr*>pins (rmod->port_count());
vector<bool>pins_fromwc (rmod->port_count(), false);
vector<bool>pins_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.
@ -466,6 +479,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;
@ -1176,8 +1192,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope)
pull = new NetLogic(scope, scope->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;
}

View File

@ -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<struct_member_t*>::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;
@ -450,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<const netenum_t *>(elab_type);
break;
case STRUCT: {
const netstruct_t *struct_type = dynamic_cast<const netstruct_t *>(elab_type);
type_ok = struct_type && !struct_type->union_flag();
break;
}
case UNION: {
const netstruct_t *struct_type = dynamic_cast<const netstruct_t *>(elab_type);
type_ok = struct_type && struct_type->union_flag();
break;
}
case CLASS:
type_ok = dynamic_cast<const netclass_t *>(elab_type);
break;
default:
break;
}
bool type_ok = basic_type.matches(elab_type);
if (!type_ok) {
cerr << data_type->get_fileline() << " error: "

View File

@ -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
@ -52,6 +52,7 @@
# include "netscalar.h"
# include "netclass.h"
# include "netmisc.h"
# include "PModport.h"
# include "util.h"
# include "parse_api.h"
# include "compiler.h"
@ -115,19 +116,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;
@ -135,8 +133,8 @@ 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) {
elaborate_unpacked_array_(des, scope, lval);
if (lval->unpacked_dimensions() > 0) {
elaborate_unpacked_array_(des, scope, lval, drive, delays);
return;
}
@ -214,7 +212,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<NetESelect*>(rval_expr)) ||
(dynamic_cast<NetEConcat*>(rval_expr)))) {
need_driver_flag = true;
@ -242,11 +240,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));
@ -267,7 +265,8 @@ NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &l
<< endl;
des->errors++;
return nullptr;
} else if (dynamic_cast<PEAssignPattern*> (expr)) {
} else if (dynamic_cast<PEAssignPattern*> (expr) ||
dynamic_cast<PEString*> (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);
@ -313,11 +312,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,
@ -825,8 +827,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;
@ -858,12 +861,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]);
@ -1203,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<PEIdent*> (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) {
@ -1237,32 +1247,12 @@ void elaborate_unpacked_port(Design *des, NetScope *scope, NetNet *port_net,
assign_unpacked_with_bufz(des, scope, port_net, port_net, expr_net);
}
/*
* Instantiate a module by recursively elaborating it. Set the path of
* the recursive elaboration so that signal names get properly
* set. Connect the ports of the instantiated module to the signals of
* 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
bool PGModule::match_module_ports_(Design*des, const Module*rmod,
NetScope*scope,
vector<PExpr*>&pins,
vector<bool>&pins_fromwc,
vector<bool>&pins_is_explicitly_not_connected) const
{
ivl_assert(*this, scope);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Instantiate module "
<< rmod->mod_name() << " with instance name "
<< get_name() << " in scope " << scope_path(scope) << endl;
}
// This is the array of pin expressions, shuffled to match the
// order of the declaration. If the source instantiation uses
// bind by order, this is the same as the source list. Otherwise,
// the source list is rearranged by name binding into this list.
vector<PExpr*>pins (rmod->port_count());
vector<bool>pins_fromwc (rmod->port_count(), false);
vector<bool>pins_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.
@ -1271,8 +1261,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// Scan the bindings, matching them with port names.
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
// Handle wildcard named port
// 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]) {
@ -1281,7 +1270,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
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[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true);
pins[j]->set_lineno(get_lineno());
pins[j]->set_file(get_file());
@ -1307,7 +1298,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
}
// If I am overriding a wildcard port, delete and
// override it
// override it.
if (pins_fromwc[pidx]) {
delete pins[pidx];
pins_fromwc[pidx] = false;
@ -1331,36 +1322,387 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
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 */
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;
return false;
}
std::copy(get_pins().begin(), get_pins().end(), pins.begin());
}
return true;
}
struct interface_actual_scope_t {
interface_actual_scope_t() : scope(nullptr), modport(nullptr) { }
NetScope*scope;
const PModport*modport;
perm_string display_name;
};
struct interface_actual_array_t {
std::map<long,NetScope::interface_port_alias_t> 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,
interface_actual_scope_t&res)
{
res = interface_actual_scope_t();
const PEIdent*actual_ident = dynamic_cast<const PEIdent*>(actual);
if (!actual_ident || actual_ident->path().package ||
actual_ident->path().name.size() != 1 ||
actual_ident->path().name.front().index.size() > 1) {
return false;
}
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(),
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;
}
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<const PEIdent*>(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()) {
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];
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, nullptr);
}
return true;
}
const map<long,NetScope::interface_port_alias_t>*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,
const vector<PExpr*>&pins,
const vector<bool>&) 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[idx]) {
cerr << get_fileline() << ": error: Interface port `"
<< port->name << "' of module " << rmod->mod_name()
<< " is not connected." << endl;
des->errors += 1;
flag = false;
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 != nullptr;
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 (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()) {
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 `"
<< port->name << "' must be connected to a simple "
"interface instance name." << endl;
des->errors += 1;
flag = false;
continue;
}
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() != formal.module->mod_name()) {
cerr << pins[idx]->get_fileline() << ": error: Interface port `"
<< port->name << "' expects interface type `"
<< port->interface_type << "' but actual `" << actual.display_name
<< "' has type `" << actual.scope->module_name() << "'." << endl;
des->errors += 1;
flag = false;
continue;
}
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.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,
modport);
}
return flag;
}
/*
* Instantiate a module by recursively elaborating it. Set the path of
* the recursive elaboration so that signal names get properly
* set. Connect the ports of the instantiated module to the signals of
* the parameters. This is done with BUFZ gates so that they look just
* like continuous assignment connections.
*/
void PGModule::elaborate_mod_(Design*des, const Module*rmod, NetScope*scope) const
{
ivl_assert(*this, scope);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Instantiate module "
<< rmod->mod_name() << " with instance name "
<< get_name() << " in scope " << scope_path(scope) << endl;
}
// This is the array of pin expressions, shuffled to match the
// order of the declaration. If the source instantiation uses
// bind by order, this is the same as the source list. Otherwise,
// the source list is rearranged by name binding into this list.
vector<PExpr*>pins (rmod->port_count());
vector<bool>pins_fromwc (rmod->port_count(), false);
vector<bool>pins_is_explicitly_not_connected (rmod->port_count(), false);
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
// the ports represented by NetNet objects. I will find them
@ -1392,6 +1734,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
@ -2106,7 +2455,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)
@ -2123,8 +2472,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);
}
}
@ -2143,9 +2491,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;
@ -5125,6 +5471,9 @@ cerr << endl;
case PEEvent::NEGEDGE:
cerr << "negedge";
break;
case PEEvent::EDGE:
cerr << "edge";
break;
default:
cerr << "unknown edge type!";
ivl_assert(*this, 0);

View File

@ -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

View File

@ -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;

1
ivtest/.gitignore vendored
View File

@ -34,4 +34,5 @@ tmp_blif.vvp
dump.vcd
dump.lxt
dump.lx2
dump.fst
foo.vcd

70
ivtest/Makefile.in Normal file
View File

@ -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-vvp || status=1; \
$(MAKE) check-installed-vvp-py || status=1; \
$(MAKE) check-installed-vpi || 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

View File

@ -0,0 +1 @@
FST info: dumpfile dump.fst opened for output.

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More