diff --git a/yosys/.clang-format b/yosys/.clang-format new file mode 100644 index 000000000..28d13da25 --- /dev/null +++ b/yosys/.clang-format @@ -0,0 +1,13 @@ +# Default Linux style +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Linux +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false + +# From CodingReadme +TabWidth: 8 +ContinuationIndentWidth: 2 +ColumnLimit: 150 +# BreakBeforeBraces: Linux diff --git a/yosys/.dockerignore b/yosys/.dockerignore new file mode 100644 index 000000000..9910e9954 --- /dev/null +++ b/yosys/.dockerignore @@ -0,0 +1,13 @@ +.editorconfig +.gitignore +.gitmodules +.github +.git +Dockerfile +README.md +manual +CodingReadme +CodeOfConduct +.travis +.travis.yml + diff --git a/yosys/.editorconfig b/yosys/.editorconfig new file mode 100644 index 000000000..4d6f5ef7a --- /dev/null +++ b/yosys/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +indent_style = tab +indent_size = tab +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/yosys/.github/issue_template.md b/yosys/.github/issue_template.md new file mode 100644 index 000000000..5a0723c3e --- /dev/null +++ b/yosys/.github/issue_template.md @@ -0,0 +1,24 @@ +## Steps to reproduce the issue + +*Provide instructions for reproducing the issue. Make sure to include +all necessary source files. (You can simply drag&drop a .zip file into +the issue editor.)* + +Also, make sure that the issue is actually reproducable in current git +master of Yosys. + +See https://stackoverflow.com/help/mcve for some information on how to +create a Minimal, Complete, and Verifiable example (MCVE). + +Please do not waste our time with issues that lack sufficient information +to reproduce the issue easily. We will simply close those issues. + +Contact https://www.symbioticeda.com/ if you need commercial support for Yosys. + +## Expected behavior + +*Please describe the behavior you would have expected from the tool.* + +## Actual behavior + +*Please describe how the behavior you see differs from the expected behavior.* diff --git a/yosys/.gitignore b/yosys/.gitignore index 93e28cd6c..76f53cd06 100644 --- a/yosys/.gitignore +++ b/yosys/.gitignore @@ -1,6 +1,10 @@ *.o *.d .*.swp +*.gch +*.gcda +*.gcno +__pycache__ /.cproject /.project /.settings @@ -9,6 +13,8 @@ /qtcreator.config /qtcreator.creator /qtcreator.creator.user +/coverage.info +/coverage_html /Makefile.conf /abc /viz.js @@ -19,11 +25,18 @@ /yosys-abc.exe /yosys-config /yosys-smtbmc +/yosys-smtbmc.exe +/yosys-smtbmc-script.py /yosys-filterlib /yosys-filterlib.exe +/kernel/*.pyh +/kernel/python_wrappers.cc /kernel/version_*.cc /share /yosys-win32-mxebin-* /yosys-win32-vcxsrc-* /yosysjs-* /libyosys.so +/tests/unit/bintest/ +/tests/unit/objtest/ +/tests/ystests diff --git a/yosys/.travis.yml b/yosys/.travis.yml index 9f0cc06e7..c253b2ff7 100644 --- a/yosys/.travis.yml +++ b/yosys/.travis.yml @@ -1,34 +1,140 @@ sudo: false -script: make && make test language: cpp -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gperf - - build-essential - - clang - - bison - - flex - - libreadline-dev - - gawk - - tcl-dev - - libffi-dev - - git - - mercurial - - graphviz - - xdot - - pkg-config - - python - - g++-4.8 + +cache: + ccache: true + directories: + - ~/.local-bin + + +env: + global: + - MAKEFLAGS="-j 2" + +matrix: + include: + # Latest gcc-4.8, earliest version supported by Travis + - os: linux + addons: + apt: + packages: + - g++-4.8 + - gperf + - build-essential + - bison + - flex + - libreadline-dev + - gawk + - tcl-dev + - libffi-dev + - git + - graphviz + - xdot + - pkg-config + - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + env: + - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" + + # Latest gcc supported on Travis Linux + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-9 + - gperf + - build-essential + - bison + - flex + - libreadline-dev + - gawk + - tcl-dev + - libffi-dev + - git + - graphviz + - xdot + - pkg-config + - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + env: + - MATRIX_EVAL="CONFIG=gcc && CC=gcc-9 && CXX=g++-9" + + # Clang which ships on Trusty Linux + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + - gperf + - build-essential + - bison + - flex + - libreadline-dev + - gawk + - tcl-dev + - libffi-dev + - git + - graphviz + - xdot + - pkg-config + - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + env: + - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" + + # Latest clang supported by Travis Linux + - os: linux + addons: + apt: + sources: + - llvm-toolchain-xenial-8 + packages: + - clang-8 + - gperf + - build-essential + - bison + - flex + - libreadline-dev + - gawk + - tcl-dev + - libffi-dev + - git + - graphviz + - xdot + - pkg-config + - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + env: + - MATRIX_EVAL="CONFIG=clang && CC=clang-8 && CXX=clang++-8" + +# # Latest clang on Mac OS X +# - os: osx +# osx_image: xcode9.4 +# env: +# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" + before_install: - - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi - - git clone git://github.com/steveicarus/iverilog.git - - (cd iverilog && autoconf && ./configure --prefix=$HOME/iverilog && make && make install) - - export PATH=$PATH:$HOME/iverilog/bin -compiler: -# - clang - - gcc -os: - - linux + - ./.travis/setup.sh + +script: + - ./.travis/build-and-test.sh + +after_success: + - ./.travis/deploy-after-success.sh diff --git a/yosys/.travis/build-and-test.sh b/yosys/.travis/build-and-test.sh new file mode 100755 index 000000000..b8c35041d --- /dev/null +++ b/yosys/.travis/build-and-test.sh @@ -0,0 +1,51 @@ +#! /bin/bash + +set -e + +source .travis/common.sh + +########################################################################## + +echo +echo 'Configuring...' && echo -en 'travis_fold:start:script.configure\\r' +echo + +if [ "$CONFIG" = "gcc" ]; then + echo "Configuring for gcc." + make config-gcc +elif [ "$CONFIG" = "clang" ]; then + echo "Configuring for clang." + make config-clang +fi + +echo +echo -en 'travis_fold:end:script.configure\\r' +echo + +########################################################################## + +echo +echo 'Building...' && echo -en 'travis_fold:start:script.build\\r' +echo + +make + +echo +echo -en 'travis_fold:end:script.build\\r' +echo + +########################################################################## + +./yosys tests/simple/fiedler-cooley.v + +echo +echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r' +echo + +make test + +echo +echo -en 'travis_fold:end:script.test\\r' +echo + +########################################################################## diff --git a/yosys/.travis/common.sh b/yosys/.travis/common.sh new file mode 100644 index 000000000..8eecc4c09 --- /dev/null +++ b/yosys/.travis/common.sh @@ -0,0 +1,15 @@ +#! /bin/bash + +# Setup the CC / CXX from the matrix config +eval "${MATRIX_EVAL}" + +# Look for location binaries first +export PATH="$HOME/.local-bin/bin:$PATH" + +# OS X specific common setup +if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + export PATH="/usr/local/opt/ccache/libexec:$PATH" +fi + +# Parallel builds! +MAKEFLAGS="-j 2" diff --git a/yosys/.travis/deploy-after-success.sh b/yosys/.travis/deploy-after-success.sh new file mode 100755 index 000000000..d64e95244 --- /dev/null +++ b/yosys/.travis/deploy-after-success.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +set -x +set -e + +# FIXME: Upload the build results somewhere... diff --git a/yosys/.travis/setup.sh b/yosys/.travis/setup.sh new file mode 100755 index 000000000..02879b974 --- /dev/null +++ b/yosys/.travis/setup.sh @@ -0,0 +1,63 @@ +#! /bin/bash + +set -e + +source .travis/common.sh + +########################################################################## + +# Output status information. +( + set +e + set -x + git status + git branch -v + git log -n 5 --graph + git log --format=oneline -n 20 --graph +) +echo +echo -en 'travis_fold:end:before_install.git\\r' +echo + +########################################################################## + +# Mac OS X specific setup. +if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + ( + echo + echo 'Setting up brew...' && echo -en 'travis_fold:start:before_install.brew\\r' + echo + brew update + brew tap Homebrew/bundle + brew bundle + brew install ccache + echo + echo -en 'travis_fold:end:before_install.brew\\r' + echo + ) +fi + +########################################################################## + +# Install iverilog +( + if [ ! -e ~/.local-bin/bin/iverilog ]; then + echo + echo 'Building iverilog...' && echo -en 'travis_fold:start:before_install.iverilog\\r' + echo + mkdir -p ~/.local-src + mkdir -p ~/.local-bin + cd ~/.local-src + git clone git://github.com/steveicarus/iverilog.git + cd iverilog + autoconf + CC=gcc CXX=g++ ./configure --prefix=$HOME/.local-bin + make + make install + echo + echo -en 'travis_fold:end:before_install.iverilog\\r' + echo + fi +) + +########################################################################## diff --git a/yosys/Brewfile b/yosys/Brewfile index 0c58ce161..4ffe50e86 100644 --- a/yosys/Brewfile +++ b/yosys/Brewfile @@ -6,3 +6,4 @@ brew "git" brew "graphviz" brew "pkg-config" brew "python3" +brew "tcl-tk" diff --git a/yosys/CHANGELOG b/yosys/CHANGELOG index 36b64e111..afbcffa26 100644 --- a/yosys/CHANGELOG +++ b/yosys/CHANGELOG @@ -3,21 +3,124 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.8 .. Yosys 0.8-dev +Yosys 0.8 .. Yosys 0.9 -------------------------- * Various - - Added $changed support to read_verilog + - Many bugfixes and small improvements + - Added support for SystemVerilog interfaces and modports - Added "write_edif -attrprop" - - Added "ice40_unlut" pass - Added "opt_lut" pass - - Added "synth_ice40 -relut" - - Added "synth_ice40 -noabc" - Added "gate2lut.v" techmap rule - Added "rename -src" - Added "equiv_opt" pass - - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" + - Added "flowmap" LUT mapping pass + - Added "rename -wire" to rename cells based on the wires they drive + - Added "bugpoint" for creating minimised testcases + - Added "write_edif -gndvccy" + - "write_verilog" to escape Verilog keywords + - Fixed sign handling of real constants + - "write_verilog" to write initial statement for initial flop state + - Added pmgen pattern matcher generator + - Fixed opt_rmdff handling of $_DFFSR_???_ and $_DLATCHSR_???_ + - Added "setundef -params" to replace undefined cell parameters + - Renamed "yosys -D" to "yosys -U", added "yosys -D" to set Verilog defines + - Fixed handling of defparam when default_nettype is none + - Fixed "wreduce" flipflop handling + - Fixed FIRRTL to Verilog process instance subfield assignment + - Added "write_verilog -siminit" + - Several fixes and improvements for mem2reg memories + - Fixed handling of task output ports in clocked always blocks + - Improved handling of and-with-1 and or-with-0 in "opt_expr" + - Added "read_aiger" frontend + - Added "mutate" pass + - Added "hdlname" attribute + - Added "rename -output" + - Added "read_ilang -lib" + - Improved "proc" full_case detection and handling + - Added "whitebox" and "lib_whitebox" attributes + - Added "read_verilog -nowb", "flatten -wb" and "wbflip" + - Added Python bindings and support for Python plug-ins + - Added "pmux2shiftx" + - Added log_debug framework for reduced default verbosity + - Improved "opt_expr" and "opt_clean" handling of (partially) undriven and/or unused wires + - Added "peepopt" peephole optimisation pass using pmgen + - Added approximate support for SystemVerilog "var" keyword + - Added parsing of "specify" blocks into $specrule and $specify[23] + - Added support for attributes on parameters and localparams + - Added support for parsing attributes on port connections + - Added "wreduce -keepdc" + - Added support for optimising $dffe and $_DFFE_* cells in "opt_rmdff" + - Added Verilog wand/wor wire type support + - Added support for elaboration system tasks + - Added "muxcover -mux{4,8,16}=" + - Added "muxcover -dmux=" + - Added "muxcover -nopartial" + - Added "muxpack" pass + - Added "pmux2shiftx -norange" + - Added support for "~" in filename parsing + - Added "read_verilog -pwires" feature to turn parameters into wires + - Fixed sign extension of unsized constants with 'bx and 'bz MSB + - Fixed genvar to be a signed type + - Added support for attributes on case rules + - Added "upto" and "offset" to JSON frontend and backend + - Several liberty file parser improvements + - Fixed handling of more complex BRAM patterns + - Add "write_aiger -I -O -B" + * Formal Verification + - Added $changed support to read_verilog + - Added "read_verilog -noassert -noassume -assert-assumes" + - Added btor ops for $mul, $div, $mod and $concat + - Added yosys-smtbmc support for btor witnesses + - Added "supercover" pass + - Fixed $global_clock handling vs autowire + - Added $dffsr support to "async2sync" + - Added "fmcombine" pass + - Added memory init support in "write_btor" + - Added "cutpoint" pass + - Changed "ne" to "neq" in btor2 output + - Added support for SVA "final" keyword + - Added "fmcombine -initeq -anyeq" + - Added timescale and generated-by header to yosys-smtbmc vcd output + - Improved BTOR2 handling of undriven wires + + * Verific support + - Enabled Verific flags vhdl_support_variable_slice and veri_elaborate_top_level_modules_having_interface_ports + - Improved support for asymmetric memories + - Added "verific -chparam" + - Fixed "verific -extnets" for more complex situations + - Added "read -verific" and "read -noverific" + - Added "hierarchy -chparam" + + * New back-ends + - Added initial Anlogic support + - Added initial SmartFusion2 and IGLOO2 support + + * ECP5 support + - Added "synth_ecp5 -nowidelut" + - Added BRAM inference support to "synth_ecp5" + - Added support for transforming Diamond IO and flipflop primitives + + * iCE40 support + - Added "ice40_unlut" pass + - Added "synth_ice40 -relut" + - Added "synth_ice40 -noabc" + - Added "synth_ice40 -dffe_min_ce_use" + - Added DSP inference support using pmgen + - Added support for initialising BRAM primitives from a file + - Added iCE40 Ultra RGB LED driver cells + + * Xilinx support + - Use "write_edif -pvector bra" for Xilinx EDIF files + - Fixes for VPR place and route support with "synth_xilinx" + - Added more cell simulation models + - Added "synth_xilinx -family" + - Added "stat -tech xilinx" to estimate logic cell usage + - Added "synth_xilinx -nocarry" + - Added "synth_xilinx -nowidelut" + - "synth_xilinx" to now infer hard shift registers (-nosrl to disable) + - Added support for mapping RAM32X1D Yosys 0.7 .. Yosys 0.8 ---------------------- @@ -30,7 +133,7 @@ Yosys 0.7 .. Yosys 0.8 - Added "write_verilog -decimal" - Added "scc -set_attr" - Added "verilog_defines" command - - Remeber defines from one read_verilog to next + - Remember defines from one read_verilog to next - Added support for hierarchical defparam - Added FIRRTL back-end - Improved ABC default scripts @@ -39,7 +142,7 @@ Yosys 0.7 .. Yosys 0.8 - Added Verilog $rtoi and $itor support - Added "check -initdrv" - Added "read_blif -wideports" - - Added support for systemVerilog "++" and "--" operators + - Added support for SystemVerilog "++" and "--" operators - Added support for SystemVerilog unique, unique0, and priority case - Added "write_edif" options for edif "flavors" - Added support for resetall compiler directive diff --git a/yosys/CMakeLists.txt b/yosys/CMakeLists.txt deleted file mode 100644 index 9ec574964..000000000 --- a/yosys/CMakeLists.txt +++ /dev/null @@ -1,103 +0,0 @@ -cmake_minimum_required(VERSION 3.3.0) - -include(CMakeParseArguments) - -project(yosys) - -# Version number -set(YOSYS_VERSION_MAJOR 0.7) -set(YOSYS_VERSION_MINOR 0) -set(YOSYS_VERSION_PATCH 0) - -# Options to enable/disable dependencies -option(YOSYS_ENABLE_TCL, "Enable TCL parser integrated in yosys" ON) -option(YOSYS_ENABLE_ABC, "Enable ABC library integrated in yosys" ON) -option(YOSYS_ENABLE_PLUGINS, "Enable plug-in in yosys" ON) -option(YOSYS_ENABLE_READLINE, "Enable readline library in yosys" ON) -option(YOSYS_ENABLE_VERIFIC, "Enable verification library in yosys" OFF) -option(YOSYS_ENABLE_COVER, "Enable coverage test in yosys" ON) -option(YOSYS_ENABLE_LIBYOSYS, "Enable static library compiled yosys" OFF) -option(YOSYS_ENABLE_GPROF, "Enable profiling in compiled yosys" OFF) -option(YOSYS_ENABLE_NDEBUG, "Enable non-debugging feature in compiled yosys" OFF) - -# -## Search and link dependent packages -## We need readline to compile -if (YOSYS_ENABLE_READLINE) - find_package(Readline REQUIRED) -endif() -# -######################### -## # -## Compiler Flags Setup # -## # -######################### -# -## Compiler flag configuration checks -include(CheckCCompilerFlag) -include(CheckCXXCompilerFlag) -# -## Required Compiler Standard -#set(CMAKE_CXX_STANDARD 11) # need at least c+11 standard -#set(CMAKE_CXX_STANDARD_REQUIRED ON) -# -## Set warning flags -#set(WARN_FLAGS_TO_CHECK "") # checklist of warning flags -#set(WARN_FLAGS "") # actual warning flags to be added during compilation -## Add warning flags depending on options -#if (YOSYS_ENABLE_NDEBUG) -# set(WARN_FLAGS_TO_CHECK, ${WARN_FLAGS_TO_CHECK}, "-O3") -#endif() -# -# -##Collect the source files -#file(GLOB_RECURSE EXEC_YOSYS kernel/yosys.cc) -#file(GLOB_RECURSE LIB_SOURCES kernel/*.cc) -#file(GLOB_RECURSE LIB_HEADERS kernel/*.h) -#files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) -# -## Use c++ compiler for c source files -#set_source_files_properties(${LIB_SOURCES} PROPERTIES LANGUAGE CXX) -#set_source_files_properties(${EXEC_SOURCES} PROPERTIES LANGUAGE CXX) -#set_source_files_properties(${EXEC_SOURCES_SHELL} PROPERTIES LANGUAGE CXX) -# -##Build the library -#add_library(libyosys STATIC -# ${LIB_HEADERS} -# ${LIB_SOURCES}) -# -## add header files to be included -#target_include_directories(libyosys PUBLIC ${LIB_INCLUDE_DIRS}) -#set_target_properties(libyosys PROPERTIES PREFIX "") #Avoid extra 'lib' prefix#Create the executable -# -##Specify link-time dependancies -#target_link_libraries(libyosys -# readline) -# -## Build targets -## 1. yosys -#add_executable(yosys ${EXEC_SOURCES}) -#target_link_libraries(vpr -# libyosys) -# 2. yosys-config - -# run makefile provided, we pass-on the options to the local make file -add_custom_target( - yosys ALL - COMMAND - $(MAKE) - #CC=${CMAKE_C_COMPILER} - #CXX=${CMAKE_CXX_COMPILER} - #LD=${CMAKE_CXX_COMPILER} - #ENABLE_TCL=${YOSYS_ENABLE_TCL} - #ENABLE_ABC=${YOSYS_ENABLE_ABC} - #ENABLE_PLUGINS=${YOSYS_ENABLE_PLUGINS} - #ENABLE_READLINE=${YOSYS_ENABLE_READLINE} - #ENABLE_VERIFIC=${YOSYS_ENABLE_VERIFIC} - #ENABLE_COVER=${YOSYS_ENABLE_COVER} - #ENABLE_LIBYOSYS=${YOSYS_ENABLE_LIBYOSYS} - #ENABLE_GPROF=${YOSYS_ENABLE_GPROF} - #ENABLE_NDEBUG=${YOSYS_ENABLE_NDEBUG} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Compile Yosys with given Makefile" -) diff --git a/yosys/COPYING b/yosys/COPYING index a121cdfe9..0839088c3 100644 --- a/yosys/COPYING +++ b/yosys/COPYING @@ -1,4 +1,4 @@ -Copyright (C) 2012 - 2018 Clifford Wolf +Copyright (C) 2012 - 2019 Clifford 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 diff --git a/yosys/Dockerfile b/yosys/Dockerfile new file mode 100644 index 000000000..3c7188d82 --- /dev/null +++ b/yosys/Dockerfile @@ -0,0 +1,33 @@ +FROM ubuntu:18.04 as builder +LABEL author="Abdelrahman Hosny " +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y build-essential \ + clang \ + bison \ + flex \ + libreadline-dev \ + gawk \ + tcl-dev \ + libffi-dev \ + git \ + pkg-config \ + python3 && \ + rm -rf /var/lib/apt/lists +COPY . / +RUN make && \ + make install + +FROM ubuntu:18.04 +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y libreadline-dev tcl-dev + +COPY --from=builder /yosys /build/yosys +COPY --from=builder /yosys-abc /build/yosys-abc +COPY --from=builder /yosys-config /build/yosys-config +COPY --from=builder /yosys-filterlib /build/yosys-filterlib +COPY --from=builder /yosys-smtbmc /build/yosys-smtbmc + +ENV PATH /build:$PATH +RUN useradd -m yosys +USER yosys +ENTRYPOINT ["yosys"] diff --git a/yosys/Makefile b/yosys/Makefile index bf0f1ca0c..a67315415 100644 --- a/yosys/Makefile +++ b/yosys/Makefile @@ -1,7 +1,8 @@ -# CONFIG := clang -CONFIG := gcc +CONFIG := clang +# CONFIG := gcc # CONFIG := gcc-4.8 +# CONFIG := afl-gcc # CONFIG := emcc # CONFIG := mxe # CONFIG := msys2 @@ -21,12 +22,6 @@ ENABLE_PROTOBUF := 0 # python wrappers ENABLE_PYOSYS := 0 -PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" -PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) -PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") -PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.) -PYTHON_PREFIX := `$(PYTHON_EXECUTABLE)-config --prefix` -PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages # other configuration flags ENABLE_GCOV := 0 @@ -51,6 +46,10 @@ OS := $(shell uname -s) PREFIX ?= /usr/local INSTALL_SUDO := +ifneq ($(wildcard Makefile.conf),) +include Makefile.conf +endif + BINDIR := $(PREFIX)/bin LIBDIR := $(PREFIX)/lib DATDIR := $(PREFIX)/share/yosys @@ -90,6 +89,11 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup # homebrew search paths ifneq ($(shell which brew),) BREW_PREFIX := $(shell brew --prefix)/opt +$(info $$BREW_PREFIX is [${BREW_PREFIX}]) +ifeq ($(ENABLE_PYOSYS),1) +CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost +LDFLAGS += -L$(BREW_PREFIX)/boost/lib +endif CXXFLAGS += -I$(BREW_PREFIX)/readline/include LDFLAGS += -L$(BREW_PREFIX)/readline/lib PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) @@ -110,7 +114,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; }) +YOSYS_VER := 0.9 GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN) OBJS = kernel/version_$(GIT_REV).o @@ -139,6 +143,21 @@ $(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$ include Makefile.conf endif +ifeq ($(ENABLE_PYOSYS),1) +PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" +PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) +PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") +PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.) +PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix) +PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages + +# Reload Makefile.conf to override python specific variables if defined +ifneq ($(wildcard Makefile.conf),) +include Makefile.conf +endif + +endif + ifeq ($(CONFIG),clang) CXX = clang LD = clang++ @@ -186,6 +205,12 @@ LD = gcc-4.8 CXXFLAGS += -std=c++11 -Os ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" +else ifeq ($(CONFIG),afl-gcc) +CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc +LD = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc +CXXFLAGS += -std=c++11 -Os +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" + else ifeq ($(CONFIG),cygwin) CXX = gcc LD = gcc @@ -237,7 +262,8 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc" +# TODO: Try to solve pthread linking issue in more appropriate way +ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LDFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc" EXE = .exe else ifeq ($(CONFIG),msys2) @@ -273,30 +299,51 @@ endif ifeq ($(ENABLE_PYOSYS),1) #Detect name of boost_python library. Some distros usbe boost_python-py, other boost_python, some only use the major version number, some a concatenation of major and minor version numbers +ifeq ($(OS), Darwin) +BOOST_PYTHON_LIB ?= $(shell \ + if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \ + if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ + if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \ + if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ + echo ""; fi; fi; fi; fi;) +else BOOST_PYTHON_LIB ?= $(shell \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ echo ""; fi; fi; fi; fi;) +endif ifeq ($(BOOST_PYTHON_LIB),) $(error BOOST_PYTHON_LIB could not be detected. Please define manualy) endif +ifeq ($(OS), Darwin) ifeq ($(PYTHON_MAJOR_VERSION),3) -LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON +LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem +CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON else -LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON +LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem +CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON +endif +else +ifeq ($(PYTHON_MAJOR_VERSION),3) +LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem +CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON +else +LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem +CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON +endif endif +ifeq ($(ENABLE_PYOSYS),1) PY_WRAPPER_FILE = kernel/python_wrappers OBJS += $(PY_WRAPPER_FILE).o PY_GEN_SCRIPT= py_wrap_generator PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") endif +endif ifeq ($(ENABLE_READLINE),1) CXXFLAGS += -DYOSYS_ENABLE_READLINE @@ -350,7 +397,7 @@ endif ifeq ($(CONFIG),mxe) CXXFLAGS += -DYOSYS_ENABLE_TCL -LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz +LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv else CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL ifeq ($(OS), FreeBSD) @@ -541,7 +588,11 @@ yosys$(EXE): $(OBJS) $(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS) libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) +ifeq ($(OS), Darwin) + $(P) $(LD) -o libyosys.so -shared -Wl,-install_name,libyosys.so $(LDFLAGS) $^ $(LDLIBS) +else $(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS) +endif %.o: %.cc $(Q) mkdir -p $(dir $@) @@ -551,9 +602,11 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) $(Q) mkdir -p $(dir $@) $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P - +ifeq ($(ENABLE_PYOSYS),1) $(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) $(Q) mkdir -p $(dir $@) $(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" +endif %.o: %.cpp $(Q) mkdir -p $(dir $@) @@ -616,6 +669,12 @@ else SEEDOPT="" endif +ifneq ($(ABCEXTERNAL),) +ABCOPT="-A $(ABCEXTERNAL)" +else +ABCOPT="" +endif + test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/simple && bash run-test.sh $(SEEDOPT) +cd tests/hana && bash run-test.sh $(SEEDOPT) @@ -624,13 +683,14 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/share && bash run-test.sh $(SEEDOPT) +cd tests/fsm && bash run-test.sh $(SEEDOPT) +cd tests/techmap && bash run-test.sh - +cd tests/memories && bash run-test.sh $(SEEDOPT) + +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT) +cd tests/bram && bash run-test.sh $(SEEDOPT) +cd tests/various && bash run-test.sh +cd tests/sat && bash run-test.sh +cd tests/svinterfaces && bash run-test.sh $(SEEDOPT) +cd tests/opt && bash run-test.sh - +cd tests/aiger && bash run-test.sh + +cd tests/aiger && bash run-test.sh $(ABCOPT) + +cd tests/arch && bash run-test.sh @echo "" @echo " Passed \"make test\"." @echo "" @@ -651,7 +711,7 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS) ystests: $(TARGETS) $(EXTRA_TARGETS) rm -rf tests/ystests - git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests + git clone -b yosys-0.9-rc https://github.com/YosysHQ/yosys-tests.git tests/ystests +$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests @echo "" @echo " Finished \"make ystests\"." @@ -788,6 +848,9 @@ config-gcc-static: clean config-gcc-4.8: clean echo 'CONFIG := gcc-4.8' > Makefile.conf +config-afl-gcc: clean + echo 'CONFIG := afl-gcc' > Makefile.conf + config-emcc: clean echo 'CONFIG := emcc' > Makefile.conf echo 'ENABLE_TCL := 0' >> Makefile.conf @@ -801,9 +864,11 @@ config-mxe: clean config-msys2: clean echo 'CONFIG := msys2' > Makefile.conf + echo 'ENABLE_PLUGINS := 0' >> Makefile.conf config-msys2-64: clean echo 'CONFIG := msys2-64' > Makefile.conf + echo 'ENABLE_PLUGINS := 0' >> Makefile.conf config-cygwin: clean echo 'CONFIG := cygwin' > Makefile.conf @@ -834,5 +899,5 @@ echo-git-rev: -include techlibs/*/*.d .PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator coverage vcxsrc mxebin -.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-gprof config-sudo +.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-afl-gcc config-gprof config-sudo diff --git a/yosys/README b/yosys/README deleted file mode 100644 index 8e43d4446..000000000 --- a/yosys/README +++ /dev/null @@ -1,451 +0,0 @@ - - /-----------------------------------------------------------------------------\ - | | - | yosys -- Yosys Open SYnthesis Suite | - | | - | Copyright (C) 2012 - 2016 Clifford 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. | - | | - \-----------------------------------------------------------------------------/ - - -yosys -- Yosys Open SYnthesis Suite -=================================== - -This is a framework for RTL synthesis tools. It currently has -extensive Verilog-2005 support and provides a basic set of -synthesis algorithms for various application domains. - -Yosys can be adapted to perform any synthesis job by combining -the existing passes (algorithms) using synthesis scripts and -adding additional passes as needed by extending the yosys C++ -code base. - -Yosys is free software licensed under the ISC license (a GPL -compatible license that is similar in terms to the MIT license -or the 2-clause BSD license). - - -Web Site -======== - -More information and documentation can be found on the Yosys web site: - - http://www.clifford.at/yosys/ - - -Getting Started -=============== - -You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is -recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make. -TCL, readline and libffi are optional (see ENABLE_* settings in Makefile). -Xdot (graphviz) is used by the "show" command in yosys to display schematics. -For example on Ubuntu Linux 16.04 LTS the following commands will install all -prerequisites for building yosys: - - $ sudo apt-get install build-essential clang bison flex \ - libreadline-dev gawk tcl-dev libffi-dev git mercurial \ - graphviz xdot pkg-config python3 - -There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well -as a source distribution for Visual Studio. Visit the Yosys download page for -more information: - - http://www.clifford.at/yosys/download.html - -To configure the build system to use a specific compiler, use one of - - $ make config-clang - $ make config-gcc - -For other compilers and build configurations it might be -necessary to make some changes to the config section of the -Makefile. - - $ vi Makefile ..or.. - $ vi Makefile.conf - -To build Yosys simply type 'make' in this directory. - - $ make - $ make test - $ sudo make install - -Note that this also downloads, builds and installs ABC (using yosys-abc -as executable name). - -Yosys can be used with the interactive command shell, with -synthesis scripts or with command line arguments. Let's perform -a simple synthesis job using the interactive command shell: - - $ ./yosys - yosys> - -the command "help" can be used to print a list of all available -commands and "help " to print details on the specified command: - - yosys> help help - -reading the design using the Verilog frontend: - - yosys> read_verilog tests/simple/fiedler-cooley.v - -writing the design to the console in yosys's internal format: - - yosys> write_ilang - -elaborate design hierarchy: - - yosys> hierarchy - -convert processes ("always" blocks) to netlist elements and perform -some simple optimizations: - - yosys> proc; opt - -display design netlist using xdot: - - yosys> show - -the same thing using 'gv' as postscript viewer: - - yosys> show -format ps -viewer gv - -translating netlist to gate logic and perform some simple optimizations: - - yosys> techmap; opt - -write design netlist to a new Verilog file: - - yosys> write_verilog synth.v - -a similar synthesis can be performed using yosys command line options only: - - $ ./yosys -o synth.v -p hierarchy -p proc -p opt \ - -p techmap -p opt tests/simple/fiedler-cooley.v - -or using a simple synthesis script: - - $ cat synth.ys - read_verilog tests/simple/fiedler-cooley.v - hierarchy; proc; opt; techmap; opt - write_verilog synth.v - - $ ./yosys synth.ys - -It is also possible to only have the synthesis commands but not the read/write -commands in the synthesis script: - - $ cat synth.ys - hierarchy; proc; opt; techmap; opt - - $ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys - -The following very basic synthesis script should work well with all designs: - - # check design hierarchy - hierarchy - - # translate processes (always blocks) - proc; opt - - # detect and optimize FSM encodings - fsm; opt - - # implement memories (arrays) - memory; opt - - # convert to gate logic - techmap; opt - -If ABC is enabled in the Yosys build configuration and a cell library is given -in the liberty file mycells.lib, the following synthesis script will synthesize -for the given cell library: - - # the high-level stuff - hierarchy; proc; fsm; opt; memory; opt - - # mapping to internal cell library - techmap; opt - - # mapping flip-flops to mycells.lib - dfflibmap -liberty mycells.lib - - # mapping logic to mycells.lib - abc -liberty mycells.lib - - # cleanup - clean - -If you do not have a liberty file but want to test this synthesis script, -you can use the file examples/cmos/cmos_cells.lib from the yosys sources. - -Liberty file downloads for and information about free and open ASIC standard -cell libraries can be found here: - - http://www.vlsitechnology.org/html/libraries.html - http://www.vlsitechnology.org/synopsys/vsclib013.lib - -The command "synth" provides a good default synthesis script (see "help synth"). -If possible a synthesis script should borrow from "synth". For example: - - # the high-level stuff - hierarchy - synth -run coarse - - # mapping to internal cells - techmap; opt -fast - dfflibmap -liberty mycells.lib - abc -liberty mycells.lib - clean - -Yosys is under construction. A more detailed documentation will follow. - - -Unsupported Verilog-2005 Features -================================= - -The following Verilog-2005 features are not supported by -yosys and there are currently no plans to add support -for them: - -- Non-synthesizable language features as defined in - IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002 - -- The "tri", "triand", "trior", "wand" and "wor" net types - -- The "config" keyword and library map files - -- The "disable", "primitive" and "specify" statements - -- Latched logic (is synthesized as logic with feedback loops) - - -Verilog Attributes and non-standard features -============================================ - -- The 'full_case' attribute on case statements is supported - (also the non-standard "// synopsys full_case" directive) - -- The 'parallel_case' attribute on case statements is supported - (also the non-standard "// synopsys parallel_case" directive) - -- The "// synopsys translate_off" and "// synopsys translate_on" - directives are also supported (but the use of `ifdef .. `endif - is strongly recommended instead). - -- The "nomem2reg" attribute on modules or arrays prohibits the - automatic early conversion of arrays to separate registers. This - is potentially dangerous. Usually the front-end has good reasons - for converting an array to a list of registers. Prohibiting this - step will likely result in incorrect synthesis results. - -- The "mem2reg" attribute on modules or arrays forces the early - conversion of arrays to separate registers. - -- The "nomeminit" attribute on modules or arrays prohibits the - creation of initialized memories. This effectively puts "mem2reg" - on all memories that are written to in an "initial" block and - are not ROMs. - -- The "nolatches" attribute on modules or always-blocks - prohibits the generation of logic-loops for latches. Instead - all not explicitly assigned values default to x-bits. This does - not affect clocked storage elements such as flip-flops. - -- The "nosync" attribute on registers prohibits the generation of a - storage element. The register itself will always have all bits set - to 'x' (undefined). The variable may only be used as blocking assigned - temporary variable within an always block. This is mostly used internally - by yosys to synthesize Verilog functions and access arrays. - -- The "onehot" attribute on wires mark them as onehot state register. This - is used for example for memory port sharing and set by the fsm_map pass. - -- The "blackbox" attribute on modules is used to mark empty stub modules - that have the same ports as the real thing but do not contain information - on the internal configuration. This modules are only used by the synthesis - passes to identify input and output ports of cells. The Verilog backend - also does not output blackbox modules on default. - -- The "keep" attribute on cells and wires is used to mark objects that should - never be removed by the optimizer. This is used for example for cells that - have hidden connections that are not part of the netlist, such as IO pads. - Setting the "keep" attribute on a module has the same effect as setting it - on all instances of the module. - -- The "keep_hierarchy" attribute on cells and modules keeps the "flatten" - command from flattening the indicated cells and modules. - -- The "init" attribute on wires is set by the frontend when a register is - initialized "FPGA-style" with 'reg foo = val'. It can be used during synthesis - to add the necessary reset logic. - -- The "top" attribute on a module marks this module as the top of the - design hierarchy. The "hierarchy" command sets this attribute when called - with "-top". Other commands, such as "flatten" and various backends - use this attribute to determine the top module. - -- The "src" attribute is set on cells and wires created by to the string - ":" by the HDL front-end and is then carried - through the synthesis. When entities are combined, a new |-separated - string is created that contains all the string from the original entities. - -- In addition to the (* ... *) attribute syntax, yosys supports - the non-standard {* ... *} attribute syntax to set default attributes - for everything that comes after the {* ... *} statement. (Reset - by adding an empty {* *} statement.) - -- In module parameter and port declarations, and cell port and parameter - lists, a trailing comma is ignored. This simplifies writing verilog code - generators a bit in some cases. - -- Modules can be declared with "module mod_name(...);" (with three dots - instead of a list of module ports). With this syntax it is sufficient - to simply declare a module port as 'input' or 'output' in the module - body. - -- When defining a macro with `define, all text between triple double quotes - is interpreted as macro body, even if it contains unescaped newlines. The - tipple double quotes are removed from the macro body. For example: - - `define MY_MACRO(a, b) """ - assign a = 23; - assign b = 42; - """ - -- The attribute "via_celltype" can be used to implement a Verilog task or - function by instantiating the specified cell type. The value is the name - of the cell type to use. For functions the name of the output port can - be specified by appending it to the cell type separated by a whitespace. - The body of the task or function is unused in this case and can be used - to specify a behavioral model of the cell type for simulation. For example: - - module my_add3(A, B, C, Y); - parameter WIDTH = 8; - input [WIDTH-1:0] A, B, C; - output [WIDTH-1:0] Y; - ... - endmodule - - module top; - ... - (* via_celltype = "my_add3 Y" *) - (* via_celltype_defparam_WIDTH = 32 *) - function [31:0] add3; - input [31:0] A, B, C; - begin - add3 = A + B + C; - end - endfunction - ... - endmodule - -- A limited subset of DPI-C functions is supported. The plugin mechanism - (see "help plugin") can be used to load .so files with implementations - of DPI-C routines. As a non-standard extension it is possible to specify - a plugin alias using the ":" syntax. for example: - - module dpitest; - import "DPI-C" function foo:round = real my_round (real); - parameter real r = my_round(12.345); - endmodule - - $ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v' - -- Sized constants (the syntax 's?[bodh]) support constant - expressions as . If the expression is not a simple identifier, it - must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010 - -- The system tasks $finish and $display are supported in initial blocks - in an unconditional context (only if/case statements on parameters - and constant values). The intended use for this is synthesis-time DRC. - - -Non-standard or SystemVerilog features for formal verification -============================================================== - -- Support for "assert", "assume", and "restrict" is enabled when - read_verilog is called with -formal. - -- The system task $initstate evaluates to 1 in the initial state and - to 0 otherwise. - -- The system task $anyconst evaluates to any constant value. - -- The system task $anyseq evaluates to any value, possibly a different - value in each cycle. - -- The SystemVerilog tasks $past, $stable, $rose and $fell are supported - in any clocked block. - -- The syntax @($global_clock) can be used to create FFs that have no - explicit clock input ($ff cells). - - -Supported features from SystemVerilog -===================================== - -When read_verilog is called with -sv, it accepts some language features -from SystemVerilog: - -- The "assert" statement from SystemVerilog is supported in its most basic - form. In module context: "assert property ();" and within an - always block: "assert();". It is transformed to a $assert cell. - -- The "assume" and "restrict" statements from SystemVerilog are also - supported. The same limitations as with the "assert" statement apply. - -- The keywords "always_comb", "always_ff" and "always_latch", "logic" and - "bit" are supported. - -- SystemVerilog packages are supported. Once a SystemVerilog file is read - into a design with "read_verilog", all its packages are available to - SystemVerilog files being read into the same design afterwards. - - -Building the documentation -========================== - -Note that there is no need to build the manual if you just want to read it. -Simply download the PDF from http://www.clifford.at/yosys/documentation.html -instead. - -On Ubuntu, texlive needs these packages to be able to build the manual: - - sudo apt-get install texlive-binaries - sudo apt-get install texlive-science # install algorithm2e.sty - sudo apt-get install texlive-bibtex-extra # gets multibib.sty - sudo apt-get install texlive-fonts-extra # gets skull.sty and dsfont.sty - sudo apt-get install texlive-publishers # IEEEtran.cls - -Also the non-free font luximono should be installed, there is unfortunately -no Ubuntu package for this so it should be installed separately using -`getnonfreefonts`: - - wget https://tug.org/fonts/getnonfreefonts/install-getnonfreefonts - sudo texlua install-getnonfreefonts # will install to /usr/local by default, can be changed by editing BINDIR at MANDIR at the top of the script - getnonfreefonts luximono # installs to /home/user/texmf - -Then execute, from the root of the repository: - - make manual - -Notes: - -- To run `make manual` you need to have installed yosys with `make install`, - otherwise it will fail on finding `kernel/yosys.h` while building - `PRESENTATION_Prog`. - diff --git a/yosys/README.md b/yosys/README.md index efb74ef4e..5132332a5 100644 --- a/yosys/README.md +++ b/yosys/README.md @@ -1,7 +1,7 @@ ``` yosys -- Yosys Open SYnthesis Suite -Copyright (C) 2012 - 2018 Clifford Wolf +Copyright (C) 2012 - 2019 Clifford 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 @@ -69,11 +69,14 @@ prerequisites for building yosys: graphviz xdot pkg-config python3 libboost-system-dev \ libboost-python-dev libboost-filesystem-dev -Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: +Similarily, on Mac OS X Homebrew can be used to install dependencies: $ brew tap Homebrew/bundle && brew bundle + +or MacPorts: + $ sudo port install bison flex readline gawk libffi \ - git graphviz pkgconfig python36 boost + git graphviz pkgconfig python36 boost tcl On FreeBSD use the following command to install all prerequisites: @@ -257,7 +260,7 @@ for them: - Non-synthesizable language features as defined in IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002 -- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types +- The ``tri``, ``triand`` and ``trior`` net types - The ``config`` and ``disable`` keywords and library map files @@ -350,6 +353,14 @@ Verilog Attributes and non-standard features through the synthesis. When entities are combined, a new |-separated string is created that contains all the string from the original entities. +- The ``defaultvalue`` attribute is used to store default values for + module inputs. The attribute is attached to the input wire by the HDL + front-end when the input is declared with a default value. + +- The ``parameter`` and ``localparam`` attributes are used to mark wires + that represent module parameters or localparams (when the HDL front-end + is run in -pwires mode). + - In addition to the ``(* ... *)`` attribute syntax, Yosys supports the non-standard ``{* ... *}`` attribute syntax to set default attributes for everything that comes after the ``{* ... *}`` statement. (Reset @@ -413,7 +424,7 @@ Verilog Attributes and non-standard features $ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v' - Sized constants (the syntax ``'s?[bodh]``) support constant - expressions as . If the expression is not a simple identifier, it + expressions as ````. If the expression is not a simple identifier, it must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010`` - The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in diff --git a/yosys/abc.rc b/yosys/abc.rc deleted file mode 100644 index 64e78950f..000000000 --- a/yosys/abc.rc +++ /dev/null @@ -1,174 +0,0 @@ -# global parameters -set check # checks intermediate networks -#set checkfio # prints warnings when fanins/fanouts are duplicated -set checkread # checks new networks after reading from file -set backup # saves backup networks retrived by "undo" and "recall" -set savesteps 1 # sets the maximum number of backup networks to save -set progressbar # display the progress bar - -# program names for internal calls -set dotwin dot.exe -set dotunix dot -set gsviewwin gsview32.exe -set gsviewunix gv -set siswin sis.exe -set sisunix sis -set mvsiswin mvsis.exe -set mvsisunix mvsis -set capowin MetaPl-Capo10.1-Win32.exe -set capounix MetaPl-Capo10.1 -set gnuplotwin wgnuplot.exe -set gnuplotunix gnuplot - -# standard aliases -alias b balance -alias cl cleanup -alias clp collapse -alias esd ext_seq_dcs -alias f fraig -alias fs fraig_sweep -alias fsto fraig_store -alias fres fraig_restore -alias ft fraig_trust -alias lp lutpack -alias pd print_dsd -alias pex print_exdc -d -alias pf print_factor -alias pfan print_fanio -alias pl print_level -alias pio print_io -alias pk print_kmap -alias ps print_stats -alias psu print_supp -alias psy print_symm -alias pun print_unate -alias q quit -alias r read -alias r3 retime -M 3 -alias r3f retime -M 3 -f -alias r3b retime -M 3 -b -alias ren renode -alias rh read_hie -alias rl read_blif -alias rb read_bench -alias ret retime -alias rp read_pla -alias rt read_truth -alias rv read_verilog -alias rvl read_verlib -alias rsup read_super mcnc5_old.super -alias rlib read_library -alias rlibc read_library cadence.genlib -alias rw rewrite -alias rwz rewrite -z -alias rf refactor -alias rfz refactor -z -alias re restructure -alias rez restructure -z -alias rs resub -alias rsz resub -z -alias sa set autoexec ps -alias scl scleanup -alias sif if -s -alias so source -x -alias st strash -alias sw sweep -alias ssw ssweep -alias tr0 trace_start -alias tr1 trace_check -alias trt "r c.blif; st; tr0; b; tr1" -alias u undo -alias w write -alias wa write_aiger -alias wb write_bench -alias wc write_cnf -alias wh write_hie -alias wl write_blif -alias wp write_pla -alias wv write_verilog - -# standard scripts -alias share "b; ren -s; fx; b" -alias sharedsd "b; ren -b; dsd -g; sw; fx; b" -alias resyn "b; rw; rwz; b; rwz; b" -alias resyn2 "b; rw; rf; b; rw; rwz; b; rfz; rwz; b" -alias resyn2a "b; rw; b; rw; rwz; b; rwz; b" -alias resyn3 "b; rs; rs -K 6; b; rsz; rsz -K 6; b; rsz -K 5; b" -alias compress "b -l; rw -l; rwz -l; b -l; rwz -l; b -l" -alias compress2 "b -l; rw -l; rf -l; b -l; rw -l; rwz -l; b -l; rfz -l; rwz -l; b -l" -alias choice "fraig_store; resyn; fraig_store; resyn2; fraig_store; fraig_restore" -alias choice2 "fraig_store; balance; fraig_store; resyn; fraig_store; resyn2; fraig_store; resyn2; fraig_store; fraig_restore" -alias rwsat "st; rw -l; b -l; rw -l; rf -l" -alias rwsat2 "st; rw -l; b -l; rw -l; rf -l; fraig; rw -l; b -l; rw -l; rf -l" -alias shake "st; ps; sat -C 5000; rw -l; ps; sat -C 5000; b -l; rf -l; ps; sat -C 5000; rfz -l; ps; sat -C 5000; rwz -l; ps; sat -C 5000; rfz -l; ps; sat -C 5000" - -# resubstitution scripts for the IWLS paper -alias src_rw "st; rw -l; rwz -l; rwz -l" -alias src_rs "st; rs -K 6 -N 2 -l; rs -K 9 -N 2 -l; rs -K 12 -N 2 -l" -alias src_rws "st; rw -l; rs -K 6 -N 2 -l; rwz -l; rs -K 9 -N 2 -l; rwz -l; rs -K 12 -N 2 -l" -alias resyn2rs "b; rs -K 6; rw; rs -K 6 -N 2; rf; rs -K 8; b; rs -K 8 -N 2; rw; rs -K 10; rwz; rs -K 10 -N 2; b; rs -K 12; rfz; rs -K 12 -N 2; rwz; b" -alias compress2rs "b -l; rs -K 6 -l; rw -l; rs -K 6 -N 2 -l; rf -l; rs -K 8 -l; b -l; rs -K 8 -N 2 -l; rw -l; rs -K 10 -l; rwz -l; rs -K 10 -N 2 -l; b -l; rs -K 12 -l; rfz -l; rs -K 12 -N 2 -l; rwz -l; b -l" - -# experimental implementation of don't-cares -alias resyn2rsdc "b; rs -K 6 -F 2; rw; rs -K 6 -N 2 -F 2; rf; rs -K 8 -F 2; b; rs -K 8 -N 2 -F 2; rw; rs -K 10 -F 2; rwz; rs -K 10 -N 2 -F 2; b; rs -K 12 -F 2; rfz; rs -K 12 -N 2 -F 2; rwz; b" -alias compress2rsdc "b -l; rs -K 6 -F 2 -l; rw -l; rs -K 6 -N 2 -F 2 -l; rf -l; rs -K 8 -F 2 -l; b -l; rs -K 8 -N 2 -F 2 -l; rw -l; rs -K 10 -F 2 -l; rwz -l; rs -K 10 -N 2 -F 2 -l; b -l; rs -K 12 -F 2 -l; rfz -l; rs -K 12 -N 2 -F 2 -l; rwz -l; b -l" - -# minimizing for FF literals -alias fflitmin "compress2rs; ren; sop; ps -f" - -# temporaries -#alias t "rvl th/lib.v; rvv th/t2.v" -#alias t "so c/pure_sat/test.c" -#alias t "r c/14/csat_998.bench; st; ps" -#alias t0 "r res.blif; aig; mfs" -#alias t "r res2.blif; aig; mfs" - -#alias tt "r a/quip_opt/nut_001_opt.blif" -#alias ttb "wh a/quip_opt/nut_001_opt.blif 1.blif" -#alias ttv "wh a/quip_opt/nut_001_opt.blif 1.v" - -alias reach "st; ps; compress2; ps; qrel; ps; compress2; ps; qreach -v; ps" - -alias qs1 "qvar -I 96 -u; ps; qbf -P 96" -alias qs2 "qvar -I 96 -u; qvar -I 97 -u; ps; qbf -P 96" -alias qs3 "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; ps; qbf -P 96" -alias qs4 "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; qvar -I 99 -u; ps; qbf -P 96" -alias qs5 "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; qvar -I 99 -u; qvar -I 100 -u; ps; qbf -P 96" -alias qs6 "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; qvar -I 99 -u; qvar -I 100 -u; qvar -I 101 -u; ps; qbf -P 96" -alias qs7 "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; qvar -I 99 -u; qvar -I 100 -u; qvar -I 101 -u; qvar -I 102 -u; ps; qbf -P 96" -alias qs8 "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; qvar -I 99 -u; qvar -I 100 -u; qvar -I 101 -u; qvar -I 102 -u; qvar -I 103 -u; ps; qbf -P 96" -alias qs9 "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; qvar -I 99 -u; qvar -I 100 -u; qvar -I 101 -u; qvar -I 102 -u; qvar -I 103 -u; qvar -I 104 -u; ps; qbf -P 96" -alias qsA "qvar -I 96 -u; qvar -I 97 -u; qvar -I 98 -u; qvar -I 99 -u; qvar -I 100 -u; qvar -I 101 -u; qvar -I 102 -u; qvar -I 103 -u; qvar -I 104 -u; qvar -I 105 -u; ps; qbf -P 96" - -alias chnew "st; haig_start; resyn2; haig_use" -alias chnewrs "st; haig_start; resyn2rs; haig_use" - -alias stdsd "r test/6in.blif; st; ps; u; bdd; dsd -g; st; ps" -alias trec "rec_start; r c.blif; st; rec_add; rec_use" -alias trec4 "rec_start -K 4; r i10.blif; st; rec_add; rec_use" -alias trec5 "rec_start -K 5; r i10.blif; st; rec_add; rec_use" -alias trec6 "rec_start -K 6; r i10.blif; st; rec_add; rec_use" -alias trec7 "rec_start -K 7; r i10.blif; st; rec_add; rec_use" -alias trec8 "rec_start -K 8; r i10.blif; st; rec_add; rec_use" -alias trec10 "rec_start -K 10; r i10.blif; st; rec_add; rec_use" -alias trec12 "rec_start -K 12; r i10.blif; st; rec_add; rec_use" - -#alias tsh "r i10_if.blif; st; ps; u; sw; st; ps; cec" -alias tst4 "r i10_if4.blif; st; ps; r x/rec4_.blif; st; rec_start; r i10_if4.blif; st -r; ps; cec" -alias tst4n "r i10_if4.blif; st; ps; r 5npn/all_functions.aig; st; rec_start; r i10_if4.blif; st -r; ps; cec" -alias tst6 "r i10_if6.blif; st; ps; r x/rec6_16_.blif; st; rec_start; r i10_if6.blif; st -r; ps; cec" - -#alias t "r c.blif; st; wc c.cnf" -#alias t "r test/dsdmap6.blif; lutpack -vw; cec" -#alias t "r i10_if4.blif; lp" -#alias t1 "r pj1_if4.blif; lp" -#alias t2 "r pj1_if6.blif; lp" -#alias t "r pj/pj1.blif; st; dfraig -v" -#alias t "r c/16/csat_2.bench; st; dfraig -C 100 -v -r" -#alias t "r c/16/csat_147.bench; st; dfraig -C 10 -v -r" -#alias t "r i10.blif; st; ps; csweep; ps; cec" -#alias t "r c/5/csat_777.bench; st; csweep -v" -#alias t "r i10.blif; st; drw -v" -alias t "r c.blif; st; drf" - - diff --git a/yosys/backends/aiger/aiger.cc b/yosys/backends/aiger/aiger.cc index dfe506c66..6863b40fa 100644 --- a/yosys/backends/aiger/aiger.cc +++ b/yosys/backends/aiger/aiger.cc @@ -89,7 +89,8 @@ struct AigerWriter aig_map[bit] = mkgate(a0, a1); } else if (alias_map.count(bit)) { - aig_map[bit] = bit2aig(alias_map.at(bit)); + int a = bit2aig(alias_map.at(bit)); + aig_map[bit] = a; } if (bit == State::Sx || bit == State::Sz) @@ -776,6 +777,7 @@ struct AigerBackend : public Backend { writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); if (!map_filename.empty()) { + rewrite_filename(filename); std::ofstream mapf; mapf.open(map_filename.c_str(), std::ofstream::trunc); if (mapf.fail()) diff --git a/yosys/backends/blif/blif.cc b/yosys/backends/blif/blif.cc index b6dbd84cb..a1761b662 100644 --- a/yosys/backends/blif/blif.cc +++ b/yosys/backends/blif/blif.cc @@ -409,12 +409,26 @@ struct BlifDumper f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type)); for (auto &conn : cell->connections()) - for (int i = 0; i < conn.second.size(); i++) { - if (conn.second.size() == 1) - f << stringf(" %s", cstr(conn.first)); - else - f << stringf(" %s[%d]", cstr(conn.first), i); - f << stringf("=%s", cstr(conn.second.extract(i, 1))); + { + if (conn.second.size() == 1) { + f << stringf(" %s=%s", cstr(conn.first), cstr(conn.second[0])); + continue; + } + + Module *m = design->module(cell->type); + Wire *w = m ? m->wire(conn.first) : nullptr; + + if (w == nullptr) { + for (int i = 0; i < GetSize(conn.second); i++) + f << stringf(" %s[%d]=%s", cstr(conn.first), i, cstr(conn.second[i])); + } else { + for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) { + SigBit sig(w, i); + f << stringf(" %s[%d]=%s", cstr(conn.first), sig.wire->upto ? + sig.wire->start_offset+sig.wire->width-sig.offset-1 : + sig.wire->start_offset+sig.offset, cstr(conn.second[i])); + } + } } f << stringf("\n"); diff --git a/yosys/backends/btor/btor.cc b/yosys/backends/btor/btor.cc index 91f238fa5..a507b120b 100644 --- a/yosys/backends/btor/btor.cc +++ b/yosys/backends/btor/btor.cc @@ -17,6 +17,11 @@ * */ +// [[CITE]] Btor2 , BtorMC and Boolector 3.0 +// Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere +// Computer Aided Verification - 30th International Conference, CAV 2018 +// https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/ + #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" @@ -129,7 +134,13 @@ struct BtorWorker void export_cell(Cell *cell) { - log_assert(cell_recursion_guard.count(cell) == 0); + if (cell_recursion_guard.count(cell)) { + string cell_list; + for (auto c : cell_recursion_guard) + cell_list += stringf("\n %s", log_id(c)); + log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list.c_str()); + } + cell_recursion_guard.insert(cell); btorf_push(log_id(cell)); @@ -869,9 +880,28 @@ struct BtorWorker else { if (bit_cell.count(bit) == 0) - log_error("No driver for signal bit %s.\n", log_signal(bit)); - export_cell(bit_cell.at(bit)); - log_assert(bit_nid.count(bit)); + { + SigSpec s = bit; + + while (i+GetSize(s) < GetSize(sig) && sig[i+GetSize(s)].wire != nullptr && + bit_cell.count(sig[i+GetSize(s)]) == 0) + s.append(sig[i+GetSize(s)]); + + log_warning("No driver for signal %s.\n", log_signal(s)); + + int sid = get_bv_sid(GetSize(s)); + int nid = next_nid++; + btorf("%d input %d %s\n", nid, sid); + nid_width[nid] = GetSize(s); + + i += GetSize(s)-1; + continue; + } + else + { + export_cell(bit_cell.at(bit)); + log_assert(bit_nid.count(bit)); + } } } diff --git a/yosys/backends/ilang/ilang_backend.cc b/yosys/backends/ilang/ilang_backend.cc index 04d1ee311..313af7d5c 100644 --- a/yosys/backends/ilang/ilang_backend.cc +++ b/yosys/backends/ilang/ilang_backend.cc @@ -204,6 +204,11 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { + for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) { + f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str()); + dump_const(f, ait->second); + f << stringf("\n"); + } f << stringf("%s case ", indent.c_str()); for (size_t i = 0; i < (*it)->compare.size(); i++) { if (i > 0) @@ -483,6 +488,7 @@ struct DumpPass : public Pass { std::stringstream buf; if (!filename.empty()) { + rewrite_filename(filename); std::ofstream *ff = new std::ofstream; ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc); if (ff->fail()) { diff --git a/yosys/backends/json/json.cc b/yosys/backends/json/json.cc index f5c687981..dda4dfedd 100644 --- a/yosys/backends/json/json.cc +++ b/yosys/backends/json/json.cc @@ -126,6 +126,10 @@ struct JsonWriter f << stringf("%s\n", first ? "" : ","); f << stringf(" %s: {\n", get_name(n).c_str()); f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output"); + if (w->start_offset) + f << stringf(" \"offset\": %d,\n", w->start_offset); + if (w->upto) + f << stringf(" \"upto\": 1,\n"); f << stringf(" \"bits\": %s\n", get_bits(w).c_str()); f << stringf(" }"); first = false; @@ -189,6 +193,10 @@ struct JsonWriter f << stringf(" %s: {\n", get_name(w->name).c_str()); f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); + if (w->start_offset) + f << stringf(" \"offset\": %d,\n", w->start_offset); + if (w->upto) + f << stringf(" \"upto\": 1,\n"); f << stringf(" \"attributes\": {"); write_parameters(w->attributes); f << stringf("\n }\n"); @@ -525,6 +533,7 @@ struct JsonPass : public Pass { std::stringstream buf; if (!filename.empty()) { + rewrite_filename(filename); std::ofstream *ff = new std::ofstream; ff->open(filename.c_str(), std::ofstream::trunc); if (ff->fail()) { diff --git a/yosys/backends/protobuf/protobuf.cc b/yosys/backends/protobuf/protobuf.cc index 549fc73ae..fff110bb0 100644 --- a/yosys/backends/protobuf/protobuf.cc +++ b/yosys/backends/protobuf/protobuf.cc @@ -336,6 +336,7 @@ struct ProtobufPass : public Pass { std::stringstream buf; if (!filename.empty()) { + rewrite_filename(filename); std::ofstream *ff = new std::ofstream; ff->open(filename.c_str(), std::ofstream::trunc); if (ff->fail()) { diff --git a/yosys/backends/smt2/smtio.py b/yosys/backends/smt2/smtio.py index ab20a4af2..ae7968a1b 100644 --- a/yosys/backends/smt2/smtio.py +++ b/yosys/backends/smt2/smtio.py @@ -1023,6 +1023,8 @@ class MkVcd: assert t >= self.t if t != self.t: if self.t == -1: + print("$version Generated by Yosys-SMTBMC $end", file=self.f) + print("$timescale 1ns $end", file=self.f) print("$var integer 32 t smt_step $end", file=self.f) print("$var event 1 ! smt_clock $end", file=self.f) @@ -1041,7 +1043,10 @@ class MkVcd: scope = scope[:-1] while uipath[:-1] != scope: - print("$scope module %s $end" % uipath[len(scope)], file=self.f) + scopename = uipath[len(scope)] + if scopename.startswith("$"): + scopename = "\\" + scopename + print("$scope module %s $end" % scopename, file=self.f) scope.append(uipath[len(scope)]) if path in self.clocks and self.clocks[path][1] == "event": diff --git a/yosys/backends/verilog/verilog_backend.cc b/yosys/backends/verilog/verilog_backend.cc index 827af5d85..087c6fec6 100644 --- a/yosys/backends/verilog/verilog_backend.cc +++ b/yosys/backends/verilog/verilog_backend.cc @@ -364,20 +364,22 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) } } -void dump_attributes(std::ostream &f, std::string indent, dict &attributes, char term = '\n', bool modattr = false) +void dump_attributes(std::ostream &f, std::string indent, dict &attributes, char term = '\n', bool modattr = false, bool as_comment = false) { if (noattr) return; + if (attr2comment) + as_comment = true; for (auto it = attributes.begin(); it != attributes.end(); ++it) { - f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str()); + f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str()); f << stringf(" = "); if (modattr && (it->second == Const(0, 1) || it->second == Const(0))) f << stringf(" 0 "); else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) f << stringf(" 1 "); else - dump_const(f, it->second, -1, 0, false, attr2comment); - f << stringf(" %s%c", attr2comment ? "*/" : "*)", term); + dump_const(f, it->second, -1, 0, false, as_comment); + f << stringf(" %s%c", as_comment ? "*/" : "*)", term); } } @@ -1492,12 +1494,14 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw return; } + dump_attributes(f, indent, sw->attributes); f << stringf("%s" "casez (", indent.c_str()); dump_sigspec(f, sw->signal); f << stringf(")\n"); bool got_default = false; for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { + dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*as_comment=*/true); if ((*it)->compare.size() == 0) { if (got_default) continue; @@ -1662,7 +1666,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) } } - dump_attributes(f, indent, module->attributes, '\n', true); + dump_attributes(f, indent, module->attributes, '\n', /*attr2comment=*/true); f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str()); bool keep_running = true; for (int port_id = 1; keep_running; port_id++) { diff --git a/yosys/frontends/aiger/aigerparse.cc b/yosys/frontends/aiger/aigerparse.cc index 38348cd65..68552fd06 100644 --- a/yosys/frontends/aiger/aigerparse.cc +++ b/yosys/frontends/aiger/aigerparse.cc @@ -34,354 +34,389 @@ YOSYS_NAMESPACE_BEGIN AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name) - : design(design), f(f), clk_name(clk_name) + : design(design), f(f), clk_name(clk_name) { - module = new RTLIL::Module; - module->name = module_name; - if (design->module(module->name)) - log_error("Duplicate definition of module %s!\n", log_id(module->name)); + module = new RTLIL::Module; + module->name = module_name; + if (design->module(module->name)) + log_error("Duplicate definition of module %s!\n", log_id(module->name)); } void AigerReader::parse_aiger() { - std::string header; - f >> header; - if (header != "aag" && header != "aig") - log_error("Unsupported AIGER file!\n"); + std::string header; + f >> header; + if (header != "aag" && header != "aig") + log_error("Unsupported AIGER file!\n"); - // Parse rest of header - if (!(f >> M >> I >> L >> O >> A)) - log_error("Invalid AIGER header\n"); + // Parse rest of header + if (!(f >> M >> I >> L >> O >> A)) + log_error("Invalid AIGER header\n"); - // Optional values - B = C = J = F = 0; - if (f.peek() != ' ') goto end_of_header; - if (!(f >> B)) log_error("Invalid AIGER header\n"); - if (f.peek() != ' ') goto end_of_header; - if (!(f >> C)) log_error("Invalid AIGER header\n"); - if (f.peek() != ' ') goto end_of_header; - if (!(f >> J)) log_error("Invalid AIGER header\n"); - if (f.peek() != ' ') goto end_of_header; - if (!(f >> F)) log_error("Invalid AIGER header\n"); + // Optional values + B = C = J = F = 0; + if (f.peek() != ' ') goto end_of_header; + if (!(f >> B)) log_error("Invalid AIGER header\n"); + if (f.peek() != ' ') goto end_of_header; + if (!(f >> C)) log_error("Invalid AIGER header\n"); + if (f.peek() != ' ') goto end_of_header; + if (!(f >> J)) log_error("Invalid AIGER header\n"); + if (f.peek() != ' ') goto end_of_header; + if (!(f >> F)) log_error("Invalid AIGER header\n"); end_of_header: - std::string line; - std::getline(f, line); // Ignore up to start of next line, as standard - // says anything that follows could be used for - // optional sections + std::string line; + std::getline(f, line); // Ignore up to start of next line, as standard + // says anything that follows could be used for + // optional sections - log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F); + log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F); - line_count = 1; + line_count = 1; - if (header == "aag") - parse_aiger_ascii(); - else if (header == "aig") - parse_aiger_binary(); - else - log_abort(); + if (header == "aag") + parse_aiger_ascii(); + else if (header == "aig") + parse_aiger_binary(); + else + log_abort(); - // Parse footer (symbol table, comments, etc.) - unsigned l1; - std::string s; - for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) { - if (c == 'i' || c == 'l' || c == 'o') { - f.ignore(1); - if (!(f >> l1 >> s)) - log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count); + RTLIL::Wire* n0 = module->wire("\\n0"); + if (n0) + module->connect(n0, RTLIL::S0); - if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size())) - log_error("Line %u has invalid symbol position!\n", line_count); + for (unsigned i = 0; i < outputs.size(); ++i) { + RTLIL::Wire *wire = outputs[i]; + if (wire->port_input) { + RTLIL::Wire *o_wire = module->addWire(wire->name.str() + "_o"); + o_wire->port_output = true; + wire->port_output = false; + module->connect(o_wire, wire); + outputs[i] = o_wire; + } + } - RTLIL::Wire* wire; - if (c == 'i') wire = inputs[l1]; - else if (c == 'l') wire = latches[l1]; - else if (c == 'o') wire = outputs[l1]; - else log_abort(); + // Parse footer (symbol table, comments, etc.) + unsigned l1; + std::string s; + for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) { + if (c == 'i' || c == 'l' || c == 'o' || c == 'b') { + f.ignore(1); + if (!(f >> l1 >> s)) + log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count); - module->rename(wire, stringf("\\%s", s.c_str())); - } - else if (c == 'b' || c == 'j' || c == 'f') { - // TODO - } - else if (c == 'c') { - f.ignore(1); - if (f.peek() == '\n') - break; - // Else constraint (TODO) - } - else - log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); - std::getline(f, line); // Ignore up to start of next line - } + if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size())) + log_error("Line %u has invalid symbol position!\n", line_count); - module->fixup_ports(); - design->add(module); + RTLIL::Wire* wire; + if (c == 'i') wire = inputs[l1]; + else if (c == 'l') wire = latches[l1]; + else if (c == 'o') wire = outputs[l1]; + else if (c == 'b') wire = bad_properties[l1]; + else log_abort(); + + module->rename(wire, stringf("\\%s", s.c_str())); + } + else if (c == 'j' || c == 'f') { + // TODO + } + else if (c == 'c') { + f.ignore(1); + if (f.peek() == '\n') + break; + // Else constraint (TODO) + } + else + log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); + std::getline(f, line); // Ignore up to start of next line + } + + module->fixup_ports(); + design->add(module); } static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal) { - const unsigned variable = literal >> 1; - const bool invert = literal & 1; - RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix? - RTLIL::Wire *wire = module->wire(wire_name); - if (wire) return wire; - log_debug("Creating %s\n", wire_name.c_str()); - wire = module->addWire(wire_name); - if (!invert) return wire; - RTLIL::IdString wire_inv_name(stringf("\\n%d", variable)); - RTLIL::Wire *wire_inv = module->wire(wire_inv_name); - if (wire_inv) { - if (module->cell(wire_inv_name)) return wire; - } - else { - log_debug("Creating %s\n", wire_inv_name.c_str()); - wire_inv = module->addWire(wire_inv_name); - } + const unsigned variable = literal >> 1; + const bool invert = literal & 1; + RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix? + RTLIL::Wire *wire = module->wire(wire_name); + if (wire) return wire; + log_debug("Creating %s\n", wire_name.c_str()); + wire = module->addWire(wire_name); + if (!invert) return wire; + RTLIL::IdString wire_inv_name(stringf("\\n%d", variable)); + RTLIL::Wire *wire_inv = module->wire(wire_inv_name); + if (wire_inv) { + if (module->cell(wire_inv_name)) return wire; + } + else { + log_debug("Creating %s\n", wire_inv_name.c_str()); + wire_inv = module->addWire(wire_inv_name); + } - log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); - module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix? + log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); + module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix? - return wire; + return wire; } void AigerReader::parse_aiger_ascii() { - std::string line; - std::stringstream ss; + std::string line; + std::stringstream ss; - unsigned l1, l2, l3; + unsigned l1, l2, l3; - // Parse inputs - for (unsigned i = 0; i < I; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an input!\n", line_count); - log_debug("%d is an input\n", l1); - log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted? - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_input = true; - inputs.push_back(wire); - } + // Parse inputs + for (unsigned i = 1; i <= I; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as an input!\n", line_count); + log_debug("%d is an input\n", l1); + log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted? + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_input = true; + inputs.push_back(wire); + } - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - } - for (unsigned i = 0; i < L; ++i, ++line_count) { - if (!(f >> l1 >> l2)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - log_debug("%d %d is a latch\n", l1, l2); - log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted? - RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); + // Parse latches + RTLIL::Wire *clk_wire = nullptr; + if (L > 0) { + clk_wire = module->wire(clk_name); + log_assert(!clk_wire); + log_debug("Creating %s\n", clk_name.c_str()); + clk_wire = module->addWire(clk_name); + clk_wire->port_input = true; + } + for (unsigned i = 0; i < L; ++i, ++line_count) { + if (!(f >> l1 >> l2)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); + log_debug("%d %d is a latch\n", l1, l2); + log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted? + RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); + module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); - // Reset logic is optional in AIGER 1.9 - if (f.peek() == ' ') { - if (!(f >> l3)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); + // Reset logic is optional in AIGER 1.9 + if (f.peek() == ' ') { + if (!(f >> l3)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); - if (l3 == 0 || l3 == 1) - q_wire->attributes["\\init"] = RTLIL::Const(l3); - else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); - } - else - log_error("Line %u has invalid reset literal for latch!\n", line_count); - } - else { - // AIGER latches are assumed to be initialized to zero - q_wire->attributes["\\init"] = RTLIL::Const(0); - } - latches.push_back(q_wire); - } + if (l3 == 0) + q_wire->attributes["\\init"] = RTLIL::S0; + else if (l3 == 1) + q_wire->attributes["\\init"] = RTLIL::S1; + else if (l3 == l1) { + //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); + } + else + log_error("Line %u has invalid reset literal for latch!\n", line_count); + } + else { + // AIGER latches are assumed to be initialized to zero + q_wire->attributes["\\init"] = RTLIL::S0; + } + latches.push_back(q_wire); + } - // Parse outputs - for (unsigned i = 0; i < O; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an output!\n", line_count); + // Parse outputs + for (unsigned i = 0; i < O; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as an output!\n", line_count); - log_debug("%d is an output\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_output = true; - outputs.push_back(wire); - } - std::getline(f, line); // Ignore up to start of next line + log_debug("%d is an output\n", l1); + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_output = true; + outputs.push_back(wire); + } - // TODO: Parse bad state properties - for (unsigned i = 0; i < B; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + // Parse bad properties + for (unsigned i = 0; i < B; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); - // TODO: Parse invariant constraints - for (unsigned i = 0; i < C; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + log_debug("%d is a bad state property\n", l1); + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_output = true; + bad_properties.push_back(wire); + } - // TODO: Parse justice properties - for (unsigned i = 0; i < J; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + // TODO: Parse invariant constraints + for (unsigned i = 0; i < C; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line - // TODO: Parse fairness constraints - for (unsigned i = 0; i < F; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + // TODO: Parse justice properties + for (unsigned i = 0; i < J; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line - // Parse AND - for (unsigned i = 0; i < A; ++i) { - if (!(f >> l1 >> l2 >> l3)) - log_error("Line %u cannot be interpreted as an AND!\n", line_count); + // TODO: Parse fairness constraints + for (unsigned i = 0; i < F; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line - log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire); - } - std::getline(f, line); // Ignore up to start of next line + // Parse AND + for (unsigned i = 0; i < A; ++i) { + if (!(f >> l1 >> l2 >> l3)) + log_error("Line %u cannot be interpreted as an AND!\n", line_count); + + log_debug("%d %d %d is an AND\n", l1, l2, l3); + log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? + RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); + RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); + module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire); + } + std::getline(f, line); // Ignore up to start of next line } static unsigned parse_next_delta_literal(std::istream &f, unsigned ref) { - unsigned x = 0, i = 0; - unsigned char ch; - while ((ch = f.get()) & 0x80) - x |= (ch & 0x7f) << (7 * i++); - return ref - (x | (ch << (7 * i))); + unsigned x = 0, i = 0; + unsigned char ch; + while ((ch = f.get()) & 0x80) + x |= (ch & 0x7f) << (7 * i++); + return ref - (x | (ch << (7 * i))); } void AigerReader::parse_aiger_binary() { - unsigned l1, l2, l3; - std::string line; + unsigned l1, l2, l3; + std::string line; - // Parse inputs - for (unsigned i = 1; i <= I; ++i) { - RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); - wire->port_input = true; - inputs.push_back(wire); - } + // Parse inputs + for (unsigned i = 1; i <= I; ++i) { + RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); + wire->port_input = true; + inputs.push_back(wire); + } - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - } - l1 = (I+1) * 2; - for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) { - if (!(f >> l2)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - log_debug("%d %d is a latch\n", l1, l2); - RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); + // Parse latches + RTLIL::Wire *clk_wire = nullptr; + if (L > 0) { + clk_wire = module->wire(clk_name); + log_assert(!clk_wire); + log_debug("Creating %s\n", clk_name.c_str()); + clk_wire = module->addWire(clk_name); + clk_wire->port_input = true; + } + l1 = (I+1) * 2; + for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) { + if (!(f >> l2)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); + log_debug("%d %d is a latch\n", l1, l2); + RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - module->addDff(NEW_ID, clk_wire, d_wire, q_wire); + module->addDff(NEW_ID, clk_wire, d_wire, q_wire); - // Reset logic is optional in AIGER 1.9 - if (f.peek() == ' ') { - if (!(f >> l3)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); + // Reset logic is optional in AIGER 1.9 + if (f.peek() == ' ') { + if (!(f >> l3)) + log_error("Line %u cannot be interpreted as a latch!\n", line_count); - if (l3 == 0 || l3 == 1) - q_wire->attributes["\\init"] = RTLIL::Const(l3); - else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); - } - else - log_error("Line %u has invalid reset literal for latch!\n", line_count); - } - else { - // AIGER latches are assumed to be initialized to zero - q_wire->attributes["\\init"] = RTLIL::Const(0); - } - latches.push_back(q_wire); - } + if (l3 == 0) + q_wire->attributes["\\init"] = RTLIL::S0; + else if (l3 == 1) + q_wire->attributes["\\init"] = RTLIL::S1; + else if (l3 == l1) { + //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); + } + else + log_error("Line %u has invalid reset literal for latch!\n", line_count); + } + else { + // AIGER latches are assumed to be initialized to zero + q_wire->attributes["\\init"] = RTLIL::S0; + } + latches.push_back(q_wire); + } - // Parse outputs - for (unsigned i = 0; i < O; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an output!\n", line_count); + // Parse outputs + for (unsigned i = 0; i < O; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as an output!\n", line_count); - log_debug("%d is an output\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_output = true; - outputs.push_back(wire); - } - std::getline(f, line); // Ignore up to start of next line + log_debug("%d is an output\n", l1); + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_output = true; + outputs.push_back(wire); + } + std::getline(f, line); // Ignore up to start of next line - // TODO: Parse bad state properties - for (unsigned i = 0; i < B; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + // Parse bad properties + for (unsigned i = 0; i < B; ++i, ++line_count) { + if (!(f >> l1)) + log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); - // TODO: Parse invariant constraints - for (unsigned i = 0; i < C; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + log_debug("%d is a bad state property\n", l1); + RTLIL::Wire *wire = createWireIfNotExists(module, l1); + wire->port_output = true; + bad_properties.push_back(wire); + } + if (B > 0) + std::getline(f, line); // Ignore up to start of next line - // TODO: Parse justice properties - for (unsigned i = 0; i < J; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + // TODO: Parse invariant constraints + for (unsigned i = 0; i < C; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line - // TODO: Parse fairness constraints - for (unsigned i = 0; i < F; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line + // TODO: Parse justice properties + for (unsigned i = 0; i < J; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line - // Parse AND - l1 = (I+L+1) << 1; - for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) { - l2 = parse_next_delta_literal(f, l1); - l3 = parse_next_delta_literal(f, l2); + // TODO: Parse fairness constraints + for (unsigned i = 0; i < F; ++i, ++line_count) + std::getline(f, line); // Ignore up to start of next line - log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); + // Parse AND + l1 = (I+L+1) << 1; + for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) { + l2 = parse_next_delta_literal(f, l1); + l3 = parse_next_delta_literal(f, l2); - RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_"); - and_cell->setPort("\\A", i1_wire); - and_cell->setPort("\\B", i2_wire); - and_cell->setPort("\\Y", o_wire); - } + log_debug("%d %d %d is an AND\n", l1, l2, l3); + log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? + RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); + RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); + + RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_"); + and_cell->setPort("\\A", i1_wire); + and_cell->setPort("\\B", i2_wire); + and_cell->setPort("\\Y", o_wire); + } } struct AigerFrontend : public Frontend { - AigerFrontend() : Frontend("aiger", "read AIGER file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_aiger [options] [filename]\n"); - log("\n"); - log("Load module from an AIGER file into the current design.\n"); - log("\n"); - log(" -module_name \n"); - log(" Name of module to be created (default: )" + AigerFrontend() : Frontend("aiger", "read AIGER file") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" read_aiger [options] [filename]\n"); + log("\n"); + log("Load module from an AIGER file into the current design.\n"); + log("\n"); + log(" -module_name \n"); + log(" Name of module to be created (default: " #ifdef _WIN32 - "top" // FIXME + "top" // FIXME #else - "" + "" #endif - ")\n"); - log("\n"); - log(" -clk_name \n"); - log(" AIGER latches to be transformed into posedge DFFs clocked by wire of"); - log(" this name (default: clk)\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing AIGER frontend.\n"); + ")\n"); + log("\n"); + log(" -clk_name \n"); + log(" AIGER latches to be transformed into posedge DFFs clocked by wire of"); + log(" this name (default: clk)\n"); + log("\n"); + } + void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing AIGER frontend.\n"); - RTLIL::IdString clk_name = "\\clk"; - RTLIL::IdString module_name; + RTLIL::IdString clk_name = "\\clk"; + RTLIL::IdString module_name; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -398,19 +433,19 @@ struct AigerFrontend : public Frontend { } extra_args(f, filename, args, argidx); - if (module_name.empty()) { + if (module_name.empty()) { #ifdef _WIN32 - module_name = "top"; // FIXME: basename equivalent on Win32? + module_name = "top"; // FIXME: basename equivalent on Win32? #else - char* bn = strdup(filename.c_str()); - module_name = RTLIL::escape_id(bn); - free(bn); + char* bn = strdup(filename.c_str()); + module_name = RTLIL::escape_id(bn); + free(bn); #endif - } + } - AigerReader reader(design, *f, module_name, clk_name); + AigerReader reader(design, *f, module_name, clk_name); reader.parse_aiger(); - } + } } AigerFrontend; YOSYS_NAMESPACE_END diff --git a/yosys/frontends/aiger/aigerparse.h b/yosys/frontends/aiger/aigerparse.h index c49cd152d..0e3719cc4 100644 --- a/yosys/frontends/aiger/aigerparse.h +++ b/yosys/frontends/aiger/aigerparse.h @@ -39,6 +39,7 @@ struct AigerReader std::vector inputs; std::vector latches; std::vector outputs; + std::vector bad_properties; AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name); void parse_aiger(); diff --git a/yosys/frontends/ast/ast.cc b/yosys/frontends/ast/ast.cc index 5623541b2..3d066af53 100644 --- a/yosys/frontends/ast/ast.cc +++ b/yosys/frontends/ast/ast.cc @@ -46,7 +46,7 @@ namespace AST { // instantiate global variables (private API) namespace AST_INTERNAL { bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_autowire; + bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_autowire; AstNode *current_ast, *current_ast_mod; std::map current_scope; const dict *genRTLIL_subst_ptr = NULL; @@ -154,6 +154,7 @@ std::string AST::type2str(AstNodeType type) X(AST_GENIF) X(AST_GENCASE) X(AST_GENBLOCK) + X(AST_TECALL) X(AST_POSEDGE) X(AST_NEGEDGE) X(AST_EDGE) @@ -194,6 +195,9 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch is_logic = false; is_signed = false; is_string = false; + is_wand = false; + is_wor = false; + is_unsized = false; was_checked = false; range_valid = false; range_swapped = false; @@ -722,7 +726,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) } // create an AST node for a constant (using a bit vector as value) -AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed) +AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) { AstNode *node = new AstNode(AST_CONSTANT); node->is_signed = is_signed; @@ -736,9 +740,15 @@ AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signe node->range_valid = true; node->range_left = node->bits.size()-1; node->range_right = 0; + node->is_unsized = is_unsized; return node; } +AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed) +{ + return mkconst_bits(v, is_signed, false); +} + // create an AST node for a constant (using a string in bit vector form as value) AstNode *AstNode::mkconst_str(const std::vector &v) { @@ -775,6 +785,14 @@ bool AstNode::bits_only_01() const return true; } +RTLIL::Const AstNode::bitsAsUnsizedConst(int width) +{ + RTLIL::State extbit = bits.back(); + while (width > int(bits.size())) + bits.push_back(extbit); + return RTLIL::Const(bits); +} + RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed) { std::vector bits = this->bits; @@ -1094,6 +1112,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast current_module->nowb = flag_nowb; current_module->noopt = flag_noopt; current_module->icells = flag_icells; + current_module->pwires = flag_pwires; current_module->autowire = flag_autowire; current_module->fixup_ports(); @@ -1108,7 +1127,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast // create AstModule instances for all modules in the AST tree and add them to 'design' void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, - bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) + bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire) { current_ast = ast; flag_dump_ast1 = dump_ast1; @@ -1126,6 +1145,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump flag_nowb = nowb; flag_noopt = noopt; flag_icells = icells; + flag_pwires = pwires; flag_autowire = autowire; log_assert(current_ast->type == AST_DESIGN); @@ -1462,6 +1482,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dictlib = lib; new_mod->noopt = noopt; new_mod->icells = icells; + new_mod->pwires = pwires; new_mod->autowire = autowire; return new_mod; diff --git a/yosys/frontends/ast/ast.h b/yosys/frontends/ast/ast.h index 281cbe086..54b2fb319 100644 --- a/yosys/frontends/ast/ast.h +++ b/yosys/frontends/ast/ast.h @@ -137,7 +137,8 @@ namespace AST AST_GENIF, AST_GENCASE, AST_GENBLOCK, - + AST_TECALL, + AST_POSEDGE, AST_NEGEDGE, AST_EDGE, @@ -173,7 +174,7 @@ namespace AST // node content - most of it is unused in most node types std::string str; std::vector bits; - bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked; + bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized; int port_id, range_left, range_right; uint32_t integer; double realvalue; @@ -262,6 +263,7 @@ namespace AST // helper functions for creating AST nodes for constants static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32); + static AstNode *mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); static AstNode *mkconst_bits(const std::vector &v, bool is_signed); static AstNode *mkconst_str(const std::vector &v); static AstNode *mkconst_str(const std::string &str); @@ -269,6 +271,7 @@ namespace AST // helper function for creating sign-extended const objects RTLIL::Const bitsAsConst(int width, bool is_signed); RTLIL::Const bitsAsConst(int width = -1); + RTLIL::Const bitsAsUnsizedConst(int width); RTLIL::Const asAttrConst(); RTLIL::Const asParaConst(); uint64_t asInt(bool is_signed); @@ -283,13 +286,13 @@ namespace AST // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit, - bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire); + bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire); // parametric modules are supported directly by the AST library // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions struct AstModule : RTLIL::Module { AstNode *ast; - bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, autowire; + bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire; ~AstModule() YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict parameters, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict parameters, dict interfaces, dict modports, bool mayfail) YS_OVERRIDE; @@ -322,7 +325,7 @@ namespace AST_INTERNAL { // internal state variables extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_pwires, flag_autowire; extern AST::AstNode *current_ast, *current_ast_mod; extern std::map current_scope; extern const dict *genRTLIL_subst_ptr; diff --git a/yosys/frontends/ast/genrtlil.cc b/yosys/frontends/ast/genrtlil.cc index 379fed641..571ddd988 100644 --- a/yosys/frontends/ast/genrtlil.cc +++ b/yosys/frontends/ast/genrtlil.cc @@ -504,6 +504,7 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::CaseRule *backup_case = current_case; current_case = new RTLIL::CaseRule; + current_case->attributes["\\src"] = stringf("%s:%d", child->filename.c_str(), child->linenum); last_generated_case = current_case; addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); for (auto node : child->children) { @@ -853,7 +854,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_FUNCTION: case AST_DPI_FUNCTION: case AST_AUTOWIRE: - case AST_LOCALPARAM: case AST_DEFPARAM: case AST_GENVAR: case AST_GENFOR: @@ -895,6 +895,26 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // remember the parameter, needed for example in techmap case AST_PARAMETER: current_module->avail_parameters.insert(str); + /* fall through */ + case AST_LOCALPARAM: + if (flag_pwires) + { + if (GetSize(children) < 1 || children[0]->type != AST_CONSTANT) + log_file_error(filename, linenum, "Parameter `%s' with non-constant value!\n", str.c_str()); + + RTLIL::Const val = children[0]->bitsAsConst(); + RTLIL::Wire *wire = current_module->addWire(str, GetSize(val)); + current_module->connect(wire, val); + + wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); + wire->attributes[type == AST_PARAMETER ? "\\parameter" : "\\localparam"] = 1; + + for (auto &attr : attributes) { + if (attr.second->type != AST_CONSTANT) + log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); + wire->attributes[attr.first] = attr.second->asAttrConst(); + } + } break; // create an RTLIL::Wire for an AST_WIRE node @@ -904,7 +924,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (!range_valid) log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str()); - log_assert(range_left >= range_right || (range_left == -1 && range_right == 0)); + if (!(range_left >= range_right || (range_left == -1 && range_right == 0))) + log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1); RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -919,6 +940,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); wire->attributes[attr.first] = attr.second->asAttrConst(); } + + if (is_wand) wire->set_bool_attribute("\\wand"); + if (is_wor) wire->set_bool_attribute("\\wor"); } break; @@ -963,8 +987,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) detectSignWidth(width_hint, sign_hint); is_signed = sign_hint; - if (type == AST_CONSTANT) - return RTLIL::SigSpec(bitsAsConst()); + if (type == AST_CONSTANT) { + if (is_unsized) { + return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint)); + } else { + return RTLIL::SigSpec(bitsAsConst()); + } + } RTLIL::SigSpec sig = realAsConst(width_hint); log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); @@ -1566,6 +1595,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) delete always; } break; + case AST_TECALL: { + int sz = children.size(); + if (str == "$info") { + if (sz > 0) + log_file_info(filename, linenum, "%s.\n", children[0]->str.c_str()); + else + log_file_info(filename, linenum, "\n"); + } else if (str == "$warning") { + if (sz > 0) + log_file_warning(filename, linenum, "%s.\n", children[0]->str.c_str()); + else + log_file_warning(filename, linenum, "\n"); + } else if (str == "$error") { + if (sz > 0) + log_file_error(filename, linenum, "%s.\n", children[0]->str.c_str()); + else + log_file_error(filename, linenum, "\n"); + } else if (str == "$fatal") { + // TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish() + // if no parameter is given, default value is 1 + // dollar_finish(sz ? children[0] : 1); + // perhaps create & use log_file_fatal() + if (sz > 0) + log_file_error(filename, linenum, "FATAL: %s.\n", children[0]->str.c_str()); + else + log_file_error(filename, linenum, "FATAL.\n"); + } else { + log_file_error(filename, linenum, "Unknown elabortoon system task '%s'.\n", str.c_str()); + } + } break; + case AST_FCALL: { if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { diff --git a/yosys/frontends/ilang/ilang_parser.y b/yosys/frontends/ilang/ilang_parser.y index 44c99906a..b4b9693da 100644 --- a/yosys/frontends/ilang/ilang_parser.y +++ b/yosys/frontends/ilang/ilang_parser.y @@ -282,14 +282,14 @@ proc_stmt: } case_body sync_list TOK_END EOL; switch_stmt: - attr_list TOK_SWITCH sigspec EOL { + TOK_SWITCH sigspec EOL { RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; - rule->signal = *$3; + rule->signal = *$2; rule->attributes = attrbuf; switch_stack.back()->push_back(rule); attrbuf.clear(); - delete $3; - } switch_body TOK_END EOL; + delete $2; + } attr_list switch_body TOK_END EOL; attr_list: /* empty */ | @@ -298,9 +298,11 @@ attr_list: 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(); @@ -319,12 +321,15 @@ compare_list: /* 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_ilang_yyerror("dangling attribute"); case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); delete $2; delete $3; diff --git a/yosys/frontends/json/jsonparse.cc b/yosys/frontends/json/jsonparse.cc index 82361ea9b..f5ae8eb72 100644 --- a/yosys/frontends/json/jsonparse.cc +++ b/yosys/frontends/json/jsonparse.cc @@ -292,6 +292,18 @@ void json_import(Design *design, string &modname, JsonNode *node) if (port_wire == nullptr) port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array)); + if (port_node->data_dict.count("upto") != 0) { + JsonNode *val = port_node->data_dict.at("upto"); + if (val->type == 'N') + port_wire->upto = val->data_number != 0; + } + + if (port_node->data_dict.count("offset") != 0) { + JsonNode *val = port_node->data_dict.at("offset"); + if (val->type == 'N') + port_wire->start_offset = val->data_number; + } + if (port_direction_node->data_string == "input") { port_wire->port_input = true; } else @@ -372,6 +384,18 @@ void json_import(Design *design, string &modname, JsonNode *node) if (wire == nullptr) wire = module->addWire(net_name, GetSize(bits_node->data_array)); + if (net_node->data_dict.count("upto") != 0) { + JsonNode *val = net_node->data_dict.at("upto"); + if (val->type == 'N') + wire->upto = val->data_number != 0; + } + + if (net_node->data_dict.count("offset") != 0) { + JsonNode *val = net_node->data_dict.at("offset"); + if (val->type == 'N') + wire->start_offset = val->data_number; + } + for (int i = 0; i < GetSize(bits_node->data_array); i++) { JsonNode *bitval_node = bits_node->data_array.at(i); diff --git a/yosys/frontends/verific/verific.cc b/yosys/frontends/verific/verific.cc index 21a1bbbbe..2bf99e58e 100644 --- a/yosys/frontends/verific/verific.cc +++ b/yosys/frontends/verific/verific.cc @@ -48,6 +48,14 @@ USING_YOSYS_NAMESPACE #include "VhdlUnits.h" #include "VeriLibrary.h" +#ifndef SYMBIOTIC_VERIFIC_API_VERSION +# error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific." +#endif + +#if SYMBIOTIC_VERIFIC_API_VERSION < 1 +# error "Please update your version of Symbiotic EDA flavored Verific." +#endif + #ifdef __clang__ #pragma clang diagnostic pop #endif @@ -2016,6 +2024,9 @@ struct VerificPass : public Pass { // WARNING: instantiating unknown module 'XYZ' (VERI-1063) Message::SetMessageType("VERI-1063", VERIFIC_ERROR); + // https://github.com/YosysHQ/yosys/issues/1055 + RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; + #ifndef DB_PRESERVE_INITIAL_VALUE # warning Verific was built without DB_PRESERVE_INITIAL_VALUE. #endif diff --git a/yosys/frontends/verilog/const2ast.cc b/yosys/frontends/verilog/const2ast.cc index 7848c626d..f6a17b242 100644 --- a/yosys/frontends/verilog/const2ast.cc +++ b/yosys/frontends/verilog/const2ast.cc @@ -71,7 +71,7 @@ static int my_ilog2(int x) } // parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') -static void my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type) +static void my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized) { // all digits in string (MSB at index 0) std::vector digits; @@ -129,6 +129,9 @@ static void my_strtobin(std::vector &data, const char *str, int le return; } + if (is_unsized && (len > len_in_bits)) + log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len); + for (len = len - 1; len >= 0; len--) if (data[len] == RTLIL::S1) break; @@ -150,7 +153,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn { if (warn_z) { AstNode *ret = const2ast(code, case_type); - if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) + if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", current_filename.c_str(), get_line_num()); return ret; @@ -186,7 +189,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn // Simple base-10 integer if (*endptr == 0) { std::vector data; - my_strtobin(data, str, -1, 10, case_type); + my_strtobin(data, str, -1, 10, case_type, false); if (data.back() == RTLIL::S1) data.push_back(RTLIL::S0); return AstNode::mkconst_bits(data, true); @@ -201,6 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn { std::vector data; bool is_signed = false; + bool is_unsized = len_in_bits < 0; if (*(endptr+1) == 's') { is_signed = true; endptr++; @@ -209,28 +213,34 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn { case 'b': case 'B': - my_strtobin(data, endptr+2, len_in_bits, 2, case_type); + my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized); break; case 'o': case 'O': - my_strtobin(data, endptr+2, len_in_bits, 8, case_type); + my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized); break; case 'd': case 'D': - my_strtobin(data, endptr+2, len_in_bits, 10, case_type); + my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized); break; case 'h': case 'H': - my_strtobin(data, endptr+2, len_in_bits, 16, case_type); + my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized); break; default: - return NULL; + char next_char = char(tolower(*(endptr+1))); + if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') { + is_unsized = true; + my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized); + } else { + return NULL; + } } if (len_in_bits < 0) { if (is_signed && data.back() == RTLIL::S1) data.push_back(RTLIL::S0); } - return AstNode::mkconst_bits(data, is_signed); + return AstNode::mkconst_bits(data, is_signed, is_unsized); } return NULL; diff --git a/yosys/frontends/verilog/verilog_frontend.cc b/yosys/frontends/verilog/verilog_frontend.cc index 01e589efb..0e2bead6f 100644 --- a/yosys/frontends/verilog/verilog_frontend.cc +++ b/yosys/frontends/verilog/verilog_frontend.cc @@ -168,6 +168,9 @@ struct VerilogFrontend : public Frontend { log(" -icells\n"); log(" interpret cell types starting with '$' as internal cell types\n"); log("\n"); + log(" -pwires\n"); + log(" add a wire for each module parameter\n"); + log("\n"); log(" -nooverwrite\n"); log(" ignore re-definitions of modules. (the default behavior is to\n"); log(" create an error message if the existing module is not a black box\n"); @@ -228,6 +231,7 @@ struct VerilogFrontend : public Frontend { bool flag_nodpi = false; bool flag_noopt = false; bool flag_icells = false; + bool flag_pwires = false; bool flag_nooverwrite = false; bool flag_overwrite = false; bool flag_defer = false; @@ -368,6 +372,10 @@ struct VerilogFrontend : public Frontend { flag_icells = true; continue; } + if (arg == "-pwires") { + flag_pwires = true; + continue; + } if (arg == "-ignore_redef" || arg == "-nooverwrite") { flag_nooverwrite = true; flag_overwrite = false; @@ -458,7 +466,7 @@ struct VerilogFrontend : public Frontend { error_on_dpi_function(current_ast); AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, - flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; diff --git a/yosys/frontends/verilog/verilog_lexer.l b/yosys/frontends/verilog/verilog_lexer.l index 142d05d45..951d9c66f 100644 --- a/yosys/frontends/verilog/verilog_lexer.l +++ b/yosys/frontends/verilog/verilog_lexer.l @@ -193,6 +193,8 @@ YOSYS_NAMESPACE_END to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some global state.. its a mess) */ [a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { + if (!strcmp(yytext, "default")) + return TOK_DEFAULT; frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); return TOK_SVA_LABEL; } @@ -218,6 +220,8 @@ YOSYS_NAMESPACE_END "output" { return TOK_OUTPUT; } "inout" { return TOK_INOUT; } "wire" { return TOK_WIRE; } +"wor" { return TOK_WOR; } +"wand" { return TOK_WAND; } "reg" { return TOK_REG; } "integer" { return TOK_INTEGER; } "signed" { return TOK_SIGNED; } @@ -232,7 +236,7 @@ YOSYS_NAMESPACE_END return TOK_CONSTVAL; } -[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ { +[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { frontend_verilog_yylval.string = new std::string(yytext); return TOK_CONSTVAL; } @@ -309,6 +313,11 @@ supply1 { return TOK_SUPPLY1; } return TOK_ID; } +"$"(info|warning|error|fatal) { + frontend_verilog_yylval.string = new std::string(yytext); + return TOK_MSG_TASKS; +} + "$signed" { return TOK_TO_SIGNED; } "$unsigned" { return TOK_TO_UNSIGNED; } diff --git a/yosys/frontends/verilog/verilog_parser.y b/yosys/frontends/verilog/verilog_parser.y index 132468f0c..0fec445fa 100644 --- a/yosys/frontends/verilog/verilog_parser.y +++ b/yosys/frontends/verilog/verilog_parser.y @@ -133,13 +133,13 @@ struct specify_rise_fall { } %token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE -%token TOK_SVA_LABEL TOK_SPECIFY_OPER +%token TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR -%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC +%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC @@ -319,15 +319,17 @@ module_para_list: single_module_para: /* empty */ | - TOK_PARAMETER { + attr TOK_PARAMETER { if (astbuf1) delete astbuf1; astbuf1 = new AstNode(AST_PARAMETER); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(astbuf1, $1); } param_signed param_integer param_range single_param_decl | - TOK_LOCALPARAM { + attr TOK_LOCALPARAM { if (astbuf1) delete astbuf1; astbuf1 = new AstNode(AST_LOCALPARAM); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(astbuf1, $1); } param_signed param_integer param_range single_param_decl | single_param_decl; @@ -345,7 +347,13 @@ module_arg_opt_assignment: if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { AstNode *wire = new AstNode(AST_IDENTIFIER); wire->str = ast_stack.back()->children.back()->str; - if (ast_stack.back()->children.back()->is_reg) + if (ast_stack.back()->children.back()->is_input) { + AstNode *n = ast_stack.back()->children.back(); + if (n->attributes.count("\\defaultvalue")) + delete n->attributes.at("\\defaultvalue"); + n->attributes["\\defaultvalue"] = $2; + } else + if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic) ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2)))); else ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); @@ -485,6 +493,12 @@ wire_type_token_io: wire_type_token: TOK_WIRE { } | + TOK_WOR { + astbuf3->is_wor = true; + } | + TOK_WAND { + astbuf3->is_wand = true; + } | TOK_REG { astbuf3->is_reg = true; } | @@ -503,6 +517,7 @@ wire_type_token: TOK_GENVAR { astbuf3->type = AST_GENVAR; astbuf3->is_reg = true; + astbuf3->is_signed = true; astbuf3->range_left = 31; astbuf3->range_right = 0; } | @@ -1006,13 +1021,8 @@ list_of_specparam_assignments: specparam_assignment: ignspec_id '=' constant_mintypmax_expression ; -/* -pulsestyle_declaration : - ; - -showcancelled_declaration : - ; -*/ +ignspec_opt_cond: + TOK_IF '(' ignspec_expr ')' | /* empty */; path_declaration : simple_path_declaration ';' @@ -1021,8 +1031,8 @@ path_declaration : ; simple_path_declaration : - parallel_path_description '=' path_delay_value | - full_path_description '=' path_delay_value + ignspec_opt_cond parallel_path_description '=' path_delay_value | + ignspec_opt_cond full_path_description '=' path_delay_value ; path_delay_value : @@ -1032,32 +1042,20 @@ path_delay_value : ; list_of_path_delay_extra_expressions : -/* - t_path_delay_expression - | trise_path_delay_expression ',' tfall_path_delay_expression - | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression - | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ',' - tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression - | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ',' - tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ',' - t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ',' - tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression -*/ - ',' path_delay_expression - | ',' path_delay_expression ',' path_delay_expression - | ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression - | ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression - ; + ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions; + +specify_edge_identifier : + TOK_POSEDGE | TOK_NEGEDGE ; parallel_path_description : - '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ; + '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' | + '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' | + '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ; full_path_description : - '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ; + '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' | + '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' | + '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ; // This was broken into 2 rules to solve shift/reduce conflicts list_of_path_inputs : @@ -1097,56 +1095,6 @@ system_timing_args : system_timing_arg | system_timing_args ',' system_timing_arg ; -/* -t_path_delay_expression : - path_delay_expression; - -trise_path_delay_expression : - path_delay_expression; - -tfall_path_delay_expression : - path_delay_expression; - -tz_path_delay_expression : - path_delay_expression; - -t01_path_delay_expression : - path_delay_expression; - -t10_path_delay_expression : - path_delay_expression; - -t0z_path_delay_expression : - path_delay_expression; - -tz1_path_delay_expression : - path_delay_expression; - -t1z_path_delay_expression : - path_delay_expression; - -tz0_path_delay_expression : - path_delay_expression; - -t0x_path_delay_expression : - path_delay_expression; - -tx1_path_delay_expression : - path_delay_expression; - -t1x_path_delay_expression : - path_delay_expression; - -tx0_path_delay_expression : - path_delay_expression; - -txz_path_delay_expression : - path_delay_expression; - -tzx_path_delay_expression : - path_delay_expression; -*/ - path_delay_expression : ignspec_constant_expression; @@ -1205,6 +1153,7 @@ param_decl: attr TOK_PARAMETER { astbuf1 = new AstNode(AST_PARAMETER); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(astbuf1, $1); } param_signed param_integer param_real param_range param_decl_list ';' { delete astbuf1; }; @@ -1213,6 +1162,7 @@ localparam_decl: attr TOK_LOCALPARAM { astbuf1 = new AstNode(AST_LOCALPARAM); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(astbuf1, $1); } param_signed param_integer param_real param_range param_decl_list ';' { delete astbuf1; }; @@ -1354,7 +1304,12 @@ wire_name_and_opt_assign: wire_name '=' expr { AstNode *wire = new AstNode(AST_IDENTIFIER); wire->str = ast_stack.back()->children.back()->str; - if (astbuf1->is_reg) + if (astbuf1->is_input) { + if (astbuf1->attributes.count("\\defaultvalue")) + delete astbuf1->attributes.at("\\defaultvalue"); + astbuf1->attributes["\\defaultvalue"] = $3; + } else + if (astbuf1->is_reg || astbuf1->is_logic) ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3)))); else ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3)); @@ -1379,7 +1334,13 @@ wire_name: node->children.push_back(rng); } node->type = AST_MEMORY; - node->children.push_back($2); + auto *rangeNode = $2; + if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { + // SV array size [n], rewrite as [n-1:0] + rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true)); + rangeNode->children.push_back(AstNode::mkconst_int(0, false)); + } + node->children.push_back(rangeNode); } if (current_function_or_task == NULL) { if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) { @@ -1526,27 +1487,40 @@ cell_port_list_rules: cell_port | cell_port_list_rules ',' cell_port; cell_port: - /* empty */ { + attr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); + free_attr($1); } | - expr { + attr expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); - node->children.push_back($1); + node->children.push_back($2); + free_attr($1); } | - '.' TOK_ID '(' expr ')' { + attr '.' TOK_ID '(' expr ')' { AstNode *node = new AstNode(AST_ARGUMENT); - node->str = *$2; + node->str = *$3; astbuf2->children.push_back(node); - node->children.push_back($4); - delete $2; + node->children.push_back($5); + delete $3; + free_attr($1); } | - '.' TOK_ID '(' ')' { + attr '.' TOK_ID '(' ')' { AstNode *node = new AstNode(AST_ARGUMENT); - node->str = *$2; + node->str = *$3; astbuf2->children.push_back(node); - delete $2; + delete $3; + free_attr($1); + } | + attr '.' TOK_ID { + AstNode *node = new AstNode(AST_ARGUMENT); + node->str = *$3; + astbuf2->children.push_back(node); + node->children.push_back(new AstNode(AST_IDENTIFIER)); + node->children.back()->str = *$3; + delete $3; + free_attr($1); }; always_stmt: @@ -1862,6 +1836,16 @@ behavioral_stmt: } opt_arg_list ';'{ ast_stack.pop_back(); } | + TOK_MSG_TASKS attr { + AstNode *node = new AstNode(AST_TCALL); + node->str = *$1; + delete $1; + ast_stack.back()->children.push_back(node); + ast_stack.push_back(node); + append_attr(node, $2); + } opt_arg_list ';'{ + ast_stack.pop_back(); + } | attr TOK_BEGIN opt_label { AstNode *node = new AstNode(AST_BLOCK); ast_stack.back()->children.push_back(node); @@ -2157,6 +2141,15 @@ gen_stmt: if ($6 != NULL) delete $6; ast_stack.pop_back(); + } | + TOK_MSG_TASKS { + AstNode *node = new AstNode(AST_TECALL); + node->str = *$1; + delete $1; + ast_stack.back()->children.push_back(node); + ast_stack.push_back(node); + } opt_arg_list ';'{ + ast_stack.pop_back(); }; gen_stmt_block: diff --git a/yosys/kernel/log.cc b/yosys/kernel/log.cc index 9a9104e26..a7820950c 100644 --- a/yosys/kernel/log.cc +++ b/yosys/kernel/log.cc @@ -230,6 +230,9 @@ static void logv_warning_with_prefix(const char *prefix, } else { + int bak_log_make_debug = log_make_debug; + log_make_debug = 0; + for (auto &re : log_werror_regexes) if (std::regex_search(message, re)) log_error("%s", message.c_str()); @@ -254,6 +257,7 @@ static void logv_warning_with_prefix(const char *prefix, } log_warnings_count++; + log_make_debug = bak_log_make_debug; } } @@ -273,11 +277,22 @@ void log_file_warning(const std::string &filename, int lineno, va_list ap; va_start(ap, format); std::string prefix = stringf("%s:%d: Warning: ", - filename.c_str(), lineno); + filename.c_str(), lineno); logv_warning_with_prefix(prefix.c_str(), format, ap); va_end(ap); } +void log_file_info(const std::string &filename, int lineno, + const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string fmt = stringf("%s:%d: Info: %s", + filename.c_str(), lineno, format); + logv(fmt.c_str(), ap); + va_end(ap); +} + YS_ATTRIBUTE(noreturn) static void logv_error_with_prefix(const char *prefix, const char *format, va_list ap) @@ -285,6 +300,9 @@ static void logv_error_with_prefix(const char *prefix, #ifdef EMSCRIPTEN auto backup_log_files = log_files; #endif + int bak_log_make_debug = log_make_debug; + log_make_debug = 0; + log_suppressed(); if (log_errfile != NULL) log_files.push_back(log_errfile); @@ -298,6 +316,8 @@ static void logv_error_with_prefix(const char *prefix, log("%s%s", prefix, log_last_error.c_str()); log_flush(); + log_make_debug = bak_log_make_debug; + if (log_error_atexit) log_error_atexit(); diff --git a/yosys/kernel/log.h b/yosys/kernel/log.h index e6afae716..3e1facae8 100644 --- a/yosys/kernel/log.h +++ b/yosys/kernel/log.h @@ -80,6 +80,7 @@ void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); // Log with filename to report a problem in a source file. void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); +void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); diff --git a/yosys/kernel/register.cc b/yosys/kernel/register.cc index 71eb6b187..26da96b95 100644 --- a/yosys/kernel/register.cc +++ b/yosys/kernel/register.cc @@ -545,6 +545,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vectoropen(filename.c_str(), std::ofstream::trunc); yosys_output_files.insert(filename); diff --git a/yosys/kernel/rtlil.cc b/yosys/kernel/rtlil.cc index 790ba52a3..a09f4a0d1 100644 --- a/yosys/kernel/rtlil.cc +++ b/yosys/kernel/rtlil.cc @@ -1381,7 +1381,34 @@ void RTLIL::Module::check() for (auto &it : processes) { log_assert(it.first == it.second->name); log_assert(!it.first.empty()); - // FIXME: More checks here.. + log_assert(it.second->root_case.compare.empty()); + std::vector all_cases = {&it.second->root_case}; + for (size_t i = 0; i < all_cases.size(); i++) { + for (auto &switch_it : all_cases[i]->switches) { + for (auto &case_it : switch_it->cases) { + for (auto &compare_it : case_it->compare) { + log_assert(switch_it->signal.size() == compare_it.size()); + } + all_cases.push_back(case_it); + } + } + } + for (auto &sync_it : it.second->syncs) { + switch (sync_it->type) { + case SyncType::ST0: + case SyncType::ST1: + case SyncType::STp: + case SyncType::STn: + case SyncType::STe: + log_assert(!sync_it->signal.empty()); + break; + case SyncType::STa: + case SyncType::STg: + case SyncType::STi: + log_assert(sync_it->signal.empty()); + break; + } + } } for (auto &it : connections_) { diff --git a/yosys/kernel/rtlil.h b/yosys/kernel/rtlil.h index 81ca93dce..7b7367fba 100644 --- a/yosys/kernel/rtlil.h +++ b/yosys/kernel/rtlil.h @@ -601,6 +601,7 @@ struct RTLIL::SigChunk RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default; RTLIL::SigChunk extract(int offset, int length) const; + inline int size() const { return width; } bool operator <(const RTLIL::SigChunk &other) const; bool operator ==(const RTLIL::SigChunk &other) const; @@ -1314,7 +1315,7 @@ public: #endif }; -struct RTLIL::CaseRule +struct RTLIL::CaseRule : public RTLIL::AttrObject { std::vector compare; std::vector actions; diff --git a/yosys/kernel/yosys.cc b/yosys/kernel/yosys.cc index 377572fc2..69a141768 100644 --- a/yosys/kernel/yosys.cc +++ b/yosys/kernel/yosys.cc @@ -129,7 +129,7 @@ void yosys_banner() log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2018 Clifford Wolf |\n"); + log(" | Copyright (C) 2012 - 2019 Clifford Wolf |\n"); log(" | |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n"); @@ -651,6 +651,10 @@ void rewrite_filename(std::string &filename) filename = filename.substr(1, GetSize(filename)-2); if (filename.substr(0, 2) == "+/") filename = proc_share_dirname() + filename.substr(2); +#ifndef _WIN32 + if (filename.substr(0, 2) == "~/") + filename = filename.replace(0, 1, getenv("HOME")); +#endif } #ifdef YOSYS_ENABLE_TCL diff --git a/yosys/kernel/yosys.h b/yosys/kernel/yosys.h index c7b671724..730efe825 100644 --- a/yosys/kernel/yosys.h +++ b/yosys/kernel/yosys.h @@ -87,6 +87,10 @@ extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName); extern void Tcl_Finalize(void); extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); extern const char *Tcl_GetStringResult(Tcl_Interp *interp); +extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length); +extern Tcl_Obj *Tcl_NewIntObj(int intValue); +extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); +extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); # endif #endif diff --git a/yosys/manual/CHAPTER_Overview.tex b/yosys/manual/CHAPTER_Overview.tex index 2feb0f1cb..3009bf2c0 100644 --- a/yosys/manual/CHAPTER_Overview.tex +++ b/yosys/manual/CHAPTER_Overview.tex @@ -331,8 +331,9 @@ to update {\tt \textbackslash{}q}. An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and exactly one RTLIL::CaseRule object, which is called the {\it root case}. -An RTLIL::SyncRule object contains an (optional) synchronization condition -(signal and edge-type) and zero or more assignments (RTLIL::SigSig). +An RTLIL::SyncRule object contains an (optional) synchronization condition (signal and edge-type) and zero or +more assignments (RTLIL::SigSig). The {\tt always} synchronization condition is used to break combinatorial +loops when a latch should be inferred instead. An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig) and zero or more RTLIL::SwitchRule objects. An RTLIL::SwitchRule objects is a @@ -350,6 +351,18 @@ and this bit is a one (the second ``1'').} for {\tt \textbackslash{}reset == 1} sets {\tt \$0\textbackslash{}q[0:0]} to the value of {\tt \textbackslash{}d} if {\tt \textbackslash{}enable} is active (lines $6 \dots 11$). +A case can specify zero or more compare values that will determine whether it matches. Each of the compare values +must be the exact same width as the control signal. When more than one compare value is specified, the case matches +if any of them matches the control signal; when zero compare values are specified, the case always matches (i.e. +it is the default case). + +A switch prioritizes cases from first to last: multiple cases can match, but only the first matched case becomes +active. This normally synthesizes to a priority encoder. The {\tt parallel\_case} attribute allows passes to assume +that no more than one case will match, and {\tt full\_case} attribute allows passes to assume that exactly one +case will match; if these invariants are ever dynamically violated, the behavior is undefined. These attributes +are useful when an invariant invisible to the synthesizer causes the control signal to never take certain +bit patterns. + The lines $13 \dots 16$ then cause {\tt \textbackslash{}q} to be updated whenever there is a positive clock edge on {\tt \textbackslash{}clock} or {\tt \textbackslash{}reset}. diff --git a/yosys/misc/launcher.c b/yosys/misc/launcher.c index 157d68cf3..e0d8208f1 100644 --- a/yosys/misc/launcher.c +++ b/yosys/misc/launcher.c @@ -61,6 +61,7 @@ SOFTWARE. */ #include #include #include +#include int child_pid=0; @@ -338,7 +339,7 @@ int run(int argc, char **argv, int is_gui) { if (is_gui) { /* Use exec, we don't need to wait for the GUI to finish */ - execv(ptr, (const char * const *)(newargs)); + execv(ptr, (char * const *)(newargs)); return fail("Could not exec %s", ptr); /* shouldn't get here! */ } diff --git a/yosys/misc/py_wrap_generator.py b/yosys/misc/py_wrap_generator.py index 09f934040..66d661fa1 100644 --- a/yosys/misc/py_wrap_generator.py +++ b/yosys/misc/py_wrap_generator.py @@ -779,6 +779,9 @@ class WClass: #if self.link_type != link_types.pointer: text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" + text += "\n\t\t\tif(ref == nullptr){" + text += "\n\t\t\t\tthrow std::runtime_error(\"" + self.name + " does not exist.\");" + text += "\n\t\t\t}" text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" if self.link_type == link_types.pointer: text += "\n\t\t\tret->ref_obj = ref;" @@ -2026,7 +2029,6 @@ def gen_wrappers(filename, debug_level_ = 0): #include #include #include -#include USING_YOSYS_NAMESPACE @@ -2060,7 +2062,6 @@ namespace YOSYS_PYTHON { Yosys::log_streams.push_back(&std::cout); Yosys::log_error_stderr = true; Yosys::yosys_setup(); - Yosys::yosys_banner(); } } diff --git a/yosys/passes/cmds/blackbox.cc b/yosys/passes/cmds/blackbox.cc index 6094f8f16..d09ed872e 100644 --- a/yosys/passes/cmds/blackbox.cc +++ b/yosys/passes/cmds/blackbox.cc @@ -23,7 +23,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct BlackboxPass : public Pass { - BlackboxPass() : Pass("blackbox", "change type of cells in the design") { } + BlackboxPass() : Pass("blackbox", "convert modules into blackbox modules") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/yosys/passes/cmds/setundef.cc b/yosys/passes/cmds/setundef.cc index f6949c820..3eedc86b8 100644 --- a/yosys/passes/cmds/setundef.cc +++ b/yosys/passes/cmds/setundef.cc @@ -393,44 +393,112 @@ struct SetundefPass : public Pass { ffbits.insert(bit); } - for (auto wire : module->wires()) + auto process_initwires = [&]() { - if (!wire->attributes.count("\\init")) - continue; + dict wire_weights; - for (auto bit : sigmap(wire)) - ffbits.erase(bit); - - initwires.insert(wire); - } - - for (int wire_types = 0; wire_types < 2; wire_types++) - for (auto wire : module->wires()) + for (auto wire : initwires) { - if (wire->name[0] == (wire_types ? '\\' : '$')) - next_wire: - continue; + int weight = 0; for (auto bit : sigmap(wire)) - if (!ffbits.count(bit)) - goto next_wire; + weight += ffbits.count(bit) ? +1 : -1; - for (auto bit : sigmap(wire)) - ffbits.erase(bit); - - initwires.insert(wire); + wire_weights[wire] = weight; } - for (auto wire : initwires) - { - Const &initval = wire->attributes["\\init"]; + initwires.sort([&](Wire *a, Wire *b) { return wire_weights.at(a) > wire_weights.at(b); }); - for (int i = 0; i < GetSize(wire); i++) - if (GetSize(initval) <= i) - initval.bits.push_back(worker.next_bit()); - else if (initval.bits[i] == State::Sx) - initval.bits[i] = worker.next_bit(); + for (auto wire : initwires) + { + Const &initval = wire->attributes["\\init"]; + initval.bits.resize(GetSize(wire), State::Sx); + + for (int i = 0; i < GetSize(wire); i++) { + SigBit bit = sigmap(SigBit(wire, i)); + if (initval[i] == State::Sx && ffbits.count(bit)) { + initval[i] = worker.next_bit(); + ffbits.erase(bit); + } + } + + if (initval.is_fully_undef()) + wire->attributes.erase("\\init"); + } + + initwires.clear(); + }; + + for (int wire_types = 0; wire_types < 2; wire_types++) + { + // prioritize wires that already have an init attribute + if (!ffbits.empty()) + { + for (auto wire : module->wires()) + { + if (wire->name[0] == (wire_types ? '\\' : '$')) + continue; + + if (!wire->attributes.count("\\init")) + continue; + + Const &initval = wire->attributes["\\init"]; + initval.bits.resize(GetSize(wire), State::Sx); + + if (initval.is_fully_undef()) { + wire->attributes.erase("\\init"); + continue; + } + + for (int i = 0; i < GetSize(wire); i++) + if (initval[i] != State::Sx) + ffbits.erase(sigmap(SigBit(wire, i))); + + initwires.insert(wire); + } + + process_initwires(); + } + + // next consider wires that completely contain bits to be initialized + if (!ffbits.empty()) + { + for (auto wire : module->wires()) + { + if (wire->name[0] == (wire_types ? '\\' : '$')) + continue; + + for (auto bit : sigmap(wire)) + if (!ffbits.count(bit)) + goto next_wire; + + initwires.insert(wire); + + next_wire: + continue; + } + + process_initwires(); + } + + // finally use whatever wire we can find. + if (!ffbits.empty()) + { + for (auto wire : module->wires()) + { + if (wire->name[0] == (wire_types ? '\\' : '$')) + continue; + + for (auto bit : sigmap(wire)) + if (ffbits.count(bit)) + initwires.insert(wire); + } + + process_initwires(); + } } + + log_assert(ffbits.empty()); } module->rewrite_sigspecs(worker); diff --git a/yosys/passes/cmds/stat.cc b/yosys/passes/cmds/stat.cc index d22685b62..27c5fb60c 100644 --- a/yosys/passes/cmds/stat.cc +++ b/yosys/passes/cmds/stat.cc @@ -285,8 +285,8 @@ struct StatPass : public Pass { log(" use cell area information from the provided liberty file\n"); log("\n"); log(" -tech \n"); - log(" print area estemate for the specified technology. Corrently supported\n"); - log(" calues for : xilinx\n"); + log(" print area estemate for the specified technology. Currently supported\n"); + log(" values for : xilinx\n"); log("\n"); log(" -width\n"); log(" annotate internal cell types with their word width.\n"); diff --git a/yosys/passes/cmds/tee.cc b/yosys/passes/cmds/tee.cc index ee96ace86..1a44bdaec 100644 --- a/yosys/passes/cmds/tee.cc +++ b/yosys/passes/cmds/tee.cc @@ -52,7 +52,9 @@ struct TeePass : public Pass { void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { std::vector backup_log_files, files_to_close; + std::vector backup_log_streams; int backup_log_verbose_level = log_verbose_level; + backup_log_streams = log_streams; backup_log_files = log_files; size_t argidx; @@ -60,6 +62,7 @@ struct TeePass : public Pass { { if (args[argidx] == "-q" && files_to_close.empty()) { log_files.clear(); + log_streams.clear(); continue; } if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) { @@ -89,6 +92,7 @@ struct TeePass : public Pass { for (auto cf : files_to_close) fclose(cf); log_files = backup_log_files; + log_streams = backup_log_streams; throw; } @@ -97,6 +101,7 @@ struct TeePass : public Pass { log_verbose_level = backup_log_verbose_level; log_files = backup_log_files; + log_streams = backup_log_streams; } } TeePass; diff --git a/yosys/passes/cmds/write_file.cc b/yosys/passes/cmds/write_file.cc index 9613b462b..64a762d7c 100644 --- a/yosys/passes/cmds/write_file.cc +++ b/yosys/passes/cmds/write_file.cc @@ -62,7 +62,7 @@ struct WriteFileFrontend : public Frontend { if (argidx < args.size() && args[argidx].rfind("-", 0) != 0) output_filename = args[argidx++]; else - log_cmd_error("Missing putput filename.\n"); + log_cmd_error("Missing output filename.\n"); extra_args(f, filename, args, argidx); diff --git a/yosys/passes/hierarchy/hierarchy.cc b/yosys/passes/hierarchy/hierarchy.cc index 72bc2e133..213437c01 100644 --- a/yosys/passes/hierarchy/hierarchy.cc +++ b/yosys/passes/hierarchy/hierarchy.cc @@ -562,7 +562,8 @@ struct HierarchyPass : public Pass { log("In parametric designs, a module might exists in several variations with\n"); log("different parameter values. This pass looks at all modules in the current\n"); log("design an re-runs the language frontends for the parametric modules as\n"); - log("needed.\n"); + log("needed. It also resolves assignments to wired logic data types (wand/wor),\n"); + log("resolves positional module parameters, unroll array instances, and more.\n"); log("\n"); log(" -check\n"); log(" also check the design hierarchy. this generates an error when\n"); @@ -590,6 +591,9 @@ struct HierarchyPass : public Pass { log(" module instances when the width does not match the module port. This\n"); log(" option disables this behavior.\n"); log("\n"); + log(" -nodefaults\n"); + log(" do not resolve input port default values\n"); + log("\n"); log(" -nokeep_asserts\n"); log(" per default this pass sets the \"keep\" attribute on all modules\n"); log(" that directly or indirectly contain one or more formal properties.\n"); @@ -644,6 +648,7 @@ struct HierarchyPass : public Pass { bool generate_mode = false; bool keep_positionals = false; bool keep_portwidths = false; + bool nodefaults = false; bool nokeep_asserts = false; std::vector generate_cells; std::vector generate_ports; @@ -711,6 +716,10 @@ struct HierarchyPass : public Pass { keep_portwidths = true; continue; } + if (args[argidx] == "-nodefaults") { + nodefaults = true; + continue; + } if (args[argidx] == "-nokeep_asserts") { nokeep_asserts = true; continue; @@ -939,66 +948,212 @@ struct HierarchyPass : public Pass { } } + if (!nodefaults) + { + dict> defaults_db; + + for (auto module : design->modules()) + for (auto wire : module->wires()) + if (wire->port_input && wire->attributes.count("\\defaultvalue")) + defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue"); + + for (auto module : design->modules()) + for (auto cell : module->cells()) + { + if (defaults_db.count(cell->type) == 0) + continue; + + if (keep_positionals) { + bool found_positionals = false; + for (auto &conn : cell->connections()) + if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') + found_positionals = true; + if (found_positionals) + continue; + } + + for (auto &it : defaults_db.at(cell->type)) + if (!cell->hasPort(it.first)) + cell->setPort(it.first, it.second); + } + } + std::set blackbox_derivatives; std::vector design_modules = design->modules(); for (auto module : design_modules) - for (auto cell : module->cells()) { - Module *m = design->module(cell->type); + pool wand_wor_index; + dict wand_map, wor_map; + vector new_connections; - if (m == nullptr) - continue; - - if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { - IdString new_m_name = m->derive(design, cell->parameters, true); - if (new_m_name.empty()) - continue; - if (new_m_name != m->name) { - m = design->module(new_m_name); - blackbox_derivatives.insert(m); + for (auto wire : module->wires()) + { + if (wire->get_bool_attribute("\\wand")) { + wand_map[wire] = SigSpec(); + wand_wor_index.insert(wire); + } + if (wire->get_bool_attribute("\\wor")) { + wor_map[wire] = SigSpec(); + wand_wor_index.insert(wire); } } - for (auto &conn : cell->connections()) + for (auto &conn : module->connections()) { - Wire *w = m->wire(conn.first); + SigSig new_conn; + int cursor = 0; - if (w == nullptr || w->port_id == 0) - continue; - - if (GetSize(conn.second) == 0) - continue; - - SigSpec sig = conn.second; - - if (!keep_portwidths && GetSize(w) != GetSize(conn.second)) + for (auto c : conn.first.chunks()) { - if (GetSize(w) < GetSize(conn.second)) - { - int n = GetSize(conn.second) - GetSize(w); - if (!w->port_input && w->port_output) - module->connect(sig.extract(GetSize(w), n), Const(0, n)); - sig.remove(GetSize(w), n); + Wire *w = c.wire; + SigSpec rhs = conn.second.extract(cursor, GetSize(c)); + + if (wand_wor_index.count(w) == 0) { + new_conn.first.append(c); + new_conn.second.append(rhs); + } else { + if (wand_map.count(w)) { + SigSpec sig = SigSpec(State::S1, GetSize(w)); + sig.replace(c.offset, rhs); + wand_map.at(w).append(sig); + } else { + SigSpec sig = SigSpec(State::S0, GetSize(w)); + sig.replace(c.offset, rhs); + wor_map.at(w).append(sig); + } } - else + cursor += GetSize(c); + } + new_connections.push_back(new_conn); + } + module->new_connections(new_connections); + + for (auto cell : module->cells()) + { + if (!cell->known()) + continue; + + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + SigSpec new_sig; + bool update_port = false; + + for (auto c : conn.second.chunks()) { - int n = GetSize(w) - GetSize(conn.second); - if (w->port_input && !w->port_output) - sig.append(Const(0, n)); - else - sig.append(module->addWire(NEW_ID, n)); + Wire *w = c.wire; + + if (wand_wor_index.count(w) == 0) { + new_sig.append(c); + continue; + } + + Wire *t = module->addWire(NEW_ID, GetSize(c)); + new_sig.append(t); + update_port = true; + + if (wand_map.count(w)) { + SigSpec sig = SigSpec(State::S1, GetSize(w)); + sig.replace(c.offset, t); + wand_map.at(w).append(sig); + } else { + SigSpec sig = SigSpec(State::S0, GetSize(w)); + sig.replace(c.offset, t); + wor_map.at(w).append(sig); + } } - if (!conn.second.is_fully_const() || !w->port_input || w->port_output) - log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell), - log_id(conn.first), GetSize(conn.second), GetSize(sig)); - cell->setPort(conn.first, sig); + if (update_port) + cell->setPort(conn.first, new_sig); + } + } + + for (auto w : wand_wor_index) + { + bool wand = wand_map.count(w); + SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w); + + if (GetSize(sigs) == 0) + continue; + + if (GetSize(w) == 1) { + if (wand) + module->addReduceAnd(NEW_ID, sigs, w); + else + module->addReduceOr(NEW_ID, sigs, w); + continue; } - if (w->port_output && !w->port_input && sig.has_const()) - log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n", - log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig)); + SigSpec s = sigs.extract(0, GetSize(w)); + for (int i = GetSize(w); i < GetSize(sigs); i += GetSize(w)) { + if (wand) + s = module->And(NEW_ID, s, sigs.extract(i, GetSize(w))); + else + s = module->Or(NEW_ID, s, sigs.extract(i, GetSize(w))); + } + module->connect(w, s); + } + + for (auto cell : module->cells()) + { + Module *m = design->module(cell->type); + + if (m == nullptr) + continue; + + if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { + IdString new_m_name = m->derive(design, cell->parameters, true); + if (new_m_name.empty()) + continue; + if (new_m_name != m->name) { + m = design->module(new_m_name); + blackbox_derivatives.insert(m); + } + } + + for (auto &conn : cell->connections()) + { + Wire *w = m->wire(conn.first); + + if (w == nullptr || w->port_id == 0) + continue; + + if (GetSize(conn.second) == 0) + continue; + + SigSpec sig = conn.second; + + if (!keep_portwidths && GetSize(w) != GetSize(conn.second)) + { + if (GetSize(w) < GetSize(conn.second)) + { + int n = GetSize(conn.second) - GetSize(w); + if (!w->port_input && w->port_output) + module->connect(sig.extract(GetSize(w), n), Const(0, n)); + sig.remove(GetSize(w), n); + } + else + { + int n = GetSize(w) - GetSize(conn.second); + if (w->port_input && !w->port_output) + sig.append(Const(0, n)); + else + sig.append(module->addWire(NEW_ID, n)); + } + + if (!conn.second.is_fully_const() || !w->port_input || w->port_output) + log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell), + log_id(conn.first), GetSize(conn.second), GetSize(sig)); + cell->setPort(conn.first, sig); + } + + if (w->port_output && !w->port_input && sig.has_const()) + log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n", + log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig)); + } } } diff --git a/yosys/passes/memory/memory_dff.cc b/yosys/passes/memory/memory_dff.cc index 220d29295..32b97f27a 100644 --- a/yosys/passes/memory/memory_dff.cc +++ b/yosys/passes/memory/memory_dff.cc @@ -17,6 +17,7 @@ * */ +#include #include "kernel/yosys.h" #include "kernel/sigtools.h" @@ -182,20 +183,27 @@ struct MemoryDffWorker if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data)) { - bool enable_invert = mux_cells_a.count(sig_data) != 0; - Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data); - SigSpec check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A")); + RTLIL::SigSpec en; + std::vector check_q; + + do { + bool enable_invert = mux_cells_a.count(sig_data) != 0; + Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data); + check_q.push_back(sigmap(mux->getPort(enable_invert ? "\\B" : "\\A"))); + sig_data = sigmap(mux->getPort("\\Y")); + en.append(enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S")); + } while (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data)); - sig_data = sigmap(mux->getPort("\\Y")); for (auto bit : sig_data) if (sigbit_users_count[bit] > 1) goto skip_ff_after_read_merging; - if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && sig_data == check_q) + if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && + std::all_of(check_q.begin(), check_q.end(), [&](const SigSpec &cq) {return cq == sig_data; })) { disconnect_dff(sig_data); cell->setPort("\\CLK", clk_data); - cell->setPort("\\EN", enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S")); + cell->setPort("\\EN", en.size() > 1 ? module->ReduceAnd(NEW_ID, en) : en); cell->setPort("\\DATA", sig_data); cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); diff --git a/yosys/passes/opt/Makefile.inc b/yosys/passes/opt/Makefile.inc index 337fee9e4..ea3646330 100644 --- a/yosys/passes/opt/Makefile.inc +++ b/yosys/passes/opt/Makefile.inc @@ -14,5 +14,6 @@ OBJS += passes/opt/opt_demorgan.o OBJS += passes/opt/rmports.o OBJS += passes/opt/opt_lut.o OBJS += passes/opt/pmux2shiftx.o +OBJS += passes/opt/muxpack.o endif diff --git a/yosys/passes/opt/muxpack.cc b/yosys/passes/opt/muxpack.cc new file mode 100644 index 000000000..6697d6ca1 --- /dev/null +++ b/yosys/passes/opt/muxpack.cc @@ -0,0 +1,368 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * 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. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct ExclusiveDatabase +{ + Module *module; + const SigMap &sigmap; + + dict>> sig_cmp_prev; + + ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) + { + SigSpec const_sig, nonconst_sig; + SigBit y_port; + pool reduce_or; + for (auto cell : module->cells()) { + if (cell->type == "$eq") { + nonconst_sig = sigmap(cell->getPort("\\A")); + const_sig = sigmap(cell->getPort("\\B")); + if (!const_sig.is_fully_const()) { + if (!nonconst_sig.is_fully_const()) + continue; + std::swap(nonconst_sig, const_sig); + } + y_port = sigmap(cell->getPort("\\Y")); + } + else if (cell->type == "$logic_not") { + nonconst_sig = sigmap(cell->getPort("\\A")); + const_sig = Const(RTLIL::S0, GetSize(nonconst_sig)); + y_port = sigmap(cell->getPort("\\Y")); + } + else if (cell->type == "$reduce_or") { + reduce_or.insert(cell); + continue; + } + else continue; + + log_assert(!nonconst_sig.empty()); + log_assert(!const_sig.empty()); + sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::vector{const_sig.as_const()}); + } + + for (auto cell : reduce_or) { + nonconst_sig = SigSpec(); + std::vector values; + SigSpec a_port = sigmap(cell->getPort("\\A")); + for (auto bit : a_port) { + auto it = sig_cmp_prev.find(bit); + if (it == sig_cmp_prev.end()) { + nonconst_sig = SigSpec(); + break; + } + if (nonconst_sig.empty()) + nonconst_sig = it->second.first; + else if (nonconst_sig != it->second.first) { + nonconst_sig = SigSpec(); + break; + } + for (auto value : it->second.second) + values.push_back(value); + } + if (nonconst_sig.empty()) + continue; + y_port = sigmap(cell->getPort("\\Y")); + sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::move(values)); + } + } + + bool query(const SigSpec &sig) const + { + SigSpec nonconst_sig; + pool const_values; + + for (auto bit : sig.bits()) { + auto it = sig_cmp_prev.find(bit); + if (it == sig_cmp_prev.end()) + return false; + + if (nonconst_sig.empty()) + nonconst_sig = it->second.first; + else if (nonconst_sig != it->second.first) + return false; + + for (auto value : it->second.second) + if (!const_values.insert(value).second) + return false; + } + + return true; + } +}; + + +struct MuxpackWorker +{ + Module *module; + SigMap sigmap; + + int mux_count, pmux_count; + + pool remove_cells; + + dict sig_chain_next; + dict sig_chain_prev; + pool sigbit_with_non_chain_users; + pool chain_start_cells; + pool candidate_cells; + + ExclusiveDatabase excl_db; + + void make_sig_chain_next_prev() + { + for (auto wire : module->wires()) + { + if (wire->port_output || wire->get_bool_attribute("\\keep")) { + for (auto bit : sigmap(wire)) + sigbit_with_non_chain_users.insert(bit); + } + } + + for (auto cell : module->cells()) + { + if (cell->type.in("$mux", "$pmux") && !cell->get_bool_attribute("\\keep")) + { + SigSpec a_sig = sigmap(cell->getPort("\\A")); + SigSpec b_sig; + if (cell->type == "$mux") + b_sig = sigmap(cell->getPort("\\B")); + SigSpec y_sig = sigmap(cell->getPort("\\Y")); + + if (sig_chain_next.count(a_sig)) + for (auto a_bit : a_sig.bits()) + sigbit_with_non_chain_users.insert(a_bit); + else { + sig_chain_next[a_sig] = cell; + candidate_cells.insert(cell); + } + + if (!b_sig.empty()) { + if (sig_chain_next.count(b_sig)) + for (auto b_bit : b_sig.bits()) + sigbit_with_non_chain_users.insert(b_bit); + else { + sig_chain_next[b_sig] = cell; + candidate_cells.insert(cell); + } + } + + sig_chain_prev[y_sig] = cell; + continue; + } + + for (auto conn : cell->connections()) + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + sigbit_with_non_chain_users.insert(bit); + } + } + + void find_chain_start_cells() + { + for (auto cell : candidate_cells) + { + log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type)); + + SigSpec a_sig = sigmap(cell->getPort("\\A")); + if (cell->type == "$mux") { + SigSpec b_sig = sigmap(cell->getPort("\\B")); + if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1) + goto start_cell; + + if (!sig_chain_prev.count(a_sig)) + a_sig = b_sig; + } + else if (cell->type == "$pmux") { + if (!sig_chain_prev.count(a_sig)) + goto start_cell; + } + else log_abort(); + + for (auto bit : a_sig.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + + { + Cell *prev_cell = sig_chain_prev.at(a_sig); + log_assert(prev_cell); + SigSpec s_sig = sigmap(cell->getPort("\\S")); + s_sig.append(sigmap(prev_cell->getPort("\\S"))); + if (!excl_db.query(s_sig)) + goto start_cell; + } + + continue; + + start_cell: + chain_start_cells.insert(cell); + } + } + + vector create_chain(Cell *start_cell) + { + vector chain; + + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); + + SigSpec y_sig = sigmap(c->getPort("\\Y")); + + if (sig_chain_next.count(y_sig) == 0) + break; + + c = sig_chain_next.at(y_sig); + if (chain_start_cells.count(c) != 0) + break; + } + + return chain; + } + + void process_chain(vector &chain) + { + if (GetSize(chain) < 2) + return; + + int cursor = 0; + while (cursor < GetSize(chain)) + { + int cases = GetSize(chain) - cursor; + + Cell *first_cell = chain[cursor]; + dict taps_dict; + + if (cases < 2) { + cursor++; + continue; + } + + Cell *last_cell = chain[cursor+cases-1]; + + log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n", + log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases); + + mux_count += cases; + pmux_count += 1; + + first_cell->type = "$pmux"; + SigSpec b_sig = first_cell->getPort("\\B"); + SigSpec s_sig = first_cell->getPort("\\S"); + + for (int i = 1; i < cases; i++) { + Cell* prev_cell = chain[cursor+i-1]; + Cell* cursor_cell = chain[cursor+i]; + if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) { + b_sig.append(cursor_cell->getPort("\\B")); + s_sig.append(cursor_cell->getPort("\\S")); + } + else { + log_assert(cursor_cell->type == "$mux"); + b_sig.append(cursor_cell->getPort("\\A")); + s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S"))); + } + remove_cells.insert(cursor_cell); + } + + first_cell->setPort("\\B", b_sig); + first_cell->setPort("\\S", s_sig); + first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); + first_cell->setPort("\\Y", last_cell->getPort("\\Y")); + + cursor += cases; + } + } + + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + remove_cells.clear(); + sig_chain_next.clear(); + sig_chain_prev.clear(); + chain_start_cells.clear(); + candidate_cells.clear(); + } + + MuxpackWorker(Module *module) : + module(module), sigmap(module), mux_count(0), pmux_count(0), excl_db(module, sigmap) + { + make_sig_chain_next_prev(); + find_chain_start_cells(); + + for (auto c : chain_start_cells) { + vector chain = create_chain(c); + process_chain(chain); + } + + cleanup(); + } +}; + +struct MuxpackPass : public Pass { + MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" muxpack [selection]\n"); + log("\n"); + log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n"); + log("constructs) and $mux cells (e.g. those created by if-else constructs) into\n"); + log("$pmux cells.\n"); + log("\n"); + log("This optimisation is conservative --- it will only pack $mux or $pmux cells\n"); + log("whose select lines are driven by '$eq' cells with other such cells if it can be\n"); + log("certain that their select inputs are mutually exclusive.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + int mux_count = 0; + int pmux_count = 0; + + for (auto module : design->selected_modules()) { + MuxpackWorker worker(module); + mux_count += worker.mux_count; + pmux_count += worker.pmux_count; + } + + log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count); + } +} MuxpackPass; + +PRIVATE_NAMESPACE_END diff --git a/yosys/passes/opt/opt_clean.cc b/yosys/passes/opt/opt_clean.cc index bf8020169..a8a8e0bc7 100644 --- a/yosys/passes/opt/opt_clean.cc +++ b/yosys/passes/opt/opt_clean.cc @@ -106,7 +106,7 @@ void rmunused_module_cells(Module *module, bool verbose) if (raw_bit.wire == nullptr) continue; auto bit = sigmap(raw_bit); - if (bit.wire == nullptr) + if (bit.wire == nullptr && ct_all.cell_known(cell->type)) driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict " "for %s between cell %s.%s and constant %s in %s: Resolved using constant.", log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module))); @@ -319,14 +319,15 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos wire->attributes.erase("\\init"); if (GetSize(wire) == 0) { - // delete zero-width wires - goto delete_this_wire; + // delete zero-width wires, unless they are module ports + if (wire->port_id == 0) + goto delete_this_wire; } else if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) { // do not delete anything with "keep" or module ports or initialized wires } else - if (!purge_mode && check_public_name(wire->name)) { - // do not get rid of public names unless in purge mode + if (!purge_mode && check_public_name(wire->name) && (raw_used_signals.check_any(s1) || used_signals.check_any(s2) || s1 != s2)) { + // do not get rid of public names unless in purge mode or if the wire is entirely unused, not even aliased } else if (!raw_used_signals.check_any(s1)) { // delete wires that aren't used by anything directly @@ -479,7 +480,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool std::vector delcells; for (auto cell : module->cells()) - if (cell->type.in("$pos", "$_BUF_")) { + if (cell->type.in("$pos", "$_BUF_") && !cell->has_keep_attr()) { bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool(); RTLIL::SigSpec a = cell->getPort("\\A"); RTLIL::SigSpec y = cell->getPort("\\Y"); diff --git a/yosys/passes/opt/opt_lut.cc b/yosys/passes/opt/opt_lut.cc index 26855fd70..dda10ec17 100644 --- a/yosys/passes/opt/opt_lut.cc +++ b/yosys/passes/opt/opt_lut.cc @@ -81,7 +81,7 @@ struct OptLutWorker } } - log("Number of LUTs: %8zu\n", luts.size()); + log("Number of LUTs: %8d\n", GetSize(luts)); for (int arity = 1; arity <= max_arity; arity++) { if (arity_counts[arity]) @@ -353,14 +353,14 @@ struct OptLutWorker int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size(); if (lutA_dlogic_inputs.size()) - log(" Cell A is a %d-LUT with %zu dedicated connections. ", lutA_arity, lutA_dlogic_inputs.size()); + log(" Cell A is a %d-LUT with %d dedicated connections. ", lutA_arity, GetSize(lutA_dlogic_inputs)); else log(" Cell A is a %d-LUT. ", lutA_arity); if (lutB_dlogic_inputs.size()) - log("Cell B is a %d-LUT with %zu dedicated connections.\n", lutB_arity, lutB_dlogic_inputs.size()); + log("Cell B is a %d-LUT with %d dedicated connections.\n", lutB_arity, GetSize(lutB_dlogic_inputs)); else log("Cell B is a %d-LUT.\n", lutB_arity); - log(" Cells share %zu input(s) and can be merged into one %d-LUT.\n", common_inputs.size(), lutM_arity); + log(" Cells share %d input(s) and can be merged into one %d-LUT.\n", GetSize(common_inputs), lutM_arity); const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B; int combine_mask = 0; diff --git a/yosys/passes/opt/opt_rmdff.cc b/yosys/passes/opt/opt_rmdff.cc index e8570f0eb..eeb992a3e 100644 --- a/yosys/passes/opt/opt_rmdff.cc +++ b/yosys/passes/opt/opt_rmdff.cc @@ -260,8 +260,8 @@ delete_dlatch: bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) { - RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r; - RTLIL::Const val_cp, val_rp, val_rv; + RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e; + RTLIL::Const val_cp, val_rp, val_rv, val_ep; if (dff->type == "$_FF_") { sig_d = dff->getPort("\\D"); @@ -285,6 +285,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) val_rp = RTLIL::Const(dff->type[7] == 'P', 1); val_rv = RTLIL::Const(dff->type[8] == '1', 1); } + else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" && + (dff->type[7] == 'N' || dff->type[7] == 'P') && + (dff->type[8] == 'N' || dff->type[8] == 'P')) { + sig_d = dff->getPort("\\D"); + sig_q = dff->getPort("\\Q"); + sig_c = dff->getPort("\\C"); + sig_e = dff->getPort("\\E"); + val_cp = RTLIL::Const(dff->type[7] == 'P', 1); + val_ep = RTLIL::Const(dff->type[8] == 'P', 1); + } else if (dff->type == "$ff") { sig_d = dff->getPort("\\D"); sig_q = dff->getPort("\\Q"); @@ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) sig_c = dff->getPort("\\CLK"); val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1); } + else if (dff->type == "$dffe") { + sig_e = dff->getPort("\\EN"); + sig_d = dff->getPort("\\D"); + sig_q = dff->getPort("\\Q"); + sig_c = dff->getPort("\\CLK"); + val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1); + val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1); + } else if (dff->type == "$adff") { sig_d = dff->getPort("\\D"); sig_q = dff->getPort("\\Q"); @@ -337,39 +355,60 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) } } + // If clock is driven by a constant and (i) no reset signal + // (ii) Q has no initial value + // (iii) initial value is same as reset value if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) { if (val_rv.bits.size() == 0) val_rv = val_init; + // Q is permanently reset value or initial value mod->connect(sig_q, val_rv); goto delete_dff; } + // If D is fully undefined and reset signal present and (i) Q has no initial value + // (ii) initial value is same as reset value if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) { + // Q is permanently reset value mod->connect(sig_q, val_rv); goto delete_dff; } + // If D is fully undefined and no reset signal and Q has an initial value if (sig_d.is_fully_undef() && !sig_r.size() && has_init) { + // Q is permanently initial value mod->connect(sig_q, val_init); goto delete_dff; } + // If D is fully constant and (i) no reset signal + // (ii) reset value is same as constant D + // and (a) has no initial value + // (b) initial value same as constant D if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) { + // Q is permanently D mod->connect(sig_q, sig_d); goto delete_dff; } + // If D input is same as Q output and (i) no reset signal + // (ii) no initial signal + // (iii) initial value is same as reset value if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) { + // Q is permanently reset value or initial value if (sig_r.size()) mod->connect(sig_q, val_rv); - if (has_init) + else if (has_init) mod->connect(sig_q, val_init); goto delete_dff; } + // If reset signal is present, and is fully constant if (!sig_r.empty() && sig_r.is_fully_const()) { + // If reset value is permanently active or if reset is undefined if (sig_r == val_rp || sig_r.is_fully_undef()) { + // Q is permanently reset value mod->connect(sig_q, val_rv); goto delete_dff; } @@ -389,6 +428,30 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) dff->unsetPort("\\R"); } + // If enable signal is present, and is fully constant + if (!sig_e.empty() && sig_e.is_fully_const()) + { + // If enable value is permanently inactive + if (sig_e != val_ep) { + // Q is permanently initial value + mod->connect(sig_q, val_init); + goto delete_dff; + } + + log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod)); + + if (dff->type == "$dffe") { + dff->type = "$dff"; + dff->unsetPort("\\EN"); + dff->unsetParam("\\EN_POLARITY"); + return true; + } + + log_assert(dff->type.substr(0,7) == "$_DFFE_"); + dff->type = stringf("$_DFF_%c_", + dff->type[7]); + dff->unsetPort("\\E"); + } + return false; delete_dff: @@ -489,7 +552,8 @@ struct OptRmdffPass : public Pass { if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_", - "$ff", "$dff", "$adff")) + "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_", + "$ff", "$dff", "$dffe", "$adff")) dff_list.push_back(cell->name); if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_")) diff --git a/yosys/passes/opt/pmux2shiftx.cc b/yosys/passes/opt/pmux2shiftx.cc index 29870f510..65d8b8f32 100644 --- a/yosys/passes/opt/pmux2shiftx.cc +++ b/yosys/passes/opt/pmux2shiftx.cc @@ -221,6 +221,9 @@ struct Pmux2ShiftxPass : public Pass { log(" select strategy for one-hot encoded control signals\n"); log(" default: pmux\n"); log("\n"); + log(" -norange\n"); + log(" disable $sub inference for \"range decoders\"\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -230,6 +233,7 @@ struct Pmux2ShiftxPass : public Pass { bool optimize_onehot = true; bool verbose = false; bool verbose_onehot = false; + bool norange = false; log_header(design, "Executing PMUX2SHIFTX pass.\n"); @@ -270,6 +274,10 @@ struct Pmux2ShiftxPass : public Pass { verbose_onehot = true; continue; } + if (args[argidx] == "-norange") { + norange = true; + continue; + } break; } extra_args(args, argidx, design); @@ -559,7 +567,7 @@ struct Pmux2ShiftxPass : public Pass { int this_inv_delta = this_maxval - this_minval; bool this_inv = false; - if (this_delta != this_inv_delta) + if (!norange && this_delta != this_inv_delta) this_inv = this_inv_delta < this_delta; else if (this_maxval != this_inv_maxval) this_inv = this_inv_maxval < this_maxval; @@ -574,7 +582,7 @@ struct Pmux2ShiftxPass : public Pass { if (best_src_col < 0) this_is_better = true; - else if (this_delta != best_delta) + else if (!norange && this_delta != best_delta) this_is_better = this_delta < best_delta; else if (this_maxval != best_maxval) this_is_better = this_maxval < best_maxval; @@ -656,7 +664,7 @@ struct Pmux2ShiftxPass : public Pass { // check density percentages Const offset(State::S0, GetSize(sig)); - if (absolute_density < min_density && range_density >= min_density) + if (!norange && absolute_density < min_density && range_density >= min_density) { offset = Const(min_choice, GetSize(sig)); log(" offset: %s\n", log_signal(offset)); diff --git a/yosys/passes/opt/rmports.cc b/yosys/passes/opt/rmports.cc index fc1596ebf..32363dd68 100644 --- a/yosys/passes/opt/rmports.cc +++ b/yosys/passes/opt/rmports.cc @@ -171,7 +171,7 @@ struct RmportsPassPass : public Pass { wire->port_output = false; wire->port_id = 0; } - log("Removed %zu unused ports.\n", unused_ports.size()); + log("Removed %d unused ports.\n", GetSize(unused_ports)); // Re-number all of the wires that DO have ports still on them for(size_t i=0; iports.size(); i++) diff --git a/yosys/passes/pmgen/peepopt_shiftmul.pmg b/yosys/passes/pmgen/peepopt_shiftmul.pmg index fe861b728..6adab4e5f 100644 --- a/yosys/passes/pmgen/peepopt_shiftmul.pmg +++ b/yosys/passes/pmgen/peepopt_shiftmul.pmg @@ -1,4 +1,7 @@ pattern shiftmul +// +// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] +// state shamt @@ -49,12 +52,16 @@ code if (GetSize(port(shift, \Y)) > const_factor) reject; + int factor_bits = ceil_log2(const_factor); + SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A); + + if (GetSize(shamt) < factor_bits+GetSize(mul_din)) + reject; + did_something = true; log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); - int new_const_factor_log2 = ceil_log2(const_factor); - int new_const_factor = 1 << new_const_factor_log2; - + int new_const_factor = 1 << factor_bits; SigSpec padding(State::Sx, new_const_factor-const_factor); SigSpec old_a = port(shift, \A), new_a; int trunc = 0; @@ -73,7 +80,7 @@ code if (trunc > 0) new_a.remove(GetSize(new_a)-trunc, trunc); - SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)}; + SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)}; if (param(shift, \B_SIGNED).as_bool()) new_b.append(State::S0); diff --git a/yosys/passes/proc/proc_mux.cc b/yosys/passes/proc/proc_mux.cc index aac0b121c..d029282fd 100644 --- a/yosys/passes/proc/proc_mux.cc +++ b/yosys/passes/proc/proc_mux.cc @@ -144,7 +144,13 @@ struct SnippetSwCache } }; -RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SwitchRule *sw, bool ifxmode) +void apply_attrs(RTLIL::Cell *cell, const RTLIL::SwitchRule *sw, const RTLIL::CaseRule *cs) +{ + cell->attributes = sw->attributes; + cell->add_strpool_attribute("\\src", cs->get_strpool_attribute("\\src")); +} + +RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) { std::stringstream sstr; sstr << "$procmux$" << (autoidx++); @@ -173,7 +179,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s { // create compare cell RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), ifxmode ? "$eqx" : "$eq"); - eq_cell->attributes = sw->attributes; + apply_attrs(eq_cell, sw, cs); eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0); eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0); @@ -199,7 +205,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s // reduce cmp vector to one logic signal RTLIL::Cell *any_cell = mod->addCell(sstr.str() + "_ANY", "$reduce_or"); - any_cell->attributes = sw->attributes; + apply_attrs(any_cell, sw, cs); any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0); any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width); @@ -212,7 +218,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return RTLIL::SigSpec(ctrl_wire); } -RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) +RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) { log_assert(when_signal.size() == else_signal.size()); @@ -224,7 +230,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return when_signal; // compare results - RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); + RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode); if (ctrl_sig.size() == 0) return when_signal; log_assert(ctrl_sig.size() == 1); @@ -234,7 +240,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s // create the multiplexer itself RTLIL::Cell *mux_cell = mod->addCell(sstr.str(), "$mux"); - mux_cell->attributes = sw->attributes; + apply_attrs(mux_cell, sw, cs); mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.size()); mux_cell->setPort("\\A", else_signal); @@ -246,7 +252,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s return RTLIL::SigSpec(result_wire); } -void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode) +void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) { log_assert(last_mux_cell != NULL); log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size()); @@ -254,7 +260,7 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve if (when_signal == last_mux_cell->getPort("\\A")) return; - RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode); + RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode); log_assert(ctrl_sig.size() == 1); last_mux_cell->type = "$pmux"; @@ -395,9 +401,9 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d RTLIL::CaseRule *cs2 = sw->cases[case_idx]; RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val, ifxmode); if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1]) - append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); + append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, cs2, ifxmode); else - result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); + result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, cs2, ifxmode); } } diff --git a/yosys/passes/sat/assertpmux.cc b/yosys/passes/sat/assertpmux.cc index 509cb0ba9..3b432c461 100644 --- a/yosys/passes/sat/assertpmux.cc +++ b/yosys/passes/sat/assertpmux.cc @@ -180,7 +180,7 @@ struct AssertpmuxWorker }; struct AssertpmuxPass : public Pass { - AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { } + AssertpmuxPass() : Pass("assertpmux", "adds asserts for parallel muxes") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -195,8 +195,8 @@ struct AssertpmuxPass : public Pass { log("\n"); log(" -always\n"); log(" usually the $pmux condition is only checked when the $pmux output\n"); - log(" is used be the mux tree it drives. this option will deactivate this\n"); - log(" additional constrained and check the $pmux condition always.\n"); + log(" is used by the mux tree it drives. this option will deactivate this\n"); + log(" additional constraint and check the $pmux condition always.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE diff --git a/yosys/passes/sat/cutpoint.cc b/yosys/passes/sat/cutpoint.cc index 048aec7f3..b4549bc39 100644 --- a/yosys/passes/sat/cutpoint.cc +++ b/yosys/passes/sat/cutpoint.cc @@ -24,7 +24,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct CutpointPass : public Pass { - CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { } + CutpointPass() : Pass("cutpoint", "adds formal cut points to the design") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/yosys/passes/sat/fmcombine.cc b/yosys/passes/sat/fmcombine.cc index f64d99dc2..00c098542 100644 --- a/yosys/passes/sat/fmcombine.cc +++ b/yosys/passes/sat/fmcombine.cc @@ -332,7 +332,7 @@ struct FmcombinePass : public Pass { gate_cell = module->cell(gate_name); if (gate_cell == nullptr) - log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module)); + log_cmd_error("Gate cell %s not found in module %s.\n", log_id(gate_name), log_id(module)); } else { @@ -351,7 +351,7 @@ struct FmcombinePass : public Pass { if (!gold_cell->parameters.empty()) log_cmd_error("Gold cell has unresolved instance parameters.\n"); if (!gate_cell->parameters.empty()) - log_cmd_error("Gold cell has unresolved instance parameters.\n"); + log_cmd_error("Gate cell has unresolved instance parameters.\n"); FmcombineWorker worker(design, gold_cell->type, opts); worker.generate(); diff --git a/yosys/passes/sat/sat.cc b/yosys/passes/sat/sat.cc index cbba738f0..e4654d835 100644 --- a/yosys/passes/sat/sat.cc +++ b/yosys/passes/sat/sat.cc @@ -659,6 +659,7 @@ struct SatHelper void dump_model_to_vcd(std::string vcd_file_name) { + rewrite_filename(vcd_file_name); FILE *f = fopen(vcd_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", vcd_file_name.c_str(), strerror(errno)); @@ -761,6 +762,7 @@ struct SatHelper void dump_model_to_json(std::string json_file_name) { + rewrite_filename(json_file_name); FILE *f = fopen(json_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", json_file_name.c_str(), strerror(errno)); @@ -1505,6 +1507,7 @@ struct SatPass : public Pass { { if (!cnf_file_name.empty()) { + rewrite_filename(cnf_file_name); FILE *f = fopen(cnf_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno)); @@ -1608,6 +1611,7 @@ struct SatPass : public Pass { if (!cnf_file_name.empty()) { + rewrite_filename(cnf_file_name); FILE *f = fopen(cnf_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno)); diff --git a/yosys/passes/sat/sim.cc b/yosys/passes/sat/sim.cc index 53e248adf..4c3022c70 100644 --- a/yosys/passes/sat/sim.cc +++ b/yosys/passes/sat/sim.cc @@ -88,6 +88,8 @@ struct SimInstance SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) : shared(shared), module(module), instance(instance), parent(parent), sigmap(module) { + log_assert(module); + if (parent) { log_assert(parent->children.count(instance) == 0); parent->children[instance] = this; @@ -848,6 +850,9 @@ struct SimPass : public Pass { if (design->full_selection()) { top_mod = design->top_module(); + + if (!top_mod) + log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n"); } else { auto mods = design->selected_whole_modules(); if (GetSize(mods) != 1) diff --git a/yosys/passes/techmap/abc.cc b/yosys/passes/techmap/abc.cc index 5b19d84fb..bf05c68e7 100644 --- a/yosys/passes/techmap/abc.cc +++ b/yosys/passes/techmap/abc.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff --git a/yosys/passes/techmap/flowmap.cc b/yosys/passes/techmap/flowmap.cc index f5892a60e..96d0df5f8 100644 --- a/yosys/passes/techmap/flowmap.cc +++ b/yosys/passes/techmap/flowmap.cc @@ -783,7 +783,7 @@ struct FlowmapWorker int depth = 0; for (auto label : labels) depth = max(depth, label.second); - log("Mapped to %zu LUTs with maximum depth %d.\n", lut_nodes.size(), depth); + log("Mapped to %d LUTs with maximum depth %d.\n", GetSize(lut_nodes), depth); if (debug) { @@ -1195,7 +1195,7 @@ struct FlowmapWorker bool relax_depth_for_bound(bool first, int depth_bound, dict> &lut_critical_outputs) { - size_t initial_count = lut_nodes.size(); + int initial_count = GetSize(lut_nodes); for (auto node : lut_nodes) { @@ -1215,7 +1215,7 @@ struct FlowmapWorker if (potentials.empty()) { - log(" Relaxed to %zu (+%zu) LUTs.\n", lut_nodes.size(), lut_nodes.size() - initial_count); + log(" Relaxed to %d (+%d) LUTs.\n", GetSize(lut_nodes), GetSize(lut_nodes) - initial_count); if (!first && break_num == 1) { log(" Design fully relaxed.\n"); @@ -1419,9 +1419,9 @@ struct FlowmapWorker lut_area += lut_table.size(); if ((int)input_nodes.size() >= minlut) - log(" Packed into a %zu-LUT %s.%s.\n", input_nodes.size(), log_id(module), log_id(lut)); + log(" Packed into a %d-LUT %s.%s.\n", GetSize(input_nodes), log_id(module), log_id(lut)); else - log(" Packed into a %zu-LUT %s.%s (implemented as %d-LUT).\n", input_nodes.size(), log_id(module), log_id(lut), minlut); + log(" Packed into a %d-LUT %s.%s (implemented as %d-LUT).\n", GetSize(input_nodes), log_id(module), log_id(lut), minlut); } for (auto node : mapped_nodes) diff --git a/yosys/passes/techmap/muxcover.cc b/yosys/passes/techmap/muxcover.cc index 12da9ed0c..c84cfc39a 100644 --- a/yosys/passes/techmap/muxcover.cc +++ b/yosys/passes/techmap/muxcover.cc @@ -23,6 +23,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +#define COST_DMUX 90 #define COST_MUX2 100 #define COST_MUX4 220 #define COST_MUX8 460 @@ -57,6 +58,13 @@ struct MuxcoverWorker bool use_mux8; bool use_mux16; bool nodecode; + bool nopartial; + + int cost_dmux; + int cost_mux2; + int cost_mux4; + int cost_mux8; + int cost_mux16; MuxcoverWorker(Module *module) : module(module), sigmap(module) { @@ -64,9 +72,32 @@ struct MuxcoverWorker use_mux8 = false; use_mux16 = false; nodecode = false; + nopartial = false; + cost_dmux = COST_DMUX; + cost_mux2 = COST_MUX2; + cost_mux4 = COST_MUX4; + cost_mux8 = COST_MUX8; + cost_mux16 = COST_MUX16; decode_mux_counter = 0; } + bool xcmp(std::initializer_list list) + { + auto cursor = list.begin(), end = list.end(); + log_assert(cursor != end); + SigBit tmp = *(cursor++); + while (cursor != end) { + SigBit bit = *(cursor++); + if (bit == State::Sx) + continue; + if (tmp == State::Sx) + tmp = bit; + if (bit != tmp) + return false; + } + return true; + } + void treeify() { pool roots; @@ -124,13 +155,22 @@ struct MuxcoverWorker log(" Finished treeification: Found %d trees.\n", GetSize(tree_list)); } - bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path) + bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path, bool first_layer = true) { if (*path) { - if (tree.muxes.count(bit) == 0) - return false; + if (tree.muxes.count(bit) == 0) { + if (first_layer || nopartial) + return false; + while (path[0] && path[1]) + path++; + if (path[0] == 'S') + ret_bit = State::Sx; + else + ret_bit = bit; + return true; + } char port_name[3] = {'\\', *path, 0}; - return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1); + return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1, false); } else { ret_bit = bit; return true; @@ -139,7 +179,7 @@ struct MuxcoverWorker int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit) { - if (A == B) + if (A == B || sel == State::Sx) return 0; tuple key(A, B, sel); @@ -157,7 +197,10 @@ struct MuxcoverWorker if (std::get<2>(entry)) return 0; - return COST_MUX2 / GetSize(std::get<1>(entry)); + if (A == State::Sx || B == State::Sx) + return 0; + + return cost_dmux / GetSize(std::get<1>(entry)); } void implement_decode_mux(SigBit ctrl_bit) @@ -174,9 +217,32 @@ struct MuxcoverWorker implement_decode_mux(std::get<0>(key)); implement_decode_mux(std::get<1>(key)); - module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit); + if (std::get<0>(key) == State::Sx) { + module->addBufGate(NEW_ID, std::get<1>(key), ctrl_bit); + } else if (std::get<1>(key) == State::Sx) { + module->addBufGate(NEW_ID, std::get<0>(key), ctrl_bit); + } else { + module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit); + decode_mux_counter++; + } std::get<2>(entry) = true; - decode_mux_counter++; + } + + void find_best_covers(tree_t &tree, const vector &bits) + { + for (auto bit : bits) + find_best_cover(tree, bit); + } + + int sum_best_covers(tree_t &tree, const vector &bits) + { + int sum = 0; + for (auto bit : pool(bits.begin(), bits.end())) { + int cost = tree.newmuxes.at(bit).cost; + log_debug(" Best cost for %s: %d\n", log_signal(bit), cost); + sum += cost; + } + return sum; } int find_best_cover(tree_t &tree, SigBit bit) @@ -209,9 +275,13 @@ struct MuxcoverWorker mux.inputs.push_back(B); mux.selects.push_back(S1); - mux.cost += COST_MUX2; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux2 at %s: %d\n", log_signal(bit), mux.cost); + + mux.cost += cost_mux2; + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux2 at %s: %d\n", log_signal(bit), mux.cost); best_mux = mux; } @@ -229,7 +299,7 @@ struct MuxcoverWorker ok = ok && follow_muxtree(S2, tree, bit, "BS"); if (nodecode) - ok = ok && S1 == S2; + ok = ok && xcmp({S1, S2}); ok = ok && follow_muxtree(T1, tree, bit, "S"); @@ -247,13 +317,15 @@ struct MuxcoverWorker mux.selects.push_back(S1); mux.selects.push_back(T1); - mux.cost += COST_MUX4; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux4 at %s: %d\n", log_signal(bit), mux.cost); - if (best_mux.cost > mux.cost) + mux.cost += cost_mux4; + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux4 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -277,13 +349,13 @@ struct MuxcoverWorker ok = ok && follow_muxtree(S4, tree, bit, "BBS"); if (nodecode) - ok = ok && S1 == S2 && S2 == S3 && S3 == S4; + ok = ok && xcmp({S1, S2, S3, S4}); ok = ok && follow_muxtree(T1, tree, bit, "AS"); ok = ok && follow_muxtree(T2, tree, bit, "BS"); if (nodecode) - ok = ok && T1 == T2; + ok = ok && xcmp({T1, T2}); ok = ok && follow_muxtree(U1, tree, bit, "S"); @@ -310,17 +382,15 @@ struct MuxcoverWorker mux.selects.push_back(T1); mux.selects.push_back(U1); - mux.cost += COST_MUX8; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); - mux.cost += find_best_cover(tree, E); - mux.cost += find_best_cover(tree, F); - mux.cost += find_best_cover(tree, G); - mux.cost += find_best_cover(tree, H); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux8 at %s: %d\n", log_signal(bit), mux.cost); - if (best_mux.cost > mux.cost) + mux.cost += cost_mux8; + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux8 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -356,7 +426,7 @@ struct MuxcoverWorker ok = ok && follow_muxtree(S8, tree, bit, "BBBS"); if (nodecode) - ok = ok && S1 == S2 && S2 == S3 && S3 == S4 && S4 == S5 && S5 == S6 && S6 == S7 && S7 == S8; + ok = ok && xcmp({S1, S2, S3, S4, S5, S6, S7, S8}); ok = ok && follow_muxtree(T1, tree, bit, "AAS"); ok = ok && follow_muxtree(T2, tree, bit, "ABS"); @@ -364,13 +434,13 @@ struct MuxcoverWorker ok = ok && follow_muxtree(T4, tree, bit, "BBS"); if (nodecode) - ok = ok && T1 == T2 && T2 == T3 && T3 == T4; + ok = ok && xcmp({T1, T2, T3, T4}); ok = ok && follow_muxtree(U1, tree, bit, "AS"); ok = ok && follow_muxtree(U2, tree, bit, "BS"); if (nodecode) - ok = ok && U1 == U2; + ok = ok && xcmp({U1, U2}); ok = ok && follow_muxtree(V1, tree, bit, "S"); @@ -414,25 +484,15 @@ struct MuxcoverWorker mux.selects.push_back(U1); mux.selects.push_back(V1); - mux.cost += COST_MUX16; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); - mux.cost += find_best_cover(tree, E); - mux.cost += find_best_cover(tree, F); - mux.cost += find_best_cover(tree, G); - mux.cost += find_best_cover(tree, H); - mux.cost += find_best_cover(tree, I); - mux.cost += find_best_cover(tree, J); - mux.cost += find_best_cover(tree, K); - mux.cost += find_best_cover(tree, L); - mux.cost += find_best_cover(tree, M); - mux.cost += find_best_cover(tree, N); - mux.cost += find_best_cover(tree, O); - mux.cost += find_best_cover(tree, P); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux16 at %s: %d\n", log_signal(bit), mux.cost); - if (best_mux.cost > mux.cost) + mux.cost += cost_mux16; + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux16 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -528,6 +588,7 @@ struct MuxcoverWorker void treecover(tree_t &tree) { int count_muxes_by_type[4] = {0, 0, 0, 0}; + log_debug(" Searching for best cover for tree at %s.\n", log_signal(tree.root)); find_best_cover(tree, tree.root); implement_best_cover(tree, tree.root, count_muxes_by_type); log(" Replaced tree at %s: %d MUX2, %d MUX4, %d MUX8, %d MUX16\n", log_signal(tree.root), @@ -544,12 +605,13 @@ struct MuxcoverWorker log(" Covering trees:\n"); - // pre-fill cache of decoder muxes - if (!nodecode) + if (!nodecode) { + log_debug(" Populating cache of decoder muxes.\n"); for (auto &tree : tree_list) { find_best_cover(tree, tree.root); tree.newmuxes.clear(); } + } for (auto &tree : tree_list) treecover(tree); @@ -569,15 +631,25 @@ struct MuxcoverPass : public Pass { log("\n"); log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n"); log("\n"); - log(" -mux4, -mux8, -mux16\n"); - log(" Use the specified types of MUXes. If none of those options are used,\n"); - log(" the effect is the same as if all of them where used.\n"); + log(" -mux4[=cost], -mux8[=cost], -mux16[=cost]\n"); + log(" Use the specified types of MUXes (with optional integer costs). If none\n"); + log(" of these options are given, the effect is the same as if all of them are.\n"); + log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4); + log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16); + log("\n"); + log(" -dmux=cost\n"); + log(" Use the specified cost for $_MUX_ cells used in decoders.\n"); + log(" Default cost: %d\n", COST_DMUX); log("\n"); log(" -nodecode\n"); log(" Do not insert decoder logic. This reduces the number of possible\n"); log(" substitutions, but guarantees that the resulting circuit is not\n"); log(" less efficient than the original circuit.\n"); log("\n"); + log(" -nopartial\n"); + log(" Do not consider mappings that use $_MUX_ to select from less\n"); + log(" than different signals.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -587,26 +659,52 @@ struct MuxcoverPass : public Pass { bool use_mux8 = false; bool use_mux16 = false; bool nodecode = false; + bool nopartial = false; + int cost_dmux = COST_DMUX; + int cost_mux4 = COST_MUX4; + int cost_mux8 = COST_MUX8; + int cost_mux16 = COST_MUX16; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-mux4") { + const auto &arg = args[argidx]; + if (arg.size() >= 5 && arg.substr(0,5) == "-mux4") { use_mux4 = true; + if (arg.size() > 5) { + if (arg[5] != '=') break; + cost_mux4 = atoi(arg.substr(6).c_str()); + } continue; } - if (args[argidx] == "-mux8") { + if (arg.size() >= 5 && arg.substr(0,5) == "-mux8") { use_mux8 = true; + if (arg.size() > 5) { + if (arg[5] != '=') break; + cost_mux8 = atoi(arg.substr(6).c_str()); + } continue; } - if (args[argidx] == "-mux16") { + if (arg.size() >= 6 && arg.substr(0,6) == "-mux16") { use_mux16 = true; + if (arg.size() > 6) { + if (arg[6] != '=') break; + cost_mux16 = atoi(arg.substr(7).c_str()); + } continue; } - if (args[argidx] == "-nodecode") { + if (arg.size() >= 6 && arg.substr(0,6) == "-dmux=") { + cost_dmux = atoi(arg.substr(6).c_str()); + continue; + } + if (arg == "-nodecode") { nodecode = true; continue; } + if (arg == "-nopartial") { + nopartial = true; + continue; + } break; } extra_args(args, argidx, design); @@ -623,7 +721,12 @@ struct MuxcoverPass : public Pass { worker.use_mux4 = use_mux4; worker.use_mux8 = use_mux8; worker.use_mux16 = use_mux16; + worker.cost_dmux = cost_dmux; + worker.cost_mux4 = cost_mux4; + worker.cost_mux8 = cost_mux8; + worker.cost_mux16 = cost_mux16; worker.nodecode = nodecode; + worker.nopartial = nopartial; worker.run(); } } diff --git a/yosys/passes/techmap/shregmap.cc b/yosys/passes/techmap/shregmap.cc index 75eedfbcc..004ab1eb9 100644 --- a/yosys/passes/techmap/shregmap.cc +++ b/yosys/passes/techmap/shregmap.cc @@ -293,10 +293,22 @@ struct ShregmapWorker if (opts.init || sigbit_init.count(q_bit) == 0) { - if (sigbit_chain_next.count(d_bit)) { + auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); + if (!r.second) { + // Insertion not successful means that d_bit is already + // connected to another register, thus mark it as a + // non chain user ... sigbit_with_non_chain_users.insert(d_bit); - } else - sigbit_chain_next[d_bit] = cell; + // ... and clone d_bit into another wire, and use that + // wire as a different key in the d_bit-to-cell dictionary + // so that it can be identified as another chain + // (omitting this common flop) + // Link: https://github.com/YosysHQ/yosys/pull/1085 + Wire *wire = module->addWire(NEW_ID); + module->connect(wire, d_bit); + sigmap.add(wire, d_bit); + sigbit_chain_next.insert(std::make_pair(wire, cell)); + } sigbit_chain_prev[q_bit] = cell; continue; @@ -605,6 +617,11 @@ struct ShregmapPass : public Pass { log("\n"); log(" -tech greenpak4\n"); log(" map to greenpak4 shift registers.\n"); + log(" this option also implies -clkpol pos -zinit\n"); + log("\n"); + log(" -tech xilinx\n"); + log(" map to xilinx dynamic-length shift registers.\n"); + log(" this option also implies -params -init\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE diff --git a/yosys/techlibs/anlogic/anlogic_determine_init.cc b/yosys/techlibs/anlogic/anlogic_determine_init.cc index 34b1d4f8a..c4089dac2 100644 --- a/yosys/techlibs/anlogic/anlogic_determine_init.cc +++ b/yosys/techlibs/anlogic/anlogic_determine_init.cc @@ -50,7 +50,7 @@ struct AnlogicDetermineInitPass : public Pass { extra_args(args, args.size(), design); - size_t cnt = 0; + int cnt = 0; for (auto module : design->selected_modules()) { for (auto cell : module->selected_cells()) @@ -65,7 +65,7 @@ struct AnlogicDetermineInitPass : public Pass { } } } - log_header(design, "Updated %lu cells with determined init value.\n", cnt); + log_header(design, "Updated %d cells with determined init value.\n", cnt); } } AnlogicDetermineInitPass; diff --git a/yosys/techlibs/anlogic/anlogic_eqn.cc b/yosys/techlibs/anlogic/anlogic_eqn.cc index 741bf04cc..070d39a20 100644 --- a/yosys/techlibs/anlogic/anlogic_eqn.cc +++ b/yosys/techlibs/anlogic/anlogic_eqn.cc @@ -69,7 +69,7 @@ struct AnlogicEqnPass : public Pass { extra_args(args, args.size(), design); - size_t cnt = 0; + int cnt = 0; for (auto module : design->selected_modules()) { for (auto cell : module->selected_cells()) @@ -106,7 +106,7 @@ struct AnlogicEqnPass : public Pass { } } } - log_header(design, "Updated %lu of AL_MAP_LUT* elements with equation.\n", cnt); + log_header(design, "Updated %d of AL_MAP_LUT* elements with equation.\n", cnt); } } AnlogicEqnPass; diff --git a/yosys/techlibs/ecp5/arith_map.v b/yosys/techlibs/ecp5/arith_map.v index eb7947601..17bde0497 100644 --- a/yosys/techlibs/ecp5/arith_map.v +++ b/yosys/techlibs/ecp5/arith_map.v @@ -50,20 +50,21 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); wire [Y_WIDTH2-1:0] AA = A_buf; wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf; + wire [Y_WIDTH2-1:0] BX = B_buf; wire [Y_WIDTH2-1:0] C = {CO, CI}; wire [Y_WIDTH2-1:0] FCO, Y1; genvar i; generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice CCU2C #( - .INIT0(16'b0110011010101010), - .INIT1(16'b0110011010101010), + .INIT0(16'b1001011010101010), + .INIT1(16'b1001011010101010), .INJECT1_0("NO"), .INJECT1_1("NO") ) ccu2c_i ( .CIN(C[i]), - .A0(AA[i]), .B0(BB[i]), .C0(1'b0), .D0(1'b1), - .A1(AA[i+1]), .B1(BB[i+1]), .C1(1'b0), .D1(1'b1), + .A0(AA[i]), .B0(BX[i]), .C0(BI), .D0(1'b1), + .A1(AA[i+1]), .B1(BX[i+1]), .C1(BI), .D1(1'b1), .S0(Y[i]), .S1(Y1[i]), .COUT(FCO[i]) ); diff --git a/yosys/techlibs/ecp5/cells_map.v b/yosys/techlibs/ecp5/cells_map.v index 6ab4b69f2..a90d5e034 100644 --- a/yosys/techlibs/ecp5/cells_map.v +++ b/yosys/techlibs/ecp5/cells_map.v @@ -47,8 +47,59 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED" module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule -// For Diamond compatibility, FIXME: add all Diamond flipflop mappings +// TODO: Diamond flip-flops +// module FD1P3AX(); endmodule +// module FD1P3AY(); endmodule +// module FD1P3BX(); endmodule +// module FD1P3DX(); endmodule +// module FD1P3IX(); endmodule +// module FD1P3JX(); endmodule +// module FD1S3AX(); endmodule +// module FD1S3AY(); endmodule module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +// module FL1P3AY(); endmodule +// module FL1P3AZ(); endmodule +// module FL1P3BX(); endmodule +// module FL1P3DX(); endmodule +// module FL1P3IY(); endmodule +// module FL1P3JY(); endmodule +// module FL1S3AX(); endmodule +// module FL1S3AY(); endmodule + +// Diamond I/O buffers +module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule +module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule +module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule +module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule + +// Diamond I/O registers +module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +// TODO: Diamond I/O latches +// module IFS1S1B(input PD, D, SCLK, output Q); endmodule +// module IFS1S1D(input CD, D, SCLK, output Q); endmodule +// module IFS1S1I(input PD, D, SCLK, output Q); endmodule +// module IFS1S1J(input CD, D, SCLK, output Q); endmodule `ifndef NO_LUT module \$lut (A, Y); diff --git a/yosys/techlibs/ecp5/cells_sim.v b/yosys/techlibs/ecp5/cells_sim.v index 1e4002ee0..07fadfa10 100644 --- a/yosys/techlibs/ecp5/cells_sim.v +++ b/yosys/techlibs/ecp5/cells_sim.v @@ -250,18 +250,6 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); endgenerate endmodule -// --------------------------------------- - -module OBZ(input I, T, output O); -assign O = T ? 1'bz : I; -endmodule - -// --------------------------------------- - -module IB(input I, output O); -assign O = I; -endmodule - // --------------------------------------- (* keep *) module TRELLIS_IO( @@ -293,19 +281,6 @@ endmodule // --------------------------------------- -module OB(input I, output O); -assign O = I; -endmodule - -// --------------------------------------- - -module BB(input I, T, output O, inout B); -assign B = T ? 1'bz : I; -assign O = B; -endmodule - -// --------------------------------------- - module INV(input A, output Z); assign Z = !A; endmodule @@ -558,19 +533,56 @@ module DP16KD( parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; endmodule -// For Diamond compatibility, FIXME: add all Diamond flipflop mappings -module FD1S3BX(input PD, D, CK, output Q); - TRELLIS_FF #( - .GSR("DISABLED"), - .CEMUX("1"), - .CLKMUX("CLK"), - .LSRMUX("LSR"), - .REGSET("SET"), - .SRMODE("ASYNC") - ) tff_i ( - .CLK(CK), - .LSR(PD), - .DI(D), - .Q(Q) - ); -endmodule +// TODO: Diamond flip-flops +// module FD1P3AX(); endmodule +// module FD1P3AY(); endmodule +// module FD1P3BX(); endmodule +// module FD1P3DX(); endmodule +// module FD1P3IX(); endmodule +// module FD1P3JX(); endmodule +// module FD1S3AX(); endmodule +// module FD1S3AY(); endmodule +module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +// module FL1P3AY(); endmodule +// module FL1P3AZ(); endmodule +// module FL1P3BX(); endmodule +// module FL1P3DX(); endmodule +// module FL1P3IY(); endmodule +// module FL1P3JY(); endmodule +// module FL1S3AX(); endmodule +// module FL1S3AY(); endmodule + +// Diamond I/O buffers +module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule +module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule +module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule +module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule +module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule +module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule +module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule +module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule +module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule +module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule +module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule + +// Diamond I/O registers +module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +// TODO: Diamond I/O latches +// module IFS1S1B(input PD, D, SCLK, output Q); endmodule +// module IFS1S1D(input CD, D, SCLK, output Q); endmodule +// module IFS1S1I(input PD, D, SCLK, output Q); endmodule +// module IFS1S1J(input CD, D, SCLK, output Q); endmodule diff --git a/yosys/techlibs/ecp5/synth_ecp5.cc b/yosys/techlibs/ecp5/synth_ecp5.cc index c6e12248e..01222e55c 100644 --- a/yosys/techlibs/ecp5/synth_ecp5.cc +++ b/yosys/techlibs/ecp5/synth_ecp5.cc @@ -76,7 +76,7 @@ struct SynthEcp5Pass : public ScriptPass log(" -nodram\n"); log(" do not use distributed RAM cells in output netlist\n"); log("\n"); - log(" -nomux\n"); + log(" -nowidelut\n"); log(" do not use PFU muxes to implement LUTs larger than LUT4s\n"); log("\n"); log(" -abc2\n"); @@ -93,7 +93,7 @@ struct SynthEcp5Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file; - bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, vpr; + bool noccu2, nodffe, nobram, nodram, nowidelut, flatten, retime, abc2, vpr; void clear_flags() YS_OVERRIDE { @@ -105,7 +105,7 @@ struct SynthEcp5Pass : public ScriptPass nodffe = false; nobram = false; nodram = false; - nomux = false; + nowidelut = false; flatten = true; retime = false; abc2 = false; @@ -172,8 +172,8 @@ struct SynthEcp5Pass : public ScriptPass nodram = true; continue; } - if (args[argidx] == "-nomux") { - nomux = true; + if (args[argidx] == "-nowidelut" || args[argidx] == "-nomux") { + nowidelut = true; continue; } if (args[argidx] == "-abc2") { @@ -264,7 +264,7 @@ struct SynthEcp5Pass : public ScriptPass run("abc", " (only if -abc2)"); } run("techmap -map +/ecp5/latches_map.v"); - if (nomux) + if (nowidelut) run("abc -lut 4 -dress"); else run("abc -lut 4:7 -dress"); diff --git a/yosys/techlibs/gowin/determine_init.cc b/yosys/techlibs/gowin/determine_init.cc index 991e5245a..d9a0880f6 100644 --- a/yosys/techlibs/gowin/determine_init.cc +++ b/yosys/techlibs/gowin/determine_init.cc @@ -50,7 +50,7 @@ struct DetermineInitPass : public Pass { extra_args(args, args.size(), design); - size_t cnt = 0; + int cnt = 0; for (auto module : design->selected_modules()) { for (auto cell : module->selected_cells()) @@ -65,7 +65,7 @@ struct DetermineInitPass : public Pass { } } } - log_header(design, "Updated %lu cells with determined init value.\n", cnt); + log_header(design, "Updated %d cells with determined init value.\n", cnt); } } DetermineInitPass; diff --git a/yosys/techlibs/ice40/cells_sim.v b/yosys/techlibs/ice40/cells_sim.v index e89405b22..f9945b2b5 100644 --- a/yosys/techlibs/ice40/cells_sim.v +++ b/yosys/techlibs/ice40/cells_sim.v @@ -973,6 +973,30 @@ parameter RGB1_CURRENT = "0b000000"; parameter RGB2_CURRENT = "0b000000"; endmodule +(* blackbox *) +module SB_LED_DRV_CUR( + input EN, + output LEDPU +); +endmodule + +(* blackbox *) +module SB_RGB_DRV( + input RGBLEDEN, + input RGB0PWM, + input RGB1PWM, + input RGB2PWM, + input RGBPU, + output RGB0, + output RGB1, + output RGB2 +); +parameter CURRENT_MODE = "0b0"; +parameter RGB0_CURRENT = "0b000000"; +parameter RGB1_CURRENT = "0b000000"; +parameter RGB2_CURRENT = "0b000000"; +endmodule + (* blackbox *) module SB_I2C( input SBCLKI, diff --git a/yosys/techlibs/ice40/ice40_unlut.cc b/yosys/techlibs/ice40/ice40_unlut.cc index 2428a8e78..d16e6e6a3 100644 --- a/yosys/techlibs/ice40/ice40_unlut.cc +++ b/yosys/techlibs/ice40/ice40_unlut.cc @@ -74,7 +74,7 @@ static void run_ice40_unlut(Module *module) } struct Ice40UnlutPass : public Pass { - Ice40UnlutPass() : Pass("ice40_unlut", "iCE40: perform simple optimizations") { } + Ice40UnlutPass() : Pass("ice40_unlut", "iCE40: transform SB_LUT4 cells to $lut cells") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/yosys/techlibs/xilinx/cells_sim.v b/yosys/techlibs/xilinx/cells_sim.v index 3a4540b83..f4598dcf4 100644 --- a/yosys/techlibs/xilinx/cells_sim.v +++ b/yosys/techlibs/xilinx/cells_sim.v @@ -278,6 +278,23 @@ module FDPE_1 (output reg Q, input C, CE, D, PRE); always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; endmodule +module RAM32X1D ( + output DPO, SPO, + input D, WCLK, WE, + input A0, A1, A2, A3, A4, + input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 +); + parameter INIT = 32'h0; + parameter IS_WCLK_INVERTED = 1'b0; + wire [4:0] a = {A4, A3, A2, A1, A0}; + wire [4:0] dpra = {DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}; + reg [31:0] mem = INIT; + assign SPO = mem[a]; + assign DPO = mem[dpra]; + wire clk = WCLK ^ IS_WCLK_INVERTED; + always @(posedge clk) if (WE) mem[a] <= D; +endmodule + module RAM64X1D ( output DPO, SPO, input D, WCLK, WE, diff --git a/yosys/techlibs/xilinx/cells_xtra.sh b/yosys/techlibs/xilinx/cells_xtra.sh index 8e39b440d..83863bf0b 100644 --- a/yosys/techlibs/xilinx/cells_xtra.sh +++ b/yosys/techlibs/xilinx/cells_xtra.sh @@ -116,11 +116,11 @@ function xtract_cell_decl() xtract_cell_decl PS7 "(* keep *)" xtract_cell_decl PULLDOWN xtract_cell_decl PULLUP - xtract_cell_decl RAM128X1D + #xtract_cell_decl RAM128X1D xtract_cell_decl RAM128X1S xtract_cell_decl RAM256X1S xtract_cell_decl RAM32M - xtract_cell_decl RAM32X1D + #xtract_cell_decl RAM32X1D xtract_cell_decl RAM32X1S xtract_cell_decl RAM32X1S_1 xtract_cell_decl RAM32X2S diff --git a/yosys/techlibs/xilinx/cells_xtra.v b/yosys/techlibs/xilinx/cells_xtra.v index fbcc74682..6220da703 100644 --- a/yosys/techlibs/xilinx/cells_xtra.v +++ b/yosys/techlibs/xilinx/cells_xtra.v @@ -3655,17 +3655,6 @@ module PULLUP (...); output O; endmodule -module RAM128X1D (...); - parameter [127:0] INIT = 128'h00000000000000000000000000000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - output DPO, SPO; - input [6:0] A; - input [6:0] DPRA; - input D; - input WCLK; - input WE; -endmodule - module RAM128X1S (...); parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; @@ -3705,13 +3694,6 @@ module RAM32M (...); input WE; endmodule -module RAM32X1D (...); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - output DPO, SPO; - input A0, A1, A2, A3, A4, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, WCLK, WE; -endmodule - module RAM32X1S (...); parameter [31:0] INIT = 32'h00000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; diff --git a/yosys/techlibs/xilinx/drams.txt b/yosys/techlibs/xilinx/drams.txt index 91632bcee..2613c206c 100644 --- a/yosys/techlibs/xilinx/drams.txt +++ b/yosys/techlibs/xilinx/drams.txt @@ -1,4 +1,17 @@ +bram $__XILINX_RAM32X1D + init 1 + abits 5 + dbits 1 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 2 +endbram + bram $__XILINX_RAM64X1D init 1 abits 6 @@ -25,6 +38,13 @@ bram $__XILINX_RAM128X1D clkpol 0 2 endbram +match $__XILINX_RAM32X1D + min bits 3 + min wports 1 + make_outreg + or_next_if_better +endmatch + match $__XILINX_RAM64X1D min bits 5 min wports 1 diff --git a/yosys/techlibs/xilinx/drams_map.v b/yosys/techlibs/xilinx/drams_map.v index 47476b592..77041ca86 100644 --- a/yosys/techlibs/xilinx/drams_map.v +++ b/yosys/techlibs/xilinx/drams_map.v @@ -1,4 +1,38 @@ +module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter [31:0] INIT = 32'bx; + parameter CLKPOL2 = 1; + input CLK1; + + input [4:0] A1ADDR; + output A1DATA; + + input [4:0] B1ADDR; + input B1DATA; + input B1EN; + + RAM32X1D #( + .INIT(INIT), + .IS_WCLK_INVERTED(!CLKPOL2) + ) _TECHMAP_REPLACE_ ( + .DPRA0(A1ADDR[0]), + .DPRA1(A1ADDR[1]), + .DPRA2(A1ADDR[2]), + .DPRA3(A1ADDR[3]), + .DPRA4(A1ADDR[4]), + .DPO(A1DATA), + + .A0(B1ADDR[0]), + .A1(B1ADDR[1]), + .A2(B1ADDR[2]), + .A3(B1ADDR[3]), + .A4(B1ADDR[4]), + .D(B1DATA), + .WCLK(CLK1), + .WE(B1EN) + ); +endmodule + module \$__XILINX_RAM64X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); parameter [63:0] INIT = 64'bx; parameter CLKPOL2 = 1; diff --git a/yosys/techlibs/xilinx/synth_xilinx.cc b/yosys/techlibs/xilinx/synth_xilinx.cc index c20cac09b..7dc9915e9 100644 --- a/yosys/techlibs/xilinx/synth_xilinx.cc +++ b/yosys/techlibs/xilinx/synth_xilinx.cc @@ -42,8 +42,9 @@ struct SynthXilinxPass : public ScriptPass log(" -top \n"); log(" use the specified module as top module\n"); log("\n"); - log(" -arch {xcup|xcu|xc7|xc6s}\n"); + log(" -family {xcup|xcu|xc7|xc6s}\n"); log(" run synthesis for the specified Xilinx architecture\n"); + log(" generate the synthesis netlist for the specified family.\n"); log(" default: xc7\n"); log("\n"); log(" -edif \n"); @@ -67,6 +68,12 @@ struct SynthXilinxPass : public ScriptPass log(" -nosrl\n"); log(" disable inference of shift registers\n"); log("\n"); + log(" -nocarry\n"); + log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n"); + log("\n"); + log(" -nowidelut\n"); + log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n"); + log("\n"); log(" -run :\n"); log(" only run the commands between the labels (see below). an empty\n"); log(" from label is synonymous to 'begin', and empty to label is\n"); @@ -84,8 +91,8 @@ struct SynthXilinxPass : public ScriptPass log("\n"); } - std::string top_opt, edif_file, blif_file, arch; - bool flatten, retime, vpr, nobram, nodram, nosrl; + std::string top_opt, edif_file, blif_file, family; + bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut; void clear_flags() YS_OVERRIDE { @@ -98,7 +105,9 @@ struct SynthXilinxPass : public ScriptPass nobram = false; nodram = false; nosrl = false; - arch = "xc7"; + nocarry = false; + nowidelut = false; + family = "xc7"; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -113,8 +122,8 @@ struct SynthXilinxPass : public ScriptPass top_opt = "-top " + args[++argidx]; continue; } - if (args[argidx] == "-arch" && argidx+1 < args.size()) { - arch = args[++argidx]; + if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) { + family = args[++argidx]; continue; } if (args[argidx] == "-edif" && argidx+1 < args.size()) { @@ -141,6 +150,14 @@ struct SynthXilinxPass : public ScriptPass retime = true; continue; } + if (args[argidx] == "-nocarry") { + nocarry = true; + continue; + } + if (args[argidx] == "-nowidelut") { + nowidelut = true; + continue; + } if (args[argidx] == "-vpr") { vpr = true; continue; @@ -161,8 +178,8 @@ struct SynthXilinxPass : public ScriptPass } extra_args(args, argidx, design); - if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s") - log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str()); + if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s") + log_cmd_error("Invalid Xilinx -family setting: %s\n", family.c_str()); if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); @@ -229,11 +246,6 @@ struct SynthXilinxPass : public ScriptPass run("dff2dffe"); run("opt -full"); - if (!vpr || help_mode) - run("techmap -map +/xilinx/arith_map.v"); - else - run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); - if (!nosrl || help_mode) { // shregmap operates on bit-level flops, not word-level, // so break those down here @@ -242,7 +254,15 @@ struct SynthXilinxPass : public ScriptPass run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')"); } - run("techmap"); + if (help_mode) + run("techmap -map +/techmap.v [-map +/xilinx/arith_map.v]", "(skip if '-nocarry')"); + else if (!nocarry) { + if (!vpr) + run("techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + else + run("techmap -map +/techmap.v -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); + } + run("opt -fast"); } @@ -253,7 +273,9 @@ struct SynthXilinxPass : public ScriptPass if (check_label("map_luts")) { if (help_mode) - run("abc -luts 2:2,3,6:5,10,20 [-dff]"); + run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(skip if 'nowidelut', only for '-retime')"); + else if (nowidelut) + run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); else run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); run("clean"); diff --git a/yosys/tests/aiger/.gitignore b/yosys/tests/aiger/.gitignore index 073f46157..9a26bb8f4 100644 --- a/yosys/tests/aiger/.gitignore +++ b/yosys/tests/aiger/.gitignore @@ -1,2 +1 @@ -*.log -*.out +/*_ref.v diff --git a/yosys/tests/aiger/and.aig b/yosys/tests/aiger/and.aig deleted file mode 100644 index da0fa0719..000000000 --- a/yosys/tests/aiger/and.aig +++ /dev/null @@ -1,3 +0,0 @@ -aig 3 2 0 1 1 -6 - \ No newline at end of file diff --git a/yosys/tests/aiger/and.aag b/yosys/tests/aiger/and_.aag similarity index 55% rename from yosys/tests/aiger/and.aag rename to yosys/tests/aiger/and_.aag index d1ef2c5a5..cadd505f0 100644 --- a/yosys/tests/aiger/and.aag +++ b/yosys/tests/aiger/and_.aag @@ -3,3 +3,6 @@ aag 3 2 0 1 1 4 6 6 2 4 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/yosys/tests/aiger/and_.aig b/yosys/tests/aiger/and_.aig new file mode 100644 index 000000000..13c7a0c17 --- /dev/null +++ b/yosys/tests/aiger/and_.aig @@ -0,0 +1,5 @@ +aig 3 2 0 1 1 +6 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/yosys/tests/aiger/buffer.aag b/yosys/tests/aiger/buffer.aag index 94a6fb1ed..211106ed6 100644 --- a/yosys/tests/aiger/buffer.aag +++ b/yosys/tests/aiger/buffer.aag @@ -1,3 +1,5 @@ aag 1 1 0 1 0 2 2 +i0 pi0 +o0 po0 diff --git a/yosys/tests/aiger/buffer.aig b/yosys/tests/aiger/buffer.aig index 0c715fdeb..01df6f1cf 100644 --- a/yosys/tests/aiger/buffer.aig +++ b/yosys/tests/aiger/buffer.aig @@ -1,2 +1,4 @@ aig 1 1 0 1 0 2 +i0 pi0 +o0 po0 diff --git a/yosys/tests/aiger/cnt1.aag b/yosys/tests/aiger/cnt1.aag index ce4f28fcb..75598862c 100644 --- a/yosys/tests/aiger/cnt1.aag +++ b/yosys/tests/aiger/cnt1.aag @@ -1,3 +1,4 @@ aag 1 0 1 0 0 1 2 3 2 +b0 po0 diff --git a/yosys/tests/aiger/cnt1.aig b/yosys/tests/aiger/cnt1.aig index 8d0ba13b1..6fcf62522 100644 --- a/yosys/tests/aiger/cnt1.aig +++ b/yosys/tests/aiger/cnt1.aig @@ -1,3 +1,4 @@ aig 1 0 1 0 0 1 3 2 +b0 po0 diff --git a/yosys/tests/aiger/cnt1e.aag b/yosys/tests/aiger/cnt1e.aag index 6db3f0ffd..35cd5a482 100644 --- a/yosys/tests/aiger/cnt1e.aag +++ b/yosys/tests/aiger/cnt1e.aag @@ -6,3 +6,4 @@ aag 5 1 1 0 3 1 8 4 2 10 9 7 b0 AIGER_NEVER +i0 po0 diff --git a/yosys/tests/aiger/cnt1e.aig b/yosys/tests/aiger/cnt1e.aig index d8d159f11..7284dd42a 100644 --- a/yosys/tests/aiger/cnt1e.aig +++ b/yosys/tests/aiger/cnt1e.aig @@ -1,4 +1,5 @@ aig 5 1 1 0 3 1 10 4 -b0 AIGER_NEVER +i0 po0 +b0 AIGER_NEVER diff --git a/yosys/tests/aiger/false.aag b/yosys/tests/aiger/false.aag index 421e64a91..bab4a06a6 100644 --- a/yosys/tests/aiger/false.aag +++ b/yosys/tests/aiger/false.aag @@ -1,2 +1,3 @@ aag 0 0 0 1 0 0 +o0 po0 diff --git a/yosys/tests/aiger/false.aig b/yosys/tests/aiger/false.aig index ad7d039fa..4dc442d7b 100644 --- a/yosys/tests/aiger/false.aig +++ b/yosys/tests/aiger/false.aig @@ -1,2 +1,3 @@ aig 0 0 0 1 0 0 +o0 po0 diff --git a/yosys/tests/aiger/inverter.aag b/yosys/tests/aiger/inverter.aag index ff7c28542..428bad9e4 100644 --- a/yosys/tests/aiger/inverter.aag +++ b/yosys/tests/aiger/inverter.aag @@ -1,3 +1,5 @@ aag 1 1 0 1 0 2 3 +i0 pi0 +o0 po0 diff --git a/yosys/tests/aiger/inverter.aig b/yosys/tests/aiger/inverter.aig index 525d82392..5bec90ae3 100644 --- a/yosys/tests/aiger/inverter.aig +++ b/yosys/tests/aiger/inverter.aig @@ -1,2 +1,4 @@ aig 1 1 0 1 0 3 +i0 pi0 +o0 po0 diff --git a/yosys/tests/aiger/notcnt1e.aag b/yosys/tests/aiger/notcnt1e.aag index 141c864f7..2ed645d84 100644 --- a/yosys/tests/aiger/notcnt1e.aag +++ b/yosys/tests/aiger/notcnt1e.aag @@ -6,3 +6,4 @@ aag 5 1 1 0 3 1 8 4 2 10 9 7 b0 AIGER_NEVER +i0 pi0 diff --git a/yosys/tests/aiger/notcnt1e.aig b/yosys/tests/aiger/notcnt1e.aig index 7c85a7290..fd7e94508 100644 --- a/yosys/tests/aiger/notcnt1e.aig +++ b/yosys/tests/aiger/notcnt1e.aig @@ -1,4 +1,5 @@ aig 5 1 1 0 3 1 10 5 -b0 AIGER_NEVER +i0 pi0 +b0 AIGER_NEVER diff --git a/yosys/tests/aiger/or.aig b/yosys/tests/aiger/or.aig deleted file mode 100644 index 75c9e4480..000000000 --- a/yosys/tests/aiger/or.aig +++ /dev/null @@ -1,3 +0,0 @@ -aig 3 2 0 1 1 -7 - \ No newline at end of file diff --git a/yosys/tests/aiger/or.aag b/yosys/tests/aiger/or_.aag similarity index 55% rename from yosys/tests/aiger/or.aag rename to yosys/tests/aiger/or_.aag index f780e339f..0f619dba3 100644 --- a/yosys/tests/aiger/or.aag +++ b/yosys/tests/aiger/or_.aag @@ -3,3 +3,6 @@ aag 3 2 0 1 1 4 7 6 3 5 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/yosys/tests/aiger/or_.aig b/yosys/tests/aiger/or_.aig new file mode 100644 index 000000000..051687512 --- /dev/null +++ b/yosys/tests/aiger/or_.aig @@ -0,0 +1,5 @@ +aig 3 2 0 1 1 +7 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/yosys/tests/aiger/run-test.sh b/yosys/tests/aiger/run-test.sh index e0a34f023..deaf48a3d 100755 --- a/yosys/tests/aiger/run-test.sh +++ b/yosys/tests/aiger/run-test.sh @@ -1,24 +1,54 @@ #!/bin/bash +set -e + OPTIND=1 -seed="" # default to no seed specified -while getopts "S:" opt +abcprog="../../yosys-abc" # default to built-in version of abc +while getopts "A:" opt do case "$opt" in - S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space - seed="SEED=$arg" ;; + A) abcprog="$OPTARG" ;; esac done shift "$((OPTIND-1))" -# check for Icarus Verilog -if ! which iverilog > /dev/null ; then - echo "$0: Error: Icarus Verilog 'iverilog' not found." - exit 1 -fi +# NB: *.aag and *.aig must contain a symbol table naming the primary +# inputs and outputs, otherwise ABC and Yosys will name them +# arbitrarily (and inconsistently with each other). -echo "===== AAG ======" -${MAKE:-make} -f ../tools/autotest.mk $seed *.aag EXTRA_FLAGS="-f aiger" +for aag in *.aag; do + # Since ABC cannot read *.aag, read the *.aig instead + # (which would have been created by the reference aig2aig utility, + # available from http://fmv.jku.at/aiger/) + echo "Checking $aag." + $abcprog -q "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v" + ../../yosys -qp " +read_verilog ${aag%.*}_ref.v +prep +design -stash gold +read_aiger -clk_name clock $aag +prep +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports -seq 16 miter +" +done -echo "===== AIG ======" -exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.aig EXTRA_FLAGS="-f aiger" +for aig in *.aig; do + echo "Checking $aig." + $abcprog -q "read -c $aig; write ${aig%.*}_ref.v" + ../../yosys -qp " +read_verilog ${aig%.*}_ref.v +prep +design -stash gold +read_aiger -clk_name clock $aig +prep +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports -seq 16 miter +" +done diff --git a/yosys/tests/aiger/toggle.aag b/yosys/tests/aiger/toggle.aag index 09651012d..b1a1582d7 100644 --- a/yosys/tests/aiger/toggle.aag +++ b/yosys/tests/aiger/toggle.aag @@ -2,3 +2,5 @@ aag 1 0 1 2 0 2 3 2 3 +o0 po0 +o1 po1 diff --git a/yosys/tests/aiger/toggle.aig b/yosys/tests/aiger/toggle.aig index b69e21aaf..68b41763f 100644 --- a/yosys/tests/aiger/toggle.aig +++ b/yosys/tests/aiger/toggle.aig @@ -2,3 +2,5 @@ aig 1 0 1 2 0 3 2 3 +o0 po0 +o1 po1 diff --git a/yosys/tests/aiger/true.aag b/yosys/tests/aiger/true.aag index 366893648..66a9eab46 100644 --- a/yosys/tests/aiger/true.aag +++ b/yosys/tests/aiger/true.aag @@ -1,2 +1,3 @@ aag 0 0 0 1 0 1 +o0 po0 diff --git a/yosys/tests/aiger/true.aig b/yosys/tests/aiger/true.aig index 10086f389..f9bad6000 100644 --- a/yosys/tests/aiger/true.aig +++ b/yosys/tests/aiger/true.aig @@ -1,2 +1,3 @@ aig 0 0 0 1 0 1 +o0 po0 diff --git a/yosys/tests/arch/run-test.sh b/yosys/tests/arch/run-test.sh new file mode 100755 index 000000000..5292d1615 --- /dev/null +++ b/yosys/tests/arch/run-test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +echo "Running syntax check on arch sim models" +for arch in ../../techlibs/*; do + find $arch -name cells_sim.v | while read path; do + echo -n "Test $path ->" + iverilog -t null -I$arch $path + echo " ok" + done +done + +for path in "../../techlibs/common/simcells.v" "../../techlibs/common/simlib.v"; do + echo -n "Test $path ->" + iverilog -t null $path + echo " ok" +done diff --git a/yosys/tests/memories/issue00335.v b/yosys/tests/memories/issue00335.v new file mode 100644 index 000000000..f3b6e5dfe --- /dev/null +++ b/yosys/tests/memories/issue00335.v @@ -0,0 +1,28 @@ +// expect-wr-ports 1 +// expect-rd-ports 1 +// expect-rd-clk \clk + +module ram2 (input clk, + input sel, + input we, + input [SIZE-1:0] adr, + input [63:0] dat_i, + output reg [63:0] dat_o); + parameter SIZE = 5; // Address size + + reg [63:0] mem [0:(1 << SIZE)-1]; + integer i; + + initial begin + for (i = 0; i < (1<= 0; i = i-1) begin + assign o[i] = 1'b0; + end +endgenerate +endmodule diff --git a/yosys/tests/simple/implicit_ports.v b/yosys/tests/simple/implicit_ports.v new file mode 100644 index 000000000..8b0a6f386 --- /dev/null +++ b/yosys/tests/simple/implicit_ports.v @@ -0,0 +1,16 @@ +// Test implicit port connections +module alu (input [2:0] a, input [2:0] b, input cin, output cout, output [2:0] result); + assign cout = cin; + assign result = a + b; +endmodule + +module named_ports(input [2:0] a, b, output [2:0] alu_result, output cout); + wire cin = 1; + alu alu ( + .a(a), + .b, // Implicit connection is equivalent to .b(b) + .cin(), // Explicitely unconnected + .cout(cout), + .result(alu_result) + ); +endmodule diff --git a/yosys/tests/simple/peepopt.v b/yosys/tests/simple/peepopt.v index b27b9fe57..1bf427897 100644 --- a/yosys/tests/simple/peepopt.v +++ b/yosys/tests/simple/peepopt.v @@ -2,6 +2,10 @@ module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, in assign o = i[s*W+:W]; endmodule +module peepopt_shiftmul_1 (output y, input [2:0] w); +assign y = 1'b1 >> (w * (3'b110)); +endmodule + module peepopt_muldiv_0(input [1:0] i, output [1:0] o); wire [3:0] t; assign t = i * 3; diff --git a/yosys/tests/simple/run-test.sh b/yosys/tests/simple/run-test.sh index aaa1cf940..967ac49f2 100755 --- a/yosys/tests/simple/run-test.sh +++ b/yosys/tests/simple/run-test.sh @@ -17,4 +17,5 @@ if ! which iverilog > /dev/null ; then exit 1 fi -exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v +shopt -s nullglob +exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.{sv,v} diff --git a/yosys/tests/simple/wandwor.v b/yosys/tests/simple/wandwor.v new file mode 100644 index 000000000..34404aa26 --- /dev/null +++ b/yosys/tests/simple/wandwor.v @@ -0,0 +1,36 @@ +module wandwor_test0 (A, B, C, D, X, Y, Z); + input A, B, C, D; + output wor X; + output wand Y; + output Z; + + assign X = A, X = B, Y = C, Y = D; + foo foo_0 (C, D, X); + foo foo_1 (A, B, Y); + foo foo_2 (X, Y, Z); +endmodule + +module wandwor_test1 (A, B, C, D, X, Y, Z); + input [3:0] A, B, C, D; + output wor [3:0] X; + output wand [3:0] Y; + output Z; + + bar bar_inst ( + .I0({A, B}), + .I1({B, A}), + .O({X, Y}) + ); + + assign X = C, X = D; + assign Y = C, Y = D; + assign Z = ^{X,Y}; +endmodule + +module foo(input I0, I1, output O); + assign O = I0 ^ I1; +endmodule + +module bar(input [7:0] I0, I1, output [7:0] O); + assign O = I0 + I1; +endmodule diff --git a/yosys/tests/tools/autotest.sh b/yosys/tests/tools/autotest.sh index 920474a84..4d3478628 100755 --- a/yosys/tests/tools/autotest.sh +++ b/yosys/tests/tools/autotest.sh @@ -23,12 +23,13 @@ warn_iverilog_git=false # The tests are skipped if firrtl2verilog is the empty string (the default). firrtl2verilog="" xfirrtl="../xfirrtl" +abcprog="$toolsdir/../../yosys-abc" if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 fi -while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do +while getopts xmGl:wkjvref:s:p:n:S:I:A:-: opt; do case "$opt" in x) use_xsim=true ;; @@ -65,6 +66,8 @@ while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do include_opts="$include_opts -I $OPTARG" xinclude_opts="$xinclude_opts -i $OPTARG" minclude_opts="$minclude_opts +incdir+$OPTARG" ;; + A) + abcprog="$OPTARG" ;; -) case "${OPTARG}" in xfirrtl) @@ -89,6 +92,12 @@ done compile_and_run() { exe="$1"; output="$2"; shift 2 + if [ "${2##*.}" == "sv" ]; then + language_gen="-g2012" + else + language_gen="-g2005" + fi + if $use_modelsim; then altver=$( ls -v /opt/altera/ | grep '^[0-9]' | tail -n1; ) /opt/altera/$altver/modelsim_ase/bin/vlib work @@ -99,7 +108,7 @@ compile_and_run() { /opt/Xilinx/Vivado/$xilver/bin/xvlog $xinclude_opts -d outfile=\"$output\" "$@" /opt/Xilinx/Vivado/$xilver/bin/xelab -R work.testbench else - iverilog $include_opts -Doutfile=\"$output\" -s testbench -o "$exe" "$@" + iverilog $language_gen $include_opts -Doutfile=\"$output\" -s testbench -o "$exe" "$@" vvp -n "$exe" fi } @@ -110,7 +119,7 @@ for fn do bn=${fn%.*} ext=${fn##*.} - if [[ "$ext" != "v" ]] && [[ "$ext" != "aag" ]] && [[ "$ext" != "aig" ]]; then + if [[ "$ext" != "v" ]] && [[ "$ext" != "sv" ]] && [[ "$ext" != "aag" ]] && [[ "$ext" != "aig" ]]; then echo "Invalid argument: $fn" >&2 exit 1 fi @@ -123,6 +132,10 @@ do echo -n "Test: $bn " fi + if [ "$ext" == sv ]; then + frontend="$frontend -sv" + fi + rm -f ${bn}.{err,log,skip} mkdir -p ${bn}.out rm -rf ${bn}.out/* @@ -131,22 +144,25 @@ do cd ${bn}.out fn=$(basename $fn) bn=$(basename $bn) + refext=v rm -f ${bn}_ref.fir if [[ "$ext" == "v" ]]; then egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext} + elif [[ "$ext" == "aig" ]] || [[ "$ext" == "aag" ]]; then + $abcprog -c "read_aiger ../${fn}; write ${bn}_ref.${refext}" else - "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn} - frontend="verilog -noblackbox" + refext=$ext + cp ../${fn} ${bn}_ref.${refext} fi if [ ! -f ../${bn}_tb.v ]; then - "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v + "$toolsdir"/../../yosys -f "$frontend $include_opts -D_AUTOTB" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.${refext} else cp ../${bn}_tb.v ${bn}_tb.v fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi - compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \ + compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} $libs \ "$toolsdir"/../../techlibs/common/simlib.v \ "$toolsdir"/../../techlibs/common/simcells.v if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi @@ -163,25 +179,25 @@ do test_count=$(( test_count + 1 )) } - if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.v; then + if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.${refext}; then touch ../${bn}.skip return fi if [ -n "$scriptfiles" ]; then - test_passes -f "$frontend $include_opts" ${bn}_ref.v $scriptfiles + test_passes -f "$frontend $include_opts" ${bn}_ref.${refext} $scriptfiles elif [ -n "$scriptopt" ]; then - test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.v + test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.${refext} elif [ "$frontend" = "verific" ]; then - test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -all; opt; memory;;" + test_passes -p "verific -vlog2k ${bn}_ref.${refext}; verific -import -all; opt; memory;;" elif [ "$frontend" = "verific_gates" ]; then - test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -gates -all; opt; memory;;" + test_passes -p "verific -vlog2k ${bn}_ref.${refext}; verific -import -gates -all; opt; memory;;" else - test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v - test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v + test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.${refext} + test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.${refext} if [ -n "$firrtl2verilog" ]; then if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then - "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v + "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.${refext} $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v fi diff --git a/yosys/tests/various/.gitignore b/yosys/tests/various/.gitignore index 397b4a762..7b3e8c68e 100644 --- a/yosys/tests/various/.gitignore +++ b/yosys/tests/various/.gitignore @@ -1 +1,2 @@ -*.log +/*.log +/*.out diff --git a/yosys/tests/various/attrib05_port_conn.v b/yosys/tests/various/attrib05_port_conn.v new file mode 100644 index 000000000..e20e66319 --- /dev/null +++ b/yosys/tests/various/attrib05_port_conn.v @@ -0,0 +1,21 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output reg out; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= ~inp; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance ( (* clock_connected *) clk, rst, (* this_is_the_input *) inp, out); +endmodule + diff --git a/yosys/tests/various/attrib05_port_conn.ys b/yosys/tests/various/attrib05_port_conn.ys new file mode 100644 index 000000000..27a016733 --- /dev/null +++ b/yosys/tests/various/attrib05_port_conn.ys @@ -0,0 +1,2 @@ +# Read and parse Verilog file +read_verilog attrib05_port_conn.v diff --git a/yosys/tests/various/attrib07_func_call.v b/yosys/tests/various/attrib07_func_call.v new file mode 100644 index 000000000..f55ef2316 --- /dev/null +++ b/yosys/tests/various/attrib07_func_call.v @@ -0,0 +1,21 @@ +function [7:0] do_add; + input [7:0] inp_a; + input [7:0] inp_b; + + do_add = inp_a + inp_b; + +endfunction + +module foo(clk, rst, inp_a, inp_b, out); + input wire clk; + input wire rst; + input wire [7:0] inp_a; + input wire [7:0] inp_b; + output wire [7:0] out; + + always @(posedge clk) + if (rst) out <= 0; + else out <= do_add (* combinational_adder *) (inp_a, inp_b); + +endmodule + diff --git a/yosys/tests/various/attrib07_func_call.ys b/yosys/tests/various/attrib07_func_call.ys new file mode 100644 index 000000000..774827651 --- /dev/null +++ b/yosys/tests/various/attrib07_func_call.ys @@ -0,0 +1,2 @@ +# Read and parse Verilog file +read_verilog attrib07_func_call.v diff --git a/yosys/tests/various/elab_sys_tasks.sv b/yosys/tests/various/elab_sys_tasks.sv new file mode 100644 index 000000000..774d85b32 --- /dev/null +++ b/yosys/tests/various/elab_sys_tasks.sv @@ -0,0 +1,30 @@ +module test; +localparam X=1; +genvar i; +generate +if (X == 1) + $info("X is 1"); +if (X == 1) + $warning("X is 1"); +else + $error("X is not 1"); +case (X) + 1: $info("X is 1 in a case statement"); +endcase +//case (X-1) +// 1: $warn("X is 2"); +// default: $warn("X might be anything in a case statement"); +//endcase +for (i = 0; i < 3; i = i + 1) +begin + case(i) + 0: $info; + 1: $warning; + default: $info("default case statemnent"); + endcase +end + +$info("This is a standalone $info(). Next $info has no parameters"); +$info; +endgenerate +endmodule diff --git a/yosys/tests/various/elab_sys_tasks.ys b/yosys/tests/various/elab_sys_tasks.ys new file mode 100644 index 000000000..45bee3a60 --- /dev/null +++ b/yosys/tests/various/elab_sys_tasks.ys @@ -0,0 +1 @@ +read_verilog -sv elab_sys_tasks.sv diff --git a/yosys/tests/various/muxcover.ys b/yosys/tests/various/muxcover.ys index 7ac460f13..67e9625e6 100644 --- a/yosys/tests/various/muxcover.ys +++ b/yosys/tests/various/muxcover.ys @@ -13,7 +13,7 @@ read_verilog -formal < (Q : D)) = (1, 2:3:4); +`ifndef SKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS + if (EN) (posedge CLK *> (Q : D)) = (1, 2:3:4); $setup(D, posedge CLK &&& EN, 5); $hold(posedge CLK, D &&& EN, 6); +`endif endspecify endmodule @@ -28,3 +30,10 @@ module test2 ( (B => Q) = 1.5; endspecify endmodule + +module issue01144(input clk, d, output q); +specify + (posedge clk => (q +: d)) = (3,1); + (posedge clk *> (q +: d)) = (3,1); +endspecify +endmodule diff --git a/yosys/tests/various/specify.ys b/yosys/tests/various/specify.ys index a5ca07219..00597e1e2 100644 --- a/yosys/tests/various/specify.ys +++ b/yosys/tests/various/specify.ys @@ -54,3 +54,5 @@ equiv_struct equiv_induct -seq 5 equiv_status -assert design -reset + +read_verilog -DSKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS specify.v