diff --git a/.editorconfig b/.editorconfig index 572b73bd2..bbe9c3107 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,10 @@ indent_style = space indent_size = 2 trim_trailing_whitespace = false +[*.rst] +indent_style = space +indent_size = 3 + [*.yml] indent_style = space indent_size = 2 diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 2a5b7e024..b6c9a51ac 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -55,11 +55,6 @@ jobs: submodules: true persist-credentials: false - uses: actions/setup-python@v5 - - name: Get Boost Source - shell: bash - run: | - mkdir -p boost - curl -L https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-b2-nodocs.tar.gz | tar --strip-components=1 -xzC boost - name: Get FFI shell: bash run: | @@ -103,21 +98,16 @@ jobs: CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh CIBW_ENVIRONMENT: > OPTFLAGS=-O3 - CXXFLAGS=-I./boost/pfx/include - LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig - makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a' PATH="$PWD/bison/src:$PATH" CIBW_ENVIRONMENT_MACOS: > OPTFLAGS=-O3 - CXXFLAGS=-I./boost/pfx/include - LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 - makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' + makeFlags='CONFIG=clang' PATH="$PWD/bison/src:$PATH" CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh - CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py + CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py - uses: actions/upload-artifact@v4 with: name: python-wheels-${{ matrix.os.runner }} diff --git a/.github/workflows/wheels/cibw_before_build.sh b/.github/workflows/wheels/cibw_before_build.sh index 018b0e0df..1ce96b291 100644 --- a/.github/workflows/wheels/cibw_before_build.sh +++ b/.github/workflows/wheels/cibw_before_build.sh @@ -1,8 +1,8 @@ set -e set -x -# Don't use objects from previous compiles on Windows/macOS -make clean +# Don't use Python objects from previous compiles +make clean-py # DEBUG: show python3 and python3-config outputs if [ "$(uname)" != "Linux" ]; then @@ -11,24 +11,3 @@ if [ "$(uname)" != "Linux" ]; then fi python3 --version python3-config --includes - -# Build boost -cd ./boost -## Delete the artefacts from previous builds (if any) -rm -rf ./pfx -## Bootstrap bjam -./bootstrap.sh --prefix=./pfx -## Build Boost against current version of Python, only for -## static linkage (Boost is statically linked because system boost packages -## wildly vary in versions, including the libboost_python3 version) -./b2\ - -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)\ - --prefix=./pfx\ - --with-filesystem\ - --with-system\ - --with-python\ - cxxflags="$(python3-config --includes) -std=c++17 -fPIC"\ - cflags="$(python3-config --includes) -fPIC"\ - link=static\ - variant=release\ - install diff --git a/.gitignore b/.gitignore index 47f758a9b..2367bccb3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /Brewfile.lock.json ## build artifacts +/.git-abc-submodule-hash # compiler intermediate files *.o *.d diff --git a/CHANGELOG b/CHANGELOG index 468724e81..8ceefee41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,28 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.57 .. Yosys 0.58-dev +Yosys 0.58 .. Yosys 0.59-dev -------------------------- +Yosys 0.57 .. Yosys 0.58 +-------------------------- + * Various + - Run ABC passes in parallel. + - Extending support for buffer normalization. + - Overhaul of logging APIs. + - read_blif: Represent sequential elements with gate cells. + - Support multiple lib files in abc9_exe. + + * New commands and options + - Added "-wireshape" option to "show" command to allow + control the shape of wire nodes. + - Added "-relativeshare" option to "read_verilog", "synth" + and "techmap" pass for synthesis reproducibility testing. + - "write_rtlil" pass no longer sorts design, added "-sort" + option to match old behavior + - Added "-sva-continue-on-err" to "verific" pass to allow + processing designs that includes unsupported SVA. + Yosys 0.56 .. Yosys 0.57 -------------------------- * New commands and options diff --git a/CODEOWNERS b/CODEOWNERS index 46d37ad2f..4617c39bb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -38,7 +38,8 @@ techlibs/gowin/ @pepijndevos techlibs/gatemate/ @pu-cc # pyosys -misc/*.py @btut +pyosys/* @donn +setup.py @donn backends/firrtl @ucbjrl @azidar diff --git a/Makefile b/Makefile index 5896a5080..e8ff0e85d 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,7 @@ all: top-all YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) -CXXSTD ?= c++17 +export CXXSTD ?= c++17 CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include LIBS := $(LIBS) -lstdc++ -lm PLUGIN_LINKFLAGS := @@ -148,10 +148,6 @@ LINKFLAGS += -rdynamic ifneq ($(shell :; command -v brew),) BREW_PREFIX := $(shell brew --prefix)/opt $(info $$BREW_PREFIX is [${BREW_PREFIX}]) -ifeq ($(ENABLE_PYOSYS),1) -CXXFLAGS += -I$(BREW_PREFIX)/boost/include -LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib -endif CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) @@ -180,7 +176,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.57+260 +YOSYS_VER := 0.58+80 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'.' -f3) @@ -203,7 +199,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 3aca860.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 157aabb.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -364,37 +360,24 @@ ifeq ($(ENABLE_LIBYOSYS),1) TARGETS += libyosys.so endif +PY_WRAPPER_FILE = pyosys/wrappers + +# running make clean on just those and then recompiling saves a lot of +# time when running cibuildwheel +PYTHON_OBJECTS = pyosys/wrappers.o kernel/drivers.o kernel/yosys.o passes/cmds/plugin.o + ifeq ($(ENABLE_PYOSYS),1) # python-config --ldflags includes -l and -L, but LINKFLAGS is only -L LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags)) LIBS += $(shell $(PYTHON_CONFIG) --libs) EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) -CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON +PYBIND11_INCLUDE ?= $(shell $(PYTHON_EXECUTABLE) -m pybind11 --includes) +CXXFLAGS += -I$(PYBIND11_INCLUDE) -DYOSYS_ENABLE_PYTHON +CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DYOSYS_ENABLE_PYTHON -# Detect name of boost_python library. Some distros use boost_python-py, other boost_python, some only use the major version number, some a concatenation of major and minor version numbers -CHECK_BOOST_PYTHON = (echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(LINKFLAGS) $(EXE_LIBS) $(LIBS) -l$(1) - > /dev/null 2>&1 && echo "-l$(1)") -BOOST_PYTHON_LIB ?= $(shell \ - $(call CHECK_BOOST_PYTHON,boost_python-py$(subst .,,$(PYTHON_VERSION))) || \ - $(call CHECK_BOOST_PYTHON,boost_python-py$(PYTHON_MAJOR_VERSION)) || \ - $(call CHECK_BOOST_PYTHON,boost_python$(subst .,,$(PYTHON_VERSION))) || \ - $(call CHECK_BOOST_PYTHON,boost_python$(PYTHON_MAJOR_VERSION)) \ -) - -# Inside CentOS 7 -ifeq (${PLATFORM},centos7) -BOOST_PYTHON_LIB = -L/opt/boost/lib -lboost_python38 -CXXFLAGS += -I/opt/boost/include -endif - -ifeq ($(BOOST_PYTHON_LIB),) -$(error BOOST_PYTHON_LIB could not be detected. Please define manually) -endif - -LIBS += $(BOOST_PYTHON_LIB) -lboost_filesystem -PY_WRAPPER_FILE = kernel/python_wrappers OBJS += $(PY_WRAPPER_FILE).o -PY_GEN_SCRIPT= py_wrap_generator -PY_WRAP_INCLUDES := $(shell $(PYTHON_EXECUTABLE) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") +PY_GEN_SCRIPT = pyosys/generator.py +PY_WRAP_INCLUDES := $(shell $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) endif # ENABLE_PYOSYS ifeq ($(ENABLE_BACKTRACE),1) @@ -556,7 +539,7 @@ VERIFIC_COMPONENTS += synlib CXXFLAGS += -DVERIFIC_LIBERTY_SUPPORT endif ifeq ($(ENABLE_VERIFIC_UPF),1) -VERIFIC_COMPONENTS += hdl_file_sort verilog_nl +VERIFIC_COMPONENTS += hdl_file_sort verilog_nl VERIFIC_COMPONENTS += commands upf CXXFLAGS += -DVERIFIC_UPF_SUPPORT endif @@ -602,6 +585,13 @@ $(subst //,/,$(1)/$(notdir $(2))): $(2) $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2))) endef +define add_share_file_and_rename +EXTRA_TARGETS += $(subst //,/,$(1)/$(3)) +$(subst //,/,$(1)/$(3)): $(2) + $$(P) mkdir -p $(1) + $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(3)) +endef + define add_gen_share_file EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) $(subst //,/,$(1)/$(notdir $(2))): $(2) @@ -838,9 +828,9 @@ endif $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(CXX) $(CXXFLAGS) -x c++ -o $@ -E -P - ifeq ($(ENABLE_PYOSYS),1) -$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) +$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT) pyosys/wrappers_tpl.cc $(PY_WRAP_INCLUDES) pyosys/hashlib.h $(Q) mkdir -p $(dir $@) - $(P) $(PYTHON_EXECUTABLE) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" + $(P) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) $(PY_WRAPPER_FILE).cc endif %.o: %.cpp @@ -908,7 +898,17 @@ check-git-abc: exit 1; \ fi -abc/abc$(EXE) abc/libabc.a: | check-git-abc +.git-abc-submodule-hash: FORCE + @new=$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null || echo none); \ + old=$$(cat .git-abc-submodule-hash 2>/dev/null || echo none); \ + if [ "$$new" != "$$old" ]; then \ + echo "$$new" > .git-abc-submodule-hash; \ + fi + +abc/abc$(EXE) abc/libabc.a: .git-abc-submodule-hash | check-git-abc + @if [ "$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null)" != "$$(cat ../.git-abc-submodule-hash 2>/dev/null || echo none)" ]; then \ + rm -f abc/abc$(EXE); \ + fi $(P) $(Q) mkdir -p abc && $(MAKE) -C $(PROGRAM_PREFIX)abc -f "$(realpath $(YOSYS_SRC)/abc/Makefile)" ABCSRC="$(realpath $(YOSYS_SRC)/abc/)" $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc",PROG="abc$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc.a) @@ -1088,12 +1088,12 @@ ifeq ($(ENABLE_LIBYOSYS),1) if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so; fi ifeq ($(ENABLE_PYOSYS),1) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys + $(INSTALL_SUDO) cp pyosys/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so $(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys ifeq ($(ENABLE_ABC),1) $(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc endif - $(INSTALL_SUDO) cp misc/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/ endif endif ifeq ($(ENABLE_PLUGINS),1) @@ -1183,12 +1183,10 @@ DOC_TARGET ?= html docs: docs/prep $(Q) $(MAKE) -C docs $(DOC_TARGET) -clean: +clean: clean-py rm -rf share - rm -rf kernel/*.pyh - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc + rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) rm -f kernel/version_*.o kernel/version_*.cc - rm -f kernel/python_wrappers.o rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d rm -rf tests/asicworld/*.out tests/asicworld/*.log rm -rf tests/hana/*.out tests/hana/*.log @@ -1202,12 +1200,18 @@ clean: rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS)) -$(MAKE) -C docs clean rm -rf docs/util/__pycache__ + rm -f libyosys.so + +clean-py: + rm -f $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc + rm -f $(PYTHON_OBJECTS) rm -f *.whl rm -f libyosys.so + rm -rf kernel/*.pyh clean-abc: $(MAKE) -C abc DEP= clean - rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a + rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a .git-abc-submodule-hash mrproper: clean git clean -xdf diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index bba7249c7..ca7cf8a7f 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -98,6 +98,8 @@ struct BtorWorker vector ywmap_states; dict ywmap_clock_bits; dict ywmap_clock_inputs; + vector ywmap_asserts; + vector ywmap_assumes; PrettyJson ywmap_json; @@ -1280,6 +1282,8 @@ struct BtorWorker btorf("%d or %d %d %d\n", nid_a_or_not_en, sid, nid_a, nid_not_en); btorf("%d constraint %d\n", nid, nid_a_or_not_en); + if (ywmap_json.active()) ywmap_assumes.emplace_back(cell); + btorf_pop(log_id(cell)); } @@ -1304,6 +1308,8 @@ struct BtorWorker } else { int nid = next_nid++; btorf("%d bad %d%s\n", nid, nid_en_and_not_a, getinfo(cell, true)); + + if (ywmap_json.active()) ywmap_asserts.emplace_back(cell); } } @@ -1461,6 +1467,7 @@ struct BtorWorker log_assert(cursor == 0); log_assert(GetSize(todo) == 1); btorf("%d bad %d\n", nid, todo[cursor]); + // What do we do with ywmap_asserts when using single_bad? } } @@ -1526,6 +1533,18 @@ struct BtorWorker emit_ywmap_btor_sig(entry); ywmap_json.end_array(); + ywmap_json.name("asserts"); + ywmap_json.begin_array(); + for (Cell *cell : ywmap_asserts) + ywmap_json.value(witness_path(cell)); + ywmap_json.end_array(); + + ywmap_json.name("assumes"); + ywmap_json.begin_array(); + for (Cell *cell : ywmap_assumes) + ywmap_json.value(witness_path(cell)); + ywmap_json.end_array(); + ywmap_json.end_object(); } } diff --git a/docs/.gitignore b/docs/.gitignore index 09bb59048..30a903f9a 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -6,3 +6,4 @@ /source/_images/**/*.svg /source/_images/**/*.dot /source/_images/code_examples +/venv diff --git a/docs/source/appendix/rtlil_text.rst b/docs/source/appendix/rtlil_text.rst index b1bc9c582..352b1af2e 100644 --- a/docs/source/appendix/rtlil_text.rst +++ b/docs/source/appendix/rtlil_text.rst @@ -63,6 +63,10 @@ significant bit first. Bits may be any of: - ``m``: A marked bit (internal use only) - ``-``: A don't care value +When the bit representation has fewer bits than the width, it is padded to the width with +the most significant explicit bit, or ``0`` if the most significant explicit bit is ``1``, +or ``x`` if there are no explicit bits. + An *integer* is simply a signed integer value in decimal format. **Warning:** Integer constants are limited to 32 bits. That is, they may only be in the range :math:`[-2147483648, 2147483648)`. Integers outside this range will result in an @@ -133,6 +137,7 @@ wires, memories, cells, processes, and connections. ::= * ::= module ::= ( + | | | | @@ -170,6 +175,11 @@ See :ref:`sec:rtlil_sigspec` for an overview of signal specifications. | [ (:)? ] | { * } +When a ```` is specified, the wire must have been previously declared. + +When a signal slice is specified, the left-hand integer must be greather than or +equal to the right-hand integer. + Connections ^^^^^^^^^^^ @@ -268,7 +278,7 @@ may have zero or more attributes. .. code:: BNF ::= * - := * switch + ::= * switch ::= * ::= case ? ::= (, )* @@ -295,3 +305,4 @@ be: | sync always ::= low | high | posedge | negedge | edge ::= update + | * memwr diff --git a/docs/source/code_examples/pyosys/pass.py b/docs/source/code_examples/pyosys/pass.py new file mode 100644 index 000000000..2108b48ab --- /dev/null +++ b/docs/source/code_examples/pyosys/pass.py @@ -0,0 +1,37 @@ +from pyosys import libyosys as ys + +class AllEnablePass(ys.Pass): + def __init__(self): + super().__init__( + "all_enable", + "makes all _DFF_P_ registers require an enable signal" + ) + + def execute(self, args, design): + ys.log_header(design, "Adding enable signals\n") + ys.log_push() + top_module = design.top_module() + + if "\\enable" not in top_module.wires_: + enable_line = top_module.addWire("\\enable") + enable_line.port_input = True + top_module.fixup_ports() + + for cell in top_module.cells_.values(): + if cell.type != "$_DFF_P_": + continue + cell.type = "$_DFFE_PP_" + cell.setPort("\\E", ys.SigSpec(enable_line)) + ys.log_pop() + +p = AllEnablePass() # register the pass + +# using the pass + +design = ys.Design() +ys.run_pass("read_verilog tests/simple/fiedler-cooley.v", design) +ys.run_pass("hierarchy -check -auto-top", design) +ys.run_pass("synth", design) +ys.run_pass("all_enable", design) +ys.run_pass("write_verilog out.v", design) +ys.run_pass("synth_ice40 -json out.json", design) diff --git a/docs/source/code_examples/pyosys/simple_database.py b/docs/source/code_examples/pyosys/simple_database.py new file mode 100644 index 000000000..4cfe6b586 --- /dev/null +++ b/docs/source/code_examples/pyosys/simple_database.py @@ -0,0 +1,51 @@ +from pyosys import libyosys as ys + +# loading design +design = ys.Design() + +ys.run_pass("read_verilog tests/simple/fiedler-cooley.v", design) +ys.run_pass("hierarchy -check -auto-top", design) + +# top module inspection +top_module = design.top_module() + +for id, wire in top_module.wires_.items(): + if not wire.port_input and not wire.port_output: + continue + description = "input" if wire.port_input else "output" + description += " " + wire.name.str() + if wire.width != 1: + frm = wire.start_offset + to = wire.start_offset + wire.width + if wire.upto: + to, frm = frm, to + description += f" [{to}:{frm}]" + print(description) + +# synth + +ys.run_pass("synth", design) + +# adding the enable line + +enable_line = top_module.addWire("\\enable") +enable_line.port_input = True +top_module.fixup_ports() + +# hooking the enable line to the internal dff cells + +for cell in top_module.cells_.values(): + if cell.type != "$_DFF_P_": + continue + cell.type = "$_DFFE_PP_" + cell.setPort("\\E", ys.SigSpec(enable_line)) + +# run check + +top_module.check() +ys.run_pass("stat", design) + +# write outputs + +ys.run_pass("write_verilog out.v", design) +ys.run_pass("synth_ice40 -json out.json", design) diff --git a/docs/source/conf.py b/docs/source/conf.py index 5b93e2e70..49f8f5eab 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -6,7 +6,7 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' copyright ='2025 YosysHQ GmbH' -yosys_ver = "0.57" +yosys_ver = "0.58" # select HTML theme html_theme = 'furo-ys' diff --git a/docs/source/using_yosys/index.rst b/docs/source/using_yosys/index.rst index b243d431e..93dd3629b 100644 --- a/docs/source/using_yosys/index.rst +++ b/docs/source/using_yosys/index.rst @@ -17,3 +17,4 @@ ways Yosys can interact with designs for a deeper investigation. more_scripting/index bugpoint verilog + pyosys diff --git a/docs/source/using_yosys/pyosys.rst b/docs/source/using_yosys/pyosys.rst new file mode 100644 index 000000000..8aa7fd4fe --- /dev/null +++ b/docs/source/using_yosys/pyosys.rst @@ -0,0 +1,208 @@ +Scripting with Pyosys +===================== + +Pyosys is a limited subset of the Yosys C++ API (aka "libyosys") made available +using the Python programming language. + +Like ``.ys`` and ``.tcl`` scripts, Pyosys provides an interface to write Yosys +scripts in the Python programming language, giving you the benefits of +a type system, control flow, object-oriented programming, and more; especially +that the other options lack a type system and control flow/OOP in Tcl is +limited. + +Though unlike these two, Pyosys goes a bit further, allowing you to use the +Yosys API to implement advanced functionality that would otherwise require +custom passes written in C++. + + +Getting Pyosys +-------------- + +Pyosys supports CPython 3.8 or higher. You can access Pyosys using one of two +methods: + +1. Compiling Yosys with the Makefile flag ``ENABLE_PYOSYS=1`` + + This adds the flag ``-y`` to the Yosys binary, which allows you to execute + Python scripts using an interpreter embedded in Yosys itself: + + ``yosys -y ./my_pyosys_script.py`` + +2. Installing the Pyosys wheels + + On macOS and GNU/Linux you can install pre-built wheels of Yosys using + ``pip``: + + ``python3 -m pip install pyosys`` + + Which then allows you to run your scripts as follows: + + ``python3 ./my_pyosys_script.py`` + + +Scripting and Database Inspection +--------------------------------- + +To start with, you have to import libyosys as follows: + +.. code-block:: python + + from pyosys import libyosys + + +As a reminder, Python allows you to alias imported modules and objects, so +this import may be preferable for terseness: + +.. code-block:: python + + from pyosys import libyosys as ys + + +Now, scripting is actually quite similar to ``.ys`` and ``.tcl`` script in that +you can provide mostly text commands. Albeit, you can construct your scripts +to use Python's amenities like conditional execution, loops, and functions: + +.. code-block:: python + + do_flatten = True + + ys.run_pass("read_verilog tests/simple/fiedler-cooley.v") + ys.run_pass("hierarchy -check -auto-top") + if do_flatten: + ys.run_pass("flatten") + +…but this does not strictly provide anything that Tcl scripts do not provide you +with. The real power of using Pyosys comes from the fact you can manually +instantiate, manage, and interact with the design database. + +As an example, here is the same script with a manually instantiated design. + +.. literalinclude:: /code_examples/pyosys/simple_database.py + :start-after: loading design + :end-before: top module inspection + :language: python + +What's new here is that you can manually inspect the design's database. This +gives you access to a huge chunk of the design database API as declared in +the ``kernel/rtlil.h`` header. + +For example, here's how to list the input and output ports of the top module +of your design: + +.. literalinclude:: /code_examples/pyosys/simple_database.py + :start-after: top module inspection + :end-before: # synth + :language: python + +.. tip:: + + C++ data structures in Yosys are bridged to Python such that they have a + pretty similar API to Python objects, for example: + + - ``std::vector`` supports the same methods as + `iterables `_ in + Python. + - ``std::set`` and hashlib ``pool`` support the same methods as ``set``\s in + Python. While ``set`` is ordered, ``pool`` is not and modifications may + cause a complete reordering of the set. + - ``dict`` supports the same methods as ``dict``\s in Python, albeit it is + unordered, and modifications may cause a complete reordering of the + dictionary. + - ``idict`` uses a custom set of methods because it doesn't map very cleanly + to an existing Python data structure. See ``pyosys/hashlib.h`` for more + info. + + For most operations, the Python equivalents are also supported as arguments + where they will automatically be cast to the right type, so you do not have + to manually instantiate the right underlying C++ object(s) yourself. + +Modifying the Database +---------------------- + +.. warning:: + + Any modifications to the database may invalidate previous references held + by Python, just as if you were writing C++. Pyosys does not currently attempt + to keep deleted objects alive if a reference is held by Python. + +You are not restricted to inspecting the database either: you have the ability +to modify it, and introduce new elements and/or changes to your design. + +As a demonstrative example, let's assume we want to add an enable line to all +flip-flops in our fiedler-cooley design. + +First of all, we will run :yoscrypt:`synth` to convert all of the logic to +Yosys's internal cell structure (see :ref:`sec:celllib_gates`): + +.. literalinclude:: /code_examples/pyosys/simple_database.py + :start-after: # synth + :end-before: adding the enable line + :language: python + +Next, we need to add the new port. The method for this is ``Module::addWire``\. + +.. tip:: + + IdString is Yosys's internal representation of strings used as identifiers + within Verilog designs. They are efficient as only integers are stored and + passed around, but they can be translated to and from normal strings at will. + + Pyosys will automatically cast Python strings to IdStrings for you, but the + rules around IdStrings apply, namely that *broadly*: + + - Identifiers for internal cells must start with ``$``\. + - All other identifiers must start with ``\``\. + +.. literalinclude:: /code_examples/pyosys/simple_database.py + :start-after: adding the enable line + :end-before: hooking the enable line + :language: python + +Notice how we modified the wire then called a method to make Yosys re-process +the ports. + +Next, we can iterate over all constituent cells, and if they are of the type +``$_DFF_P_``, we do two things: + +1. Change their type to ``$_DFFE_PP_`` to enable hooking up an enable signal. +2. Hooking up the enable signal. + +.. literalinclude:: /code_examples/pyosys/simple_database.py + :start-after: hooking the enable line + :end-before: run check + :language: python + +To verify that you did everything correctly, it is prudent to call ``.check()`` +on the module you're manipulating as follows after you're done with a set of +changes: + +.. literalinclude:: /code_examples/pyosys/simple_database.py + :start-after: run check + :end-before: write output + :language: python + +And then finally, write your outputs. Here, I choose an intermediate Verilog +file and :yoscrypt:`synth_ice40` to map it to the iCE40 architecture. + +.. literalinclude:: /code_examples/pyosys/simple_database.py + :start-after: write output + :language: python + +And voilà, you will note that in the intermediate output, all ``always @`` +statements should have an ``if (enable)``\. + +Encapsulating as Passes +----------------------- + +Just like when writing C++, you can encapsulate routines in terms of "passes", +which adds your Pass to a global registry of commands accessible using +``run_pass``\. + +.. literalinclude:: /code_examples/pyosys/pass.py + :language: python + +In general, abstract classes and virtual methods are not really supported by +Pyosys due to their complexity, but there are two exceptions which are: + +- ``Pass`` in ``kernel/register.h`` +- ``Monitor`` in ``kernel/rtlil.h`` diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index 1993e617a..1255f6f7c 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -36,7 +36,7 @@ The main characteristics are: all compilers, standard libraries and architectures. In addition to ``dict`` and ``pool`` there is also an ``idict`` that -creates a bijective map from ``K`` to the integers. For example: +creates a bijective map from ``K`` to incrementing integers. For example: :: diff --git a/examples/python-api/pass.py b/examples/python-api/pass.py index dbef0a13f..d5e5868b0 100755 --- a/examples/python-api/pass.py +++ b/examples/python-api/pass.py @@ -1,22 +1,25 @@ #!/usr/bin/python3 -import libyosys as ys +from pyosys import libyosys as ys + +from pathlib import Path import matplotlib.pyplot as plt -import numpy as np + +__file_dir__ = Path(__file__).absolute().parent class CellStatsPass(ys.Pass): def __init__(self): super().__init__("cell_stats", "Shows cell stats as plot") - def py_help(self): + def help(self): ys.log("This pass uses the matplotlib library to display cell stats\n") - def py_execute(self, args, design): + def execute(self, args, design): ys.log_header(design, "Plotting cell stats\n") cell_stats = {} - for module in design.selected_whole_modules_warn(): + for module in design.all_selected_whole_modules(): for cell in module.selected_cells(): if cell.type.str() in cell_stats: cell_stats[cell.type.str()] += 1 @@ -26,7 +29,14 @@ class CellStatsPass(ys.Pass): plt.xticks(range(len(cell_stats)), list(cell_stats.keys())) plt.show() - def py_clear_flags(self): + def clear_flags(self): ys.log("Clear Flags - CellStatsPass\n") -p = CellStatsPass() +p = CellStatsPass() # register + +if __name__ == "__main__": + design = ys.Design() + ys.run_pass(f"read_verilog {__file_dir__.parents[1] / 'tests' / 'simple' / 'fiedler-cooley.v'}", design) + ys.run_pass("prep", design) + ys.run_pass("opt -full", design) + ys.run_pass("cell_stats", design) diff --git a/frontends/rtlil/Makefile.inc b/frontends/rtlil/Makefile.inc index d0c0cfcf8..4649507f7 100644 --- a/frontends/rtlil/Makefile.inc +++ b/frontends/rtlil/Makefile.inc @@ -1,19 +1 @@ - -GENFILES += frontends/rtlil/rtlil_parser.tab.cc -GENFILES += frontends/rtlil/rtlil_parser.tab.hh -GENFILES += frontends/rtlil/rtlil_parser.output -GENFILES += frontends/rtlil/rtlil_lexer.cc - -frontends/rtlil/rtlil_parser.tab.cc: frontends/rtlil/rtlil_parser.y - $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -o $@ -d -r all -b frontends/rtlil/rtlil_parser $< - -frontends/rtlil/rtlil_parser.tab.hh: frontends/rtlil/rtlil_parser.tab.cc - -frontends/rtlil/rtlil_lexer.cc: frontends/rtlil/rtlil_lexer.l - $(Q) mkdir -p $(dir $@) - $(P) flex -o frontends/rtlil/rtlil_lexer.cc $< - -OBJS += frontends/rtlil/rtlil_parser.tab.o frontends/rtlil/rtlil_lexer.o OBJS += frontends/rtlil/rtlil_frontend.o - diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index e8d6ac9c9..04d01fc93 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -17,27 +17,766 @@ * * --- * - * A very simple and straightforward frontend for the RTLIL text - * representation. + * A handwritten recursive-descent parser for the RTLIL text representation. * */ -#include "rtlil_frontend.h" #include "kernel/register.h" #include "kernel/log.h" - -void rtlil_frontend_yyerror(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s); -} - -void rtlil_frontend_yywarning(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_warning("In line %d: %s\n", rtlil_frontend_yyget_lineno(), s); -} +#include "kernel/utils.h" +#include +#include +#include YOSYS_NAMESPACE_BEGIN +struct RTLILFrontendWorker { + // Forbid constants of more than 1 Gb. + // This will help us not explode on malicious RTLIL. + static constexpr int MAX_CONST_WIDTH = 1024 * 1024 * 1024; + + std::istream *f = nullptr; + RTLIL::Design *design; + bool flag_nooverwrite = false; + bool flag_overwrite = false; + bool flag_lib = false; + + int line_num; + std::string line_buf; + // Substring of line_buf. Always newline-terminated, thus never empty. + std::string_view line; + + RTLIL::Module *current_module; + dict attrbuf; + std::vector*> switch_stack; + std::vector case_stack; + + template + [[noreturn]] + void error(FmtString...> fmt, const Args &... args) + { + log_error("Parser error in line %d: %s\n", line_num, fmt.format(args...)); + } + + template + void warning(FmtString...> fmt, const Args &... args) + { + log_warning("In line %d: %s\n", line_num, fmt.format(args...)); + } + + // May return an empty line if the stream is not good(). + void advance_to_next_nonempty_line() + { + if (!f->good()) { + line = "\n"; + return; + } + while (true) { + std::getline(*f, line_buf); + line_num++; + if (line_buf.empty() || line_buf[line_buf.size() - 1] != '\n') + line_buf += '\n'; + line = line_buf; + consume_whitespace_and_comments(); + if (line[0] != '\n' || !f->good()) + break; + } + } + + void consume_whitespace_and_comments() + { + while (true) { + switch (line[0]) { + case ' ': + case '\t': + line = line.substr(1); + break; + case '#': + line = "\n"; + return; + default: + return; + } + } + } + + bool try_parse_keyword(std::string_view keyword) + { + int keyword_size = keyword.size(); + if (keyword != line.substr(0, keyword_size)) + return false; + // This index is safe because `line` is always newline-terminated + // and `keyword` never contains a newline. + char ch = line[keyword_size]; + if (ch >= 'a' && ch <= 'z') + return false; + line = line.substr(keyword_size); + consume_whitespace_and_comments(); + return true; + } + + std::string error_token() + { + std::string result; + for (char ch : line) { + if (ch == '\n' || ch == ' ' || ch == '\t') + break; + result += ch; + } + return result; + } + + void expect_keyword(std::string_view keyword) + { + if (!try_parse_keyword(keyword)) + error("Expected token `%s', got `%s'.", keyword, error_token()); + } + + bool try_parse_char(char ch) + { + if (line[0] != ch) + return false; + line = line.substr(1); + consume_whitespace_and_comments(); + return true; + } + + void expect_char(char ch) + { + if (!try_parse_char(ch)) + error("Expected `%c', got `%s'.", ch, error_token()); + } + + bool try_parse_eol() + { + if (line[0] != '\n') + return false; + advance_to_next_nonempty_line(); + return true; + } + + void expect_eol() + { + if (!try_parse_eol()) + error("Expected EOL, got `%s'.", error_token()); + } + + std::optional try_parse_id() + { + char ch = line[0]; + if (ch != '\\' && ch != '$') + return std::nullopt; + int idx = 1; + while (true) { + ch = line[idx]; + if (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) + break; + ++idx; + } + IdString result(line.substr(0, idx)); + line = line.substr(idx); + consume_whitespace_and_comments(); + return result; + } + + RTLIL::IdString parse_id() + { + std::optional id = try_parse_id(); + if (!id.has_value()) + error("Expected ID, got `%s'.", error_token()); + return std::move(*id); + } + + long long parse_integer() + { + long long result = parse_integer_alone(); + consume_whitespace_and_comments(); + return result; + } + + long long parse_integer_alone() + { + int idx = 0; + if (line[idx] == '-') + ++idx; + while (true) { + char ch = line[idx]; + if (ch < '0' || ch > '9') + break; + ++idx; + } + long long result; + if (std::from_chars(line.data(), line.data() + idx, result, 10).ec != std::errc{}) + error("Invalid integer `%s'.", error_token()); + line = line.substr(idx); + return result; + } + + std::string parse_string() + { + if (line[0] != '\"') + error("Expected string, got `%s'.", error_token()); + std::string str; + int idx = 1; + while (true) { + int start_idx = idx; + char ch; + while (true) { + ch = line[idx]; + if (ch == '"' || ch == '\n' || ch == '\\' || ch == 0) + break; + ++idx; + } + str.append(line.data() + start_idx, line.data() + idx); + ++idx; + if (ch == '"') + break; + if (ch == 0) + error("Null byte in string literal: `%s'.", line); + if (ch == '\n') + error("Unterminated string literal: `%s'.", line); + ch = line[idx++]; + if (ch == 'n') { + ch = '\n'; + } else if (ch == 't') { + ch = '\t'; + } else if (ch >= '0' && ch <= '7') { + int v = ch - '0'; + char next_ch = line[idx + 1]; + if (next_ch >= '0' && next_ch <= '7') { + ++idx; + v = v*8 + (next_ch - '0'); + next_ch = line[idx + 1]; + if (next_ch >= '0' && next_ch <= '7') { + ++idx; + v = v*8 + (next_ch - '0'); + } + } + ch = v; + } + str += ch; + } + line = line.substr(idx); + consume_whitespace_and_comments(); + return str; + } + + RTLIL::Const parse_const() + { + if (line[0] == '"') + return RTLIL::Const(parse_string()); + + bool negative_value = line[0] == '-'; + long long width = parse_integer_alone(); + // Can't test value<0 here because we need to stop parsing after '-0' + if (negative_value || line[0] != '\'') { + if (width < INT_MIN || width > INT_MAX) + error("Integer %lld out of range before `%s'.", width, error_token()); + consume_whitespace_and_comments(); + return RTLIL::Const(width); + } + + int idx = 1; + bool is_signed = line[1] == 's'; + if (is_signed) + ++idx; + + std::vector bits; + if (width > MAX_CONST_WIDTH) + error("Constant width %lld out of range before `%s`.", width, error_token()); + bits.reserve(width); + while (true) { + RTLIL::State bit; + switch (line[idx]) { + case '0': bit = RTLIL::S0; break; + case '1': bit = RTLIL::S1; break; + case 'x': bit = RTLIL::Sx; break; + case 'z': bit = RTLIL::Sz; break; + case 'm': bit = RTLIL::Sm; break; + case '-': bit = RTLIL::Sa; break; + default: goto done; + } + bits.push_back(bit); + ++idx; + } + done: + std::reverse(bits.begin(), bits.end()); + + if (GetSize(bits) > width) + bits.resize(width); + else if (GetSize(bits) < width) { + RTLIL::State extbit = RTLIL::Sx; + if (!bits.empty()) { + extbit = bits.back(); + if (extbit == RTLIL::S1) + extbit = RTLIL::S0; + } + bits.resize(width, extbit); + } + + RTLIL::Const val(std::move(bits)); + if (is_signed) + val.flags |= RTLIL::CONST_FLAG_SIGNED; + line = line.substr(idx); + consume_whitespace_and_comments(); + return val; + } + + RTLIL::SigSpec parse_sigspec() + { + RTLIL::SigSpec sig; + + if (try_parse_char('{')) { + std::vector parts; + while (!try_parse_char('}')) + parts.push_back(parse_sigspec()); + for (auto it = parts.rbegin(); it != parts.rend(); ++it) + sig.append(std::move(*it)); + } else { + // We could add a special path for parsing IdStrings that must already exist, + // as here. + // We don't need to addref/release in this case. + std::optional id = try_parse_id(); + if (id.has_value()) { + RTLIL::Wire *wire = current_module->wire(*id); + if (wire == nullptr) + error("Wire `%s' not found.", *id); + sig = RTLIL::SigSpec(wire); + } else { + sig = RTLIL::SigSpec(parse_const()); + } + } + + while (try_parse_char('[')) { + int left = parse_integer(); + if (left >= sig.size() || left < 0) + error("bit index %d out of range", left); + if (try_parse_char(':')) { + int right = parse_integer(); + if (right < 0) + error("bit index %d out of range", right); + if (left < right) + error("invalid slice [%d:%d]", left, right); + sig = sig.extract(right, left-right+1); + } else { + sig = sig.extract(left); + } + expect_char(']'); + } + + return sig; + } + + void parse_module() + { + RTLIL::IdString module_name = parse_id(); + expect_eol(); + + bool delete_current_module = false; + if (design->has(module_name)) { + RTLIL::Module *existing_mod = design->module(module_name); + if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { + log("Ignoring blackbox re-definition of module %s.\n", module_name); + delete_current_module = true; + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { + error("RTLIL error: redefinition of module %s.", module_name); + } else if (flag_nooverwrite) { + log("Ignoring re-definition of module %s.\n", module_name); + delete_current_module = true; + } else { + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", module_name); + design->remove(existing_mod); + } + } + + current_module = new RTLIL::Module; + current_module->name = std::move(module_name); + current_module->attributes = std::move(attrbuf); + if (!delete_current_module) + design->add(current_module); + + while (true) + { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + if (try_parse_keyword("parameter")) { + parse_parameter(); + continue; + } + if (try_parse_keyword("connect")) { + parse_connect(); + continue; + } + if (try_parse_keyword("wire")) { + parse_wire(); + continue; + } + if (try_parse_keyword("cell")) { + parse_cell(); + continue; + } + if (try_parse_keyword("memory")) { + parse_memory(); + continue; + } + if (try_parse_keyword("process")) { + parse_process(); + continue; + } + if (try_parse_keyword("end")) { + expect_eol(); + break; + } + error("Unexpected token in module body: %s", error_token()); + } + + if (attrbuf.size() != 0) + error("dangling attribute"); + current_module->fixup_ports(); + if (delete_current_module) + delete current_module; + else if (flag_lib) + current_module->makeblackbox(); + current_module = nullptr; + } + + void parse_attribute() + { + RTLIL::IdString id = parse_id(); + RTLIL::Const c = parse_const(); + attrbuf.insert({std::move(id), std::move(c)}); + expect_eol(); + } + + void parse_parameter() + { + RTLIL::IdString id = parse_id(); + current_module->avail_parameters(id); + if (try_parse_eol()) + return; + RTLIL::Const c = parse_const(); + current_module->parameter_default_values.insert({std::move(id), std::move(c)}); + expect_eol(); + } + + void parse_wire() + { + RTLIL::Wire *wire; + int width = 1; + int start_offset = 0; + int port_id = 0; + bool port_input = false; + bool port_output = false; + bool upto = false; + bool is_signed = false; + + while (true) + { + std::optional id = try_parse_id(); + if (id.has_value()) { + if (current_module->wire(*id) != nullptr) + error("RTLIL error: redefinition of wire %s.", *id); + wire = current_module->addWire(std::move(*id)); + break; + } + if (try_parse_keyword("width")) + width = parse_integer(); + else if (try_parse_keyword("upto")) + upto = true; + else if (try_parse_keyword("signed")) + is_signed = true; + else if (try_parse_keyword("offset")) + start_offset = parse_integer(); + else if (try_parse_keyword("input")) { + port_id = parse_integer(); + port_input = true; + } else if (try_parse_keyword("output")) { + port_id = parse_integer(); + port_output = true; + } else if (try_parse_keyword("inout")) { + port_id = parse_integer(); + port_input = true; + port_output = true; + } else if (try_parse_eol()) + error("Missing wire ID"); + else + error("Unexpected wire option: %s", error_token()); + } + + wire->attributes = std::move(attrbuf); + wire->width = width; + wire->upto = upto; + wire->start_offset = start_offset; + wire->is_signed = is_signed; + wire->port_id = port_id; + wire->port_input = port_input; + wire->port_output = port_output; + expect_eol(); + } + + void parse_memory() + { + RTLIL::Memory *memory = new RTLIL::Memory; + memory->attributes = std::move(attrbuf); + + int width = 1; + int start_offset = 0; + int size = 0; + while (true) + { + std::optional id = try_parse_id(); + if (id.has_value()) { + if (current_module->memories.count(*id) != 0) + error("RTLIL error: redefinition of memory %s.", *id); + memory->name = std::move(*id); + break; + } + if (try_parse_keyword("width")) + width = parse_integer(); + else if (try_parse_keyword("size")) + size = parse_integer(); + else if (try_parse_keyword("offset")) + start_offset = parse_integer(); + else if (try_parse_eol()) + error("Missing memory ID"); + else + error("Unexpected memory option: %s", error_token()); + } + memory->width = width; + memory->start_offset = start_offset; + memory->size = size; + current_module->memories.insert({memory->name, memory}); + expect_eol(); + } + + void parse_cell() + { + RTLIL::IdString cell_type = parse_id(); + RTLIL::IdString cell_name = parse_id(); + expect_eol(); + + if (current_module->cell(cell_name) != nullptr) + error("RTLIL error: redefinition of cell %s.", cell_name); + RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type); + cell->attributes = std::move(attrbuf); + + while (true) + { + if (try_parse_keyword("parameter")) { + bool is_signed = false; + bool is_real = false; + if (try_parse_keyword("signed")) { + is_signed = true; + } else if (try_parse_keyword("real")) { + is_real = true; + } + RTLIL::IdString param_name = parse_id(); + RTLIL::Const val = parse_const(); + if (is_signed) + val.flags |= RTLIL::CONST_FLAG_SIGNED; + if (is_real) + val.flags |= RTLIL::CONST_FLAG_REAL; + cell->parameters.insert({std::move(param_name), std::move(val)}); + expect_eol(); + } else if (try_parse_keyword("connect")) { + RTLIL::IdString port_name = parse_id(); + if (cell->hasPort(port_name)) + error("RTLIL error: redefinition of cell port %s.", port_name); + cell->setPort(std::move(port_name), parse_sigspec()); + expect_eol(); + } else if (try_parse_keyword("end")) { + expect_eol(); + break; + } else { + error("Unexpected token in cell body: %s", error_token()); + } + } + } + + void parse_connect() + { + if (attrbuf.size() != 0) + error("dangling attribute"); + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + current_module->connect(std::move(s1), std::move(s2)); + expect_eol(); + } + + void parse_case_body(RTLIL::CaseRule *current_case) + { + while (true) + { + if (try_parse_keyword("attribute")) + parse_attribute(); + else if (try_parse_keyword("switch")) + parse_switch(); + else if (try_parse_keyword("assign")) { + if (attrbuf.size() != 0) + error("dangling attribute"); + // See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this + // warning + if (!switch_stack.back()->empty()) + warning("case rule assign statements after switch statements may cause unexpected behaviour. " + "The assign statement is reordered to come before all switch statements."); + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + current_case->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2))); + expect_eol(); + } else + return; + } + } + + void parse_switch() + { + RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; + rule->signal = parse_sigspec(); + rule->attributes = std::move(attrbuf); + switch_stack.back()->push_back(rule); + expect_eol(); + + while (true) { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + + if (try_parse_keyword("end")) { + expect_eol(); + break; + } + + expect_keyword("case"); + RTLIL::CaseRule *case_rule = new RTLIL::CaseRule; + case_rule->attributes = std::move(attrbuf); + rule->cases.push_back(case_rule); + switch_stack.push_back(&case_rule->switches); + case_stack.push_back(case_rule); + + if (!try_parse_eol()) { + while (true) { + case_rule->compare.push_back(parse_sigspec()); + if (try_parse_eol()) + break; + expect_char(','); + } + } + + parse_case_body(case_rule); + + switch_stack.pop_back(); + case_stack.pop_back(); + } + } + + void parse_process() + { + RTLIL::IdString proc_name = parse_id(); + expect_eol(); + + if (current_module->processes.count(proc_name) != 0) + error("RTLIL error: redefinition of process %s.", proc_name); + RTLIL::Process *proc = current_module->addProcess(std::move(proc_name)); + proc->attributes = std::move(attrbuf); + + switch_stack.clear(); + switch_stack.push_back(&proc->root_case.switches); + case_stack.clear(); + case_stack.push_back(&proc->root_case); + + parse_case_body(&proc->root_case); + + while (try_parse_keyword("sync")) + { + RTLIL::SyncRule *rule = new RTLIL::SyncRule; + + if (try_parse_keyword("low")) rule->type = RTLIL::ST0; + else if (try_parse_keyword("high")) rule->type = RTLIL::ST1; + else if (try_parse_keyword("posedge")) rule->type = RTLIL::STp; + else if (try_parse_keyword("negedge")) rule->type = RTLIL::STn; + else if (try_parse_keyword("edge")) rule->type = RTLIL::STe; + else if (try_parse_keyword("always")) rule->type = RTLIL::STa; + else if (try_parse_keyword("global")) rule->type = RTLIL::STg; + else if (try_parse_keyword("init")) rule->type = RTLIL::STi; + else error("Unexpected sync type: %s", error_token()); + + if (rule->type != RTLIL::STa && rule->type != RTLIL::STg && rule->type != RTLIL::STi) + rule->signal = parse_sigspec(); + proc->syncs.push_back(rule); + expect_eol(); + + bool attributes_in_update_list = false; + while (true) + { + if (try_parse_keyword("update")) { + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + rule->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2))); + expect_eol(); + continue; + } + + if (try_parse_keyword("attribute")) { + attributes_in_update_list = true; + parse_attribute(); + continue; + } + + if (!try_parse_keyword("memwr")) + break; + + RTLIL::MemWriteAction act; + act.attributes = std::move(attrbuf); + act.memid = parse_id(); + act.address = parse_sigspec(); + act.data = parse_sigspec(); + act.enable = parse_sigspec(); + act.priority_mask = parse_const(); + rule->mem_write_actions.push_back(std::move(act)); + expect_eol(); + } + // The old parser allowed dangling attributes before a "sync" to carry through + // the "sync", so we will too, for now. + if (attributes_in_update_list && attrbuf.size() > 0) + error("dangling attribute"); + } + + expect_keyword("end"); + expect_eol(); + } + + RTLILFrontendWorker(RTLIL::Design *design) : design(design) {} + + void parse(std::istream *f) + { + this->f = f; + line_num = 0; + advance_to_next_nonempty_line(); + while (f->good()) + { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + if (try_parse_keyword("module")) { + parse_module(); + continue; + } + if (try_parse_keyword("autoidx")) { + autoidx = std::max(autoidx, parse_integer()); + expect_eol(); + continue; + } + error("Unexpected token: %s", error_token()); + } + if (attrbuf.size() != 0) + error("dangling attribute"); + } +}; + struct RTLILFrontend : public Frontend { RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { } void help() override @@ -63,9 +802,7 @@ struct RTLILFrontend : public Frontend { } void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = false; - RTLIL_FRONTEND::flag_lib = false; + RTLILFrontendWorker worker(design); log_header(design, "Executing RTLIL frontend.\n"); @@ -73,17 +810,17 @@ struct RTLILFrontend : public Frontend { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-nooverwrite") { - RTLIL_FRONTEND::flag_nooverwrite = true; - RTLIL_FRONTEND::flag_overwrite = false; + worker.flag_nooverwrite = true; + worker.flag_overwrite = false; continue; } if (arg == "-overwrite") { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = true; + worker.flag_nooverwrite = false; + worker.flag_overwrite = true; continue; } if (arg == "-lib") { - RTLIL_FRONTEND::flag_lib = true; + worker.flag_lib = true; continue; } break; @@ -92,14 +829,8 @@ struct RTLILFrontend : public Frontend { log("Input filename: %s\n", filename); - RTLIL_FRONTEND::lexin = f; - RTLIL_FRONTEND::current_design = design; - rtlil_frontend_yydebug = false; - rtlil_frontend_yyrestart(NULL); - rtlil_frontend_yyparse(); - rtlil_frontend_yylex_destroy(); + worker.parse(f); } } RTLILFrontend; YOSYS_NAMESPACE_END - diff --git a/frontends/rtlil/rtlil_frontend.h b/frontends/rtlil/rtlil_frontend.h deleted file mode 100644 index 31cfb80b4..000000000 --- a/frontends/rtlil/rtlil_frontend.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -#ifndef RTLIL_FRONTEND_H -#define RTLIL_FRONTEND_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -namespace RTLIL_FRONTEND { - extern std::istream *lexin; - extern RTLIL::Design *current_design; - extern bool flag_nooverwrite; - extern bool flag_overwrite; - extern bool flag_lib; -} - -YOSYS_NAMESPACE_END - -extern int rtlil_frontend_yydebug; -int rtlil_frontend_yylex(void); -void rtlil_frontend_yyerror(char const *s); -void rtlil_frontend_yywarning(char const *s); -void rtlil_frontend_yyrestart(FILE *f); -int rtlil_frontend_yyparse(void); -int rtlil_frontend_yylex_destroy(void); -int rtlil_frontend_yyget_lineno(void); - -#endif - diff --git a/frontends/rtlil/rtlil_lexer.l b/frontends/rtlil/rtlil_lexer.l deleted file mode 100644 index c374dd395..000000000 --- a/frontends/rtlil/rtlil_lexer.l +++ /dev/null @@ -1,150 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -%{ - -#ifdef __clang__ -// bison generates code using the 'register' storage class specifier -#pragma clang diagnostic ignored "-Wdeprecated-register" -#endif - -#include -#include "frontends/rtlil/rtlil_frontend.h" -#include "rtlil_parser.tab.hh" - -USING_YOSYS_NAMESPACE - -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*RTLIL_FRONTEND::lexin, buf, max_size) - -%} - -%option yylineno -%option noyywrap -%option nounput -%option prefix="rtlil_frontend_yy" - -%x STRING - -%% - -"autoidx" { return TOK_AUTOIDX; } -"module" { return TOK_MODULE; } -"attribute" { return TOK_ATTRIBUTE; } -"parameter" { return TOK_PARAMETER; } -"signed" { return TOK_SIGNED; } -"real" { return TOK_REAL; } -"wire" { return TOK_WIRE; } -"memory" { return TOK_MEMORY; } -"width" { return TOK_WIDTH; } -"upto" { return TOK_UPTO; } -"offset" { return TOK_OFFSET; } -"size" { return TOK_SIZE; } -"input" { return TOK_INPUT; } -"output" { return TOK_OUTPUT; } -"inout" { return TOK_INOUT; } -"cell" { return TOK_CELL; } -"connect" { return TOK_CONNECT; } -"switch" { return TOK_SWITCH; } -"case" { return TOK_CASE; } -"assign" { return TOK_ASSIGN; } -"sync" { return TOK_SYNC; } -"low" { return TOK_LOW; } -"high" { return TOK_HIGH; } -"posedge" { return TOK_POSEDGE; } -"negedge" { return TOK_NEGEDGE; } -"edge" { return TOK_EDGE; } -"always" { return TOK_ALWAYS; } -"global" { return TOK_GLOBAL; } -"init" { return TOK_INIT; } -"update" { return TOK_UPDATE; } -"memwr" { return TOK_MEMWR; } -"process" { return TOK_PROCESS; } -"end" { return TOK_END; } - -[a-z]+ { return TOK_INVALID; } - -"\\"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } -"$"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } - -[0-9]+'s?[01xzm-]* { rtlil_frontend_yylval.string = strdup(yytext); return TOK_VALUE; } --?[0-9]+ { - char *end = nullptr; - errno = 0; - long value = strtol(yytext, &end, 10); - log_assert(end == yytext + strlen(yytext)); - if (errno == ERANGE) - return TOK_INVALID; // literal out of range of long - if (value < INT_MIN || value > INT_MAX) - return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms) - rtlil_frontend_yylval.integer = value; - return TOK_INT; -} - -\" { BEGIN(STRING); } -\\. { yymore(); } -\" { - BEGIN(0); - char *yystr = strdup(yytext); - yystr[strlen(yytext) - 1] = 0; - int i = 0, j = 0; - while (yystr[i]) { - if (yystr[i] == '\\' && yystr[i + 1]) { - i++; - if (yystr[i] == 'n') - yystr[i] = '\n'; - else if (yystr[i] == 't') - yystr[i] = '\t'; - else if ('0' <= yystr[i] && yystr[i] <= '7') { - yystr[i] = yystr[i] - '0'; - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - } - } - yystr[j++] = yystr[i++]; - } - yystr[j] = 0; - rtlil_frontend_yylval.string = yystr; - return TOK_STRING; -} -. { yymore(); } - -"#"[^\n]* /* ignore comments */ -[ \t] /* ignore non-newline whitespaces */ -[\r\n]+ { return TOK_EOL; } - -. { return *yytext; } - -%% - -// this is a hack to avoid the 'yyinput defined but not used' error msgs -void *rtlil_frontend_avoid_input_warnings() { - return (void*)&yyinput; -} diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y deleted file mode 100644 index 2b8d7b7ab..000000000 --- a/frontends/rtlil/rtlil_parser.y +++ /dev/null @@ -1,525 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -%require "3.0" - -%{ -#include -#include "frontends/rtlil/rtlil_frontend.h" -YOSYS_NAMESPACE_BEGIN -namespace RTLIL_FRONTEND { - std::istream *lexin; - RTLIL::Design *current_design; - RTLIL::Module *current_module; - RTLIL::Wire *current_wire; - RTLIL::Memory *current_memory; - RTLIL::Cell *current_cell; - RTLIL::Process *current_process; - std::vector*> switch_stack; - std::vector case_stack; - dict attrbuf; - bool flag_nooverwrite, flag_overwrite, flag_lib; - bool delete_current_module; -} -using namespace RTLIL_FRONTEND; -YOSYS_NAMESPACE_END -USING_YOSYS_NAMESPACE -%} - -%define api.prefix {rtlil_frontend_yy} - -/* The union is defined in the header, so we need to provide all the - * includes it requires - */ -%code requires { -#include -#include -#include "frontends/rtlil/rtlil_frontend.h" -} - -%union { - char *string; - int integer; - YOSYS_NAMESPACE_PREFIX RTLIL::Const *data; - YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec; - std::vector *rsigspec; -} - -%token TOK_ID TOK_VALUE TOK_STRING -%token TOK_INT -%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT -%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC -%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT -%token TOK_UPDATE TOK_MEMWR TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET -%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO - -%type sigspec_list_reversed -%type sigspec sigspec_list -%type sync_type -%type constant - -%expect 0 -%debug - -%% - -input: - optional_eol { - attrbuf.clear(); - } design { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - }; - -EOL: - optional_eol TOK_EOL; - -optional_eol: - optional_eol TOK_EOL | /* empty */; - -design: - design module | - design attr_stmt | - design autoidx_stmt | - /* empty */; - -module: - TOK_MODULE TOK_ID EOL { - delete_current_module = false; - if (current_design->has($2)) { - RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { - log("Ignoring blackbox re-definition of module %s.\n", $2); - delete_current_module = true; - } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of module %s.", $2).c_str()); - } else if (flag_nooverwrite) { - log("Ignoring re-definition of module %s.\n", $2); - delete_current_module = true; - } else { - log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2); - current_design->remove(existing_mod); - } - } - current_module = new RTLIL::Module; - current_module->name = $2; - current_module->attributes = attrbuf; - if (!delete_current_module) - current_design->add(current_module); - attrbuf.clear(); - free($2); - } module_body TOK_END { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - current_module->fixup_ports(); - if (delete_current_module) - delete current_module; - else if (flag_lib) - current_module->makeblackbox(); - current_module = nullptr; - } EOL; - -module_body: - module_body module_stmt | - /* empty */; - -module_stmt: - param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; - -param_stmt: - TOK_PARAMETER TOK_ID EOL { - current_module->avail_parameters($2); - free($2); - }; - -param_defval_stmt: - TOK_PARAMETER TOK_ID constant EOL { - current_module->avail_parameters($2); - current_module->parameter_default_values[$2] = *$3; - delete $3; - free($2); - }; - -attr_stmt: - TOK_ATTRIBUTE TOK_ID constant EOL { - attrbuf[$2] = *$3; - delete $3; - free($2); - }; - -autoidx_stmt: - TOK_AUTOIDX TOK_INT EOL { - autoidx = max(autoidx, $2); - }; - -wire_stmt: - TOK_WIRE { - current_wire = current_module->addWire("$__rtlil_frontend_tmp__"); - current_wire->attributes = attrbuf; - attrbuf.clear(); - } wire_options TOK_ID EOL { - if (current_module->wire($4) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of wire %s.", $4).c_str()); - current_module->rename(current_wire, $4); - free($4); - }; - -wire_options: - wire_options TOK_WIDTH TOK_INT { - current_wire->width = $3; - } | - wire_options TOK_WIDTH TOK_INVALID { - rtlil_frontend_yyerror("RTLIL error: invalid wire width"); - } | - wire_options TOK_UPTO { - current_wire->upto = true; - } | - wire_options TOK_SIGNED { - current_wire->is_signed = true; - } | - wire_options TOK_OFFSET TOK_INT { - current_wire->start_offset = $3; - } | - wire_options TOK_INPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = false; - } | - wire_options TOK_OUTPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = false; - current_wire->port_output = true; - } | - wire_options TOK_INOUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = true; - } | - /* empty */; - -memory_stmt: - TOK_MEMORY { - current_memory = new RTLIL::Memory; - current_memory->attributes = attrbuf; - attrbuf.clear(); - } memory_options TOK_ID EOL { - if (current_module->memories.count($4) != 0) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of memory %s.", $4).c_str()); - current_memory->name = $4; - current_module->memories[$4] = current_memory; - free($4); - }; - -memory_options: - memory_options TOK_WIDTH TOK_INT { - current_memory->width = $3; - } | - memory_options TOK_SIZE TOK_INT { - current_memory->size = $3; - } | - memory_options TOK_OFFSET TOK_INT { - current_memory->start_offset = $3; - } | - /* empty */; - -cell_stmt: - TOK_CELL TOK_ID TOK_ID EOL { - if (current_module->cell($3) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell %s.", $3).c_str()); - current_cell = current_module->addCell($3, $2); - current_cell->attributes = attrbuf; - attrbuf.clear(); - free($2); - free($3); - } cell_body TOK_END EOL; - -cell_body: - cell_body TOK_PARAMETER TOK_ID constant EOL { - current_cell->parameters[$3] = *$4; - free($3); - delete $4; - } | - cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL { - current_cell->parameters[$4] = *$5; - current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED; - free($4); - delete $5; - } | - cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL { - current_cell->parameters[$4] = *$5; - current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL; - free($4); - delete $5; - } | - cell_body TOK_CONNECT TOK_ID sigspec EOL { - if (current_cell->hasPort($3)) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell port %s.", $3).c_str()); - current_cell->setPort($3, *$4); - delete $4; - free($3); - } | - /* empty */; - -proc_stmt: - TOK_PROCESS TOK_ID EOL { - if (current_module->processes.count($2) != 0) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str()); - current_process = current_module->addProcess($2); - current_process->attributes = attrbuf; - switch_stack.clear(); - switch_stack.push_back(¤t_process->root_case.switches); - case_stack.clear(); - case_stack.push_back(¤t_process->root_case); - attrbuf.clear(); - free($2); - } case_body sync_list TOK_END EOL; - -switch_stmt: - TOK_SWITCH sigspec EOL { - RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; - rule->signal = *$2; - rule->attributes = attrbuf; - switch_stack.back()->push_back(rule); - attrbuf.clear(); - delete $2; - } attr_list switch_body TOK_END EOL; - -attr_list: - /* empty */ | - attr_list attr_stmt; - -switch_body: - switch_body TOK_CASE { - RTLIL::CaseRule *rule = new RTLIL::CaseRule; - rule->attributes = attrbuf; - switch_stack.back()->back()->cases.push_back(rule); - switch_stack.push_back(&rule->switches); - case_stack.push_back(rule); - attrbuf.clear(); - } compare_list EOL case_body { - switch_stack.pop_back(); - case_stack.pop_back(); - } | - /* empty */; - -compare_list: - sigspec { - case_stack.back()->compare.push_back(*$1); - delete $1; - } | - compare_list ',' sigspec { - case_stack.back()->compare.push_back(*$3); - delete $3; - } | - /* empty */; - -case_body: - case_body attr_stmt | - case_body switch_stmt | - case_body assign_stmt | - /* empty */; - -assign_stmt: - TOK_ASSIGN sigspec sigspec EOL { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - - // See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this - // warning - if (!switch_stack.back()->empty()) { - rtlil_frontend_yywarning( - "case rule assign statements after switch statements may cause unexpected behaviour. " - "The assign statement is reordered to come before all switch statements." - ); - } - - case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); - delete $2; - delete $3; - }; - -sync_list: - sync_list TOK_SYNC sync_type sigspec EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType($3); - rule->signal = *$4; - current_process->syncs.push_back(rule); - delete $4; - } update_list | - sync_list TOK_SYNC TOK_ALWAYS EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STa; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_GLOBAL EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STg; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_INIT EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STi; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - /* empty */; - -sync_type: - TOK_LOW { $$ = RTLIL::ST0; } | - TOK_HIGH { $$ = RTLIL::ST1; } | - TOK_POSEDGE { $$ = RTLIL::STp; } | - TOK_NEGEDGE { $$ = RTLIL::STn; } | - TOK_EDGE { $$ = RTLIL::STe; }; - -update_list: - update_list TOK_UPDATE sigspec sigspec EOL { - current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4)); - delete $3; - delete $4; - } | - update_list attr_list TOK_MEMWR TOK_ID sigspec sigspec sigspec constant EOL { - RTLIL::MemWriteAction act; - act.attributes = attrbuf; - act.memid = $4; - act.address = *$5; - act.data = *$6; - act.enable = *$7; - act.priority_mask = *$8; - current_process->syncs.back()->mem_write_actions.push_back(std::move(act)); - attrbuf.clear(); - free($4); - delete $5; - delete $6; - delete $7; - delete $8; - } | - /* empty */; - -constant: - TOK_VALUE { - char *ep; - int width = strtol($1, &ep, 10); - bool is_signed = false; - if (*ep == '\'') { - ep++; - } - if (*ep == 's') { - is_signed = true; - ep++; - } - std::list bits; - while (*ep != 0) { - RTLIL::State bit = RTLIL::Sx; - switch (*ep) { - case '0': bit = RTLIL::S0; break; - case '1': bit = RTLIL::S1; break; - case 'x': bit = RTLIL::Sx; break; - case 'z': bit = RTLIL::Sz; break; - case '-': bit = RTLIL::Sa; break; - case 'm': bit = RTLIL::Sm; break; - } - bits.push_front(bit); - ep++; - } - - if (bits.size() == 0) - bits.push_back(RTLIL::Sx); - while ((int)bits.size() < width) { - RTLIL::State bit = bits.back(); - if (bit == RTLIL::S1) - bit = RTLIL::S0; - bits.push_back(bit); - } - while ((int)bits.size() > width) - bits.pop_back(); - RTLIL::Const::Builder builder(bits.size()); - for (RTLIL::State bit : bits) - builder.push_back(bit); - $$ = new RTLIL::Const(builder.build()); - if (is_signed) { - $$->flags |= RTLIL::CONST_FLAG_SIGNED; - } - free($1); - } | - TOK_INT { - $$ = new RTLIL::Const($1); - } | - TOK_STRING { - $$ = new RTLIL::Const($1); - free($1); - }; - -sigspec: - constant { - $$ = new RTLIL::SigSpec(*$1); - delete $1; - } | - TOK_ID { - if (current_module->wire($1) == nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str()); - $$ = new RTLIL::SigSpec(current_module->wire($1)); - free($1); - } | - sigspec '[' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0) - rtlil_frontend_yyerror("bit index out of range"); - $$ = new RTLIL::SigSpec($1->extract($3)); - delete $1; - } | - sigspec '[' TOK_INT ':' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0 || $3 < $5) - rtlil_frontend_yyerror("invalid slice"); - $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1)); - delete $1; - } | - '{' sigspec_list '}' { - $$ = $2; - }; - -sigspec_list_reversed: - sigspec_list_reversed sigspec { - $$->push_back(*$2); - delete $2; - } | - /* empty */ { - $$ = new std::vector; - }; - -sigspec_list: sigspec_list_reversed { - $$ = new RTLIL::SigSpec; - for (auto it = $1->rbegin(); it != $1->rend(); it++) - $$->append(*it); - delete $1; - }; - -conn_stmt: - TOK_CONNECT sigspec sigspec EOL { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - current_module->connect(*$2, *$3); - delete $2; - delete $3; - }; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index ec04e545f..34d3aad2a 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -135,13 +135,13 @@ void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefil if (log_verific_callback) { string full_message = stringf("%s%s\n", message_prefix, message); -#ifdef VERIFIC_LINEFILE_INCLUDES_COLUMNS - log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), - linefile ? linefile->GetLeftLine() : 0, linefile ? linefile->GetLeftCol() : 0, +#ifdef VERIFIC_LINEFILE_INCLUDES_COLUMNS + log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), + linefile ? linefile->GetLeftLine() : 0, linefile ? linefile->GetLeftCol() : 0, linefile ? linefile->GetRightLine() : 0, linefile ? linefile->GetRightCol() : 0, full_message.c_str()); #else - log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), - linefile ? LineFile::GetLineNo(linefile) : 0, 0, + log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), + linefile ? LineFile::GetLineNo(linefile) : 0, 0, linefile ? LineFile::GetLineNo(linefile) : 0, 0, full_message.c_str()); #endif } else { @@ -171,6 +171,25 @@ string get_full_netlist_name(Netlist *nl) return nl->CellBaseName(); } +std::string format_src_location(DesignObj *obj) +{ + if (obj == nullptr || !obj->Linefile()) + return std::string(); +#ifdef VERIFIC_LINEFILE_INCLUDES_COLUMNS + return stringf("%s:%d.%d-%d.%d", LineFile::GetFileName(obj->Linefile()), obj->Linefile()->GetLeftLine(), obj->Linefile()->GetLeftCol(), obj->Linefile()->GetRightLine(), obj->Linefile()->GetRightCol()); +#else + return stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); +#endif +} + +std::string announce_src_location(DesignObj *obj) +{ + std::string loc = format_src_location(obj); + if (loc.empty()) + return std::string(); + return loc + ": "; +} + #ifdef VERIFIC_SYSTEMVERILOG_SUPPORT class YosysStreamCallBackHandler : public VerificStreamCallBackHandler { @@ -313,7 +332,7 @@ static const RTLIL::Const extract_vhdl_const(const char *value, bool output_sig bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; }); if (isBinary) c = RTLIL::Const::from_string(data); - else + else c = RTLIL::Const(data); } else if (val.size()==3 && val[0]=='\'' && val.back()=='\'') { c = RTLIL::Const::from_string(val.substr(1,val.size()-2)); @@ -403,7 +422,7 @@ static const RTLIL::Const verific_const(const char* type_name, const char *value // SystemVerilog if (type_name && strcmp(type_name, "real")==0) { return extract_real_value(val); - } else + } else return extract_verilog_const(value, allow_string, output_signed); } @@ -425,14 +444,8 @@ void VerificImporter::import_attributes(dict &att MapIter mi; Att *attr; -#ifdef VERIFIC_LINEFILE_INCLUDES_COLUMNS - if (obj->Linefile()) { - attributes[ID::src] = stringf("%s:%d.%d-%d.%d", LineFile::GetFileName(obj->Linefile()), obj->Linefile()->GetLeftLine(), obj->Linefile()->GetLeftCol(), obj->Linefile()->GetRightLine(), obj->Linefile()->GetRightCol()); - } -#else if (obj->Linefile()) - attributes[ID::src] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); -#endif + attributes[ID::src] = format_src_location(obj); FOREACH_ATTRIBUTE(obj, mi, attr) { if (attr->Key()[0] == ' ' || attr->Value() == nullptr) @@ -518,7 +531,7 @@ void VerificImporter::import_attributes(dict &att } } if (p == nullptr) - log_error("Expected TypeRange value '%s' to be of form \"\" or .\n", v); + log_error("%sExpected TypeRange value '%s' to be of form \"\" or .\n", announce_src_location(obj), v); } #endif } @@ -1000,7 +1013,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr else if (net_cin == net_a_msb) cell = module->addSshr(inst_name, IN1, IN2, OUT, true); else - log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name()); + log_error("%sCan't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", announce_src_location(inst), inst->Name()); import_attributes(cell->attributes, inst); return true; } @@ -1054,7 +1067,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr else if (net_cin->IsPwr()) cell = module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); else - log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name()); + log_error("%sCan't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", announce_src_location(inst), inst->Name()); import_attributes(cell->attributes, inst); return true; } @@ -1279,7 +1292,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr for (unsigned j = 0 ; j < selector->GetNumConditions(i) ; ++j) { Array left_bound, right_bound ; selector->GetCondition(i, j, &left_bound, &right_bound); - + SigSpec sel_left = sig_select_values.extract(offset_select, select_width); offset_select += select_width; @@ -1554,7 +1567,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma char *architecture_name = name_space.ReName(nl->Name()) ; module->set_string_attribute(ID(architecture), (architecture_name) ? architecture_name : nl->Name()); } -#endif +#endif const char *param_name ; const char *param_value ; MapIter mi; @@ -1686,7 +1699,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma bits_in_word = min(bits_in_word, pr->GetInst()->Input2Size()); continue; } - log_error("Verific RamNet %s is connected to unsupported instance type %s (%s).\n", + log_error("%sVerific RamNet %s is connected to unsupported instance type %s (%s).\n", announce_src_location(pr->GetInst()), net->Name(), pr->GetInst()->View()->Owner()->Name(), pr->GetInst()->Name()); } memory->width = bits_in_word; @@ -1709,7 +1722,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (*ascii_initdata == 0) break; if (*ascii_initdata == '0' || *ascii_initdata == '1') { - initval.bits()[bit_idx] = (*ascii_initdata == '0') ? State::S0 : State::S1; + initval.set(bit_idx, (*ascii_initdata == '0') ? State::S0 : State::S1); initval_valid = true; } ascii_initdata++; @@ -1833,9 +1846,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (init_nets.count(net)) { if (init_nets.at(net) == '0') - initval.bits().at(bitidx) = State::S0; + initval.set(bitidx, State::S0); if (init_nets.at(net) == '1') - initval.bits().at(bitidx) = State::S1; + initval.set(bitidx, State::S1); initval_valid = true; init_nets.erase(net); } @@ -1908,13 +1921,13 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (bit.wire->attributes.count(ID::init)) initval = bit.wire->attributes.at(ID::init); - while (GetSize(initval) < GetSize(bit.wire)) - initval.bits().push_back(State::Sx); + if (GetSize(initval) < GetSize(bit.wire)) + initval.resize(GetSize(bit.wire), State::Sx); if (it.second == '0') - initval.bits().at(bit.offset) = State::S0; + initval.set(bit.offset, State::S0); if (it.second == '1') - initval.bits().at(bit.offset) = State::S1; + initval.set(bit.offset, State::S1); bit.wire->attributes[ID::init] = initval; } @@ -1975,7 +1988,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma { RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetInput()->Name()), nullptr); if (!memory) - log_error("Memory net '%s' missing, possibly no driver, use verific -flatten.\n", inst->GetInput()->Name()); + log_error("%sMemory net '%s' missing, possibly no driver, use verific -flatten.\n", announce_src_location(inst), inst->GetInput()->Name()); int numchunks = int(inst->OutputSize()) / memory->width; int chunksbits = ceil_log2(numchunks); @@ -2006,7 +2019,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma { RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name()), nullptr); if (!memory) - log_error("Memory net '%s' missing, possibly no driver, use verific -flatten.\n", inst->GetInput()->Name()); + log_error("%sMemory net '%s' missing, possibly no driver, use verific -flatten.\n", announce_src_location(inst), inst->GetInput()->Name()); int numchunks = int(inst->Input2Size()) / memory->width; int chunksbits = ceil_log2(numchunks); @@ -2041,7 +2054,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (import_netlist_instance_cells(inst, inst_name)) continue; if (inst->IsOperator() && !verific_sva_prims.count(inst->Type())) - log_warning("Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name()); + log_warning("%sUnsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", announce_src_location(inst), inst->View()->Owner()->Name()); } else { if (import_netlist_instance_gates(inst, inst_name)) continue; @@ -2101,7 +2114,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma } Const qx_init = Const(State::S1, width); - qx_init.bits().resize(2 * width, State::S0); + qx_init.resize(2 * width, State::S0); clocking.addDff(new_verific_id(inst), sig_dx, sig_qx, qx_init); module->addXnor(new_verific_id(inst), sig_dx, sig_qx, sig_ox); @@ -2227,10 +2240,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (inst->IsPrimitive()) { if (!mode_keep) - log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name()); + log_error("%sUnsupported Verific primitive %s of type %s\n", announce_src_location(inst), inst->Name(), inst->View()->Owner()->Name()); if (!verific_sva_prims.count(inst->Type())) - log_warning("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name()); + log_warning("%sUnsupported Verific primitive %s of type %s\n", announce_src_location(inst), inst->Name(), inst->View()->Owner()->Name()); } import_verific_cells: @@ -2366,7 +2379,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma continue; if (non_ff_bits.count(SigBit(wire, i))) - initval.bits()[i] = State::Sx; + initval.set(i, State::Sx); } if (wire->port_input) { @@ -2559,7 +2572,7 @@ Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const if (c.wire && c.wire->attributes.count(ID::init)) { Const val = c.wire->attributes.at(ID::init); for (int i = 0; i < GetSize(c); i++) - initval.bits()[offset+i] = val[c.offset+i]; + initval.set(offset+i, val[c.offset+i]); } offset += GetSize(c); } @@ -2630,7 +2643,7 @@ Cell *VerificClocking::addAldff(IdString name, RTLIL::SigSpec sig_aload, RTLIL:: if (c.wire && c.wire->attributes.count(ID::init)) { Const val = c.wire->attributes.at(ID::init); for (int i = 0; i < GetSize(c); i++) - initval.bits()[offset+i] = val[c.offset+i]; + initval.set(offset+i, val[c.offset+i]); } offset += GetSize(c); } @@ -2811,13 +2824,13 @@ void save_blackbox_msg_state() void restore_blackbox_msg_state() { #ifdef VERIFIC_SYSTEMVERILOG_SUPPORT - Message::ClearMessageType("VERI-1063") ; + Message::ClearMessageType("VERI-1063") ; if (Message::GetMessageType("VERI-1063")!=prev_1063) Message::SetMessageType("VERI-1063", prev_1063); #endif #ifdef VERIFIC_VHDL_SUPPORT - Message::ClearMessageType("VHDL-1240") ; - Message::ClearMessageType("VHDL-1241") ; + Message::ClearMessageType("VHDL-1240") ; + Message::ClearMessageType("VHDL-1241") ; if (Message::GetMessageType("VHDL-1240")!=prev_1240) Message::SetMessageType("VHDL-1240", prev_1240); if (Message::GetMessageType("VHDL-1241")!=prev_1241) @@ -3415,7 +3428,7 @@ struct VerificPass : public Pass { log("\n"); #if defined(YOSYS_ENABLE_VERIFIC) and defined(YOSYSHQ_VERIFIC_EXTENSIONS) VerificExtensions::Help(); -#endif +#endif log("Use YosysHQ Tabby CAD Suite if you need Yosys+Verific.\n"); log("https://www.yosyshq.com/\n"); log("\n"); @@ -3471,7 +3484,7 @@ struct VerificPass : public Pass { VhdlPrimaryUnit *unit ; if (!flag_lib) return; VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); - if (vhdl_lib) { + if (vhdl_lib) { FOREACH_VHDL_PRIMARY_UNIT(vhdl_lib, mi, unit) { if (!unit) continue; map.Insert(unit,unit); @@ -3503,7 +3516,7 @@ struct VerificPass : public Pass { VeriModule *veri_module ; if (!flag_lib) return; VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); - if (veri_lib) { + if (veri_lib) { FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { if (!veri_module) continue; map.Insert(veri_module,veri_module); @@ -4501,12 +4514,12 @@ struct VerificPass : public Pass { } } #ifdef YOSYSHQ_VERIFIC_EXTENSIONS - if (VerificExtensions::Execute(args, argidx, work, + if (VerificExtensions::Execute(args, argidx, work, [this](const std::vector &args, size_t argidx, std::string msg) { cmd_error(args, argidx, msg); } )) { goto check_error; } -#endif +#endif cmd_error(args, argidx, "Missing or unsupported mode parameter.\n"); diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 50e0049ae..dffe6e8e0 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -577,7 +577,7 @@ struct SvaFsm if (delta_pos >= 0 && i_within_j && j_within_i) { did_something = true; - values[i].bits()[delta_pos] = State::Sa; + values[i].set(delta_pos, State::Sa); values[j] = values.back(); values.pop_back(); goto next_pair; diff --git a/kernel/driver.cc b/kernel/driver.cc index bbe4e46f3..795fd9fc5 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -37,6 +37,12 @@ # include #endif +#ifdef YOSYS_ENABLE_PYTHON +# include +# include +namespace py = pybind11; +#endif + #include #include #include @@ -91,9 +97,10 @@ int main(int argc, char **argv) log_error_stderr = true; yosys_banner(); yosys_setup(); -#ifdef WITH_PYTHON - PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); - PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); +#ifdef YOSYS_ENABLE_PYTHON + py::object sys = py::module_::import("sys"); + sys.attr("path").attr("append")(proc_self_dirname()); + sys.attr("path").attr("append")(proc_share_dirname()); #endif if (argc == 2) @@ -226,10 +233,10 @@ int main(int argc, char **argv) cxxopts::value(),"") ("C,tcl-interactive", "enters TCL interactive shell mode") #endif // YOSYS_ENABLE_TCL -#ifdef WITH_PYTHON +#ifdef YOSYS_ENABLE_PYTHON ("y,py-scriptfile", "execute the Python